Skip to content

Commit

Permalink
[4.x] Add isDirty / isClean (#5502)
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanmitchell authored Feb 27, 2024
1 parent 6a304de commit 7da46d8
Show file tree
Hide file tree
Showing 18 changed files with 432 additions and 26 deletions.
12 changes: 10 additions & 2 deletions src/Assets/Asset.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Statamic\Contracts\Search\Searchable as SearchableContract;
use Statamic\Data\ContainsData;
use Statamic\Data\HasAugmentedInstance;
use Statamic\Data\HasDirtyState;
use Statamic\Data\TracksQueriedColumns;
use Statamic\Data\TracksQueriedRelations;
use Statamic\Events\AssetContainerBlueprintFound;
Expand Down Expand Up @@ -46,7 +47,7 @@

class Asset implements Arrayable, ArrayAccess, AssetContract, Augmentable, ContainsQueryableValues, ResolvesValuesContract, SearchableContract
{
use ContainsData, FluentlyGetsAndSets, HasAugmentedInstance,
use ContainsData, FluentlyGetsAndSets, HasAugmentedInstance, HasDirtyState,
Searchable,
TracksQueriedColumns, TracksQueriedRelations {
set as traitSet;
Expand All @@ -65,7 +66,6 @@ class Asset implements Arrayable, ArrayAccess, AssetContract, Augmentable, Conta
protected $withEvents = true;
protected $shouldHydrate = true;
protected $removedData = [];
protected $original = [];

public function syncOriginal()
{
Expand Down Expand Up @@ -1054,6 +1054,14 @@ public function getQueryableValue(string $field)
return $field->fieldtype()->toQueryableValue($value);
}

public function getCurrentDirtyStateAttributes(): array
{
return array_merge([
'path' => $this->path(),
'data' => $this->data()->toArray(),
]);
}

public function getCpSearchResultBadge(): string
{
return $this->container()->title();
Expand Down
7 changes: 7 additions & 0 deletions src/Auth/Eloquent/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -364,4 +364,11 @@ public function __set($key, $value)

return $this->$key = $value;
}

public function getCurrentDirtyStateAttributes(): array
{
return array_merge([
'email' => $this->email(),
], $this->model()->attributesToArray());
}
}
12 changes: 12 additions & 0 deletions src/Auth/File/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -356,4 +356,16 @@ public function fresh()
{
return Facades\User::find($this->id);
}

public function getCurrentDirtyStateAttributes(): array
{
return array_merge([
'email' => $this->email(),
'groups' => $this->get('groups', []),
'password_hash' => $this->passwordHash(),
'permissions' => $this->get('permissions', []),
'roles' => $this->get('roles', []),
'super' => $this->get('super', false),
], $this->data()->toArray());
}
}
5 changes: 4 additions & 1 deletion src/Auth/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Statamic\Contracts\Search\Searchable as SearchableContract;
use Statamic\Data\ContainsComputedData;
use Statamic\Data\HasAugmentedInstance;
use Statamic\Data\HasDirtyState;
use Statamic\Data\TracksQueriedColumns;
use Statamic\Data\TracksQueriedRelations;
use Statamic\Events\UserCreated;
Expand All @@ -39,7 +40,7 @@

abstract class User implements Arrayable, ArrayAccess, Augmentable, Authenticatable, AuthorizableContract, CanResetPasswordContract, ContainsQueryableValues, HasLocalePreference, ResolvesValuesContract, SearchableContract, UserContract
{
use Authorizable, CanResetPassword, ContainsComputedData, HasAugmentedInstance, HasAvatar, Notifiable, ResolvesValues, Searchable, TracksQueriedColumns, TracksQueriedRelations;
use Authorizable, CanResetPassword, ContainsComputedData, HasAugmentedInstance, HasAvatar, HasDirtyState, Notifiable, ResolvesValues, Searchable, TracksQueriedColumns, TracksQueriedRelations;

protected $afterSaveCallbacks = [];
protected $withEvents = true;
Expand Down Expand Up @@ -193,6 +194,8 @@ public function save()
UserSaved::dispatch($this);
}

$this->syncOriginal();

return $this;
}

Expand Down
59 changes: 59 additions & 0 deletions src/Data/HasDirtyState.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace Statamic\Data;

use Statamic\Support\Arr;

trait HasDirtyState
{
protected array $original = [];

abstract public function getCurrentDirtyStateAttributes(): array;

/**
* Determine if the item or any of the given attribute(s) have been modified.
*
* @param null|string|array $attributes
*/
public function isDirty($attributes = null): bool
{
$currentValues = $this->getCurrentDirtyStateAttributes();
$originalValues = $this->getOriginal();

if (! $attributes) {
return json_encode($currentValues) !== json_encode($originalValues);
}

return collect($attributes)->contains(function ($property) use ($currentValues, $originalValues) {
// In an asset, the data key holds all the data. It would be a breaking
// change to make it the root level, so we'll support both for now.
if (! array_key_exists($property, $currentValues)) {
$property = 'data.'.$property;
}

return data_get($currentValues, $property) !== data_get($originalValues, $property);
});
}

/**
* Determine if the item or all the given attribute(s) have remained the same.
*
* @param null|string|array $attributes
*/
public function isClean($attributes = null): bool
{
return ! $this->isDirty($attributes);
}

public function syncOriginal(): static
{
$this->original = $this->getCurrentDirtyStateAttributes();

return $this;
}

public function getOriginal($key = null, $fallback = null)
{
return Arr::get($this->original, $key, $fallback);
}
}
4 changes: 4 additions & 0 deletions src/Data/SyncsOriginalState.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

use Statamic\Support\Arr;

/**
* @deprecated
* @see \Statamic\Data\HasDirtyState
*/
trait SyncsOriginalState
{
protected $original = [];
Expand Down
17 changes: 17 additions & 0 deletions src/Entries/Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Statamic\Data\ContainsData;
use Statamic\Data\ExistsAsFile;
use Statamic\Data\HasAugmentedInstance;
use Statamic\Data\HasDirtyState;
use Statamic\Data\HasOrigin;
use Statamic\Data\Publishable;
use Statamic\Data\TracksLastModified;
Expand Down Expand Up @@ -56,6 +57,7 @@ class Entry implements Arrayable, ArrayAccess, Augmentable, ContainsQueryableVal
{
use ContainsComputedData, ContainsData, ExistsAsFile, FluentlyGetsAndSets, HasAugmentedInstance, Localizable, Publishable, Revisable, Searchable, TracksLastModified, TracksQueriedColumns, TracksQueriedRelations;

use HasDirtyState;
use HasOrigin {
value as originValue;
values as originValues;
Expand Down Expand Up @@ -173,6 +175,19 @@ public function newAugmentedInstance(): Augmented
return new AugmentedEntry($this);
}

public function getCurrentDirtyStateAttributes(): array
{
return array_merge([
'collection' => $this->collectionHandle(),
'locale' => $this->locale(),
'origin' => $this->hasOrigin() ? $this->origin()->id() : null,
'slug' => $this->slug(),
'date' => optional($this->date())->format('Y-m-d-Hi'),
'published' => $this->published(),
'path' => $this->initialPath() ?? $this->path(),
], $this->data()->except(['updated_at'])->toArray());
}

public function delete()
{
if (EntryDeleting::dispatch($this) === false) {
Expand Down Expand Up @@ -384,6 +399,8 @@ public function save()

$stack->pop();

$this->syncOriginal();

return true;
}

Expand Down
8 changes: 8 additions & 0 deletions src/Stache/Stores/BasicStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,21 @@ public function getItem($key)
}

if ($item = $this->getCachedItem($key)) {
if (method_exists($item, 'syncOriginal')) {
$item->syncOriginal();
}

return $item;
}

$item = $this->makeItemFromFile($path, File::get($path));

$this->cacheItem($item);

if (method_exists($item, 'syncOriginal')) {
$item->syncOriginal();
}

return $item;
}

Expand Down
3 changes: 1 addition & 2 deletions src/Stache/Stores/NavTreeStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ public function makeItemFromFile($path, $contents)
{
return $this
->newTreeClassByPath($path)
->tree(YAML::file($path)->parse($contents)['tree'] ?? [])
->syncOriginal();
->tree(YAML::file($path)->parse($contents)['tree'] ?? []);
}

protected function newTreeClassByPath($path)
Expand Down
1 change: 0 additions & 1 deletion src/Stache/Stores/TaxonomyTermsStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ public function makeItemFromFile($path, $contents)
}

$term->dataForLocale($term->defaultLocale(), $data);
$term->syncOriginal();

return $term;
}
Expand Down
18 changes: 6 additions & 12 deletions src/Structures/Tree.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use Statamic\Contracts\Data\Localization;
use Statamic\Contracts\Structures\Tree as Contract;
use Statamic\Data\ExistsAsFile;
use Statamic\Data\SyncsOriginalState;
use Statamic\Data\HasDirtyState;
use Statamic\Facades\Blink;
use Statamic\Facades\Entry;
use Statamic\Facades\Site;
Expand All @@ -14,15 +14,14 @@

abstract class Tree implements Contract, Localization
{
use ExistsAsFile, FluentlyGetsAndSets, SyncsOriginalState;
use ExistsAsFile, FluentlyGetsAndSets, HasDirtyState;

protected $handle;
protected $locale;
protected $tree = [];
protected $cachedFlattenedPages;
protected $withEntries = false;
protected $uriCacheEnabled = true;
protected $syncOriginalProperties = ['tree'];

public function idKey()
{
Expand Down Expand Up @@ -378,15 +377,10 @@ public function withEntries()
return $this;
}

public function __sleep()
public function getCurrentDirtyStateAttributes(): array
{
$vars = Arr::except(get_object_vars($this), ['original']);

return array_keys($vars);
}

public function __wakeup()
{
$this->syncOriginal();
return [
'tree' => $this->tree,
];
}
}
13 changes: 10 additions & 3 deletions src/Taxonomies/Term.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Statamic\Contracts\Taxonomies\Term as TermContract;
use Statamic\Data\ExistsAsFile;
use Statamic\Data\SyncsOriginalState;
use Statamic\Data\HasDirtyState;
use Statamic\Events\TermBlueprintFound;
use Statamic\Events\TermCreated;
use Statamic\Events\TermCreating;
Expand All @@ -22,7 +22,7 @@

class Term implements TermContract
{
use ExistsAsFile, FluentlyGetsAndSets, SyncsOriginalState;
use ExistsAsFile, FluentlyGetsAndSets, HasDirtyState;

protected $taxonomy;
protected $slug;
Expand All @@ -31,7 +31,6 @@ class Term implements TermContract
protected $data;
protected $afterSaveCallbacks = [];
protected $withEvents = true;
protected $syncOriginalProperties = ['slug'];

public function __construct()
{
Expand Down Expand Up @@ -282,6 +281,14 @@ public function set($key, $value)
return $this;
}

public function getCurrentDirtyStateAttributes(): array
{
return array_merge([
'slug' => $this->slug(),
'taxonomy' => $this->taxonomyHandle(),
], $this->data()->except(['updated_at'])->toArray());
}

public function __call($method, $args)
{
$default = $this->inDefaultLocale();
Expand Down
Loading

0 comments on commit 7da46d8

Please sign in to comment.