Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
sheadawson committed Sep 16, 2024
1 parent b36ff2d commit 982d305
Show file tree
Hide file tree
Showing 10 changed files with 649 additions and 96 deletions.
5 changes: 4 additions & 1 deletion config/revisor.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@

// config for Indra/Revisor
return [

'publish_on_created' => false,
'publish_on_updated' => false,
'record_new_version_on_created' => true,
'record_new_version_on_updated' => true,
];
215 changes: 215 additions & 0 deletions src/Concerns/HasPublishing.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
<?php

declare(strict_types=1);

namespace Indra\Revisor\Concerns;

use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Indra\Revisor\Contracts\RevisorContract;
use Indra\Revisor\Facades\Revisor;

trait HasPublishing
{
protected bool | null $publishOnCreated = null; // default to config value

protected bool | null $publishOnUpdated = null; // default to config value

protected bool $withPublishedTable = false;

public static function bootHasPublishing(): void
{
static::created(function (RevisorContract $model) {
if ($model->shouldPublishOnCreated()) {
$model->publish();
}
});

static::updated(function (RevisorContract $model) {
if ($model->shouldPublishOnUpdated()) {
$model->publish();
}
});

// static::deleted(function (Model $model): void {
// $model->revisions()->delete();
// });
//
// if (method_exists(static::class, 'restored')) {
// static::restored(function (Model $model): void {
// $model->revisions()->restore();
// });
// }
//
// if (method_exists(static::class, 'forceDeleted')) {
// static::forceDeleted(function (Model $model): void {
// $model->revisions()->forceDelete();
// });
// }
}

public function initializeHasPublishing(): void
{
$this->mergeCasts([
'published_at' => 'datetime',
'is_published' => 'boolean',
]);
}

/**
* Publish the model.
*
* Sets the base record to a published state.
* Copies the base record to the published table.
* Saves the updated base record.
*/
public function publish(): static|bool
{
if ($this->fireModelEvent('publishing') === false) {
return false;
}

// put the base record in published state
$this->setPublishedAttributes();

// copy the base record to the published table
$this->applyStateToPublishedRecord();

// save the base record
$this->saveQuietly();

// fire the published event
$this->fireModelEvent('published');

return $this->fresh();
}

/**
* Unpublish the model.
*
* Sets the base record to an unpublished state.
* Deletes the corresponding record from the published table.
* Saves the updated base record.
* Fires the unpublished event.
*/
public function unpublish(): static
{
if ($this->fireModelEvent('unpublishing') === false) {
return $this;
}

// put the base record in unpublished state
$this->setUnpublishedAttributes();

// delete the published record
static::withPublishedTable()
->firstWhere($this->getKeyName(), $this->getKey())
->deleteQuietly();

// save the base record
$this->save();

// fire the unpublished event
$this->fireModelEvent('unpublished');

return $this->fresh();
}

/**
* Set the published attributes on the model.
*
* Updates the published_at timestamp, sets is_published to true,
* and associates the current authenticated user as the publisher.
*/
public function setPublishedAttributes(): static
{
$this->published_at = now();
$this->is_published = true;
$this->publisher()->associate(auth()->user());

return $this;
}

public function applyStateToPublishedRecord(): static
{
// find or make the published record
$published = static::withPublishedTable()->findOrNew($this->{$this->getKey()});

// copy the attributes from the base record to the published record
$published->forceFill($this->attributes);

// save the published record quietly as it's effectively
// a read-only copy of the base record
$published->saveQuietly();

return $this;
}

public function setUnpublishedAttributes(): static
{
$this->published_at = null;
$this->is_published = false;
$this->publisher()->dissociate();

return $this;
}

public function publishedRecord(): HasOne
{
$instance = $this->newRelatedInstance(static::class);
$instance->setWithPublishedTable(true);
return $this->newHasOne(
$instance->newQuery(), $this, $instance->getTable().'.'.$this->getKeyName(), $this->getKeyName()
);
}

public function publisher(): MorphTo
{
return $this->morphTo('publisher');
}

public static function withPublishedTable(): static
{
$instance = new static;
$instance->setWithPublishedTable();

return $instance;
}

public function setWithPublishedTable(bool $bool = true): static
{
$this->withPublishedTable = $bool;

return $this;
}

public function publishOnCreated(bool $bool = true): static
{
$this->publishOnCreated = $bool;

return $this;
}

public function publishOnUpdated(bool $bool = true): static
{
$this->publishOnUpdated = $bool;

return $this;
}

public function shouldPublishOnCreated(): bool
{
return is_null($this->publishOnCreated) ? config('revisor.publish_on_created') : $this->publishOnCreated;
}

public function shouldPublishOnUpdated(): bool
{
return is_null($this->publishOnUpdated) ? config('revisor.publish_on_updated') : $this->publishOnUpdated;
}

public function getPublishedTable(): string
{
return Revisor::getPublishedTableFor($this->getBaseTable());
}
}
130 changes: 48 additions & 82 deletions src/Concerns/HasRevisor.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,112 +4,78 @@

namespace Indra\Revisor\Concerns;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Indra\Revisor\Facades\Revisor;

trait HasRevisor
{
protected string $baseTable;
use HasPublishing;
use HasVersioning;

protected string $versionTable;

public function initializeHasRevisor(): void
{
$this->setBaseTable($this->getTable());
$this->setVersionTable(Revisor::getVersionTableFor($this->getTable()));
$this->setPublishedTable(Revisor::getPublishedTableFor($this->getTable()));

$this->mergeCasts([
'published_at' => 'datetime',
'is_current' => 'boolean',
'is_published' => 'boolean',
]);
}

public function publisher(): MorphTo
{
return $this->morphTo('publisher');
}

public function publish(): static
{
// find or make the published record
$published = static::withPublishedScope()->findOrNew($this->{$this->getKey()});

// set the published attributes
$this->published_at = now();
$this->is_published = true;
$this->publisher()->associate(auth()->user());

// copy the attributes from the base record to the published record
$published->fill($this->attributes);
$published->title = 'YES!';

// save the published record quietly as it's effectively
// a read-only copy of the base record
$published->saveQuietly();

// save the base record
$this->save();

return $this->fresh();
}

public function scopeWithBaseTable(Builder $query): static
{
$this->setTable($this->getBaseTable());

return $this;
}

public function scopeWithPublishedTable(Builder $query): static
public function getBaseTable(): string
{
$this->setTable($this->getPublishedTable());

return $this;
return parent::getTable();
}

public function scopeWithVersionTable(Builder $query): static
public function getTable(): string
{
$this->setTable($this->getVersionTable());
if ($this->withPublishedTable) {
return Revisor::getPublishedTableFor($this->getBaseTable());
}

return $this;
}
if ($this->withVersionTable) {
return Revisor::getVersionTableFor($this->getBaseTable());
}

public function getBaseTable(): string
{
return $this->baseTable;
return parent::getTable();
}

public function setBaseTable(string $table): static
public function setWithPublishedTable(bool $bool = true): static
{
$this->baseTable = $table;
$this->withPublishedTable = $bool;
$this->withVersionTable = !$bool;

return $this;
}

public function getVersionTable(): string
{
return $this->versionTable;
}

public function setVersionTable(string $table): static
public function setWithVersionTable(bool $bool = true): static
{
$this->versionTable = $table;
$this->withVersionTable = $bool;
$this->withPublishedTable = !$bool;

return $this;
}

public function getPublishedTable(): string
/**
* TODO: This needs a rethink...
* Override the fireModelEvent method to prevent events from firing on
* the version or published tables.
*/
protected function fireModelEvent($event, $halt = true): mixed
{
return $this->publishedTable;
if ($this->getTable() !== $this->getBaseTable()) {
return true;
}

if (! isset(static::$dispatcher)) {
return true;
}

// First, we will get the proper method to call on the event dispatcher, and then we
// will attempt to fire a custom, object based event for the given event. If that
// returns a result we can return that result, or we'll call the string events.
$method = $halt ? 'until' : 'dispatch';

$result = $this->filterModelEventResults(
$this->fireCustomModelEvent($event, $method)
);

if ($result === false) {
return false;
}

return ! empty($result) ? $result : static::$dispatcher->{$method}(
"eloquent.{$event}: ".static::class, $this
);
}

public function setPublishedTable(string $table): static
{
$this->publishedTable = $table;

return $this;
}
}
Loading

0 comments on commit 982d305

Please sign in to comment.