diff --git a/config/cycle.php b/config/cycle.php
index dc12c89b..ad306524 100644
--- a/config/cycle.php
+++ b/config/cycle.php
@@ -324,4 +324,25 @@
'entityBehavior' => [
'register' => env('CYCLE_REGISTER_ENTITY_BEHAVIOUR', true),
],
+
+ 'integrations' => [
+ /*
+ * Enables migration generation for Laravel Queues
+ */
+ 'queue' => [
+ 'enabled' => env('CYCLE_ADAPTER_QUEUE_INTEGRATION', true),
+ ],
+ /*
+ * Enables migration generation for Laravel Sessions
+ */
+ 'session' => [
+ 'enabled' => env('CYCLE_ADAPTER_SESSION_INTEGRATION', true),
+ ],
+ /*
+ * Enables migration generation for Laravel Cache
+ */
+ 'cache' => [
+ 'enabled' => env('CYCLE_ADAPTER_CACHE_INTEGRATION', true),
+ ],
+ ],
];
diff --git a/docs/pages/services/_meta.json b/docs/pages/services/_meta.json
index f890979f..351d8080 100644
--- a/docs/pages/services/_meta.json
+++ b/docs/pages/services/_meta.json
@@ -4,5 +4,8 @@
"testing": "Testing",
"validation": "Validation",
"pagination": "Pagination",
+ "sessions": "Sessions",
+ "queue": "Queue",
+ "cache": "Cache",
"laravel-telescope": "Laravel Telescope"
}
diff --git a/docs/pages/services/cache.mdx b/docs/pages/services/cache.mdx
new file mode 100644
index 00000000..d423f065
--- /dev/null
+++ b/docs/pages/services/cache.mdx
@@ -0,0 +1 @@
+# Cache
diff --git a/docs/pages/services/laravel-telescope.mdx b/docs/pages/services/laravel-telescope.mdx
index 35e45c98..526194f0 100644
--- a/docs/pages/services/laravel-telescope.mdx
+++ b/docs/pages/services/laravel-telescope.mdx
@@ -21,7 +21,19 @@ Install, telescope as usual, via Composer package manager:
composer require laravel/telescope
```
-### Step 2: Publish Telescope Assets
+### Step 2: Add .env Configuration
+
+Add the following configuration to your `.env` file:
+
+```dotenv filename=".env"
+...
+
+DB_USE_TELESCOPE_LOGGER=true
+
+...
+```
+
+### Step 3: Publish Telescope Assets
After installing Telescope, publish its assets and migrations using the `telescope:install` Artisan command.
@@ -29,25 +41,10 @@ After installing Telescope, publish its assets and migrations using the `telesco
php artisan telescope:install
```
-### Step 3: Run Telescope Migrations trough Cycle-ORM-Adapter
+### Step 4: Run Telescope Migrations trough Cycle-ORM-Adapter
After installing Telescope, you should also run the migrate command in order to create the tables needed to store Telescope's data, but as you are using Cycle ORM, you should avoid using default `php artisan migrate` command, and instead, do the following steps:
-Edit `config/cycle.php` file and add the following code to the `tokenizer.directories` array:
-
-```php {7} filename="config/cycle.php"
-return [
- // ...
- 'tokenizer' => [
- // ...
- 'directories' => [
- app_path(),
- __DIR__ . '/../vendor/wayofdev/laravel-cycle-orm-adapter/src/Bridge/Telescope/Entities',
- ],
- ],
-],
-```
-
Run the following command to create the Telescope tables:
```bash
@@ -56,8 +53,7 @@ php artisan cycle:migrate:init
php artisan cycle:orm:migrate --split --run
```
-
-### Step 4: Add the CycleORM Query Watcher
+### Step 5: Add the CycleORM Query Watcher
Next, edit your `config/telescope.php` configuration file and add the following lines to the `watchers` array, right after the default`Watchers\QueryWatcher::class` line:
@@ -85,18 +81,6 @@ return [
];
```
-### Step 5: Add .env Configuration
-
-Add the following configuration to your `.env` file:
-
-```dotenv filename=".env"
-...
-
-DB_USE_TELESCOPE_LOGGER=true
-
-...
-```
-
### Step 6: Access Laravel Telescope
Finally, you may access the Telescope dashboard via the `/telescope` route. Of course, don't forget to start your Laravel application:
diff --git a/docs/pages/services/pagination.mdx b/docs/pages/services/pagination.mdx
index 2d787769..88a8d2a2 100644
--- a/docs/pages/services/pagination.mdx
+++ b/docs/pages/services/pagination.mdx
@@ -8,12 +8,68 @@ Pagination is provided by external package [wayofdev/laravel-paginator](https://
composer require wayofdev/laravel-paginator
```
-## Usage
+## Usage with Repositories
### Step 1: Define `paginate()` method in your Repository
-@todo
+Create a `paginate()` method in your abstract repository class that will return a `CyclePaginator` instance.
+
+```php filename="app/Infrastructure/Persistence/Cycle/Repository.php"
+ $select
+ */
+ public function __construct(
+ protected Select $select,
+ protected EntityManagerInterface $entityManager
+ ) {
+ parent::__construct($select);
+ }
+
+ // ...
+
+ public function paginate(int $perPage = 20, int $page = 1, string $pageName = 'page'): CyclePaginator
+ {
+ return $this->paginateQuery(
+ $this->select(),
+ $perPage,
+ $page,
+ $pageName,
+ );
+ }
+
+ protected function paginateQuery(Select $query, int $perPage = 20, int $page = 1, string $pageName = 'page'): CyclePaginator
+ {
+ return new CyclePaginator(
+ (new SpiralPaginator($perPage))->withPage($page)->paginate($query),
+ $this->createCollection($query->fetchAll()),
+ $pageName,
+ );
+ }
+
+ protected function createCollection(iterable $items): Collection
+ {
+ return new Collection($items);
+ }
+}
+```
diff --git a/docs/pages/services/queue.mdx b/docs/pages/services/queue.mdx
new file mode 100644
index 00000000..d095a2b0
--- /dev/null
+++ b/docs/pages/services/queue.mdx
@@ -0,0 +1 @@
+# Queue
diff --git a/docs/pages/services/sessions.mdx b/docs/pages/services/sessions.mdx
new file mode 100644
index 00000000..f185a0e7
--- /dev/null
+++ b/docs/pages/services/sessions.mdx
@@ -0,0 +1 @@
+# Sessions
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index b053275f..d1596566 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -13,6 +13,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/Bridge/Cache/Entities/Cache.php b/src/Bridge/Cache/Entities/Cache.php
new file mode 100644
index 00000000..8ea7a13f
--- /dev/null
+++ b/src/Bridge/Cache/Entities/Cache.php
@@ -0,0 +1,21 @@
+app->get(Repository::class);
+
+ $config->set('cycle.tokenizer.directories', array_merge(
+ $config->get('cycle.tokenizer.directories', []),
+ [__DIR__ . '/../Entities']
+ ));
+ }
+}
diff --git a/src/Bridge/Laravel/Providers/CycleServiceProvider.php b/src/Bridge/Laravel/Providers/CycleServiceProvider.php
index 5043b35c..3060f502 100644
--- a/src/Bridge/Laravel/Providers/CycleServiceProvider.php
+++ b/src/Bridge/Laravel/Providers/CycleServiceProvider.php
@@ -10,9 +10,13 @@
use Illuminate\Support\ServiceProvider;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
+use WayOfDev\Cycle\Bridge\Cache\Providers\CacheServiceProvider;
use WayOfDev\Cycle\Bridge\Laravel\Console\Commands\Database;
use WayOfDev\Cycle\Bridge\Laravel\Console\Commands\Migrations;
use WayOfDev\Cycle\Bridge\Laravel\Console\Commands\ORM;
+use WayOfDev\Cycle\Bridge\Queue\Providers\QueueServiceProvider;
+use WayOfDev\Cycle\Bridge\Session\Providers\SessionServiceProvider;
+use WayOfDev\Cycle\Bridge\Telescope\Providers\TelescopeServiceProvider;
final class CycleServiceProvider extends ServiceProvider
{
@@ -65,6 +69,24 @@ public function register(): void
foreach ($registrators as $registrator) {
(new $registrator())($this->app);
}
+
+ $this->registerIntegrations();
+ }
+
+ private function registerIntegrations(): void
+ {
+ $services = [
+ 'cycle.integrations.session.enabled' => SessionServiceProvider::class,
+ 'cycle.integrations.cache.enabled' => CacheServiceProvider::class,
+ 'cycle.integrations.queue.enabled' => QueueServiceProvider::class,
+ 'cycle.database.logger.use_telescope' => TelescopeServiceProvider::class,
+ ];
+
+ foreach ($services as $configKey => $providerClass) {
+ if (config($configKey) === true) {
+ $this->app->register($providerClass);
+ }
+ }
}
private function registerConsoleCommands(): void
diff --git a/src/Bridge/Queue/Entities/FailedJob.php b/src/Bridge/Queue/Entities/FailedJob.php
new file mode 100644
index 00000000..de1e169b
--- /dev/null
+++ b/src/Bridge/Queue/Entities/FailedJob.php
@@ -0,0 +1,36 @@
+app->get(Repository::class);
+
+ $config->set('cycle.tokenizer.directories', array_merge(
+ $config->get('cycle.tokenizer.directories', []),
+ [__DIR__ . '/../Entities']
+ ));
+ }
+}
diff --git a/src/Bridge/Session/Entities/Session.php b/src/Bridge/Session/Entities/Session.php
new file mode 100644
index 00000000..901b65f5
--- /dev/null
+++ b/src/Bridge/Session/Entities/Session.php
@@ -0,0 +1,35 @@
+app->get(Repository::class);
+
+ $config->set('cycle.tokenizer.directories', array_merge(
+ $config->get('cycle.tokenizer.directories', []),
+ [__DIR__ . '/../Entities']
+ ));
+ }
+}
diff --git a/src/Bridge/Telescope/Providers/TelescopeServiceProvider.php b/src/Bridge/Telescope/Providers/TelescopeServiceProvider.php
new file mode 100644
index 00000000..55577305
--- /dev/null
+++ b/src/Bridge/Telescope/Providers/TelescopeServiceProvider.php
@@ -0,0 +1,30 @@
+app->get(Repository::class);
+
+ $config->set('cycle.tokenizer.directories', array_merge(
+ $config->get('cycle.tokenizer.directories', []),
+ [__DIR__ . '/../Entities']
+ ));
+ }
+}
diff --git a/tests/src/Bridge/Cache/Providers/CacheServiceProviderTest.php b/tests/src/Bridge/Cache/Providers/CacheServiceProviderTest.php
new file mode 100644
index 00000000..1b1cb098
--- /dev/null
+++ b/tests/src/Bridge/Cache/Providers/CacheServiceProviderTest.php
@@ -0,0 +1,42 @@
+artisanCall('cache:clear');
+ $this->refreshApplication();
+
+ $this::assertFalse($this->app->providerIsLoaded(CacheServiceProvider::class));
+
+ $this->assertConsoleCommandOutputDoesNotContainStrings('cycle:orm:render', ['--no-color' => true], [
+ '[cache] :: default.cache',
+ '[cacheLock] :: default.cache_locks',
+ 'Entity: WayOfDev\Cycle\Bridge\Cache\Entities\Cache',
+ 'Entity: WayOfDev\Cycle\Bridge\Cache\Entities\CacheLock',
+ ]);
+ }
+
+ #[Test]
+ public function it_generates_migration_when_enabled(): void
+ {
+ $this->app->register(CacheServiceProvider::class);
+
+ $this::assertTrue($this->app->providerIsLoaded(CacheServiceProvider::class));
+ $this->assertConsoleCommandOutputContainsStrings('cycle:orm:render', ['--no-color' => true], [
+ '[cache] :: default.cache',
+ '[cacheLock] :: default.cache_locks',
+ 'Entity: WayOfDev\Cycle\Bridge\Cache\Entities\Cache',
+ 'Entity: WayOfDev\Cycle\Bridge\Cache\Entities\CacheLock',
+ ]);
+ }
+}
diff --git a/tests/src/Bridge/Laravel/Providers/CycleServiceProviderTest.php b/tests/src/Bridge/Laravel/Providers/CycleServiceProviderTest.php
index 1c167657..4ae512d9 100644
--- a/tests/src/Bridge/Laravel/Providers/CycleServiceProviderTest.php
+++ b/tests/src/Bridge/Laravel/Providers/CycleServiceProviderTest.php
@@ -5,38 +5,35 @@
namespace WayOfDev\Tests\Bridge\Laravel\Providers;
use Cycle\Database\Config\DatabaseConfig;
+use Cycle\ORM\EntityManager;
use Cycle\ORM\EntityManagerInterface;
-use Psr\Container\ContainerExceptionInterface;
-use Psr\Container\NotFoundExceptionInterface;
+use PHPUnit\Framework\Attributes\Test;
use WayOfDev\Tests\TestCase;
class CycleServiceProviderTest extends TestCase
{
- /**
- * @test
- *
- * @throws ContainerExceptionInterface
- * @throws NotFoundExceptionInterface
- */
+ #[Test]
public function it_gets_database_config_from_container(): void
{
/** @var DatabaseConfig $config */
- $config = $this->app->get(DatabaseConfig::class);
+ $config = $this->app->make(DatabaseConfig::class);
self::assertArrayHasKey('default', $config->toArray());
self::assertArrayHasKey('databases', $config->toArray());
self::assertArrayHasKey('drivers', $config->toArray());
}
- /**
- * @test
- *
- * @throws ContainerExceptionInterface
- * @throws NotFoundExceptionInterface
- */
+ #[Test]
public function it_gets_entity_manager_instance_from_container(): void
{
- $manager = $this->app->get(EntityManagerInterface::class);
+ /** @var EntityManager|null $manager */
+ $manager = $this->app->make(EntityManagerInterface::class);
self::assertInstanceOf(EntityManagerInterface::class, $manager);
}
+
+ #[Test]
+ public function it_registers_configurations_correctly(): void
+ {
+ $this::assertNotNull(config('cycle'));
+ }
}
diff --git a/tests/src/Bridge/Queue/Providers/QueueServiceProviderTest.php b/tests/src/Bridge/Queue/Providers/QueueServiceProviderTest.php
new file mode 100644
index 00000000..6478a472
--- /dev/null
+++ b/tests/src/Bridge/Queue/Providers/QueueServiceProviderTest.php
@@ -0,0 +1,45 @@
+refreshApplication();
+
+ $this::assertFalse($this->app->providerIsLoaded(QueueServiceProvider::class));
+
+ $this->assertConsoleCommandOutputDoesNotContainStrings('cycle:orm:render', ['--no-color' => true], [
+ '[job] :: default.jobs',
+ '[failedJob] :: default.failed_jobs',
+ '[jobBatch] :: default.job_batches',
+ 'Entity: WayOfDev\Cycle\Bridge\Queue\Entities\Job',
+ 'Entity: WayOfDev\Cycle\Bridge\Queue\Entities\JobBatch',
+ 'Entity: WayOfDev\Cycle\Bridge\Queue\Entities\FailedJob',
+ ]);
+ }
+
+ #[Test]
+ public function it_generates_migration_when_enabled(): void
+ {
+ $this->app->register(QueueServiceProvider::class);
+
+ $this::assertTrue($this->app->providerIsLoaded(QueueServiceProvider::class));
+ $this->assertConsoleCommandOutputContainsStrings('cycle:orm:render', ['--no-color' => true], [
+ '[job] :: default.jobs',
+ '[failedJob] :: default.failed_jobs',
+ '[jobBatch] :: default.job_batches',
+ 'Entity: WayOfDev\Cycle\Bridge\Queue\Entities\Job',
+ 'Entity: WayOfDev\Cycle\Bridge\Queue\Entities\JobBatch',
+ 'Entity: WayOfDev\Cycle\Bridge\Queue\Entities\FailedJob',
+ ]);
+ }
+}
diff --git a/tests/src/Bridge/Session/Providers/SessionServiceProviderTest.php b/tests/src/Bridge/Session/Providers/SessionServiceProviderTest.php
new file mode 100644
index 00000000..26d2563b
--- /dev/null
+++ b/tests/src/Bridge/Session/Providers/SessionServiceProviderTest.php
@@ -0,0 +1,37 @@
+refreshApplication();
+
+ $this::assertFalse($this->app->providerIsLoaded(SessionServiceProvider::class));
+
+ $this->assertConsoleCommandOutputDoesNotContainStrings('cycle:orm:render', ['--no-color' => true], [
+ '[session] :: default.sessions',
+ 'Entity: WayOfDev\Cycle\Bridge\Session\Entities\Session',
+ ]);
+ }
+
+ #[Test]
+ public function it_generates_migration_when_enabled(): void
+ {
+ $this->app->register(SessionServiceProvider::class);
+
+ $this::assertTrue($this->app->providerIsLoaded(SessionServiceProvider::class));
+ $this->assertConsoleCommandOutputContainsStrings('cycle:orm:render', ['--no-color' => true], [
+ '[session] :: default.sessions',
+ 'Entity: WayOfDev\Cycle\Bridge\Session\Entities\Session',
+ ]);
+ }
+}
diff --git a/tests/src/Bridge/Telescope/Providers/TelescopeServiceProviderTest.php b/tests/src/Bridge/Telescope/Providers/TelescopeServiceProviderTest.php
new file mode 100644
index 00000000..3842446e
--- /dev/null
+++ b/tests/src/Bridge/Telescope/Providers/TelescopeServiceProviderTest.php
@@ -0,0 +1,45 @@
+refreshApplication();
+
+ $this::assertFalse($this->app->providerIsLoaded(TelescopeServiceProvider::class));
+
+ $this->assertConsoleCommandOutputDoesNotContainStrings('cycle:orm:render', ['--no-color' => true], [
+ '[telescopeEntry] :: default.telescope_entries',
+ '[telescopeEntryTag] :: default.telescope_entries_tags',
+ '[telescopeMonitoring] :: default.telescope_monitoring',
+ 'Entity: WayOfDev\Cycle\Bridge\Telescope\Entities\Telescope',
+ 'Entity: WayOfDev\Cycle\Bridge\Telescope\Entities\TelescopeEntryTag',
+ 'Entity: WayOfDev\Cycle\Bridge\Telescope\Entities\TelescopeMonitoring',
+ ]);
+ }
+
+ #[Test]
+ public function it_generates_migration_when_enabled(): void
+ {
+ $this->app->register(TelescopeServiceProvider::class);
+
+ $this::assertTrue($this->app->providerIsLoaded(TelescopeServiceProvider::class));
+ $this->assertConsoleCommandOutputContainsStrings('cycle:orm:render', ['--no-color' => true], [
+ '[telescopeEntry] :: default.telescope_entries',
+ '[telescopeEntryTag] :: default.telescope_entries_tags',
+ '[telescopeMonitoring] :: default.telescope_monitoring',
+ 'Entity: WayOfDev\Cycle\Bridge\Telescope\Entities\Telescope',
+ 'Entity: WayOfDev\Cycle\Bridge\Telescope\Entities\TelescopeEntryTag',
+ 'Entity: WayOfDev\Cycle\Bridge\Telescope\Entities\TelescopeMonitoring',
+ ]);
+ }
+}
diff --git a/tests/src/TestCase.php b/tests/src/TestCase.php
index cbd16abe..3fe042f6 100644
--- a/tests/src/TestCase.php
+++ b/tests/src/TestCase.php
@@ -53,7 +53,6 @@ protected function setUp(): void
'cycle.tokenizer.directories' => array_merge(
config('cycle.tokenizer.directories'),
[__DIR__ . '/../app/Entities'],
- // [__DIR__ . '/../../src/Bridge/Telescope/Entities'],
),
'cycle.migrations.directory' => $this->migrationsPath,
]);
@@ -73,28 +72,45 @@ public function artisanCall(string $command, array $parameters = [])
return $this->app[Kernel::class]->call($command, $parameters);
}
- protected function assertConsoleCommandOutputContainsStrings(
+ protected function assertConsoleCommandOutput(
string $command,
- array $args = [],
- array|string $strings = []
+ array $args,
+ $strings,
+ callable $assertionCallback
): void {
$this->artisanCall($command, $args);
$output = Artisan::output();
foreach ((array) $strings as $string) {
- $this::assertStringContainsString(
- $string,
- $output,
- sprintf(
- 'Console command [%s] with args [%s] does not contain string [%s]',
- $command,
- json_encode($args),
- $string
- )
- );
+ $assertionCallback($string, $output, sprintf(
+ 'Console command [%s] with args [%s] output assertion failed for string [%s]',
+ $command,
+ json_encode($args),
+ $string
+ ));
}
}
+ protected function assertConsoleCommandOutputContainsStrings(
+ string $command,
+ array $args = [],
+ $strings = []
+ ): void {
+ $this->assertConsoleCommandOutput($command, $args, $strings, function ($string, $output, $message): void {
+ $this::assertStringContainsString($string, $output, $message);
+ });
+ }
+
+ protected function assertConsoleCommandOutputDoesNotContainStrings(
+ string $command,
+ array $args = [],
+ $strings = []
+ ): void {
+ $this->assertConsoleCommandOutput($command, $args, $strings, function ($string, $output, $message): void {
+ $this::assertStringNotContainsString($string, $output, $message);
+ });
+ }
+
protected function getPackageProviders($app): array
{
return [