[BUGFIX] Reuse entities of overridden classes in persistence session
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Persistence / Generic / Session.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\Persistence\ObjectStorage;
18
19 /**
20 * The persistence session - acts as a Unit of Work for Extbase persistence framework.
21 * @internal only to be used within Extbase, not part of TYPO3 Core API.
22 */
23 class Session implements \TYPO3\CMS\Core\SingletonInterface
24 {
25 /**
26 * @var \TYPO3\CMS\Extbase\Object\Container\Container
27 */
28 protected $objectContainer;
29
30 /**
31 * Reconstituted objects
32 *
33 * @var ObjectStorage
34 */
35 protected $reconstitutedEntities;
36
37 /**
38 * @var ObjectStorage
39 */
40 protected $objectMap;
41
42 /**
43 * @var array
44 */
45 protected $identifierMap = [];
46
47 /**
48 * Constructs a new Session
49 */
50 public function __construct(\TYPO3\CMS\Extbase\Object\Container\Container $container)
51 {
52 $this->objectContainer = $container;
53 $this->reconstitutedEntities = new ObjectStorage();
54 $this->objectMap = new ObjectStorage();
55 }
56
57 /**
58 * Registers data for a reconstituted object.
59 *
60 * $entityData format is described in
61 * "Documentation/PersistenceFramework object data format.txt"
62 *
63 * @param object $entity
64 */
65 public function registerReconstitutedEntity($entity)
66 {
67 $this->reconstitutedEntities->attach($entity);
68 }
69
70 /**
71 * Replace a reconstituted object, leaves the clean data unchanged.
72 *
73 * @param object $oldEntity
74 * @param object $newEntity
75 */
76 public function replaceReconstitutedEntity($oldEntity, $newEntity)
77 {
78 $this->reconstitutedEntities->detach($oldEntity);
79 $this->reconstitutedEntities->attach($newEntity);
80 }
81
82 /**
83 * Unregisters data for a reconstituted object
84 *
85 * @param object $entity
86 */
87 public function unregisterReconstitutedEntity($entity)
88 {
89 if ($this->reconstitutedEntities->contains($entity)) {
90 $this->reconstitutedEntities->detach($entity);
91 }
92 }
93
94 /**
95 * Returns all objects which have been registered as reconstituted
96 *
97 * @return ObjectStorage All reconstituted objects
98 */
99 public function getReconstitutedEntities()
100 {
101 return $this->reconstitutedEntities;
102 }
103
104 /**
105 * Tells whether the given object is a reconstituted entity.
106 *
107 * @param object $entity
108 * @return bool
109 */
110 public function isReconstitutedEntity($entity)
111 {
112 return $this->reconstitutedEntities->contains($entity);
113 }
114
115 // @todo implement the is dirty checking behaviour of the Flow persistence session here
116
117 /**
118 * Checks whether the given object is known to the identity map
119 *
120 * @param object $object
121 * @return bool
122 */
123 public function hasObject($object)
124 {
125 return $this->objectMap->contains($object);
126 }
127
128 /**
129 * Checks whether the given identifier is known to the identity map
130 *
131 * @param string $identifier
132 * @param string $className
133 * @return bool
134 */
135 public function hasIdentifier($identifier, $className)
136 {
137 return isset($this->identifierMap[$this->getClassIdentifier($className)][$identifier]);
138 }
139
140 /**
141 * Returns the object for the given identifier
142 *
143 * @param string $identifier
144 * @param string $className
145 * @return object
146 */
147 public function getObjectByIdentifier($identifier, $className)
148 {
149 return $this->identifierMap[$this->getClassIdentifier($className)][$identifier];
150 }
151
152 /**
153 * Returns the identifier for the given object from
154 * the session, if the object was registered.
155 *
156 *
157 * @param object $object
158 * @return string
159 */
160 public function getIdentifierByObject($object)
161 {
162 if ($this->hasObject($object)) {
163 return $this->objectMap[$object];
164 }
165 return null;
166 }
167
168 /**
169 * Register an identifier for an object
170 *
171 * @param object $object
172 * @param string $identifier
173 */
174 public function registerObject($object, $identifier)
175 {
176 $this->objectMap[$object] = $identifier;
177 $this->identifierMap[$this->getClassIdentifier(get_class($object))][$identifier] = $object;
178 }
179
180 /**
181 * Unregister an object
182 *
183 * @param object $object
184 */
185 public function unregisterObject($object)
186 {
187 unset($this->identifierMap[$this->getClassIdentifier(get_class($object))][$this->objectMap[$object]]);
188 $this->objectMap->detach($object);
189 }
190
191 /**
192 * Destroy the state of the persistence session and reset
193 * all internal data.
194 */
195 public function destroy()
196 {
197 $this->identifierMap = [];
198 $this->objectMap = new ObjectStorage();
199 $this->reconstitutedEntities = new ObjectStorage();
200 }
201
202 /**
203 * Objects are stored in the cache with their implementation class name
204 * to allow reusing instances of different classes that point to the same implementation
205 *
206 * @param string $className
207 * @return string a unique class identifier respecting configured implementation class names
208 */
209 protected function getClassIdentifier($className): string
210 {
211 return strtolower($this->objectContainer->getImplementationClassName($className));
212 }
213 }