Skip to content

Commit

Permalink
Merge pull request #10 from plank/models-from-container
Browse files Browse the repository at this point in the history
register models in / use models from container
  • Loading branch information
kfriars authored Dec 15, 2021
2 parents a58cdb1 + cd81096 commit 74b2c16
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 41 deletions.
3 changes: 3 additions & 0 deletions psalm.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
<errorLevel type="suppress">
<referencedMethod name="Plank\Checkpoint\Models\Checkpoint::first" />
<referencedMethod name="Plank\Checkpoint\Models\Checkpoint::select" />
<referencedMethod name="Plank\Checkpoint\Models\Checkpoint::olderThanEquals" />
<referencedMethod name="Plank\Checkpoint\Models\Checkpoint::newerThan" />
</errorLevel>
</UndefinedMagicMethod>
<InvalidReturnType>
Expand All @@ -59,6 +61,7 @@
<PossiblyFalseOperand>
<errorLevel type="suppress">
<file name="src/Helpers/RelationHelper.php" />
<file name="src/CheckpointServiceProvider.php" />
</errorLevel>
</PossiblyFalseOperand>
<MissingClosureReturnType>
Expand Down
23 changes: 23 additions & 0 deletions src/CheckpointServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@

class CheckpointServiceProvider extends ServiceProvider
{
protected $models = [
\Plank\Checkpoint\Models\Revision::class,
\Plank\Checkpoint\Models\Checkpoint::class,
\Plank\Checkpoint\Models\Timeline::class,
];

/**
* Bootstrap the application services.
*/
Expand Down Expand Up @@ -52,5 +58,22 @@ public function register()
{
// Automatically apply the package configuration
$this->mergeConfigFrom(__DIR__.'/../config/checkpoint.php', 'checkpoint');

$this->registerModels();
}

/**
* Bind user-defined models from config to corresponding package models
*/
public function registerModels()
{
$config = config('checkpoint.models');

foreach ($this->models as $model) {
$key = lcfirst(substr($model, strrpos($model, '\\') + 1));
$this->app->bind($model, function () use ($config, $key) {
return new $config[$key];
});
}
}
}
40 changes: 26 additions & 14 deletions src/Models/Checkpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,18 +169,26 @@ public static function active(): ?Checkpoint
}

/**
* Get the timeline the checkpoint belongs to
* Get the name of the "timeline id" column.
*
* @return BelongsTo
* @return string
*/
public function timeline(): BelongsTo
public function getTimelineKeyName()
{
/** @var class-string<Timeline> $timelineModel */
$timelineModel = config('checkpoint.models.timeline');
return static::TIMELINE_ID;
}

return $this->belongsTo($timelineModel, static::TIMELINE_ID);
/**
* Get the "timeline" key.
*
* @return \Illuminate\Support\Carbon|string
*/
public function getTimelineKey()
{
return $this->{$this->getTimelineKeyName()};
}


/**
* Get the name of the "checkpoint date" column.
*
Expand Down Expand Up @@ -231,17 +239,24 @@ public function next()
return static::newerThan($this)->first();
}

/**
* Get the timeline the checkpoint belongs to
*
* @return BelongsTo
*/
public function timeline(): BelongsTo
{
return $this->belongsTo(get_class(app(Timeline::class)), $this->getTimelineKeyName());
}

/**
* Retrieve all revision intermediaries associated with this checkpoint
*
* @return HasMany
*/
public function revisions(): HasMany
{
/** @var Revision|string $revisionClass */
$revisionClass = config('checkpoint.models.revision');

return $this->hasMany($revisionClass, $revisionClass::CHECKPOINT_ID);
return $this->hasMany(get_class(app(Revision::class)), app(Revision::class)->getCheckpointKeyName());
}

/**
Expand All @@ -253,12 +268,9 @@ public function revisions(): HasMany
*/
public function modelsOf(string $type): MorphToMany
{
/** @var string $revisionClass */
$revisionClass = config('checkpoint.models.revision');

return $this->morphedByMany($type, 'revisionable', 'revisions', 'checkpoint_id')
->withPivot('metadata', 'previous_revision_id', 'original_revisionable_id')->withTimestamps()
->using($revisionClass);
->using(get_class(app(Revision::class)));
}

/**
Expand Down
40 changes: 28 additions & 12 deletions src/Models/Revision.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,21 @@ protected static function boot()
*
* @return string
*/
public function getCheckpointIdColumn()
public function getCheckpointKeyName()
{
return static::CHECKPOINT_ID;
}

/**
* Get the name of the "timeline id" column.
*
* @return string
*/
public function getTimelineKeyName()
{
return static::TIMELINE_ID;
}

/**
* Retrieve the revisioned model associated with this entry
*
Expand Down Expand Up @@ -184,17 +194,24 @@ public function originalRevisionable(): MorphTo
return $this->initialRevisionable();
}

/**
* Return the associated timeline to this revision - should match the on checkpoint, if set
*
* @return BelongsTo
*/
public function timeline(): BelongsTo
{
return $this->belongsTo(get_class(app(Timeline::class)), $this->getTimelineKeyName());
}

/**
* Return the associated checkpoint/release to this revision
*
* @return BelongsTo
*/
public function checkpoint(): BelongsTo
{
/** @var string $checkpointClass */
$checkpointClass = config('checkpoint.models.checkpoint');

return $this->belongsTo($checkpointClass, $this->getCheckpointIdColumn());
return $this->belongsTo(get_class(app(Checkpoint::class)), $this->getCheckpointKeyName());
}

/**
Expand Down Expand Up @@ -297,20 +314,19 @@ public function scopeLatestIds(Builder $q, $until = null, $since = null)
$q->withoutGlobalScopes()->selectRaw("max({$this->getKeyName()})")
->groupBy(['original_revisionable_id', 'revisionable_type'])->orderByDesc('previous_revision_id');

/** @var Checkpoint $checkpointClass */
$checkpointClass = config('checkpoint.models.checkpoint');
$keyname = $checkpointClass::getModel()->getKeyName();
$checkpoint = app(Checkpoint::class);
$keyname = $checkpoint->getKeyName();

if ($until instanceof $checkpointClass) {
if ($until instanceof $checkpoint) {
// where in given checkpoint or one of the previous ones
$q->whereIn($this->getCheckpointIdColumn(), $checkpointClass::olderThanEquals($until)->select($keyname));
$q->whereIn($this->getCheckpointKeyName(), $checkpoint->olderThanEquals($until)->select($keyname));
} elseif ($until !== null) {
$q->where($this->getQualifiedCreatedAtColumn(), '<=', $until);
}

if ($since instanceof $checkpointClass) {
if ($since instanceof $checkpoint) {
// where in one of the newer checkpoints than given
$q->whereIn($this->getCheckpointIdColumn(), $checkpointClass::newerThan($since)->select($keyname));
$q->whereIn($this->getCheckpointKeyName(), $checkpoint->newerThan($since)->select($keyname));
} elseif ($since !== null) {
$q->where($this->getQualifiedCreatedAtColumn(), '>', $since);
}
Expand Down
21 changes: 17 additions & 4 deletions src/Models/Timeline.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,22 @@ class Timeline extends Model
*/
public function checkpoints(): HasMany
{
/** @var Checkpoint|string $checkpointClass */
$checkpointClass = config('checkpoint.models.checkpoint');
return $this->hasMany(
get_class(app(Checkpoint::class)),
app(Checkpoint::class)->getTimelineKeyName()
);
}

return $this->hasMany($checkpointClass, $checkpointClass::TIMELINE_ID);
/**
* Get all checkpoints associated with the Timeline
*
* @return HasMany
*/
public function revisions(): HasMany
{
return $this->hasMany(
get_class(app(Revision::class)),
app(Revision::class)->getTimelineKeyName()
);
}
}
}
16 changes: 5 additions & 11 deletions src/Observers/CheckpointObserver.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,10 @@ class CheckpointObserver
*/
public function updated(Checkpoint $checkpoint)
{
/** @var Checkpoint $revision */
$checkpointClass = config('checkpoint.models.checkpoint');

if ($checkpoint->isDirty($checkpointClass::TIMELINE_ID)) {
/** @var Revision $revision */
$revision = config('checkpoint.models.revision');
if ($checkpoint->isDirty($checkpoint->getTimelineKeyName())) {

$checkpoint->revisions()->update([
$revision::TIMELINE_ID => $checkpoint->{$checkpointClass::TIMELINE_ID}
app(Revision::class)->getTimelineKeyName() => $checkpoint->getTimelineKey()
]);

// Ensure the model has the proper timeline loaded
Expand All @@ -43,12 +38,11 @@ public function deleting(Checkpoint $checkpoint)
/** @var Checkpoint $checkpointClass */
$checkpointClass = config('checkpoint.models.checkpoint');

/** @var Revision $revision */
$revision = config('checkpoint.models.revision');
$revision = app(Revision::class);

$checkpoint->revisions()->update([
$revision::CHECKPOINT_ID => null,
$revision::TIMELINE_ID => null
$revision->getCheckpointKeyName() => null,
$revision->getTimelineKeyName() => null,
]);

$active = $checkpointClass::active();
Expand Down

0 comments on commit 74b2c16

Please sign in to comment.