-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6 from plank/1-contentable-polymorphic
Implement basic contentable functionality
- Loading branch information
Showing
20 changed files
with
540 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
use Illuminate\Database\Migrations\Migration; | ||
use Illuminate\Database\Schema\Blueprint; | ||
use Illuminate\Support\Facades\Schema; | ||
|
||
return new class extends Migration | ||
{ | ||
public function up() | ||
{ | ||
Schema::create('contents', function (Blueprint $table) { | ||
$table->id(); | ||
$table->string('identifier')->nullable(); | ||
$table->morphs('contentable'); | ||
$table->morphs('renderable'); | ||
$table->integer('order'); | ||
$table->timestamps(); | ||
}); | ||
} | ||
|
||
public function down() | ||
{ | ||
Schema::dropIfExists('contents'); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
<?php | ||
|
||
namespace Plank\Contentable\Concerns; | ||
|
||
use Illuminate\Database\Eloquent\Relations\MorphOne; | ||
use Illuminate\Database\Eloquent\SoftDeletes; | ||
use Plank\Contentable\Contracts\Contentable; | ||
use Plank\Contentable\Contracts\Renderable; | ||
|
||
trait CanRender | ||
{ | ||
public static function bootCanRender() | ||
{ | ||
static::updated(function (Renderable $renderable) { | ||
$renderable->contentable()?->clearCache(); | ||
}); | ||
|
||
static::deleted(function (Renderable $renderable) { | ||
$renderable->contentable()?->clearCache(); | ||
}); | ||
|
||
if (in_array(SoftDeletes::class, class_uses_recursive(static::class))) { | ||
static::restored(function (Renderable $renderable) { | ||
$renderable->contentable()?->clearCache(); | ||
}); | ||
} | ||
} | ||
|
||
public function content(): MorphOne | ||
{ | ||
$contentModel = config('contentable.model'); | ||
|
||
return $this->morphOne($contentModel, 'renderable'); | ||
} | ||
|
||
public function contentable(): ?Contentable | ||
{ | ||
return $this->content?->contentable; | ||
} | ||
|
||
/** | ||
* Encodes the renderable fields as JSON to be passed to the front-end. | ||
*/ | ||
public function renderJson($fields = []): string | ||
{ | ||
return json_encode($this->only($fields ?: $this->renderableFields())); | ||
} | ||
|
||
/** | ||
* Accessor for fields that are set to be rendered when serializing to | ||
* | ||
* @return string[] | ||
*/ | ||
public function renderableFields(): array | ||
{ | ||
return property_exists($this, 'renderableFields') ? $this->renderableFields : ['title', 'body']; | ||
} | ||
|
||
public function formatKeys(): array | ||
{ | ||
return [ | ||
'renderable_type' => static::class, | ||
'renderable_id' => $this->getKey(), | ||
]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<?php | ||
|
||
namespace Plank\Contentable\Concerns; | ||
|
||
use Illuminate\Database\Eloquent\Relations\MorphMany; | ||
use Illuminate\Support\Facades\Cache; | ||
|
||
trait HasContent | ||
{ | ||
public function contents(): MorphMany | ||
{ | ||
$contentModel = config('contentable.model'); | ||
|
||
return $this->morphMany($contentModel, 'contentable'); | ||
} | ||
|
||
public function renderHtml(): string | ||
{ | ||
if (Cache::has("contentable.html.{$this->getKey()}")) { | ||
return Cache::get("contentable.html.{$this->getKey()}"); | ||
} | ||
|
||
$output = ''; | ||
foreach ($this->contents as $content) { | ||
$output .= $content->renderable->renderHtml()."\n"; | ||
} | ||
|
||
Cache::put("contentable.html.{$this->getKey()}", $output, config('contentable.cache.ttl')); | ||
|
||
return $output; | ||
} | ||
|
||
public function renderJson(): string | ||
{ | ||
if (Cache::has("contentable.json.{$this->getKey()}")) { | ||
return Cache::get("contentable.json.{$this->getKey()}"); | ||
} | ||
|
||
$output = []; | ||
|
||
foreach ($this->contents as $content) { | ||
$output[] = $content->renderable->renderJson(); | ||
} | ||
|
||
$output = json_encode($output); | ||
|
||
Cache::put("contentable.json.{$this->id}", $output, config('contentable.cache.ttl')); | ||
|
||
return $output; | ||
} | ||
|
||
public function clearCache($key = null): void | ||
{ | ||
$key = $key ?? $this->getKey(); | ||
|
||
if (Cache::has("contentable.html.{$key}")) { | ||
Cache::delete("contentable.html.{$key}"); | ||
} | ||
|
||
if (Cache::has("contentable.json.{$key}")) { | ||
Cache::delete("contentable.json.{$key}"); | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?php | ||
|
||
namespace Plank\Contentable\Contracts; | ||
|
||
use Illuminate\Database\Eloquent\Relations\MorphTo; | ||
|
||
interface Content | ||
{ | ||
public function renderable(): MorphTo; | ||
|
||
public function contentable(): MorphTo; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?php | ||
|
||
namespace Plank\Contentable\Contracts; | ||
|
||
use Illuminate\Database\Eloquent\Relations\MorphMany; | ||
|
||
/** | ||
* @property string $render_order_column | ||
*/ | ||
interface Contentable | ||
{ | ||
public function contents(): MorphMany; | ||
|
||
public function renderHtml(): string; | ||
|
||
public function renderJson(): string; | ||
|
||
public function clearCache(): void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
namespace Plank\Contentable\Contracts; | ||
|
||
use Illuminate\Database\Eloquent\Relations\MorphOne; | ||
|
||
interface Renderable | ||
{ | ||
public function renderHtml(): string; | ||
|
||
public function renderJson(): string; | ||
|
||
public function renderableFields(): array; | ||
|
||
public function content(): MorphOne; | ||
|
||
public function contentable(): ?Contentable; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
|
||
namespace Plank\Contentable\Models; | ||
|
||
use Illuminate\Database\Eloquent\Builder; | ||
use Illuminate\Database\Eloquent\Model; | ||
use Illuminate\Database\Eloquent\Relations\MorphTo; | ||
use Plank\Contentable\Contracts\Content as ContentInterface; | ||
|
||
class Content extends Model implements ContentInterface | ||
{ | ||
protected $fillable = [ | ||
'contentable_id', | ||
'contentable_type', | ||
'renderable_id', | ||
'renderable_type', | ||
'identifier', | ||
'order', | ||
]; | ||
|
||
protected static function boot() | ||
{ | ||
static::saved(function (ContentInterface $content) { | ||
$content->contentable->clearCache(); | ||
}); | ||
|
||
parent::boot(); | ||
} | ||
|
||
public function renderable(): MorphTo | ||
{ | ||
return $this->morphTo(); | ||
} | ||
|
||
public function contentable(): MorphTo | ||
{ | ||
return $this->morphTo(); | ||
} | ||
|
||
public function scopeInRenderableOrder(Builder $query): void | ||
{ | ||
$query->orderBy($this->renderOrderColumnField()); | ||
} | ||
|
||
public function renderOrderColumnField(): string | ||
{ | ||
return $this->render_order_column ?? $this->getKeyName(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<?php | ||
|
||
use Plank\Contentable\Tests\Helper\Models\FakeModule; | ||
use Plank\Contentable\Tests\Helper\Models\Page; | ||
|
||
it('can format keys as expected for easy creation', function () { | ||
$renderable = FakeModule::factory()->create(); | ||
|
||
$expected = [ | ||
'renderable_type' => FakeModule::class, | ||
'renderable_id' => $renderable->id, | ||
]; | ||
|
||
expect($renderable->formatKeys())->toEqual($expected); | ||
}); | ||
|
||
it('can attach new renderables to a piece of content', function () { | ||
$page = Page::factory()->create(); | ||
$renderable = FakeModule::factory()->create(); | ||
|
||
$identifier = 'Fake Identifier'; | ||
$attached = $page->contents()->create(array_merge($renderable->formatKeys(), ['identifier' => $identifier]))->first(); | ||
|
||
expect($page->contents) | ||
->toHaveCount(1); | ||
|
||
$module = $page->contents->first(); | ||
expect($module->identifier)->toEqual($identifier); | ||
expect($module->renderable)->toEqual($renderable->fresh()); | ||
|
||
expect($attached->renderable_id)->toEqual($renderable->id); | ||
expect($attached->renderable_type)->toEqual($renderable::class); | ||
expect($attached->contentable_id)->toEqual($page->id); | ||
expect($attached->contentable_type)->toEqual($page::class); | ||
}); | ||
|
||
it('can have many renderables attached in one go using collection high order functions', function () { | ||
$page = Page::factory()->create(); | ||
$renderables = FakeModule::factory(10)->create(); | ||
|
||
$attached = $page->contents()->createMany($renderables->map->formatKeys()); | ||
|
||
expect($attached->count())->toEqual(10); | ||
}); |
Oops, something went wrong.