Skip to content

Commit c51442f

Browse files
author
Pantea Marius-ciclistu
committed
POC for laravel/framework#31778 improve getDirty calls laravel/framework#57627
1 parent 8899de9 commit c51442f

File tree

1 file changed

+85
-0
lines changed

1 file changed

+85
-0
lines changed

src/Models/BaseModel.php

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Carbon\Carbon;
66
use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;
7+
use Illuminate\Database\Eloquent\Builder;
78
use Illuminate\Database\Eloquent\Model;
89
use Illuminate\Support\Collection;
910
use Illuminate\Support\Facades\Cache;
@@ -47,6 +48,13 @@ abstract class BaseModel extends Model
4748
protected $hidden = [
4849
'laravel_through_key'
4950
];
51+
52+
/**
53+
* Temporary cache to avoid multiple getDirty calls generating multiple set calls for
54+
* sync/merge casted attributes to objects to persist the possible changes made to those objects
55+
*/
56+
protected ?array $tmpDirtyCache = null;
57+
5058
private array $incrementsToRefresh = [];
5159

5260
/**
@@ -591,6 +599,83 @@ public function syncOriginalAttributes($attributes): static
591599
return $this;
592600
}
593601

602+
/**
603+
* @inheritdoc
604+
*/
605+
public function isDirty($attributes = null): bool
606+
{
607+
return [] !== $this->getDirty(\is_array($attributes) ? $attributes : \func_get_args());
608+
}
609+
610+
/**
611+
* Get the attributes that have been changed since the last sync.
612+
* @param string|array $attributes
613+
* @return array
614+
*/
615+
public function getDirty(): array
616+
{
617+
if (isset($this->tmpDirtyCache)) {
618+
if ([] !== $args = \func_get_args()) {
619+
return \array_intersect_key($this->tmpDirtyCache, \array_flip((array)$args[0]));
620+
}
621+
622+
return $this->tmpDirtyCache;
623+
}
624+
625+
$attributes = (array)(\func_get_args()[0] ?? \array_keys($this->attributes));
626+
627+
$dirty = [];
628+
629+
foreach ($attributes as $key) {
630+
// this will merge/sync before the if condition
631+
$value = $this->getAttributeFromArray($key);
632+
633+
if (!$this->originalIsEquivalent($key)) {
634+
$dirty[$key] = $value;
635+
}
636+
}
637+
638+
return $dirty;
639+
}
640+
641+
/**
642+
* @inheritdoc
643+
*/
644+
protected function performUpdate(Builder $query): bool
645+
{
646+
if ($this->fireModelEvent('updating') === false) {
647+
return false;
648+
}
649+
650+
if ($this->usesTimestamps()) {
651+
$this->updateTimestamps();
652+
}
653+
654+
// this is needed because updating event might change the model
655+
$dirty = $this->getDirtyForUpdate();
656+
657+
if ([] !== $dirty) {
658+
$this->setKeysForSaveQuery($query)->update($dirty);
659+
$this->tmpDirtyCache = $dirty;
660+
$this->syncChanges();
661+
unset($this->tmpDirtyCache);
662+
663+
$this->fireModelEvent('updated', false);
664+
}
665+
666+
return true;
667+
}
668+
669+
/**
670+
* Get the attributes that have been changed since the last sync for an update operation.
671+
*
672+
* @return array
673+
*/
674+
protected function getDirtyForUpdate(): array
675+
{
676+
return $this->getDirty();
677+
}
678+
594679
/**
595680
* Get an attribute from the $attributes array without transformation
596681
* @see self::getAttributeValue

0 commit comments

Comments
 (0)