[TASK] Update php-cs-fixer to 2.5.0
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / DomainObject / AbstractDomainObject.php
1 <?php
2 namespace TYPO3\CMS\Extbase\DomainObject;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * A generic Domain Object.
19 *
20 * All Model domain objects need to inherit from either AbstractEntity or AbstractValueObject, as this provides important framework information.
21 */
22 abstract class AbstractDomainObject implements DomainObjectInterface, \TYPO3\CMS\Extbase\Persistence\ObjectMonitoringInterface
23 {
24 /**
25 * @var int The uid of the record. The uid is only unique in the context of the database table.
26 */
27 protected $uid;
28
29 /**
30 * @var int The uid of the localized record. In TYPO3 v4.x the property "uid" holds the uid of the record in default language (the translationOrigin).
31 */
32 protected $_localizedUid;
33
34 /**
35 * @var int The uid of the language of the object. In TYPO3 v4.x this is the uid of the language record in the table sys_language.
36 */
37 protected $_languageUid;
38
39 /**
40 * @var int The uid of the versioned record.
41 */
42 protected $_versionedUid;
43
44 /**
45 * @var int The id of the page the record is "stored".
46 */
47 protected $pid;
48
49 /**
50 * TRUE if the object is a clone
51 *
52 * @var bool
53 */
54 private $_isClone = false;
55
56 /**
57 * @var array An array holding the clean property values. Set right after reconstitution of the object
58 */
59 private $_cleanProperties = [];
60
61 /**
62 * Getter for uid.
63 *
64 * @return int the uid or NULL if none set yet.
65 */
66 public function getUid()
67 {
68 if ($this->uid !== null) {
69 return (int)$this->uid;
70 }
71 return null;
72 }
73
74 /**
75 * Setter for the pid.
76 *
77 * @param int|NULL $pid
78 */
79 public function setPid($pid)
80 {
81 if ($pid === null) {
82 $this->pid = null;
83 } else {
84 $this->pid = (int)$pid;
85 }
86 }
87
88 /**
89 * Getter for the pid.
90 *
91 * @return int The pid or NULL if none set yet.
92 */
93 public function getPid()
94 {
95 if ($this->pid === null) {
96 return null;
97 }
98 return (int)$this->pid;
99 }
100
101 /**
102 * Reconstitutes a property. Only for internal use.
103 *
104 * @param string $propertyName
105 * @param mixed $propertyValue
106 * @return bool
107 */
108 public function _setProperty($propertyName, $propertyValue)
109 {
110 if ($this->_hasProperty($propertyName)) {
111 $this->{$propertyName} = $propertyValue;
112 return true;
113 }
114 return false;
115 }
116
117 /**
118 * Returns the property value of the given property name. Only for internal use.
119 *
120 * @param string $propertyName
121 * @return mixed The propertyValue
122 */
123 public function _getProperty($propertyName)
124 {
125 return $this->{$propertyName};
126 }
127
128 /**
129 * Returns a hash map of property names and property values. Only for internal use.
130 *
131 * @return array The properties
132 */
133 public function _getProperties()
134 {
135 $properties = get_object_vars($this);
136 foreach ($properties as $propertyName => $propertyValue) {
137 if ($propertyName[0] === '_') {
138 unset($properties[$propertyName]);
139 }
140 }
141 return $properties;
142 }
143
144 /**
145 * Returns the property value of the given property name. Only for internal use.
146 *
147 * @param string $propertyName
148 * @return bool TRUE bool true if the property exists, FALSE if it doesn't exist or NULL in case of an error.
149 */
150 public function _hasProperty($propertyName)
151 {
152 return property_exists($this, $propertyName);
153 }
154
155 /**
156 * Returns TRUE if the object is new (the uid was not set, yet). Only for internal use
157 *
158 * @return bool
159 */
160 public function _isNew()
161 {
162 return $this->uid === null;
163 }
164
165 /**
166 * Register an object's clean state, e.g. after it has been reconstituted
167 * from the database.
168 *
169 * @param string $propertyName The name of the property to be memorized. If omitted all persistable properties are memorized.
170 */
171 public function _memorizeCleanState($propertyName = null)
172 {
173 if ($propertyName !== null) {
174 $this->_memorizePropertyCleanState($propertyName);
175 } else {
176 $this->_cleanProperties = [];
177 $properties = get_object_vars($this);
178 foreach ($properties as $propertyName => $propertyValue) {
179 if ($propertyName[0] === '_') {
180 continue;
181 }
182 // Do not memorize "internal" properties
183 $this->_memorizePropertyCleanState($propertyName);
184 }
185 }
186 }
187
188 /**
189 * Register an properties's clean state, e.g. after it has been reconstituted
190 * from the database.
191 *
192 * @param string $propertyName The name of the property to be memorized. If omittet all persistable properties are memorized.
193 */
194 public function _memorizePropertyCleanState($propertyName)
195 {
196 $propertyValue = $this->{$propertyName};
197 if (is_object($propertyValue)) {
198 $this->_cleanProperties[$propertyName] = clone $propertyValue;
199 // We need to make sure the clone and the original object
200 // are identical when compared with == (see _isDirty()).
201 // After the cloning, the Domain Object will have the property
202 // "isClone" set to TRUE, so we manually have to set it to FALSE
203 // again. Possible fix: Somehow get rid of the "isClone" property,
204 // which is currently needed in Fluid.
205 if ($propertyValue instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject) {
206 $this->_cleanProperties[$propertyName]->_setClone(false);
207 }
208 } else {
209 $this->_cleanProperties[$propertyName] = $propertyValue;
210 }
211 }
212
213 /**
214 * Returns a hash map of clean properties and $values.
215 *
216 * @return array
217 */
218 public function _getCleanProperties()
219 {
220 return $this->_cleanProperties;
221 }
222
223 /**
224 * Returns the clean value of the given property. The returned value will be NULL if the clean state was not memorized before, or
225 * if the clean value is NULL.
226 *
227 * @param string $propertyName The name of the property to be memorized.
228 * @return mixed The clean property value or NULL
229 */
230 public function _getCleanProperty($propertyName)
231 {
232 return isset($this->_cleanProperties[$propertyName]) ? $this->_cleanProperties[$propertyName] : null;
233 }
234
235 /**
236 * Returns TRUE if the properties were modified after reconstitution
237 *
238 * @param string $propertyName An optional name of a property to be checked if its value is dirty
239 * @throws \TYPO3\CMS\Extbase\Persistence\Generic\Exception\TooDirtyException
240 * @return bool
241 */
242 public function _isDirty($propertyName = null)
243 {
244 if ($this->uid !== null && $this->_getCleanProperty('uid') !== null && $this->uid != $this->_getCleanProperty('uid')) {
245 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\TooDirtyException('The uid "' . $this->uid . '" has been modified, that is simply too much.', 1222871239);
246 }
247
248 if ($propertyName === null) {
249 foreach ($this->_getCleanProperties() as $propertyName => $cleanPropertyValue) {
250 if ($this->isPropertyDirty($cleanPropertyValue, $this->{$propertyName}) === true) {
251 return true;
252 }
253 }
254 } else {
255 if ($this->isPropertyDirty($this->_getCleanProperty($propertyName), $this->{$propertyName}) === true) {
256 return true;
257 }
258 }
259 return false;
260 }
261
262 /**
263 * Checks the $value against the $cleanState.
264 *
265 * @param mixed $previousValue
266 * @param mixed $currentValue
267 * @return bool
268 */
269 protected function isPropertyDirty($previousValue, $currentValue)
270 {
271 // In case it is an object and it implements the ObjectMonitoringInterface, we call _isDirty() instead of a simple comparison of objects.
272 // 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
273 if (is_object($currentValue)) {
274 if ($currentValue instanceof DomainObjectInterface) {
275 $result = !is_object($previousValue) || get_class($previousValue) !== get_class($currentValue) || $currentValue->getUid() !== $previousValue->getUid();
276 } elseif ($currentValue instanceof \TYPO3\CMS\Extbase\Persistence\ObjectMonitoringInterface) {
277 $result = !is_object($previousValue) || $currentValue->_isDirty() || get_class($previousValue) !== get_class($currentValue);
278 } else {
279 // For all other objects we do only a simple comparison (!=) as we want cloned objects to return the same values.
280 $result = $previousValue != $currentValue;
281 }
282 } else {
283 $result = $previousValue !== $currentValue;
284 }
285 return $result;
286 }
287
288 /**
289 * Returns TRUE if the object has been clonesd, cloned, FALSE otherwise.
290 *
291 * @return bool TRUE if the object has been cloned
292 */
293 public function _isClone()
294 {
295 return $this->_isClone;
296 }
297
298 /**
299 * Setter whether this Domain Object is a clone of another one.
300 * NEVER SET THIS PROPERTY DIRECTLY. We currently need it to make the
301 * _isDirty check inside AbstractEntity work, but it is just a work-
302 * around right now.
303 *
304 * @param bool $clone
305 */
306 public function _setClone($clone)
307 {
308 $this->_isClone = (bool)$clone;
309 }
310
311 /**
312 * Clone method. Sets the _isClone property.
313 */
314 public function __clone()
315 {
316 $this->_isClone = true;
317 }
318
319 /**
320 * Returns the class name and the uid of the object as string
321 *
322 * @return string
323 */
324 public function __toString()
325 {
326 return get_class($this) . ':' . (string)$this->uid;
327 }
328 }