Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
sheadawson committed Sep 14, 2024
1 parent eb28ea5 commit b36ff2d
Show file tree
Hide file tree
Showing 8 changed files with 264 additions and 39 deletions.
115 changes: 115 additions & 0 deletions src/Concerns/HasRevisor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

declare(strict_types=1);

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;

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
{
$this->setTable($this->getPublishedTable());

return $this;
}

public function scopeWithVersionTable(Builder $query): static
{
$this->setTable($this->getVersionTable());

return $this;
}

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

public function setBaseTable(string $table): static
{
$this->baseTable = $table;

return $this;
}

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

public function setVersionTable(string $table): static
{
$this->versionTable = $table;

return $this;
}

public function getPublishedTable(): string
{
return $this->publishedTable;
}

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

return $this;
}
}
7 changes: 7 additions & 0 deletions src/Contracts/RevisorContract.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

declare(strict_types=1);

namespace Indra\Revisor\Contracts;

interface RevisorContract {}
2 changes: 2 additions & 0 deletions src/Facades/Revisor.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Indra\Revisor\Facades;

use Illuminate\Support\Facades\Facade;
Expand Down
70 changes: 51 additions & 19 deletions src/Revisor.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Indra\Revisor;

use Illuminate\Database\Schema\Blueprint;
Expand All @@ -9,50 +11,80 @@ class Revisor
{
/**
* Creates 3 tables for the given table name:
* - {table}_versions, which holds all the versions of the records
* - {table}_live, which holds the published version of the records
* - {table}, which holds the base data / drafts of the records
* - {baseTableName}_versions, which holds all the versions of the records
* - {baseTableName}_live, which holds the published version of the records
* - {baseTableName}, which holds the base data / drafts of the records
**/
public function schemaCreate(string $table, \Closure $callback): void
public function createTableSchemas(string $baseTableName, \Closure $callback): void
{
$baseTableName = $table;

// create the versions table
Schema::create(static::getVersionsTableNameFor($table), function (Blueprint $table) use ($callback, $baseTableName) {
Schema::create(static::getVersionTableFor($baseTableName), function (Blueprint $table) use ($callback, $baseTableName) {
$callback($table);
$table->nullableMorphs('publisher');
$table->timestamp('published_at')->nullable();
$table->boolean('is_current')->default(false);
$table->boolean('is_published')->default(false);
$table->boolean('is_current')->default(0);
$table->boolean('is_published')->default(0);
$table->foreignId('record_id')->constrained($baseTableName)->cascadeOnDelete();
});

// create the live table
Schema::create(static::getPublishedTableNameFor($table), function (Blueprint $table) use ($callback) {
Schema::create(static::getPublishedTableFor($baseTableName), function (Blueprint $table) use ($callback) {
$callback($table);
$table->nullableMorphs('publisher');
$table->timestamp('published_at')->nullable();
$table->boolean('is_current')->default(false);
$table->boolean('is_published')->default(false);
$table->boolean('is_current')->default(0);
$table->boolean('is_published')->default(0);
});

// create the base table
Schema::create($table, function (Blueprint $table) use ($callback) {
Schema::create($baseTableName, function (Blueprint $table) use ($callback) {
$callback($table);
$table->nullableMorphs('publisher');
$table->timestamp('published_at')->nullable();
$table->boolean('is_current')->default(false);
$table->boolean('is_published')->default(false);
$table->boolean('is_current')->default(0);
$table->boolean('is_published')->default(0);
});
}

public static function getVersionsTableNameFor(string $table): string
/**
* Amends 3 tables for the given baseTableName:
* - {baseTableName}_versions, which holds all the versions of the records
* - {baseTableName}_live, which holds the published version of the records
* - {baseTableName}, which holds the base data / drafts of the records
**/
public function amendTableSchemas(string $baseTableName, \Closure $callback): void
{
return str($table)->singular().'_versions';
// amend the versions table
Schema::table(static::getVersionTableFor($baseTableName), function (Blueprint $table) use ($callback) {
$callback($table);
});

// amend the live table
Schema::table(static::getPublishedTableFor($baseTableName), function (Blueprint $table) use ($callback) {
$callback($table);
});

// amend the base table
Schema::table($baseTableName, function (Blueprint $table) use ($callback) {
$callback($table);
});
}

public static function getPublishedTableNameFor(string $table): string
/**
* Get the name of the table that holds the versions
* of the records for the given baseTableName
**/
public static function getVersionTableFor(string $baseTableName): string
{
return str($baseTableName)->singular().'_versions';
}

/**
* Get the name of the table that holds the published verions
* of the records for the given baseTableName
**/
public static function getPublishedTableFor(string $baseTableName): string
{
return $table.'_live';
return $baseTableName.'_live';
}
}
49 changes: 33 additions & 16 deletions tests/MigrationsTest.php
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
<?php

use Illuminate\Database\Schema\Blueprint;
declare(strict_types=1);

use Illuminate\Support\Facades\Schema;
use Indra\Revisor\Facades\Revisor;

it('creates revisor schemas', function () {
Revisor::schemaCreate('foo', function (Blueprint $table): void {
$table->id();
$table->string('title');
});
it('creates and amends revisor schemas', function () {
// table creation and amendments in TestCase.php

expect(Schema::hasTable('foo'))->toBeTrue();
expect(Schema::hasTable(Revisor::getVersionsTableNameFor('foo')))->toBeTrue();
expect(Schema::hasTable(Revisor::getPublishedTableNameFor('foo')))->toBeTrue();
// assert that expected tables exist
expect(Schema::hasTable('pages'))->toBeTrue();
expect(Schema::hasTable(Revisor::getVersionTableFor('pages')))->toBeTrue();
expect(Schema::hasTable(Revisor::getPublishedTableFor('pages')))->toBeTrue();

// define expected columns
$expectedColumns = [
'id',
'title',
'is_current',
'publisher_type',
'publisher_id',
'is_published',
'published_at',
'published_by',
'is_current',
'is_published',
'content',
'created_at',
'updated_at',
];
//expect([])->toMatchArray(Schema::getColumnListing('foo')); ?
expect(Schema::hasColumns('foo', $expectedColumns))->toBeTrue();
expect(Schema::hasColumns(Revisor::getVersionsTableNameFor('foo'), $expectedColumns + ['record_id']))->toBeTrue();
expect(Schema::hasColumns(Revisor::getPublishedTableNameFor('foo'), $expectedColumns))->toBeTrue();

sort($expectedColumns);

// assert that expected columns exist for base table
$actualColumns = Schema::getColumnListing('pages');
sort($actualColumns);
expect($expectedColumns)->toMatchArray($actualColumns);

// assert that expected columns exist for versions table
$actualColumns = Schema::getColumnListing(Revisor::getVersionTableFor('pages'));
sort($actualColumns);
$expectedVersionsColumns = array_merge($expectedColumns, ['record_id']);
sort($expectedVersionsColumns);
expect($expectedVersionsColumns)->toMatchArray($actualColumns);

// assert that expected columns exist for published table
$actualColumns = Schema::getColumnListing(Revisor::getPublishedTableFor('pages'));
sort($actualColumns);
expect($expectedColumns)->toMatchArray($actualColumns);
});
19 changes: 19 additions & 0 deletions tests/Models/Page.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Indra\Revisor\Tests\Models;

use Illuminate\Database\Eloquent\Model;
use Indra\Revisor\Concerns\HasRevisor;
use Indra\Revisor\Contracts\RevisorContract;

class Page extends Model implements RevisorContract
{
use HasRevisor;

protected $fillable = [
'title',
'description',
];
}
19 changes: 19 additions & 0 deletions tests/PublishingTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

use Indra\Revisor\Tests\Models\Page;

it('publishes records as expected', function () {
$page = Page::create(['title' => 'Home']);
$page->refresh();

expect($page->is_published)->toBe(false);

$page->publish();
expect($page->is_published)->toBe(true);

$published = Page::withPublishedTable()->where('id', $page->id)->ddRawSQL();
dd($published);

});
22 changes: 18 additions & 4 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace Indra\Revisor\Tests;

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Database\Schema\Blueprint;
use Indra\Revisor\Facades\Revisor;
use Indra\Revisor\RevisorServiceProvider;
use Orchestra\Testbench\TestCase as Orchestra;

Expand All @@ -28,9 +30,21 @@ public function getEnvironmentSetUp($app)
{
config()->set('database.default', 'testing');

/*
$migration = include __DIR__.'/../database/migrations/create_laravel-revisor_table.php.stub';
$migration->up();
*/
$this->setUpDatabase();
}

protected function setUpDatabase()
{
// create tables
Revisor::createTableSchemas('pages', function (Blueprint $table): void {
$table->id();
$table->string('title');
$table->timestamps();
});

// amend tables
Revisor::amendTableSchemas('pages', function (Blueprint $table): void {
$table->string('content')->nullable();
});
}
}

0 comments on commit b36ff2d

Please sign in to comment.