[TASK] Refactor element dependency resolving
[Packages/TYPO3.CMS.git] / typo3 / sysext / version / Classes / Dependency / ElementEntity.php
1 <?php
2 namespace TYPO3\CMS\Version\Dependency;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010-2013 Oliver Hader <oliver@typo3.org>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the text file GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Object to hold information on a dependent database element in abstract.
31 */
32 class ElementEntity {
33
34 const REFERENCES_ChildOf = 'childOf';
35 const REFERENCES_ParentOf = 'parentOf';
36 const EVENT_Construct = 'TYPO3\\CMS\\Version\\Dependency\\ElementEntity::construct';
37 const EVENT_CreateChildReference = 'TYPO3\\CMS\\Version\\Dependency\\ElementEntity::createChildReference';
38 const EVENT_CreateParentReference = 'TYPO3\\CMS\\Version\\Dependency\\ElementEntity::createParentReference';
39 const RESPONSE_Skip = 'TYPO3\\CMS\\Version\\Dependency\\ElementEntity->skip';
40
41 /**
42 * @var bool
43 */
44 protected $invalid = FALSE;
45
46 /**
47 * @var string
48 */
49 protected $table;
50
51 /**
52 * @var integer
53 */
54 protected $id;
55
56 /**
57 * @var array
58 */
59 protected $data;
60
61 /**
62 * @var array
63 */
64 protected $record;
65
66 /**
67 * @var \TYPO3\CMS\Version\Dependency\DependencyResolver
68 */
69 protected $dependency;
70
71 /**
72 * @var array
73 */
74 protected $children;
75
76 /**
77 * @var array
78 */
79 protected $parents;
80
81 /**
82 * @var boolean
83 */
84 protected $traversingParents = FALSE;
85
86 /**
87 * @var \TYPO3\CMS\Version\Dependency\ElementEntity
88 */
89 protected $outerMostParent;
90
91 /**
92 * @var array
93 */
94 protected $nestedChildren;
95
96 /**
97 * Creates this object.
98 *
99 * @param string $table
100 * @param integer $id
101 * @param array $data (optional)
102 * @param \TYPO3\CMS\Version\Dependency\DependencyResolver $dependency
103 */
104 public function __construct($table, $id, array $data = array(), \TYPO3\CMS\Version\Dependency\DependencyResolver $dependency) {
105 $this->table = $table;
106 $this->id = (int)$id;
107 $this->data = $data;
108 $this->dependency = $dependency;
109 $this->dependency->executeEventCallback(self::EVENT_Construct, $this);
110 }
111
112 /**
113 * @param bool $invalid
114 */
115 public function setInvalid($invalid) {
116 $this->invalid = (bool)$invalid;
117 }
118
119 /**
120 * @return bool
121 */
122 public function isInvalid() {
123 return $this->invalid;
124 }
125
126 /**
127 * Gets the table.
128 *
129 * @return string
130 */
131 public function getTable() {
132 return $this->table;
133 }
134
135 /**
136 * Gets the id.
137 *
138 * @return integer
139 */
140 public function getId() {
141 return $this->id;
142 }
143
144 /**
145 * Sets the id.
146 *
147 * @param int $id
148 */
149 public function setId($id) {
150 $this->id = (int)$id;
151 }
152
153 /**
154 * Gets the data.
155 *
156 * @return array
157 */
158 public function getData() {
159 return $this->data;
160 }
161
162 /**
163 * Gets a value for a particular key from the data.
164 *
165 * @param string $key
166 * @return mixed
167 */
168 public function getDataValue($key) {
169 $result = NULL;
170 if ($this->hasDataValue($key)) {
171 $result = $this->data[$key];
172 }
173 return $result;
174 }
175
176 /**
177 * Sets a value for a particular key in the data.
178 *
179 * @param string $key
180 * @param mixed $value
181 * @return void
182 */
183 public function setDataValue($key, $value) {
184 $this->data[$key] = $value;
185 }
186
187 /**
188 * Determines whether a particular key holds data.
189 *
190 * @param string $key
191 * @return bool
192 */
193 public function hasDataValue($key) {
194 return isset($this->data[$key]);
195 }
196
197 /**
198 * Converts this object for string representation.
199 *
200 * @return string
201 */
202 public function __toString() {
203 return self::getIdentifier($this->table, $this->id);
204 }
205
206 /**
207 * Gets the parent dependency object.
208 *
209 * @return \TYPO3\CMS\Version\Dependency\DependencyResolver
210 */
211 public function getDependency() {
212 return $this->dependency;
213 }
214
215 /**
216 * Gets all child references.
217 *
218 * @return array|ReferenceEntity[]
219 */
220 public function getChildren() {
221 if (!isset($this->children)) {
222 $this->children = array();
223 $where = 'tablename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->table, 'sys_refindex') . ' AND recuid='
224 . $this->id . ' AND workspace=' . $this->dependency->getWorkspace();
225 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'sys_refindex', $where, '', 'sorting');
226 if (is_array($rows)) {
227 foreach ($rows as $row) {
228 $arguments = array('table' => $row['ref_table'], 'id' => $row['ref_uid'], 'field' => $row['field'], 'scope' => self::REFERENCES_ChildOf);
229 $callbackResponse = $this->dependency->executeEventCallback(self::EVENT_CreateChildReference, $this, $arguments);
230 if ($callbackResponse !== self::RESPONSE_Skip) {
231 $this->children[] = $this->getDependency()->getFactory()->getReferencedElement(
232 $row['ref_table'],
233 $row['ref_uid'],
234 $row['field'],
235 array(),
236 $this->getDependency()
237 );
238 }
239 }
240 }
241 }
242 return $this->children;
243 }
244
245 /**
246 * Gets all parent references.
247 *
248 * @return array|ReferenceEntity[]
249 */
250 public function getParents() {
251 if (!isset($this->parents)) {
252 $this->parents = array();
253 $where = 'ref_table=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->table, 'sys_refindex')
254 . ' AND deleted=0 AND ref_uid=' . $this->id . ' AND workspace=' . $this->dependency->getWorkspace();
255 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'sys_refindex', $where, '', 'sorting');
256 if (is_array($rows)) {
257 foreach ($rows as $row) {
258 $arguments = array('table' => $row['tablename'], 'id' => $row['recuid'], 'field' => $row['field'], 'scope' => self::REFERENCES_ParentOf);
259 $callbackResponse = $this->dependency->executeEventCallback(self::EVENT_CreateParentReference, $this, $arguments);
260 if ($callbackResponse !== self::RESPONSE_Skip) {
261 $this->parents[] = $this->getDependency()->getFactory()->getReferencedElement(
262 $row['tablename'],
263 $row['recuid'],
264 $row['field'],
265 array(),
266 $this->getDependency()
267 );
268 }
269 }
270 }
271 }
272 return $this->parents;
273 }
274
275 /**
276 * Determines whether there are child or parent references.
277 *
278 * @return boolean
279 */
280 public function hasReferences() {
281 return count($this->getChildren()) > 0 || count($this->getParents()) > 0;
282 }
283
284 /**
285 * Gets the outermost parent element.
286 *
287 * @return ElementEntity
288 */
289 public function getOuterMostParent() {
290 if (!isset($this->outerMostParent)) {
291 $parents = $this->getParents();
292 if (count($parents) === 0) {
293 $this->outerMostParent = $this;
294 } else {
295 $this->outerMostParent = FALSE;
296 /** @var $parent \TYPO3\CMS\Version\Dependency\ReferenceEntity */
297 foreach ($parents as $parent) {
298 $outerMostParent = $parent->getElement()->getOuterMostParent();
299 if ($outerMostParent instanceof \TYPO3\CMS\Version\Dependency\ElementEntity) {
300 $this->outerMostParent = $outerMostParent;
301 break;
302 } elseif ($outerMostParent === FALSE) {
303 break;
304 }
305 }
306 }
307 }
308 return $this->outerMostParent;
309 }
310
311 /**
312 * Gets nested children accumulated.
313 *
314 * @return array|ReferenceEntity[]
315 */
316 public function getNestedChildren() {
317 if (!isset($this->nestedChildren)) {
318 $this->nestedChildren = array();
319 $children = $this->getChildren();
320 /** @var $child \TYPO3\CMS\Version\Dependency\ReferenceEntity */
321 foreach ($children as $child) {
322 $this->nestedChildren = array_merge($this->nestedChildren, array($child->getElement()->__toString() => $child->getElement()), $child->getElement()->getNestedChildren());
323 }
324 }
325 return $this->nestedChildren;
326 }
327
328 /**
329 * Converts the object for string representation.
330 *
331 * @param string $table
332 * @param integer $id
333 * @return string
334 */
335 static public function getIdentifier($table, $id) {
336 return $table . ':' . $id;
337 }
338
339 /**
340 * Gets the database record of this element.
341 *
342 * @return array
343 */
344 public function getRecord() {
345 if (empty($this->record['uid']) || (int)$this->record['uid'] !== $this->id) {
346 $this->record = array();
347 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,pid,t3ver_wsid,t3ver_state,t3ver_oid', $this->getTable(), 'uid=' . $this->getId());
348 if (is_array($rows)) {
349 $this->record = $rows[0];
350 }
351 }
352 return $this->record;
353 }
354
355 }