From 69d6c4312c830276d6993b845203374af26bff8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9=20Pearce?= Date: Mon, 22 Nov 2021 15:09:47 +0100 Subject: [PATCH 1/7] Refactor the create command --- ...ommand.php => CreateProjectionCommand.php} | 12 ++--- ...ctor.php.stub => KeyedProjection.php.stub} | 2 +- ...Projector.php.stub => Projection.php.stub} | 2 +- src/LaravelCargoServiceProvider.php | 4 +- ...st.php => CreateProjectionCommandTest.php} | 54 +++++++++---------- 5 files changed, 37 insertions(+), 37 deletions(-) rename src/Commands/{CreateProjectorCommand.php => CreateProjectionCommand.php} (78%) rename src/Commands/stubs/{KeyedProjector.php.stub => KeyedProjection.php.stub} (91%) rename src/Commands/stubs/{Projector.php.stub => Projection.php.stub} (89%) rename tests/Commands/{CreateProjectorCommandTest.php => CreateProjectionCommandTest.php} (57%) diff --git a/src/Commands/CreateProjectorCommand.php b/src/Commands/CreateProjectionCommand.php similarity index 78% rename from src/Commands/CreateProjectorCommand.php rename to src/Commands/CreateProjectionCommand.php index 81ad5bb..8ef105d 100644 --- a/src/Commands/CreateProjectorCommand.php +++ b/src/Commands/CreateProjectionCommand.php @@ -5,21 +5,21 @@ use Illuminate\Console\GeneratorCommand; use Symfony\Component\Console\Input\InputOption; -class CreateProjectorCommand extends GeneratorCommand +class CreateProjectionCommand extends GeneratorCommand { /** * The name of the console command. * * @var string */ - public $name = 'make:projector'; + public $name = 'make:projection'; /** * The console command description. * * @var string */ - public $description = 'Create a new projector class'; + public $description = 'Create a new projection model'; /** * Get the stub used for the file generation. @@ -27,8 +27,8 @@ class CreateProjectorCommand extends GeneratorCommand protected function getStub() { return $this->option('key') ? - __DIR__ . '/stubs/KeyedProjector.php.stub' : - __DIR__ . '/stubs/Projector.php.stub'; + __DIR__ . '/stubs/KeyedProjection.php.stub' : + __DIR__ . '/stubs/Projection.php.stub'; } /** @@ -36,7 +36,7 @@ protected function getStub() */ protected function getDefaultNamespace($rootNamespace) { - return $rootNamespace . '\Projectors'; + return $rootNamespace . '\Models\Projections'; } /** diff --git a/src/Commands/stubs/KeyedProjector.php.stub b/src/Commands/stubs/KeyedProjection.php.stub similarity index 91% rename from src/Commands/stubs/KeyedProjector.php.stub rename to src/Commands/stubs/KeyedProjection.php.stub index 18ca2fe..3fc5220 100644 --- a/src/Commands/stubs/KeyedProjector.php.stub +++ b/src/Commands/stubs/KeyedProjection.php.stub @@ -9,7 +9,7 @@ use Laravelcargo\LaravelCargo\Projector; class {{ class }} extends Projector { /** - * Lists the time intervals used to compute the projections. + * Lists the available periods. * * @var string[] */ diff --git a/src/Commands/stubs/Projector.php.stub b/src/Commands/stubs/Projection.php.stub similarity index 89% rename from src/Commands/stubs/Projector.php.stub rename to src/Commands/stubs/Projection.php.stub index 54b0429..86b232b 100644 --- a/src/Commands/stubs/Projector.php.stub +++ b/src/Commands/stubs/Projection.php.stub @@ -9,7 +9,7 @@ use Laravelcargo\LaravelCargo\Projector; class {{ class }} extends Projector { /** - * Lists the time intervals used to compute the projections. + * Lists the available periods. * * @var string[] */ diff --git a/src/LaravelCargoServiceProvider.php b/src/LaravelCargoServiceProvider.php index 0dd0185..44edae0 100644 --- a/src/LaravelCargoServiceProvider.php +++ b/src/LaravelCargoServiceProvider.php @@ -3,7 +3,7 @@ namespace Laravelcargo\LaravelCargo; use Illuminate\Support\ServiceProvider; -use Laravelcargo\LaravelCargo\Commands\CreateProjectorCommand; +use Laravelcargo\LaravelCargo\Commands\CreateProjectionCommand; class LaravelCargoServiceProvider extends ServiceProvider { @@ -22,7 +22,7 @@ public function boot() if ($this->app->runningInConsole()) { $this->commands([ - CreateProjectorCommand::class, + CreateProjectionCommand::class, ]); } } diff --git a/tests/Commands/CreateProjectorCommandTest.php b/tests/Commands/CreateProjectionCommandTest.php similarity index 57% rename from tests/Commands/CreateProjectorCommandTest.php rename to tests/Commands/CreateProjectionCommandTest.php index 4f9c35c..8553974 100644 --- a/tests/Commands/CreateProjectorCommandTest.php +++ b/tests/Commands/CreateProjectionCommandTest.php @@ -5,53 +5,53 @@ use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\File; -class CreateProjectorCommandTest extends TestCase +class CreateProjectionCommandTest extends TestCase { - protected string $projectorClassName; + protected string $projectionClassName; /** @test */ - public function it_creates_a_new_projector_file() + public function it_creates_a_new_projection_file() { - $projectorClass = app_path('Projectors/ProjectorClass.php'); + $projectionClass = app_path('Models/Projections/ProjectionClass.php'); - $this->assertMissingFile($projectorClass); + $this->assertMissingFile($projectionClass); - $this->createProjectorFile($projectorClass); + $this->createProjectionFile($projectionClass); - $this->assertProjectorFileContent($projectorClass); + $this->assertProjectorFileContent($projectionClass); } /** @test */ public function it_creates_a_new_projector_with_key_file() { - $projectorClass = app_path('Projectors/ProjectorClass.php'); + $projectionClass = app_path('Models/Projections/ProjectionClass.php'); - $this->assertMissingFile($projectorClass); + $this->assertMissingFile($projectionClass); - $this->createKeyedProjectorFile($projectorClass); + $this->createKeyedProjectionFile($projectionClass); - $this->assertKeyedProjectorFileContent($projectorClass); + $this->assertKeyedProjectionFileContent($projectionClass); } - private function assertMissingFile(string $projectorClass) + private function assertMissingFile(string $projectionClass) { - if (File::exists($projectorClass)) { - unlink($projectorClass); + if (File::exists($projectionClass)) { + unlink($projectionClass); } - $this->assertFalse(File::exists($projectorClass)); + $this->assertFalse(File::exists($projectionClass)); } - private function createProjectorFile(string $projectorClass) + private function createProjectionFile(string $projectionClass) { - Artisan::call('make:projector ProjectorClass'); + Artisan::call('make:projection ProjectionClass'); - $this->assertTrue(File::exists($projectorClass)); + $this->assertTrue(File::exists($projectionClass)); } - private function createKeyedProjectorFile(string $projectorClass) + private function createKeyedProjectionFile(string $projectorClass) { - Artisan::call('make:projector ProjectorClass --key'); + Artisan::call('make:projection ProjectionClass --key'); $this->assertTrue(File::exists($projectorClass)); } @@ -63,16 +63,16 @@ private function assertProjectorFileContent(string $projectorClass) $expectedContents = <<assertEquals($expectedContents, file_get_contents($projectorClass)); } - private function assertKeyedProjectorFileContent(string $projectorClass) + private function assertKeyedProjectionFileContent(string $projectorClass) { // Assert the file contains the right contents $expectedContents = << Date: Mon, 22 Nov 2021 17:02:27 +0100 Subject: [PATCH 2/7] Refactoring global structure and start fixing tests --- src/Commands/stubs/KeyedProjection.php.stub | 4 +-- src/Commands/stubs/Projection.php.stub | 4 +-- ...torContract.php => ProjectionContract.php} | 4 +-- src/Projector.php | 32 +++++++++++++------ src/WithProjections.php | 12 +++---- .../Commands/CreateProjectionCommandTest.php | 8 ++--- tests/Models/Log.php | 2 +- tests/Models/Message.php | 2 +- tests/ProjectionCollectionTest.php | 4 +-- tests/ProjectionTest.php | 18 +++++------ tests/Projectors/MultiplePeriodsProjector.php | 9 +++--- .../Projectors/SinglePeriodKeyedProjector.php | 9 +++--- tests/Projectors/SinglePeriodProjector.php | 9 +++--- .../SinglePeriodProjectorWithUniqueKey.php | 9 +++--- tests/WithProjectableFactory.php | 4 +-- tests/WithProjectionTest.php | 26 +++++++-------- 16 files changed, 86 insertions(+), 70 deletions(-) rename src/Contracts/{ProjectorContract.php => ProjectionContract.php} (71%) diff --git a/src/Commands/stubs/KeyedProjection.php.stub b/src/Commands/stubs/KeyedProjection.php.stub index 3fc5220..6a49692 100644 --- a/src/Commands/stubs/KeyedProjection.php.stub +++ b/src/Commands/stubs/KeyedProjection.php.stub @@ -4,9 +4,9 @@ namespace {{ namespace }}; use Illuminate\Database\Eloquent\Model; use Laravelcargo\LaravelCargo\Models\Projection; -use Laravelcargo\LaravelCargo\Projector; +use Laravelcargo\LaravelCargo\Contracts\ProjectionContract; -class {{ class }} extends Projector +class {{ class }} extends Projection implements ProjectionContract { /** * Lists the available periods. diff --git a/src/Commands/stubs/Projection.php.stub b/src/Commands/stubs/Projection.php.stub index 86b232b..fdea4e5 100644 --- a/src/Commands/stubs/Projection.php.stub +++ b/src/Commands/stubs/Projection.php.stub @@ -4,9 +4,9 @@ namespace {{ namespace }}; use Illuminate\Database\Eloquent\Model; use Laravelcargo\LaravelCargo\Models\Projection; -use Laravelcargo\LaravelCargo\Projector; +use Laravelcargo\LaravelCargo\Contracts\ProjectionContract; -class {{ class }} extends Projector +class {{ class }} extends Projection implements ProjectionContract { /** * Lists the available periods. diff --git a/src/Contracts/ProjectorContract.php b/src/Contracts/ProjectionContract.php similarity index 71% rename from src/Contracts/ProjectorContract.php rename to src/Contracts/ProjectionContract.php index c354b63..d28f01a 100644 --- a/src/Contracts/ProjectorContract.php +++ b/src/Contracts/ProjectionContract.php @@ -4,7 +4,7 @@ use Illuminate\Database\Eloquent\Model; -interface ProjectorContract +interface ProjectionContract { /** * The default projection content. @@ -14,5 +14,5 @@ public static function defaultContent(): array; /** * Compute the projection. */ - public function handle(array $content, Model $model): array; + public static function handle(array $content, Model $model): array; } diff --git a/src/Projector.php b/src/Projector.php index 94c25c8..4eae757 100644 --- a/src/Projector.php +++ b/src/Projector.php @@ -5,17 +5,18 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Carbon; use Illuminate\Support\Str; -use Laravelcargo\LaravelCargo\Contracts\ProjectorContract; use Laravelcargo\LaravelCargo\Models\Projection; +use ReflectionException; +use ReflectionProperty; -abstract class Projector implements ProjectorContract +class Projector { /** * Lists the time intervals used to compute the projections. */ protected array $periods; - public function __construct(protected Model $model) + public function __construct(protected Model $projectedModel, protected string $projectionName) { } @@ -29,10 +30,13 @@ public function key(Model $model): bool | int | string /** * Parses the periods defined as class attribute. + * @throws ReflectionException */ public function parsePeriods(): void { - collect($this->periods)->each(fn (string $period) => $this->parsePeriod($period)); + $periods = (new ReflectionProperty($this->projectionName, 'periods'))->getValue(); + + collect($periods)->each(fn (string $period) => $this->parsePeriod($period)); } /** @@ -56,7 +60,7 @@ private function findProjection(string $period, int $quantity, string $periodTyp { return Projection::firstWhere([ ['projector_name', $this::class], - ['key', $this->hasKey() ? $this->key($this->model) : null], + ['key', $this->hasKey() ? $this->key($this->projectedModel) : null], ['period', $period], ['start_date', Carbon::now()->floorUnit($periodType, $quantity)], ]); @@ -67,12 +71,12 @@ private function findProjection(string $period, int $quantity, string $periodTyp */ private function createProjection(string $period, int $quantity, string $periodType): void { - $this->model->projections()->create([ + $this->projectedModel->projections()->create([ 'projector_name' => $this::class, - 'key' => $this->hasKey() ? $this->key($this->model) : null, + 'key' => $this->hasKey() ? $this->key($this->projectedModel) : null, 'period' => $period, 'start_date' => Carbon::now()->floorUnit($periodType, $quantity), - 'content' => $this->handle($this::defaultContent(), $this->model), + 'content' => $this->getProjectedContent(), ]); } @@ -81,7 +85,7 @@ private function createProjection(string $period, int $quantity, string $periodT */ private function updateProjection(Projection $projection): void { - $projection->content = $this->handle($projection->content, $this->model); + $projection->content = $this->getProjectedContent(); $projection->save(); } @@ -91,6 +95,14 @@ private function updateProjection(Projection $projection): void */ private function hasKey(): bool { - return $this->key($this->model) !== false; + return $this->key($this->projectedModel) !== false; + } + + /** + * Get the projected content. + */ + private function getProjectedContent(): array + { + return $this->projectionName::handle($this->projectionName::defaultContent(), $this->projectedModel); } } diff --git a/src/WithProjections.php b/src/WithProjections.php index a12f01a..4b98f09 100644 --- a/src/WithProjections.php +++ b/src/WithProjections.php @@ -26,9 +26,9 @@ public static function bootWithProjections(): void */ public function bootProjectors(): void { - collect($this->projectors)->each( - fn (string $projector) => - (new $projector($this))->parsePeriods() + collect($this->projections)->each( + fn (string $projection) => + (new Projector($this, $projection))->parsePeriods() ); } @@ -61,7 +61,7 @@ public function projections( } /** - * Get the first projection + * Get the first projection. */ public function firstProjection( string | null $projectorName = null, @@ -73,8 +73,8 @@ public function firstProjection( /** * Set the projectors. */ - public function setProjectors(array $projectors) + public function setProjections(array $projections) { - $this->projectors = $projectors; + $this->projections = $projections; } } diff --git a/tests/Commands/CreateProjectionCommandTest.php b/tests/Commands/CreateProjectionCommandTest.php index 8553974..ac21057 100644 --- a/tests/Commands/CreateProjectionCommandTest.php +++ b/tests/Commands/CreateProjectionCommandTest.php @@ -66,10 +66,10 @@ private function assertProjectorFileContent(string $projectorClass) namespace App\Models\Projections; use Illuminate\Database\Eloquent\Model; +use Laravelcargo\LaravelCargo\Contracts\ProjectionContract; use Laravelcargo\LaravelCargo\Models\Projection; -use Laravelcargo\LaravelCargo\Projector; -class ProjectionClass extends Projector +class ProjectionClass extends Projection implements ProjectionContract { /** * Lists the available periods. @@ -110,10 +110,10 @@ private function assertKeyedProjectionFileContent(string $projectorClass) namespace App\Models\Projections; use Illuminate\Database\Eloquent\Model; +use Laravelcargo\LaravelCargo\Contracts\ProjectionContract; use Laravelcargo\LaravelCargo\Models\Projection; -use Laravelcargo\LaravelCargo\Projector; -class ProjectionClass extends Projector +class ProjectionClass extends Projection implements ProjectionContract { /** * Lists the available periods. diff --git a/tests/Models/Log.php b/tests/Models/Log.php index 053a42e..e31e44f 100644 --- a/tests/Models/Log.php +++ b/tests/Models/Log.php @@ -15,7 +15,7 @@ class Log extends Model /** * The lists of the projectors. */ - protected array $projectors = [SinglePeriodProjector::class]; + protected array $projections = [SinglePeriodProjector::class]; // /** // * API wip. diff --git a/tests/Models/Message.php b/tests/Models/Message.php index 64b6ab2..ec5ee9b 100644 --- a/tests/Models/Message.php +++ b/tests/Models/Message.php @@ -15,5 +15,5 @@ class Message extends Model /** * The lists of the projectors. */ - protected array $projectors = [SinglePeriodProjector::class]; + protected array $projections = [SinglePeriodProjector::class]; } diff --git a/tests/ProjectionCollectionTest.php b/tests/ProjectionCollectionTest.php index 023fa9a..ddf3233 100644 --- a/tests/ProjectionCollectionTest.php +++ b/tests/ProjectionCollectionTest.php @@ -107,7 +107,7 @@ public function it_raises_an_exception_when_a_multiple_projection_name_collectio { $this->expectException(MultipleProjectorsException::class); - $this->createModelWithProjectors(Log::class, [SinglePeriodProjector::class, MultiplePeriodsProjector::class]); + $this->createModelWithProjections(Log::class, [SinglePeriodProjector::class, MultiplePeriodsProjector::class]); /** @var ProjectionCollection $collection */ $collection = Projection::all(); @@ -125,7 +125,7 @@ public function it_raises_an_exception_when_a_multiple_periods_collection_is_fil { $this->expectException(MultiplePeriodsException::class); - $this->createModelWithProjectors(Log::class, [MultiplePeriodsProjector::class]); + $this->createModelWithProjections(Log::class, [MultiplePeriodsProjector::class]); /** @var ProjectionCollection $collection */ $collection = Projection::all(); diff --git a/tests/ProjectionTest.php b/tests/ProjectionTest.php index 4e5484d..d6b3508 100644 --- a/tests/ProjectionTest.php +++ b/tests/ProjectionTest.php @@ -45,8 +45,8 @@ public function it_has_a_relationship_with_the_model() /** @test */ public function it_get_the_projections_from_projector_name() { - $this->createModelWithProjectors(Log::class, [SinglePeriodProjector::class]); - $this->createModelWithProjectors(Log::class, [MultiplePeriodsProjector::class]); + $this->createModelWithProjections(Log::class, [SinglePeriodProjector::class]); + $this->createModelWithProjections(Log::class, [MultiplePeriodsProjector::class]); $numberOfProjections = Projection::fromProjector(SinglePeriodProjector::class)->count(); @@ -56,10 +56,10 @@ public function it_get_the_projections_from_projector_name() /** @test */ public function it_get_the_projections_from_a_single_period() { - $this->createModelWithProjectors(Log::class, [MultiplePeriodsProjector::class]); // 1 - $this->createModelWithProjectors(Log::class, [MultiplePeriodsProjector::class]); // 1 + $this->createModelWithProjections(Log::class, [MultiplePeriodsProjector::class]); // 1 + $this->createModelWithProjections(Log::class, [MultiplePeriodsProjector::class]); // 1 $this->travel(6)->minutes(); - $this->createModelWithProjectors(Log::class, [MultiplePeriodsProjector::class]); // 2 + $this->createModelWithProjections(Log::class, [MultiplePeriodsProjector::class]); // 2 $numberOfProjections = Projection::period('5 minutes')->count(); @@ -146,8 +146,8 @@ public function it_does_not_include_a_projection_with_a_start_date_equals_to_the /** @test */ public function it_get_the_projection_from_a_single_key() { - $log = $this->createModelWithProjectors(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); - $this->createModelWithProjectors(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); + $log = $this->createModelWithProjections(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); + $this->createModelWithProjections(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); $numberOfProjections = Projection::key($log->id)->count(); @@ -157,8 +157,8 @@ public function it_get_the_projection_from_a_single_key() /** @test */ public function it_get_the_projections_from_multiples_keys() { - $log = $this->createModelWithProjectors(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); - $anotherLog = $this->createModelWithProjectors(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); + $log = $this->createModelWithProjections(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); + $anotherLog = $this->createModelWithProjections(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); $numberOfProjections = Projection::key([$log->id, $anotherLog->id])->count(); diff --git a/tests/Projectors/MultiplePeriodsProjector.php b/tests/Projectors/MultiplePeriodsProjector.php index ba92ae9..19aceb9 100644 --- a/tests/Projectors/MultiplePeriodsProjector.php +++ b/tests/Projectors/MultiplePeriodsProjector.php @@ -3,14 +3,15 @@ namespace Laravelcargo\LaravelCargo\Tests\Projectors; use Illuminate\Database\Eloquent\Model; -use Laravelcargo\LaravelCargo\Projector; +use Laravelcargo\LaravelCargo\Models\Projection; +use Laravelcargo\LaravelCargo\Contracts\ProjectionContract; -class MultiplePeriodsProjector extends Projector +class MultiplePeriodsProjector extends Projection implements ProjectionContract { /** * Lists the time intervals used to compute the projections. */ - protected array $periods = [ + public static array $periods = [ '5 minutes', '1 hour', '6 hours', @@ -34,7 +35,7 @@ public static function defaultContent(): array /** * Compute the projection's content. */ - public function handle(array $content, Model $model): array + public static function handle(array $content, Model $model): array { return [ 'number of logs' => $content['number of logs'] + 1, diff --git a/tests/Projectors/SinglePeriodKeyedProjector.php b/tests/Projectors/SinglePeriodKeyedProjector.php index 75a9f07..b509d0a 100644 --- a/tests/Projectors/SinglePeriodKeyedProjector.php +++ b/tests/Projectors/SinglePeriodKeyedProjector.php @@ -3,14 +3,15 @@ namespace Laravelcargo\LaravelCargo\Tests\Projectors; use Illuminate\Database\Eloquent\Model; -use Laravelcargo\LaravelCargo\Projector; +use Laravelcargo\LaravelCargo\Contracts\ProjectionContract; +use Laravelcargo\LaravelCargo\Models\Projection; -class SinglePeriodKeyedProjector extends Projector +class SinglePeriodKeyedProjector extends Projection implements ProjectionContract { /** * Lists the time intervals used to compute the projections. */ - protected array $periods = ['5 minutes']; + public static array $periods = ['5 minutes']; /** * The default projection content. @@ -33,7 +34,7 @@ public function key(Model $model): string /** * Compute the projection. */ - public function handle(array $content, Model $model): array + public static function handle(array $content, Model $model): array { return [ 'number of logs' => $content['number of logs'] + 1, diff --git a/tests/Projectors/SinglePeriodProjector.php b/tests/Projectors/SinglePeriodProjector.php index 01dd9ee..866e62a 100644 --- a/tests/Projectors/SinglePeriodProjector.php +++ b/tests/Projectors/SinglePeriodProjector.php @@ -3,14 +3,15 @@ namespace Laravelcargo\LaravelCargo\Tests\Projectors; use Illuminate\Database\Eloquent\Model; -use Laravelcargo\LaravelCargo\Projector; +use Laravelcargo\LaravelCargo\Contracts\ProjectionContract; +use Laravelcargo\LaravelCargo\Models\Projection; -class SinglePeriodProjector extends Projector +class SinglePeriodProjector extends Projection implements ProjectionContract { /** * Lists the time intervals used to compute the projections. */ - protected array $periods = ['5 minutes']; + public static array $periods = ['5 minutes']; /** * The default projection content. @@ -25,7 +26,7 @@ public static function defaultContent(): array /** * Compute the projection. */ - public function handle(array $content, Model $model): array + public static function handle(array $content, Model $model): array { return [ 'number of logs' => $content['number of logs'] + 1, diff --git a/tests/Projectors/SinglePeriodProjectorWithUniqueKey.php b/tests/Projectors/SinglePeriodProjectorWithUniqueKey.php index f2671fd..e23a7b4 100644 --- a/tests/Projectors/SinglePeriodProjectorWithUniqueKey.php +++ b/tests/Projectors/SinglePeriodProjectorWithUniqueKey.php @@ -3,14 +3,15 @@ namespace Laravelcargo\LaravelCargo\Tests\Projectors; use Illuminate\Database\Eloquent\Model; -use Laravelcargo\LaravelCargo\Projector; +use Laravelcargo\LaravelCargo\Contracts\ProjectionContract; +use Laravelcargo\LaravelCargo\Models\Projection; -class SinglePeriodProjectorWithUniqueKey extends Projector +class SinglePeriodProjectorWithUniqueKey extends Projection implements ProjectionContract { /** * Lists the time intervals used to compute the projections. */ - protected array $periods = ['5 minutes']; + public static array $periods = ['5 minutes']; /** * The default projection content. @@ -33,7 +34,7 @@ public function key(Model $model): string /** * Compute the projection. */ - public function handle(array $content, Model $model): array + public static function handle(array $content, Model $model): array { return [ 'number of logs' => $content['number of logs'] + 1, diff --git a/tests/WithProjectableFactory.php b/tests/WithProjectableFactory.php index db00b50..9163492 100644 --- a/tests/WithProjectableFactory.php +++ b/tests/WithProjectableFactory.php @@ -9,11 +9,11 @@ trait WithProjectableFactory /** * Create the model with the given projectors. */ - public function createModelWithProjectors(string $modelName, array $projectors): Model + public function createModelWithProjections(string $modelName, array $projections): Model { $model = $modelName::factory()->make(); - $model->setProjectors($projectors); + $model->setProjections($projections); $model->save(); return $model; diff --git a/tests/WithProjectionTest.php b/tests/WithProjectionTest.php index 334e21e..5b5b84b 100644 --- a/tests/WithProjectionTest.php +++ b/tests/WithProjectionTest.php @@ -20,7 +20,7 @@ class WithProjectionTest extends TestCase /** @test */ public function it_creates_a_projection_for_each_interval_when_a_model_with_projections_is_created() { - $this->createModelWithProjectors(Log::class, [MultiplePeriodsProjector::class]); + $this->createModelWithProjections(Log::class, [MultiplePeriodsProjector::class]); $this->assertDatabaseCount('cargo_projections', 8); } @@ -98,7 +98,7 @@ public function it_has_a_relationship_with_the_projection() /** @test */ public function it_get_the_projections_from_a_single_type() { - $log = $this->createModelWithProjectors(Log::class, [ + $log = $this->createModelWithProjections(Log::class, [ SinglePeriodProjector::class, MultiplePeriodsProjector::class, ]); @@ -113,7 +113,7 @@ public function it_get_the_projections_from_a_single_type() /** @test */ public function it_get_the_projections_from_a_single_type_and_period() { - $log = $this->createModelWithProjectors(Log::class, [ + $log = $this->createModelWithProjections(Log::class, [ SinglePeriodProjector::class, MultiplePeriodsProjector::class, ]); @@ -127,7 +127,7 @@ public function it_get_the_projections_from_a_single_type_and_period() /** @test */ public function it_get_the_projections_from_a_single_type_and_multiple_periods() { - $log = $this->createModelWithProjectors(Log::class, [ + $log = $this->createModelWithProjections(Log::class, [ SinglePeriodProjector::class, MultiplePeriodsProjector::class, ]); @@ -143,8 +143,8 @@ public function it_get_the_projections_from_a_single_type_and_multiple_periods() /** @test */ public function it_creates_a_single_projection_for_models_with_the_same_projection() { - $this->createModelWithProjectors(Log::class, [SinglePeriodProjector::class]); - $this->createModelWithProjectors(Message::class, [SinglePeriodProjector::class]); + $this->createModelWithProjections(Log::class, [SinglePeriodProjector::class]); + $this->createModelWithProjections(Message::class, [SinglePeriodProjector::class]); $this->assertEquals(1, Projection::count()); } @@ -152,10 +152,10 @@ public function it_creates_a_single_projection_for_models_with_the_same_projecti /** @test */ public function it_updates_a_projection_for_a_single_projectable_type_and_interval() { - $log = $this->createModelWithProjectors(Log::class, [SinglePeriodProjector::class]); - $message = $this->createModelWithProjectors(Message::class, [MultiplePeriodsProjector::class]); + $log = $this->createModelWithProjections(Log::class, [SinglePeriodProjector::class]); + $message = $this->createModelWithProjections(Message::class, [MultiplePeriodsProjector::class]); - $this->createModelWithProjectors(Log::class, [SinglePeriodProjector::class]); + $this->createModelWithProjections(Log::class, [SinglePeriodProjector::class]); $logProjection = $log->projections(SinglePeriodProjector::class, '5 minutes')->first(); $messageProjection = $message->projections(MultiplePeriodsProjector::class, '5 minutes')->first(); @@ -167,8 +167,8 @@ public function it_updates_a_projection_for_a_single_projectable_type_and_interv /** @test */ public function it_creates_a_projection_for_each_different_key() { - $this->createModelWithProjectors(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); - $this->createModelWithProjectors(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); + $this->createModelWithProjections(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); + $this->createModelWithProjections(Log::class, [SinglePeriodProjectorWithUniqueKey::class]); $this->assertEquals(2, Projection::count()); } @@ -176,8 +176,8 @@ public function it_creates_a_projection_for_each_different_key() /** @test */ public function it_creates_a_single_projection_for_a_similar_key() { - $this->createModelWithProjectors(Log::class, [SinglePeriodKeyedProjector::class]); - $this->createModelWithProjectors(Log::class, [SinglePeriodKeyedProjector::class]); + $this->createModelWithProjections(Log::class, [SinglePeriodKeyedProjector::class]); + $this->createModelWithProjections(Log::class, [SinglePeriodKeyedProjector::class]); $this->assertEquals(1, Projection::count()); } From 4cf7769b9a8837f7165793e647a325c08ce39bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9=20Pearce?= Date: Mon, 22 Nov 2021 18:23:32 +0100 Subject: [PATCH 3/7] Fix tests --- src/Projector.php | 36 ++++++++++--------- src/WithProjections.php | 2 ++ .../Projectors/SinglePeriodKeyedProjector.php | 2 +- .../SinglePeriodProjectorWithUniqueKey.php | 2 +- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/Projector.php b/src/Projector.php index 4eae757..6257b77 100644 --- a/src/Projector.php +++ b/src/Projector.php @@ -20,14 +20,6 @@ public function __construct(protected Model $projectedModel, protected string $p { } - /** - * The key used to query the projection. - */ - public function key(Model $model): bool | int | string - { - return false; - } - /** * Parses the periods defined as class attribute. * @throws ReflectionException @@ -58,12 +50,14 @@ private function parsePeriod(string $period): void */ private function findProjection(string $period, int $quantity, string $periodType): Projection | null { - return Projection::firstWhere([ - ['projector_name', $this::class], - ['key', $this->hasKey() ? $this->key($this->projectedModel) : null], + $query = Projection::where([ + ['projector_name', $this->projectionName], + ['key', $this->hasKey() ? $this->key() : null], ['period', $period], ['start_date', Carbon::now()->floorUnit($periodType, $quantity)], ]); + + return $query->first(); } /** @@ -72,11 +66,11 @@ private function findProjection(string $period, int $quantity, string $periodTyp private function createProjection(string $period, int $quantity, string $periodType): void { $this->projectedModel->projections()->create([ - 'projector_name' => $this::class, + 'projector_name' => $this->projectionName, 'key' => $this->hasKey() ? $this->key($this->projectedModel) : null, 'period' => $period, 'start_date' => Carbon::now()->floorUnit($periodType, $quantity), - 'content' => $this->getProjectedContent(), + 'content' => $this->getProjectedContent($this->projectionName::defaultContent()), ]); } @@ -85,7 +79,7 @@ private function createProjection(string $period, int $quantity, string $periodT */ private function updateProjection(Projection $projection): void { - $projection->content = $this->getProjectedContent(); + $projection->content = $this->getProjectedContent($projection->content); $projection->save(); } @@ -95,14 +89,22 @@ private function updateProjection(Projection $projection): void */ private function hasKey(): bool { - return $this->key($this->projectedModel) !== false; + return method_exists($this->projectionName, 'key'); + } + + /** + * The key used to query the projection. + */ + public function key(): bool | int | string + { + return $this->projectionName::key($this->projectedModel); } /** * Get the projected content. */ - private function getProjectedContent(): array + private function getProjectedContent(array $baseContent): array { - return $this->projectionName::handle($this->projectionName::defaultContent(), $this->projectedModel); + return $this->projectionName::handle($baseContent, $this->projectedModel); } } diff --git a/src/WithProjections.php b/src/WithProjections.php index 4b98f09..080dbac 100644 --- a/src/WithProjections.php +++ b/src/WithProjections.php @@ -6,6 +6,7 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany; use Laravelcargo\LaravelCargo\Jobs\ProcessProjection; use Laravelcargo\LaravelCargo\Models\Projection; +use ReflectionException; trait WithProjections { @@ -23,6 +24,7 @@ public static function bootWithProjections(): void /** * Boot the projectors. + * @throws ReflectionException */ public function bootProjectors(): void { diff --git a/tests/Projectors/SinglePeriodKeyedProjector.php b/tests/Projectors/SinglePeriodKeyedProjector.php index b509d0a..4a88391 100644 --- a/tests/Projectors/SinglePeriodKeyedProjector.php +++ b/tests/Projectors/SinglePeriodKeyedProjector.php @@ -26,7 +26,7 @@ public static function defaultContent(): array /** * The key used to query the projection. */ - public function key(Model $model): string + public static function key(Model $model): string { return '1'; } diff --git a/tests/Projectors/SinglePeriodProjectorWithUniqueKey.php b/tests/Projectors/SinglePeriodProjectorWithUniqueKey.php index e23a7b4..1697737 100644 --- a/tests/Projectors/SinglePeriodProjectorWithUniqueKey.php +++ b/tests/Projectors/SinglePeriodProjectorWithUniqueKey.php @@ -26,7 +26,7 @@ public static function defaultContent(): array /** * The key used to query the projection. */ - public function key(Model $model): string + public static function key(Model $model): string { return (string) $model->id; } From 2e36072fea2a2f48e27e1bc2af884d497cf5bd09 Mon Sep 17 00:00:00 2001 From: TimothePearce Date: Mon, 22 Nov 2021 17:24:02 +0000 Subject: [PATCH 4/7] Fix styling --- tests/Projectors/MultiplePeriodsProjector.php | 2 +- tests/database/migrations/create_logs_table.php | 2 +- tests/database/migrations/create_messages_table.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Projectors/MultiplePeriodsProjector.php b/tests/Projectors/MultiplePeriodsProjector.php index 19aceb9..65cdfa9 100644 --- a/tests/Projectors/MultiplePeriodsProjector.php +++ b/tests/Projectors/MultiplePeriodsProjector.php @@ -3,8 +3,8 @@ namespace Laravelcargo\LaravelCargo\Tests\Projectors; use Illuminate\Database\Eloquent\Model; -use Laravelcargo\LaravelCargo\Models\Projection; use Laravelcargo\LaravelCargo\Contracts\ProjectionContract; +use Laravelcargo\LaravelCargo\Models\Projection; class MultiplePeriodsProjector extends Projection implements ProjectionContract { diff --git a/tests/database/migrations/create_logs_table.php b/tests/database/migrations/create_logs_table.php index 46b4ec9..347a650 100644 --- a/tests/database/migrations/create_logs_table.php +++ b/tests/database/migrations/create_logs_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class() extends Migration { +return new class () extends Migration { public function up() { Schema::create('logs', function (Blueprint $table) { diff --git a/tests/database/migrations/create_messages_table.php b/tests/database/migrations/create_messages_table.php index e346f1b..389ae60 100644 --- a/tests/database/migrations/create_messages_table.php +++ b/tests/database/migrations/create_messages_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class() extends Migration { +return new class () extends Migration { public function up() { Schema::create('messages', function (Blueprint $table) { From d5f602a657b48882a9a516c08e4ffb9770fc2cf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9=20Pearce?= Date: Tue, 23 Nov 2021 12:31:23 +0100 Subject: [PATCH 5/7] Rename namespace --- .github/ISSUE_TEMPLATE/config.yml | 6 +++--- README.md | 4 ++-- composer.json | 20 +++++++++++-------- src/Commands/CreateProjectionCommand.php | 2 +- src/Commands/stubs/KeyedProjection.php.stub | 4 ++-- src/Commands/stubs/Projection.php.stub | 4 ++-- src/Contracts/ProjectionContract.php | 2 +- .../EmptyProjectionCollectionException.php | 2 +- .../MissingProjectionPeriodException.php | 2 +- .../MissingProjectorNameException.php | 2 +- src/Exceptions/MultiplePeriodsException.php | 2 +- .../MultipleProjectorsException.php | 2 +- .../OverlappingFillBetweenDatesException.php | 2 +- src/Jobs/ProcessProjection.php | 2 +- src/Models/Projection.php | 8 ++++---- src/ProjectionCollection.php | 12 +++++------ src/Projector.php | 4 ++-- ...Provider.php => QuasarServiceProvider.php} | 6 +++--- src/WithProjections.php | 6 +++--- testbench.yaml | 2 +- .../Commands/CreateProjectionCommandTest.php | 11 +++++----- tests/Models/Log.php | 6 +++--- tests/Models/Message.php | 6 +++--- tests/ProjectionCollectionTest.php | 20 +++++++++---------- tests/ProjectionTest.php | 18 ++++++++--------- tests/Projectors/MultiplePeriodsProjector.php | 6 +++--- .../Projectors/SinglePeriodKeyedProjector.php | 6 +++--- tests/Projectors/SinglePeriodProjector.php | 6 +++--- .../SinglePeriodProjectorWithUniqueKey.php | 6 +++--- tests/TestCase.php | 11 +++++----- tests/WithProjectableFactory.php | 2 +- tests/WithProjectionTest.php | 18 ++++++++--------- tests/database/factories/LogFactory.php | 4 ++-- tests/database/factories/MessageFactory.php | 4 ++-- 34 files changed, 112 insertions(+), 106 deletions(-) rename src/{LaravelCargoServiceProvider.php => QuasarServiceProvider.php} (82%) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index c1575c9..df85c12 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,11 +1,11 @@ blank_issues_enabled: false contact_links: - name: Ask a question - url: https://github.com/timothepearce/laravel-cargo/discussions/new?category=q-a + url: https://github.com/timothepearce/laravel-quasar/discussions/new?category=q-a about: Ask the community for help - name: Request a feature - url: https://github.com/timothepearce/laravel-cargo/discussions/new?category=ideas + url: https://github.com/timothepearce/laravel-quasar/discussions/new?category=ideas about: Share ideas for new features - name: Report a bug - url: https://github.com/timothepearce/laravel-cargo/issues/new + url: https://github.com/timothepearce/laravel-quasar/issues/new about: Report a reproducable bug diff --git a/README.md b/README.md index be78658..31aa589 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,13 @@ composer require laravelcargo/laravel-cargo You can publish and run the migrations with: ```bash -php artisan vendor:publish --provider="Laravelcargo\LaravelCargo\LaravelCargoServiceProvider" --tag="laravel-cargo-migrations" +php artisan vendor:publish --provider="Laravelcargo\LaravelCargo\QuasarServiceProvider" --tag="laravel-cargo-migrations" php artisan migrate ``` You can publish the config file with: ```bash -php artisan vendor:publish --provider="Laravelcargo\LaravelCargo\LaravelCargoServiceProvider" --tag="laravel-cargo-config" +php artisan vendor:publish --provider="Laravelcargo\LaravelCargo\QuasarServiceProvider" --tag="laravel-cargo-config" ``` This is the contents of the published config file: diff --git a/composer.json b/composer.json index ad0e62a..4850adf 100644 --- a/composer.json +++ b/composer.json @@ -1,12 +1,16 @@ { - "name": "timothepearce/laravel-cargo", + "name": "timothepearce/laravel-quasar", "description": "This is my package LaravelCargo", "keywords": [ - "LaravelCargo", + "LaravelQuasar", + "laravel-quasar", "laravel", - "laravel-cargo" + "quasar", + "statistics", + "projections", + "projectors" ], - "homepage": "https://github.com/timothepearce/laravel-cargo", + "homepage": "https://github.com/timothepearce/laravel-quasar", "license": "MIT", "authors": [ { @@ -29,13 +33,13 @@ }, "autoload": { "psr-4": { - "Laravelcargo\\LaravelCargo\\": "src" + "TimothePearce\\Quasar\\": "src" } }, "autoload-dev": { "psr-4": { - "Laravelcargo\\LaravelCargo\\Tests\\": "tests", - "Laravelcargo\\LaravelCargo\\Tests\\Database\\Factories\\": "tests/database/factories" + "TimothePearce\\Quasar\\Tests\\": "tests", + "TimothePearce\\Quasar\\Tests\\Database\\Factories\\": "tests/database/factories" } }, "scripts": { @@ -49,7 +53,7 @@ "extra": { "laravel": { "providers": [ - "Laravelcargo\\LaravelCargo\\LaravelCargoServiceProvider" + "TimothePearce\\Quasar\\QuasarServiceProvider" ] } }, diff --git a/src/Commands/CreateProjectionCommand.php b/src/Commands/CreateProjectionCommand.php index 8ef105d..e712108 100644 --- a/src/Commands/CreateProjectionCommand.php +++ b/src/Commands/CreateProjectionCommand.php @@ -1,6 +1,6 @@ 'Laravelcargo\\LaravelCargo\\Tests\\Database\\Factories\\'.class_basename($modelName).'Factory' + fn (string $modelName) => 'TimothePearce\\Quasar\\Tests\\Database\\Factories\\'.class_basename($modelName).'Factory' ); } protected function getPackageProviders($app) { return [ - LaravelCargoServiceProvider::class, + QuasarServiceProvider::class, ]; } /** * Define environment setup. * - * @param \Illuminate\Foundation\Application $app + * @param Application $app * @return void */ protected function defineEnvironment($app) diff --git a/tests/WithProjectableFactory.php b/tests/WithProjectableFactory.php index 9163492..55ef8e5 100644 --- a/tests/WithProjectableFactory.php +++ b/tests/WithProjectableFactory.php @@ -1,6 +1,6 @@ Date: Tue, 23 Nov 2021 11:31:45 +0000 Subject: [PATCH 6/7] Fix styling --- src/Projector.php | 2 +- src/WithProjections.php | 2 +- tests/TestCase.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Projector.php b/src/Projector.php index 33519ae..788fc3b 100644 --- a/src/Projector.php +++ b/src/Projector.php @@ -5,9 +5,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Carbon; use Illuminate\Support\Str; -use TimothePearce\Quasar\Models\Projection; use ReflectionException; use ReflectionProperty; +use TimothePearce\Quasar\Models\Projection; class Projector { diff --git a/src/WithProjections.php b/src/WithProjections.php index 8dd7a37..f1d363e 100644 --- a/src/WithProjections.php +++ b/src/WithProjections.php @@ -4,9 +4,9 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphToMany; +use ReflectionException; use TimothePearce\Quasar\Jobs\ProcessProjection; use TimothePearce\Quasar\Models\Projection; -use ReflectionException; trait WithProjections { diff --git a/tests/TestCase.php b/tests/TestCase.php index 31416b1..e0116f5 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -4,8 +4,8 @@ use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Foundation\Application; -use TimothePearce\Quasar\QuasarServiceProvider; use Orchestra\Testbench\TestCase as Orchestra; +use TimothePearce\Quasar\QuasarServiceProvider; class TestCase extends Orchestra { From d1caa076ce97658ea882bec5e1cea14bbbad7754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9=20Pearce?= Date: Tue, 23 Nov 2021 12:36:56 +0100 Subject: [PATCH 7/7] Fix PSALM --- src/Projector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Projector.php b/src/Projector.php index 788fc3b..8098f4a 100644 --- a/src/Projector.php +++ b/src/Projector.php @@ -67,7 +67,7 @@ private function createProjection(string $period, int $quantity, string $periodT { $this->projectedModel->projections()->create([ 'projector_name' => $this->projectionName, - 'key' => $this->hasKey() ? $this->key($this->projectedModel) : null, + 'key' => $this->hasKey() ? $this->key() : null, 'period' => $period, 'start_date' => Carbon::now()->floorUnit($periodType, $quantity), 'content' => $this->getProjectedContent($this->projectionName::defaultContent()),