[TASK] Streamline phpdoc annotations in EXT:extbase
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Persistence / Generic / LazyObjectStorage.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Persistence\Generic;
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 use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface;
18 use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
19 use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper;
20
21 /**
22 * A proxy that can replace any object and replaces itself in it's parent on
23 * first access (call, get, set, isset, unset).
24 * @internal only to be used within Extbase, not part of TYPO3 Core API.
25 */
26 class LazyObjectStorage extends \TYPO3\CMS\Extbase\Persistence\ObjectStorage implements \TYPO3\CMS\Extbase\Persistence\Generic\LoadingStrategyInterface
27 {
28 /**
29 * This field is only needed to make debugging easier:
30 * If you call current() on a class that implements Iterator, PHP will return the first field of the object
31 * instead of calling the current() method of the interface.
32 * We use this unusual behavior of PHP to return the warning below in this case.
33 *
34 * @var string
35 */
36 private $warning = 'You should never see this warning. If you do, you probably used PHP array functions like current() on the TYPO3\\CMS\\Extbase\\Persistence\\Generic\\LazyObjectStorage. To retrieve the first result, you can use the rewind() and current() methods.';
37
38 /**
39 * @var ?DataMapper
40 */
41 protected $dataMapper;
42
43 /**
44 * The object this property is contained in.
45 *
46 * @var \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface
47 */
48 protected $parentObject;
49
50 /**
51 * The name of the property represented by this proxy.
52 *
53 * @var string
54 */
55 protected $propertyName;
56
57 /**
58 * The raw field value.
59 *
60 * @var mixed
61 */
62 protected $fieldValue;
63
64 /**
65 * @var bool
66 */
67 protected $isInitialized = false;
68
69 /**
70 * @var ObjectManagerInterface
71 */
72 protected $objectManager;
73
74 /**
75 * @param ObjectManagerInterface $objectManager
76 */
77 public function injectObjectManager(ObjectManagerInterface $objectManager)
78 {
79 $this->objectManager = $objectManager;
80 }
81
82 /**
83 * Returns the state of the initialization
84 *
85 * @return bool
86 */
87 public function isInitialized()
88 {
89 return $this->isInitialized;
90 }
91
92 /**
93 * Constructs this proxy instance.
94 *
95 * @param DomainObjectInterface $parentObject The object instance this proxy is part of
96 * @param string $propertyName The name of the proxied property in it's parent
97 * @param mixed $fieldValue The raw field value.
98 * @param ?DataMapper $dataMapper
99 */
100 public function __construct($parentObject, $propertyName, $fieldValue, ?DataMapper $dataMapper = null)
101 {
102 $this->parentObject = $parentObject;
103 $this->propertyName = $propertyName;
104 $this->fieldValue = $fieldValue;
105 reset($this->storage);
106 $this->dataMapper = $dataMapper;
107 }
108
109 /**
110 * Object initialization called when object is created with ObjectManager, after constructor
111 */
112 public function initializeObject()
113 {
114 if (!$this->dataMapper) {
115 $this->dataMapper = $this->objectManager->get(DataMapper::class);
116 }
117 }
118
119 /**
120 * This is a function lazy load implementation.
121 */
122 protected function initialize()
123 {
124 if (!$this->isInitialized) {
125 $this->isInitialized = true;
126 $objects = $this->dataMapper->fetchRelated($this->parentObject, $this->propertyName, $this->fieldValue, false);
127 foreach ($objects as $object) {
128 parent::attach($object);
129 }
130 $this->_memorizeCleanState();
131 if (!$this->isStorageAlreadyMemorizedInParentCleanState()) {
132 $this->parentObject->_memorizeCleanState($this->propertyName);
133 }
134 }
135 }
136
137 /**
138 * @return bool
139 */
140 protected function isStorageAlreadyMemorizedInParentCleanState()
141 {
142 return $this->parentObject->_getCleanProperty($this->propertyName) === $this;
143 }
144
145 // Delegation to the ObjectStorage methods below
146 /**
147 * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $storage
148 *
149 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::addAll
150 */
151 public function addAll(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $storage)
152 {
153 $this->initialize();
154 parent::addAll($storage);
155 }
156
157 /**
158 * @param object $object The object to add.
159 * @param mixed $data The data to associate with the object.
160 *
161 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::attach
162 */
163 public function attach($object, $data = null)
164 {
165 $this->initialize();
166 parent::attach($object, $data);
167 }
168
169 /**
170 * @param object $object The object to look for.
171 * @return bool
172 *
173 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::contains
174 */
175 public function contains($object)
176 {
177 $this->initialize();
178 return parent::contains($object);
179 }
180
181 /**
182 * Counts the elements in the storage array
183 *
184 * @throws Exception
185 * @return int The number of elements in the ObjectStorage
186 */
187 public function count()
188 {
189 $columnMap = $this->dataMapper->getDataMap(get_class($this->parentObject))->getColumnMap($this->propertyName);
190 $numberOfElements = null;
191 if (!$this->isInitialized && $columnMap->getTypeOfRelation() === Mapper\ColumnMap::RELATION_HAS_MANY) {
192 $numberOfElements = $this->dataMapper->countRelated($this->parentObject, $this->propertyName, $this->fieldValue);
193 } else {
194 $this->initialize();
195 $numberOfElements = count($this->storage);
196 }
197 if ($numberOfElements === null) {
198 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception('The number of elements could not be determined.', 1252514486);
199 }
200 return $numberOfElements;
201 }
202
203 /**
204 * @return object The object at the current iterator position.
205 *
206 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::current
207 */
208 public function current()
209 {
210 $this->initialize();
211 return parent::current();
212 }
213
214 /**
215 * @param object $object The object to remove.
216 *
217 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::detach
218 */
219 public function detach($object)
220 {
221 $this->initialize();
222 parent::detach($object);
223 }
224
225 /**
226 * @return string The index corresponding to the position of the iterator.
227 *
228 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::key
229 */
230 public function key()
231 {
232 $this->initialize();
233 return parent::key();
234 }
235
236 /**
237 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::next
238 */
239 public function next()
240 {
241 $this->initialize();
242 parent::next();
243 }
244
245 /**
246 * @param object $object The object to look for.
247 * @return bool
248 *
249 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::offsetExists
250 */
251 public function offsetExists($object)
252 {
253 $this->initialize();
254 return parent::offsetExists($object);
255 }
256
257 /**
258 * @param object $object The object to look for.
259 * @return mixed
260 *
261 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::offsetGet
262 */
263 public function offsetGet($object)
264 {
265 $this->initialize();
266 return parent::offsetGet($object);
267 }
268
269 /**
270 * @param object $object The object to add.
271 * @param mixed $info The data to associate with the object.
272 *
273 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::offsetSet
274 */
275 public function offsetSet($object, $info)
276 {
277 $this->initialize();
278 parent::offsetSet($object, $info);
279 }
280
281 /**
282 * @param object $object The object to remove.
283 *
284 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::offsetUnset
285 */
286 public function offsetUnset($object)
287 {
288 $this->initialize();
289 parent::offsetUnset($object);
290 }
291
292 /**
293 * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $storage The storage containing the elements to remove.
294 *
295 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::removeAll
296 */
297 public function removeAll(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $storage)
298 {
299 $this->initialize();
300 parent::removeAll($storage);
301 }
302
303 /**
304 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::rewind
305 */
306 public function rewind()
307 {
308 $this->initialize();
309 parent::rewind();
310 }
311
312 /**
313 * @return bool
314 *
315 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::valid
316 */
317 public function valid()
318 {
319 $this->initialize();
320 return parent::valid();
321 }
322
323 /**
324 * @return array
325 *
326 * @see \TYPO3\CMS\Extbase\Persistence\ObjectStorage::toArray
327 */
328 public function toArray()
329 {
330 $this->initialize();
331 return parent::toArray();
332 }
333
334 /**
335 * @param mixed $object
336 * @return int|null
337 */
338 public function getPosition($object)
339 {
340 $this->initialize();
341 return parent::getPosition($object);
342 }
343 }