‪TYPO3CMS  ‪main
AbstractDomainObject.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
23 
31 {
32  public const ‪PROPERTY_UID = 'uid';
33  public const ‪PROPERTY_PID = 'pid';
34  public const ‪PROPERTY_LOCALIZED_UID = '_localizedUid';
35  public const ‪PROPERTY_LANGUAGE_UID = '_languageUid';
36  public const ‪PROPERTY_VERSIONED_UID = '_versionedUid';
37 
41  protected ?int ‪$uid = null;
42 
49  protected ?int ‪$_localizedUid = null;
50 
57  protected ?int ‪$_languageUid = null;
58 
65  protected ?int ‪$_versionedUid = null;
66 
70  protected ?int ‪$pid = null;
71 
77  private bool ‪$_isClone = false;
78 
84  private array ‪$_cleanProperties = [];
85 
89  public function ‪getUid(): ?int
90  {
91  if ($this->‪uid !== null) {
92  return (int)‪$this->uid;
93  }
94  return null;
95  }
96 
100  public function ‪setPid(int $pid): void
101  {
102  $this->‪pid = ‪$pid;
103  }
104 
108  public function ‪getPid(): ?int
109  {
110  if ($this->‪pid === null) {
111  return null;
112  }
113  return (int)‪$this->pid;
114  }
115 
119  public function ‪_setProperty(string $propertyName, mixed $value): bool
120  {
121  if ($this->‪_hasProperty($propertyName)) {
122  $this->{$propertyName} = $value;
123  return true;
124  }
125  return false;
126  }
127 
131  public function ‪_getProperty(string $propertyName): mixed
132  {
133  return $this->‪_hasProperty($propertyName) && isset($this->{$propertyName})
134  ? $this->{$propertyName}
135  : null;
136  }
137 
143  public function _getProperties(): array
144  {
145  $properties = get_object_vars($this);
146  foreach ($properties as $propertyName => $propertyValue) {
147  if (str_starts_with($propertyName, '_')) {
148  unset($properties[$propertyName]);
149  }
150  }
151  return $properties;
152  }
153 
159  public function ‪_hasProperty(string $propertyName): bool
160  {
161  return property_exists($this, $propertyName);
162  }
163 
169  public function ‪_isNew(): bool
170  {
171  return $this->‪uid === null;
172  }
173 
180  public function ‪_memorizeCleanState(?string $propertyName = null): void
181  {
182  if ($propertyName !== null) {
183  $this->‪_memorizePropertyCleanState($propertyName);
184  } else {
185  $this->‪_cleanProperties = [];
186  foreach ($this->_getProperties() as $propertyName => $propertyValue) {
187  $this->‪_memorizePropertyCleanState($propertyName);
188  }
189  }
190  }
191 
198  public function ‪_memorizePropertyCleanState(string $propertyName): void
199  {
200  $propertyValue = $this->‪_getProperty($propertyName);
201  if (is_object($propertyValue) && !($propertyValue instanceof \UnitEnum)) {
202  $propertyValueClone = clone $propertyValue;
203  // We need to make sure the clone and the original object
204  // are identical when compared with == (see _isDirty()).
205  // After the cloning, the Domain Object will have the property
206  // "isClone" set to TRUE, so we manually have to set it to FALSE
207  // again. Possible fix: Somehow get rid of the "isClone" property,
208  // which is currently needed in Fluid.
209  if ($propertyValueClone instanceof ‪AbstractDomainObject) {
210  $propertyValueClone->_setClone(false);
211  }
212 
213  $this->‪_cleanProperties[$propertyName] = $propertyValueClone;
214  } else {
215  $this->‪_cleanProperties[$propertyName] = $propertyValue;
216  }
217  }
218 
224  public function _getCleanProperties(): array
225  {
227  }
228 
237  public function ‪_getCleanProperty(string $propertyName): mixed
238  {
239  return $this->‪_cleanProperties[$propertyName] ?? null;
240  }
241 
249  public function ‪_isDirty(?string $propertyName = null): bool
250  {
251  if ($this->‪uid !== null && $this->‪_getCleanProperty(self::PROPERTY_UID) !== null && $this->‪uid != $this->‪_getCleanProperty(self::PROPERTY_UID)) {
252  throw new ‪TooDirtyException('The ' . self::PROPERTY_UID . ' "' . $this->‪uid . '" has been modified, that is simply too much.', 1222871239);
253  }
254 
255  if ($propertyName === null) {
256  foreach ($this->_getCleanProperties() as $propertyName => $cleanPropertyValue) {
257  if ($this->‪isPropertyDirty($cleanPropertyValue, $this->‪_getProperty($propertyName)) === true) {
258  return true;
259  }
260  }
261  return false;
262  }
263 
264  if ($this->‪isPropertyDirty($this->‪_getCleanProperty($propertyName), $this->‪_getProperty($propertyName)) === true) {
265  return true;
266  }
267 
268  return false;
269  }
270 
274  protected function ‪isPropertyDirty(mixed $previousValue, mixed $currentValue): bool
275  {
276  // In case it is an object and it implements the ObjectMonitoringInterface, we call _isDirty() instead of a simple comparison of objects.
277  // We do this, because if the object itself contains a lazy loaded property, the comparison of the objects might fail even if the object didn't change
278  if (is_object($currentValue)) {
279  $currentTypeString = null;
280  if ($currentValue instanceof ‪LazyLoadingProxy) {
281  $currentTypeString = $currentValue->_getTypeAndUidString();
282  } elseif ($currentValue instanceof ‪DomainObjectInterface) {
283  $currentTypeString = $currentValue::class . ':' . $currentValue->getUid();
284  }
285 
286  if ($currentTypeString !== null) {
287  $previousTypeString = null;
288  if ($previousValue instanceof ‪LazyLoadingProxy) {
289  $previousTypeString = $previousValue->_getTypeAndUidString();
290  } elseif ($previousValue instanceof ‪DomainObjectInterface) {
291  $previousTypeString = $previousValue::class . ':' . $previousValue->getUid();
292  }
293 
294  $result = $currentTypeString !== $previousTypeString;
295  } elseif ($currentValue instanceof ‪ObjectMonitoringInterface) {
296  $result = !is_object($previousValue) || $currentValue->_isDirty() || $previousValue::class !== $currentValue::class;
297  } else {
298  // For all other objects we do only a simple comparison (!=) as we want cloned objects to return the same values.
299  $result = $previousValue != $currentValue;
300  }
301  } else {
302  $result = $previousValue !== $currentValue;
303  }
304  return $result;
305  }
306 
307  public function ‪_isClone(): bool
308  {
309  return ‪$this->_isClone;
310  }
311 
320  public function ‪_setClone(bool $clone)
321  {
322  $this->‪_isClone = $clone;
323  }
324 
325  public function ‪__clone(): void
326  {
327  $this->‪_isClone = true;
328  }
329 
333  public function ‪__toString(): string
334  {
335  return static::class . ':' . ‪$this->uid;
336  }
337 }
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\$_isClone
‪bool $_isClone
Definition: AbstractDomainObject.php:77
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\__toString
‪non empty string __toString()
Definition: AbstractDomainObject.php:333
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\$_versionedUid
‪int $_versionedUid
Definition: AbstractDomainObject.php:65
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\_getProperty
‪_getProperty(string $propertyName)
Definition: AbstractDomainObject.php:131
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\isPropertyDirty
‪isPropertyDirty(mixed $previousValue, mixed $currentValue)
Definition: AbstractDomainObject.php:274
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\PROPERTY_PID
‪const PROPERTY_PID
Definition: AbstractDomainObject.php:33
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\_getCleanProperty
‪_getCleanProperty(string $propertyName)
Definition: AbstractDomainObject.php:237
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\PROPERTY_LOCALIZED_UID
‪const PROPERTY_LOCALIZED_UID
Definition: AbstractDomainObject.php:34
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface\getPid
‪getPid()
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\_isDirty
‪_isDirty(?string $propertyName=null)
Definition: AbstractDomainObject.php:249
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\_memorizeCleanState
‪_memorizeCleanState(?string $propertyName=null)
Definition: AbstractDomainObject.php:180
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface\_isNew
‪_isNew()
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\setPid
‪setPid(int $pid)
Definition: AbstractDomainObject.php:100
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\pid
‪int< 0, function getPid():?int { if( $this->pid===null) { return null;} return(int) $this-> pid
Definition: AbstractDomainObject.php:113
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface
Definition: DomainObjectInterface.php:33
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject
Definition: AbstractDomainObject.php:31
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface\getUid
‪getUid()
‪TYPO3\CMS\Extbase\DomainObject
Definition: AbstractDomainObject.php:18
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\PROPERTY_LANGUAGE_UID
‪const PROPERTY_LANGUAGE_UID
Definition: AbstractDomainObject.php:35
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\PROPERTY_VERSIONED_UID
‪const PROPERTY_VERSIONED_UID
Definition: AbstractDomainObject.php:36
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\$_cleanProperties
‪array $_cleanProperties
Definition: AbstractDomainObject.php:84
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\_setProperty
‪_setProperty(string $propertyName, mixed $value)
Definition: AbstractDomainObject.php:119
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\uid
‪int< 1, function getUid():?int { if( $this->uid !==null) { return(int) $this-> uid
Definition: AbstractDomainObject.php:92
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\$pid
‪int $pid
Definition: AbstractDomainObject.php:70
‪TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy
Definition: LazyLoadingProxy.php:30
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\_memorizePropertyCleanState
‪_memorizePropertyCleanState(string $propertyName)
Definition: AbstractDomainObject.php:198
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\$_languageUid
‪int $_languageUid
Definition: AbstractDomainObject.php:57
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\_setClone
‪_setClone(bool $clone)
Definition: AbstractDomainObject.php:320
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\$uid
‪int $uid
Definition: AbstractDomainObject.php:41
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\_isClone
‪_isClone()
Definition: AbstractDomainObject.php:307
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\PROPERTY_UID
‪const PROPERTY_UID
Definition: AbstractDomainObject.php:32
‪TYPO3\CMS\Extbase\Persistence\Generic\Exception\TooDirtyException
Definition: TooDirtyException.php:25
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\$_localizedUid
‪int $_localizedUid
Definition: AbstractDomainObject.php:49
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\_cleanProperties
‪array< non-empty-string, function _getCleanProperties():array { return $this-> _cleanProperties
Definition: AbstractDomainObject.php:226
‪TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject\__clone
‪__clone()
Definition: AbstractDomainObject.php:325
‪TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface\_hasProperty
‪_hasProperty(string $propertyName)
‪TYPO3\CMS\Extbase\Persistence\ObjectMonitoringInterface
Definition: ObjectMonitoringInterface.php:27