[FEATURE] TCA-record-collection based on collection interfaces
[Packages/TYPO3.CMS.git] / t3lib / collection / AbstractRecordCollection.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2011 Steffen Ritter <typo3@steffen-ritter.net>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28
29 /**
30 * Abstract implementation of a RecordCollection
31 *
32 * RecordCollection is a collections of TCA-Records.
33 * The collection is meant to be stored in TCA-table sys_collections and is manageable
34 * via TCEforms.
35 *
36 * A RecordCollection might be used to group a set of records (e.g. news, images, contentElements)
37 * for output in frontend
38 *
39 * The AbstractRecordCollection uses SplDoublyLinkedList for internal storage
40 *
41 * @author Steffen Ritter <typo3@steffen-ritter.net>
42 * @abstract
43 * @package TYPO3
44 * @subpackage t3lib
45 */
46 abstract class t3lib_collection_AbstractRecordCollection implements t3lib_collection_RecordCollection, t3lib_collection_Persistable, t3lib_collection_Sortable {
47
48 /**
49 * The table name collections are stored to
50 *
51 * @var string
52 */
53 protected static $storageTableName = 'sys_collection';
54
55 /**
56 * The table name collections are stored to
57 *
58 * @var string
59 */
60 protected static $storageItemsField = 'items';
61
62 /**
63 * Uid of the storage
64 *
65 * @var int
66 */
67 protected $uid = 0;
68
69 /**
70 * Collection title
71 *
72 * @var string
73 */
74 protected $title;
75
76 /**
77 * Collection description
78 *
79 * @var string
80 */
81 protected $description;
82
83 /**
84 * Table name of the records stored in this collection
85 *
86 * @var string
87 */
88 protected $itemTableName;
89
90
91 /**
92 * The local storage
93 *
94 * @var SplDoublyLinkedList
95 */
96 protected $storage;
97
98 public function __construct() {
99 $this->storage = new SplDoublyLinkedList();
100 }
101
102 /**
103 * (PHP 5 &gt;= 5.1.0)<br/>
104 * Return the current element
105 *
106 * @link http://php.net/manual/en/iterator.current.php
107 * @return mixed Can return any type.
108 */
109 public function current() {
110 return $this->storage->current();
111 }
112
113 /**
114 * (PHP 5 &gt;= 5.1.0)<br/>
115 * Move forward to next element
116 *
117 * @link http://php.net/manual/en/iterator.next.php
118 * @return void Any returned value is ignored.
119 */
120 public function next() {
121 $this->storage->next();
122 }
123
124 /**
125 * (PHP 5 &gt;= 5.1.0)<br/>
126 * Return the key of the current element
127 *
128 * @link http://php.net/manual/en/iterator.key.php
129 * @return scalar scalar on success, integer
130 * 0 on failure.
131 */
132 public function key() {
133 $currentRecord = $this->storage->current();
134 return $currentRecord['uid'];
135 }
136
137 /**
138 * (PHP 5 &gt;= 5.1.0)<br/>
139 * Checks if current position is valid
140 *
141 * @link http://php.net/manual/en/iterator.valid.php
142 * @return boolean The return value will be casted to boolean and then evaluated.
143 * Returns true on success or false on failure.
144 */
145 public function valid() {
146 return $this->storage->valid();
147 }
148
149 /**
150 * (PHP 5 &gt;= 5.1.0)<br/>
151 * Rewind the Iterator to the first element
152 *
153 * @link http://php.net/manual/en/iterator.rewind.php
154 * @return void Any returned value is ignored.
155 */
156 public function rewind() {
157 $this->storage->rewind();
158 }
159
160 /**
161 * (PHP 5 &gt;= 5.1.0)<br/>
162 * String representation of object
163 *
164 * @link http://php.net/manual/en/serializable.serialize.php
165 * @return string the string representation of the object or &null;
166 */
167 public function serialize() {
168 $data = array(
169 'uid' => $this->getIdentifier(),
170 );
171 return serialize($data);
172 }
173
174 /**
175 * (PHP 5 &gt;= 5.1.0)<br/>
176 * Constructs the object
177 *
178 * @link http://php.net/manual/en/serializable.unserialize.php
179 * @param string $serialized <p>
180 * The string representation of the object.
181 * </p>
182 * @return mixed the original value unserialized.
183 */
184 public function unserialize($serialized) {
185 $data = unserialize($serialized);
186 return self::load($data['uid']);
187 }
188
189 /**
190 * (PHP 5 &gt;= 5.1.0)<br/>
191 * Count elements of an object
192 *
193 * @link http://php.net/manual/en/countable.count.php
194 * @return int The custom count as an integer.
195 * </p>
196 * <p>
197 * The return value is cast to an integer.
198 */
199 public function count() {
200 return $this->storage->count();
201 }
202
203 /**
204 * Getter for the title
205 *
206 * @return string
207 */
208 public function getTitle() {
209 return $this->title;
210 }
211
212 /**
213 * Getter for the description
214 *
215 * @return string
216 */
217 public function getDescription() {
218 return $this->description;
219 }
220
221 /**
222 * Setter for the title
223 *
224 * @param string $title
225 * @return void
226 */
227 public function setTitle($title) {
228 $this->title = $title;
229 }
230
231 /**
232 * Setter for the description
233 *
234 * @param string $desc
235 * @return void
236 */
237 public function setDescription($desc) {
238 $this->description = $desc;
239 }
240
241
242 /**
243 * Setter for the name of the data-source table
244 *
245 * @return string
246 */
247 public function getItemTableName() {
248 return $this->itemTableName;
249 }
250
251 /**
252 * Setter for the name of the data-source table
253 *
254 * @param string $tableName
255 * @return void
256 */
257 public function setItemTableName($tableName) {
258 $this->itemTableName = $tableName;
259 }
260
261 /**
262 * Sorts collection via given callBackFunction
263 *
264 * The comparison function given as must return an integer less than, equal to, or greater than
265 * zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
266 *
267 * @param $callbackFunction
268 * @see http://www.php.net/manual/en/function.usort.php
269 * @return void
270 */
271 public function usort($callbackFunction) {
272 // TODO: Implement usort() method with TCEforms in mind
273 throw new RuntimeException('This method is not yet supported.', 1322545589);
274 }
275
276 /**
277 * Moves the item within the collection
278 *
279 * the item at $currentPosition will be moved to
280 * $newPosition. Ommiting $newPosition will move to top.
281 *
282 * @param int $currentPosition
283 * @param int $newPosition
284 * @return void
285 */
286 public function moveItemAt($currentPosition, $newPosition = 0) {
287 // TODO: Implement usort() method with TCEforms in mind
288 throw new RuntimeException('This method is not yet supported.', 1322545626);
289 }
290
291
292 /**
293 * Returns the uid of the collection
294 *
295 * @return integer
296 */
297 public function getIdentifier() {
298 return $this->uid;
299 }
300
301 /**
302 * Sets the identifier of the collection
303 *
304 * @param int $id
305 * @return void
306 */
307 public function setIdentifier($id) {
308 $this->uid = intval($id);
309 }
310
311
312 /**
313 * Loads the collections with the given id from persistence
314 *
315 * For memory reasons, per default only f.e. title, database-table,
316 * identifier (what ever static data is defined) is loaded.
317 * Entries can be load on first access.
318 *
319 * @static
320 * @param int|string $id
321 * @param boolean $fillItems Populates the entries directly on load, might be bad for memory on large collections
322 * @return t3lib_collection_Collection
323 */
324 public static function load($id, $fillItems = FALSE) {
325 $collection = new static();
326 t3lib_div::loadTCA(static::$storageTableName);
327
328 $collectionRecord = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
329 '*',
330 static::$storageTableName,
331 'uid=' . intval($id) . t3lib_BEfunc::deleteClause(static::$storageTableName)
332 );
333
334 $collection->fromArray($collectionRecord);
335
336 if ($fillItems) {
337 $collection->loadContents();
338 }
339
340 return $collection;
341 }
342
343 /**
344 * Persists current collection state to underlying storage
345 *
346 * @return void
347 */
348 public function persist() {
349 $uid = $this->getIdentifier() == 0 ? 'NEW' . rand(100000, 999999) : $this->getIdentifier();
350 $data = array(
351 trim(static::$storageTableName) => array(
352 $uid => $this->getPersistableDataArray()
353 )
354 );
355 // new records always must have a pid
356 if ($this->getIdentifier() == 0) {
357 $data[trim(static::$storageTableName)][$uid]['pid'] = 0;
358 }
359
360 /** @var t3lib_TCEmain $tce */
361 $tce = t3lib_div::makeInstance('t3lib_TCEmain');
362 $tce->stripslashes_values = 0;
363 $tce->start($data, array());
364 $tce->process_datamap();
365 }
366
367 /**
368 * Returns an array of the persistable properties and contents
369 * which are processable by TCEmain.
370 *
371 * for internal usage in persist only.
372 *
373 * @abstract
374 * @return array
375 */
376 abstract protected function getPersistableDataArray();
377
378 /**
379 * Generates comma-separated list of entry uids for usage in TCEmain
380 *
381 * also allow to add table name, if it might be needed by TCEmain for
382 * storing the relation
383 *
384 * @param bool $includeTableName
385 * @return string
386 */
387 protected function getItemUidList($includeTableName = FALSE) {
388 $list = array();
389 foreach($this->storage AS $entry) {
390 $list[] = $this->getItemTableName() . '_' . $entry['uid'];
391 }
392 return implode(',', $list);
393 }
394
395 /**
396 * Builds an array representation of this collection
397 *
398 * @return array
399 */
400 public function toArray() {
401 $itemArray = array();
402 foreach ($this->storage as $item) {
403 $itemArray[] = $item;
404 }
405 return array(
406 'uid' => $this->getIdentifier(),
407 'title' => $this->getTitle(),
408 'description' => $this->getDescription(),
409 'table_name' => $this->getItemTableName(),
410 'items' => $itemArray
411 );
412 }
413
414 /**
415 * Loads the properties of this collection from an array
416 *
417 * @param array $array
418 * @return void
419 */
420 public function fromArray(array $array) {
421 $this->uid = $array['uid'];
422 $this->title = $array['title'];
423 $this->description = $array['description'];
424 $this->itemTableName= $array['table_name'];
425 }
426
427 }
428
429 ?>