Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements multiple events #5

Merged
merged 24 commits into from
Nov 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9aba310
refacto
timothepearce Nov 28, 2021
e94f655
Merge branch 'main' of https://github.com/TimothePearce/laravel-quasar
timothepearce Nov 28, 2021
79287f5
refacto
timothepearce Nov 28, 2021
83d4e55
Start implementing the updated event
timothepearce Nov 28, 2021
7ff12a7
Fix styling
timothepearce Nov 28, 2021
f3335e3
Refactor
timothepearce Nov 28, 2021
660769b
Merge branch 'implements-multiple-events' of https://github.com/Timot…
timothepearce Nov 28, 2021
e745a87
Fix styling
timothepearce Nov 28, 2021
f4725f0
Refactor
timothepearce Nov 28, 2021
78da17d
Merge branch 'implements-multiple-events' of https://github.com/Timot…
timothepearce Nov 28, 2021
ee1411d
Fix styling
timothepearce Nov 28, 2021
f06d96d
Refactor & implements deleted event
timothepearce Nov 28, 2021
f40a02d
Merge branch 'implements-multiple-events' of https://github.com/Timot…
timothepearce Nov 28, 2021
e64a9d4
Fix styling
timothepearce Nov 28, 2021
27c1531
Start defining the resolve callable method
timothepearce Nov 28, 2021
72aaef7
Merge branch 'implements-multiple-events' of https://github.com/Timot…
timothepearce Nov 28, 2021
6315dc2
Fix styling
timothepearce Nov 28, 2021
f0c66cc
Implements the resolve callable method
timothepearce Nov 30, 2021
890ce0b
Merge branch 'implements-multiple-events' of https://github.com/Timot…
timothepearce Nov 30, 2021
a5df6df
Fix styling
timothepearce Nov 30, 2021
b30c3ca
Disable unused variable and params on psalm
timothepearce Nov 30, 2021
f5e8d44
Merge branch 'implements-multiple-events' of https://github.com/Timot…
timothepearce Nov 30, 2021
a8b1446
Implements Exception
timothepearce Nov 30, 2021
a03d84b
Fix styling
timothepearce Nov 30, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Commands/ProjectModelsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function handle(): void
->flatten()
->sortBy('created_at')
->each
->projectModel();
->projectModel('created');

$this->info('Projections have been refreshed!');
}
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/stubs/KeyedProjection.php.stub
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class {{ class }} extends Projection implements ProjectionContract
/**
* Compute the projection.
*/
public static function handle(array $content, Model $model): array
public static function projectableCreated(array $content, Model $model): array
{
return [];
}
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/stubs/Projection.php.stub
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class {{ class }} extends Projection implements ProjectionContract
/**
* Compute the projection.
*/
public static function handle(array $content, Model $model): array
public static function projectableCreated(array $content, Model $model): array
{
return [];
}
Expand Down
7 changes: 0 additions & 7 deletions src/Contracts/ProjectionContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,10 @@

namespace TimothePearce\Quasar\Contracts;

use Illuminate\Database\Eloquent\Model;

interface ProjectionContract
{
/**
* The default projection content.
*/
public static function defaultContent(): array;

/**
* Compute the projection.
*/
public static function handle(array $content, Model $model): array;
}
10 changes: 10 additions & 0 deletions src/Exceptions/MissingCallableMethodException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace TimothePearce\Quasar\Exceptions;

use Exception;

class MissingCallableMethodException extends Exception
{
protected $message = "Missing callable method from Projection.";
}
6 changes: 3 additions & 3 deletions src/Jobs/ProcessProjection.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ class ProcessProjection implements ShouldQueue
/**
* Create a new job instance.
*/
public function __construct(protected Model $model)
public function __construct(protected Model $model, protected string $eventName)
{
$this->onQueue(config('quasar.queue_name'));
}

/**
* Execute the job.
*/
public function handle()
public function created()
{
$this->model->bootProjectors();
$this->model->bootProjectors($this->eventName);
}
}
24 changes: 13 additions & 11 deletions src/Models/Traits/Projectable.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,44 @@ trait Projectable
*/
public static function bootProjectable(): void
{
static::created(fn (Model $model) => $model->projectModel());
static::created(fn (Model $model) => $model->projectModel('created'));
static::updated(fn (Model $model) => $model->projectModel('updated'));
static::deleted(fn (Model $model) => $model->projectModel('deleted'));
}

/**
* Projects the model.
* @throws ReflectionException
*/
public function projectModel(): void
public function projectModel(string $eventName): void
{
config('quasar.queue') ?
ProcessProjection::dispatch($this) :
$this->bootProjectors();
ProcessProjection::dispatch($this, $eventName) :
$this->bootProjectors($eventName);
}

/**
* Boot the projectors.
* @throws ReflectionException
*/
public function bootProjectors(): void
public function bootProjectors(string $eventName): void
{
collect($this->projections)->each(
fn (string $projection) => (new Projector($this, $projection))->parsePeriods()
fn (string $projection) => (new Projector($this, $projection, $eventName))->parsePeriods()
);
}

/**
* Get all the projections of the model.
*/
public function projections(
string|null $projectorName = null,
string|null $projectionName = null,
string|array|null $periods = null,
): MorphToMany {
$query = $this->morphToMany(Projection::class, 'projectable', 'quasar_projectables');

if (isset($projectorName)) {
$query->where('projection_name', $projectorName);
if (isset($projectionName)) {
$query->where('projection_name', $projectionName);
}

if (isset($periods) && gettype($periods) === 'string') {
Expand All @@ -73,10 +75,10 @@ public function projections(
* Get the first projection.
*/
public function firstProjection(
string|null $projectorName = null,
string|null $projectionName = null,
string|array|null $periods = null,
): null|Projection {
return $this->projections($projectorName, $periods)->first();
return $this->projections($projectionName, $periods)->first();
}

/**
Expand Down
50 changes: 39 additions & 11 deletions src/Projector.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Support\Str;
use ReflectionException;
use ReflectionProperty;
use TimothePearce\Quasar\Exceptions\MissingCallableMethodException;
use TimothePearce\Quasar\Models\Projection;

class Projector
Expand All @@ -15,13 +16,17 @@ class Projector
*/
protected array $periods;

public function __construct(protected Model $projectedModel, protected string $projectionName)
{
public function __construct(
protected Model $projectedModel,
protected string $projectionName,
protected string $eventName
) {
}

/**
* Parses the periods defined as class attribute.
* @throws ReflectionException
* @throws MissingCallableMethodException
*/
public function parsePeriods(): void
{
Expand All @@ -32,6 +37,7 @@ public function parsePeriods(): void

/**
* Parses the given period.
* @throws MissingCallableMethodException
*/
private function parsePeriod(string $period): void
{
Expand All @@ -45,22 +51,21 @@ private function parsePeriod(string $period): void
}

/**
* Try to find the projection.
* Finds the projection if it exists.
*/
private function findProjection(string $period, int $quantity, string $periodType): Projection|null
{
$query = Projection::where([
return Projection::firstWhere([
['projection_name', $this->projectionName],
['key', $this->hasKey() ? $this->key() : null],
['period', $period],
['start_date', $this->projectedModel->created_at->floorUnit($periodType, $quantity)],
]);

return $query->first();
}

/**
* Creates the projection.
* @throws MissingCallableMethodException
*/
private function createProjection(string $period, int $quantity, string $periodType): void
{
Expand All @@ -69,16 +74,17 @@ private function createProjection(string $period, int $quantity, string $periodT
'key' => $this->hasKey() ? $this->key() : null,
'period' => $period,
'start_date' => $this->projectedModel->created_at->floorUnit($periodType, $quantity),
'content' => $this->getProjectedContent($this->projectionName::defaultContent()),
'content' => $this->mergeProjectedContent($this->projectionName::defaultContent()),
]);
}

/**
* Updates the projection.
* @throws MissingCallableMethodException
*/
private function updateProjection(Projection $projection): void
{
$projection->content = $this->getProjectedContent($projection->content);
$projection->content = $this->mergeProjectedContent($projection->content);

$projection->save();
}
Expand All @@ -100,10 +106,32 @@ public function key(): bool|int|string
}

/**
* Get the projected content.
* Merges the projected content with the given one.
* @throws MissingCallableMethodException
*/
private function mergeProjectedContent(array $content): array
{
return array_merge($content, $this->resolveCallableMethod($content));
}

/**
* Resolves the callable method.
* @throws MissingCallableMethodException
*/
private function getProjectedContent(array $baseContent): array
private function resolveCallableMethod(array $content): array
{
return $this->projectionName::handle($baseContent, $this->projectedModel);
$modelName = Str::of($this->projectedModel::class)->explode('\\')->last();
$callableMethod = lcfirst($modelName) . ucfirst($this->eventName);
$defaultCallable = 'projectable' . ucfirst($this->eventName);

if (method_exists($this->projectionName, $callableMethod)) {
return $this->projectionName::$callableMethod($content, $this->projectedModel);
}

if (method_exists($this->projectionName, $defaultCallable)) {
return $this->projectionName::$defaultCallable($content, $this->projectedModel);
}

throw new MissingCallableMethodException();
}
}
9 changes: 4 additions & 5 deletions src/Quasar.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use ReflectionClass;
use TimothePearce\Quasar\Models\Traits\Projectable;

class Quasar
{
Expand All @@ -19,7 +20,7 @@ public function resolveProjectableModels(): Collection
$rc = new ReflectionClass($model);
$classes = $rc->getTraits();

return isset($classes["TimothePearce\Quasar\Models\Traits\Projectable"]);
return isset($classes[Projectable::class]);
});
}

Expand All @@ -38,11 +39,9 @@ private function getModels(string $path): Collection

$filename = $path . '/' . $result;

if (is_dir($filename)) {
$models = $models->concat($this->getModels($filename));
} else {
is_dir($filename) ?
$models = $models->concat($this->getModels($filename)) :
$models->push($this->getModelNamespace($filename));
}
}

return collect($models);
Expand Down
4 changes: 2 additions & 2 deletions tests/Commands/CreateProjectionCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public static function defaultContent(): array
/**
* Compute the projection.
*/
public static function handle(array \$content, Model \$model): array
public static function projectableCreated(array \$content, Model \$model): array
{
return [];
}
Expand Down Expand Up @@ -142,7 +142,7 @@ public static function key(Model \$model): string
/**
* Compute the projection.
*/
public static function handle(array \$content, Model \$model): array
public static function projectableCreated(array \$content, Model \$model): array
{
return [];
}
Expand Down
3 changes: 3 additions & 0 deletions tests/Commands/ProjectModelsCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public function it_projects_the_models_when_executed()
$this->assertDatabaseCount('quasar_projections', 1);
}

/**
* Mocks the `resolveProjectableModels` methods from the Quasar class.
*/
private function mockResolveProjectableModels()
{
$this->partialMock(
Expand Down
2 changes: 2 additions & 0 deletions tests/Models/Log.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class Log extends Model
use HasFactory;
use Projectable;

protected $guarded = [];

/**
* The projections list.
*/
Expand Down
6 changes: 3 additions & 3 deletions tests/Models/Projections/MultiplePeriodsProjection.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ class MultiplePeriodsProjection extends Projection implements ProjectionContract
public static function defaultContent(): array
{
return [
'number of logs' => 0,
'created_count' => 0,
];
}

/**
* Compute the projection's content.
*/
public static function handle(array $content, Model $model): array
public static function projectableCreated(array $content, Model $model): array
{
return [
'number of logs' => $content['number of logs'] + 1,
'created_count' => $content['created_count'] + 1,
];
}
}
6 changes: 3 additions & 3 deletions tests/Models/Projections/SinglePeriodKeyedProjection.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class SinglePeriodKeyedProjection extends Projection implements ProjectionContra
public static function defaultContent(): array
{
return [
'number of logs' => 0,
'created_count' => 0,
];
}

Expand All @@ -34,10 +34,10 @@ public static function key(Model $model): string
/**
* Compute the projection.
*/
public static function handle(array $content, Model $model): array
public static function projectableCreated(array $content, Model $model): array
{
return [
'number of logs' => $content['number of logs'] + 1,
'created_count' => $content['created_count'] + 1,
];
}
}
Loading