JsonColumnDirtyTrait.php 1.27 KB
<?php

namespace App\Traits;

use Illuminate\Support\Arr;
use Illuminate\Support\Str;

trait JsonColumnDirtyTrait
{
    /**
     * @return array<string,mixed>
     */
    public function getDirty(): array
    {
        $dirty = [];

        foreach (static::dot($this->attributesToArray()) as $key => $value) {
            if (!$this->originalIsEquivalent($key) && $this->jsonOriginalIsEquivalent($key)) {
                $dirty[$key] = $value;
            }
        }
        return $dirty;
    }

    private function getJsonColumn(): array
    {
        return array_keys(array_filter($this->casts, static fn($value) => in_array($value, ['object', 'json'])));
    }

    /**
     * @param string $key
     * @return bool
     */
    private function jsonOriginalIsEquivalent(string $key): bool
    {
        if ($column = Arr::first($this->getJsonColumn(), static fn($column) => Str::startsWith($key, $column . '->'))) {
            $expandKey = Str::after($key, $column . '->');
            $attribute = self::dot($this->fromJson(Arr::get($this->attributes, $column, '{}')));
            $original  = self::dot($this->fromJson(Arr::get($this->original, $column, '{}')));

            return Arr::get($attribute, $expandKey) != Arr::get($original, $expandKey);
        }

        return true;
    }
}