plank/publisher

View on GitHub
src/Concerns/HasPublishableAttributes.php

Summary

Maintainability
A
0 mins
Test Coverage
B
88%
<?php

namespace Plank\Publisher\Concerns;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Plank\Publisher\Contracts\Publishable;
use Plank\Publisher\Facades\Publisher;

/**
 * @mixin FiresPublishingEvents
 * @mixin Publishable
 */
trait HasPublishableAttributes
{
    public static function bootHasPublishableAttributes()
    {
        static::retrieved(function (Publishable&Model $model) {
            if (Publisher::draftContentAllowed() && $model->isNotPublished()) {
                $model->syncAttributesFromDraft();
            }
        });

        static::publishing(function (Publishable&Model $model) {
            $model->{$model->hasBeenPublishedColumn()} = true;
        });

        static::drafting(function (Publishable&Model $model) {
            $model->putAttributesInDraft();
        });

        static::drafted(function (Publishable&Model $model) {
            $model->syncAttributesFromDraft();
        });

        static::undrafting(function (Publishable&Model $model) {
            $model->publishAttributes();
        });
    }

    public function syncAttributesFromDraft(): void
    {
        foreach ($this->{$this->draftColumn()} as $key => $value) {
            $this->attributes[$key] = $value;
            $this->syncOriginalAttribute($key);
        }
    }

    public function putAttributesInDraft(): void
    {
        $draft = [];

        foreach ($this->attributesForDraft() as $key => $value) {
            $draft[$key] = $value;
        }

        $this->{$this->draftColumn()} = $draft;

        foreach ($this->getDirtyKeys() as $key) {
            if ($this->isExcludedFromDraft($key)) {
                continue;
            }

            if (isset($this->original[$key])) {
                $this->attributes[$key] = $this->original[$key];
            }
        }
    }

    protected function attributesForDraft(): array
    {
        $draft = [];

        $excluded = array_merge(
            $this->excludedFromDraftByDefault(),
            $this->excludedFromDraft()
        );

        foreach ($this->attributes as $key => $value) {
            if (! in_array($key, $excluded)) {
                $draft[$key] = $value;
            }
        }

        return $draft;
    }

    protected function getDirtyKeys()
    {
        return array_keys($this->getDirty());
    }

    public function publishAttributes(): void
    {
        foreach ($this->getDraftAttributes() as $key => $value) {
            if ($this->isDirty($key)) {
                continue;
            }

            $this->original[$key] = ! $value;
        }

        $this->attributes[$this->draftColumn()] = null;
    }

    protected function getDraftAttributes(): array
    {
        return $this->{$this->draftColumn()} ?? [];
    }

    public function isExcludedFromDraft(string $key): bool
    {
        if (in_array($key, $this->excludedFromDraftByDefault())) {
            return true;
        }

        return in_array($key, $this->excludedFromDraft());
    }

    protected function excludedFromDraftByDefault(): array
    {
        $attributes = array_filter([
            $this->getKeyName(),
            $this->getCreatedAtColumn(),
            $this->getUpdatedAtColumn(),
            $this->workflowColumn(),
            $this->draftColumn(),
            $this->hasBeenPublishedColumn(),
            $this->shouldDeleteColumn(),
            $this->dependsOnPublishableForeignKey(),
        ]);

        if (in_array(SoftDeletes::class, class_uses_recursive($this))) {
            $attributes[] = $this->getDeletedAtColumn();
        }

        $attributes = array_merge($attributes, $this->qualifyColumns($attributes));

        return $attributes;
    }

    protected function excludedFromDraft(): array
    {
        return [];
    }

    public function hasDirtyDraftableAttributes(): bool
    {
        return ! empty($this->getDirtyDraftableAttributes());
    }

    public function getDirtyDraftableAttributes(): array
    {
        $excluded = array_merge(
            $this->excludedFromDraftByDefault(),
            $this->excludedFromDraft()
        );

        return array_diff_key($this->getDirty(), array_flip($excluded));
    }
}