Completed
Push — master ( 02c6d5...d489c9 )
by Aimeos
18:34 queued 09:56
created

Base::getItem()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 3
nop 3
dl 0
loc 22
rs 8.9197
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2011
6
 * @copyright Aimeos (aimeos.org), 2015-2016
7
 * @package MShop
8
 * @subpackage Common
9
 */
10
11
12
namespace Aimeos\MShop\Common\Manager\Lists;
13
14
15
/**
16
 * Abstract list manager implementation
17
 *
18
 * @package MShop
19
 * @subpackage Common
20
 */
21
abstract class Base
22
	extends \Aimeos\MShop\Common\Manager\Base
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces between "Base" and comma; 1 found
Loading history...
23
	implements \Aimeos\MShop\Common\Manager\Lists\Iface
24
{
25
	private $prefix;
26
	private $searchConfig;
27
28
29
	/**
30
	 * Creates the common list manager using the given context object.
31
	 *
32
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object with required objects
33
	 *
34
	 * @throws \Aimeos\MShop\Exception if no configuration is available
35
	 */
36
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
37
	{
38
		$this->searchConfig = $this->getSearchConfig();
39
40
		if( ( $entry = reset( $this->searchConfig ) ) === false ) {
41
			throw new \Aimeos\MShop\Exception( sprintf( 'Search configuration not available' ) );
42
		}
43
44
		if( ( $pos = strrpos( $entry['code'], '.' ) ) === false ) {
45
			throw new \Aimeos\MShop\Exception( sprintf( 'Search configuration for "%1$s" not available', $entry['code'] ) );
46
		}
47
48
		if( ( $this->prefix = substr( $entry['code'], 0, $pos + 1 ) ) === false ) {
49
			throw new \Aimeos\MShop\Exception( sprintf( 'Search configuration for "%1$s" not available', $entry['code'] ) );
50
		}
51
52
		parent::__construct( $context );
53
	}
54
55
56
	/**
57
	 * Counts the number items that are available for the values of the given key.
58
	 *
59
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria
60
	 * @param string $key Search key to aggregate items for
61
	 * @return array List of the search keys as key and the number of counted items as value
62
	 */
63
	public function aggregate( \Aimeos\MW\Criteria\Iface $search, $key )
64
	{
65
		$required = array( trim( $this->prefix, '.' ) );
66
		return $this->aggregateBase( $search, $key, $this->getConfigPath() . 'aggregate', $required );
67
	}
68
69
70
	/**
71
	 * Creates new common list item object.
72
	 *
73
	 * @return \Aimeos\MShop\Common\Item\Lists\Iface New list item object
74
	 */
75
	public function createItem()
76
	{
77
		$values = array(
78
			$this->prefix . 'siteid' => $this->getContext()->getLocale()->getSiteId()
79
		);
80
		return $this->createItemBase( $values );
81
82
	}
83
84
85
	/**
86
	 * Updates or adds a common list item object.
87
	 *
88
	 * @param \Aimeos\MShop\Common\Item\Lists\Iface $item List item object which should be saved
89
	 * @param boolean $fetch True if the new ID should be returned in the item
90
	 */
91
	public function saveItem( \Aimeos\MShop\Common\Item\Iface $item, $fetch = true )
92
	{
93
		$iface = '\\Aimeos\\MShop\\Common\\Item\\Lists\\Iface';
94
		if( !( $item instanceof $iface ) ) {
95
			throw new \Aimeos\MShop\Exception( sprintf( 'Object is not of required type "%1$s"', $iface ) );
96
		}
97
98
		$context = $this->getContext();
99
100
		$dbm = $context->getDatabaseManager();
101
		$dbname = $this->getResourceName();
102
		$conn = $dbm->acquire( $dbname );
103
104
		try
105
		{
106
			$id = $item->getId();
107
108
			if( $id === null ) {
109
				$type = 'insert';
110
			} else {
111
				$type = 'update';
112
			}
113
114
			$time = date( 'Y-m-d H:i:s' );
115
			$statement = $this->getCachedStatement( $conn, $this->getConfigPath() . $type );
116
117
			$statement->bind( 1, $item->getParentId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
118
			$statement->bind( 2, $context->getLocale()->getSiteId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
119
			$statement->bind( 3, $item->getTypeId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
120
			$statement->bind( 4, $item->getDomain(), \Aimeos\MW\DB\Statement\Base::PARAM_STR );
121
			$statement->bind( 5, $item->getRefId(), \Aimeos\MW\DB\Statement\Base::PARAM_STR );
122
			$statement->bind( 6, $item->getDateStart(), \Aimeos\MW\DB\Statement\Base::PARAM_STR );
123
			$statement->bind( 7, $item->getDateEnd(), \Aimeos\MW\DB\Statement\Base::PARAM_STR );
124
			$statement->bind( 8, json_encode( $item->getConfig() ), \Aimeos\MW\DB\Statement\Base::PARAM_STR );
125
			$statement->bind( 9, $item->getPosition(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
126
			$statement->bind( 10, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
127
128
			$statement->bind( 11, $time ); //mtime
129
			$statement->bind( 12, $this->getContext()->getEditor() );
130
131
132
			if( $id !== null ) {
133
				$statement->bind( 13, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
134
			} else {
135
				$statement->bind( 13, $time ); //ctime
136
			}
137
138
			$statement->execute()->finish();
139
140
			if( $fetch === true )
141
			{
142
				if( $id === null ) {
143
					$path = $this->getConfigPath() . 'newid';
144
					$item->setId( $this->newId( $conn, $path ) );
145
				} else {
146
					$item->setId( $id ); // modified false
147
				}
148
			}
149
150
			$dbm->release( $conn, $dbname );
151
		}
152
		catch( \Exception $e )
153
		{
154
			$dbm->release( $conn, $dbname );
155
			throw $e;
156
		}
157
	}
158
159
160
	/**
161
	 * Removes multiple items specified by ids in the array.
162
	 *
163
	 * @param array $ids List of IDs
164
	 */
165
	public function deleteItems( array $ids )
166
	{
167
		$this->deleteItemsBase( $ids, $this->getConfigPath() . 'delete' );
168
	}
169
170
171
	/**
172
	 * Creates common list item object for the given common list item id.
173
	 *
174
	 * @param integer $id Id of common list item object
175
	 * @param string[] $ref List of domains to fetch list items and referenced items for
176
	 * @param boolean $default Add default criteria
177
	 * @return \Aimeos\MShop\Common\Item\Lists\Iface Returns common list item object of the given id
178
	 * @throws \Aimeos\MShop\Exception If item couldn't be found
179
	 */
180
	public function getItem( $id, array $ref = [], $default = false )
181
	{
182
		if( ( $conf = reset( $this->searchConfig ) ) === false || !isset( $conf['code'] ) ) {
183
			throw new \Aimeos\MShop\Exception( sprintf( 'Search configuration not available' ) );
184
		}
185
186
		$criteria = $this->createSearch( $default );
187
		$expr = [
188
			$criteria->compare( '==', $conf['code'], $id ),
189
			$criteria->getConditions()
190
		];
191
		$criteria->setConditions( $criteria->combine( '&&', $expr ) );
192
		$items = $this->searchItems( $criteria, $ref );
193
194
		if( ( $item = reset( $items ) ) === false )
195
		{
196
			$msg = sprintf( 'List item with ID "%2$s" in "%1$s" not found', $conf['code'], $id );
197
			throw new \Aimeos\MShop\Exception( $msg );
198
		}
199
200
		return $item;
201
	}
202
203
204
	/**
205
	 * Moves the common list item object with Id in the list of Id's before the
206
	 * common list item object with reference Id of the given node.
207
	 *
208
	 * @param integer $id Id of the item which should be moved
209
	 * @param integer|null $ref Id where the given Id should be inserted before (null for appending)
210
	 */
211
	public function moveItem( $id, $ref = null )
212
	{
213
		$context = $this->getContext();
214
		$siteid = $context->getLocale()->getSiteId();
215
		$cfgPath = $this->getConfigPath();
216
217
		$listItem = $this->getItem( $id );
218
219
		$newpos = $pos = 0;
220
		$oldpos = $listItem->getPosition();
221
		$parentid = $listItem->getParentId();
222
		$typeid = $listItem->getTypeId();
223
		$domain = $listItem->getDomain();
224
225
		if( $ref !== null ) {
226
			$pos = $this->getItem( $ref )->getPosition();
227
		}
228
229
		$dbm = $context->getDatabaseManager();
230
		$dbname = $this->getResourceName();
231
		$conn = $dbm->acquire( $dbname );
232
233
		try
234
		{
235
			if( $ref !== null )
236
			{
237
				$newpos = $pos;
238
239
				$sql = $this->getSqlConfig( $cfgPath . 'move' );
240
241
				$stmt = $conn->create( $sql );
242
				$stmt->bind( 1, +1, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
243
				$stmt->bind( 2, date( 'Y-m-d H:i:s' ) ); //mtime
244
				$stmt->bind( 3, $this->getContext()->getEditor() );
245
				$stmt->bind( 4, $siteid, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
246
				$stmt->bind( 5, $parentid, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
247
				$stmt->bind( 6, $typeid, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
248
				$stmt->bind( 7, $domain );
249
				$stmt->bind( 8, $pos, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
250
251
				$stmt->execute()->finish();
252
			}
253
			else
254
			{
255
				$sql = $this->getSqlConfig( $cfgPath . 'getposmax' );
256
257
				$stmt = $conn->create( $sql );
258
259
				$stmt->bind( 1, $siteid, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
260
				$stmt->bind( 2, $parentid, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
261
				$stmt->bind( 3, $typeid, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
262
				$stmt->bind( 4, $domain );
263
264
				$result = $stmt->execute();
265
				$row = $result->fetch();
266
				$result->finish();
267
268
				if( $row !== false ) {
269
					$newpos = $row['pos'] + 1;
270
				}
271
			}
272
273
			$sql = $this->getSqlConfig( $cfgPath . 'updatepos' );
274
275
			$stmt = $conn->create( $sql );
276
			$stmt->bind( 1, $newpos, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
277
			$stmt->bind( 2, date( 'Y-m-d H:i:s' ) ); // mtime
278
			$stmt->bind( 3, $this->getContext()->getEditor() );
279
			$stmt->bind( 4, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
280
281
			$stmt->execute()->finish();
282
283
			if( $oldpos > $newpos ) {
284
				$oldpos++;
285
			}
286
287
			if( $oldpos > 0 )
288
			{
289
				$sql = $this->getSqlConfig( $cfgPath . 'move' );
290
291
				$stmt = $conn->create( $sql );
292
				$stmt->bind( 1, -1, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
293
				$stmt->bind( 2, date( 'Y-m-d H:i:s' ) ); // mtime
294
				$stmt->bind( 3, $this->getContext()->getEditor() );
295
				$stmt->bind( 4, $siteid, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
296
				$stmt->bind( 5, $parentid, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
297
				$stmt->bind( 6, $typeid, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
298
				$stmt->bind( 7, $domain );
299
				$stmt->bind( 8, $oldpos, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
300
301
				$stmt->execute()->finish();
302
			}
303
304
			$dbm->release( $conn, $dbname );
305
		}
306
		catch( \Exception $e )
307
		{
308
			$dbm->release( $conn, $dbname );
309
			throw $e;
310
		}
311
	}
312
313
314
	/**
315
	 * Search for all list items based on the given critera.
316
	 *
317
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria object
318
	 * @param string[] $ref List of domains to fetch list items and referenced items for
319
	 * @param integer|null &$total Number of items that are available in total
320
	 * @return array List of list items implementing \Aimeos\MShop\Common\Item\Lists\Iface
321
	 */
322
	public function searchItems( \Aimeos\MW\Criteria\Iface $search, array $ref = array(), &$total = null )
323
	{
324
		$items = $map = $typeIds = array();
325
326
		$dbm = $this->getContext()->getDatabaseManager();
327
		$dbname = $this->getResourceName();
328
		$conn = $dbm->acquire( $dbname );
329
330
		try
331
		{
332
			$domain = explode( '.', $this->prefix );
333
334
			if( ( $topdomain = array_shift( $domain ) ) === null ) {
335
				throw new \Aimeos\MShop\Exception( sprintf( 'Configuration not available' ) );
336
			}
337
338
			$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
339
			$cfgPathSearch = $this->getConfigPath() . 'search';
340
			$cfgPathCount = $this->getConfigPath() . 'count';
341
342
			$name = trim( $this->prefix, '.' );
343
			$required = array( $name );
344
345
			$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $level );
346
347
			while( ( $row = $results->fetch() ) !== false )
348
			{
349
				if( ( $row[$this->prefix . 'config'] = json_decode( $row[$this->prefix . 'config'], true ) ) === null ) {
350
					$row[$this->prefix . 'config'] = array();
351
				}
352
353
				$map[$row[$this->prefix . 'id']] = $row;
354
				$typeIds[$row[$this->prefix . 'typeid']] = null;
355
			}
356
357
			$dbm->release( $conn, $dbname );
358
		}
359
		catch( \Exception $e )
360
		{
361
			$dbm->release( $conn, $dbname );
362
			throw $e;
363
		}
364
365
		if( !empty( $typeIds ) )
366
		{
367
			$typeManager = $this->getSubManager( 'type' );
368
			$typeSearch = $typeManager->createSearch();
369
			$typeSearch->setConditions( $typeSearch->compare( '==', $name . '.type.id', array_keys( $typeIds ) ) );
370
			$typeSearch->setSlice( 0, $search->getSliceSize() );
371
			$typeItems = $typeManager->searchItems( $typeSearch );
372
373
			foreach( $map as $id => $row )
374
			{
375
				if( isset( $typeItems[$row[$this->prefix . 'typeid']] ) )
376
				{
377
					$row[$this->prefix . 'type'] = $typeItems[$row[$this->prefix . 'typeid']]->getCode();
378
					$row[$this->prefix . 'typename'] = $typeItems[$row[$this->prefix . 'typeid']]->getName();
379
				}
380
381
				$items[$row[$this->prefix . 'id']] = $this->createItemBase( $row );
382
			}
383
		}
384
385
		return $items;
386
	}
387
388
389
	/**
390
	 * Search for all referenced items from the list based on the given critera.
391
	 *
392
	 * Only criteria from the list and list type can be used for searching and
393
	 * sorting, but no criteria from the referenced items.
394
	 *
395
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria object
396
	 * @param string[] $ref List of domains to fetch list items and referenced items for
397
	 * @param integer|null &$total Number of items that are available in total
398
	 * @return array Associative list of domains as keys and lists with pairs of IDs and items implementing \Aimeos\MShop\Common\Item\Iface
399
	 * @throws \Aimeos\MShop\Exception If creating items failed
400
	 * @see \Aimeos\MW\Criteria\SQL
401
	 */
402
	public function searchRefItems( \Aimeos\MW\Criteria\Iface $search, array $ref = array(), &$total = null )
403
	{
404
		$items = $map = array();
405
		$context = $this->getContext();
406
407
		$dbm = $context->getDatabaseManager();
408
		$dbname = $this->getResourceName();
409
		$conn = $dbm->acquire( $dbname );
410
411
		try
412
		{
413
			$domain = explode( '.', $this->prefix );
414
415
			if( ( $topdomain = array_shift( $domain ) ) === null ) {
416
				throw new \Aimeos\MShop\Exception( sprintf( 'Configuration not available' ) );
417
			}
418
419
			$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
420
			$cfgPathSearch = $this->getConfigPath() . 'search';
421
			$cfgPathCount = $this->getConfigPath() . 'count';
422
423
			$name = trim( $this->prefix, '.' );
424
			$required = array( $name );
425
426
			$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $level );
427
428
			while( ( $row = $results->fetch() ) !== false ) {
429
				$map[$row[$this->prefix . 'domain']][] = $row[$this->prefix . 'refid'];
430
			}
431
432
			$dbm->release( $conn, $dbname );
433
		}
434
		catch( \Exception $e )
435
		{
436
			$dbm->release( $conn, $dbname );
437
			throw $e;
438
		}
439
440
441
		foreach( $map as $domain => $list )
442
		{
443
			$manager = \Aimeos\MShop\Factory::createManager( $context, $domain );
444
445
			$search = $manager->createSearch( true );
446
			$expr = array(
447
				$search->compare( '==', str_replace( '/', '.', $domain ) . '.id', $list ),
448
				$search->getConditions(),
449
			);
450
			$search->setConditions( $search->combine( '&&', $expr ) );
451
			$search->setSlice( 0, 0x7fffffff );
452
453
			$items[$domain] = $manager->searchItems( $search, $ref );
454
		}
455
456
		return $items;
457
	}
458
459
460
	/**
461
	 * Creates a search object including the base criteria (optionally).
462
	 *
463
	 * @param boolean $default Include default criteria
464
	 * @return \Aimeos\MW\Criteria\Iface Critera object
465
	 */
466
	public function createSearch( $default = false )
467
	{
468
		if( $default === true )
469
		{
470
			$prefix = rtrim( $this->getPrefix(), '.' );
471
			$object = $this->createSearchBase( $prefix );
472
473
			$expr = array();
474
			$curDate = date( 'Y-m-d H:i:00' );
475
476
			$expr[] = $object->getConditions();
477
478
			$exprTwo = array();
479
			$exprTwo[] = $object->compare( '<=', $prefix . '.datestart', $curDate );
480
			$exprTwo[] = $object->compare( '==', $prefix . '.datestart', null );
481
			$expr[] = $object->combine( '||', $exprTwo );
482
483
			$exprTwo = array();
484
			$exprTwo[] = $object->compare( '>=', $prefix . '.dateend', $curDate );
485
			$exprTwo[] = $object->compare( '==', $prefix . '.dateend', null );
486
			$expr[] = $object->combine( '||', $exprTwo );
487
488
			$object->setConditions( $object->combine( '&&', $expr ) );
489
490
			return $object;
491
		}
492
493
		return parent::createSearch();
494
	}
495
496
497
	/**
498
	 * Creates a new manager for list extensions.
499
	 *
500
	 * @param string $manager Name of the sub manager type in lower case
501
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
502
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager for different extensions, e.g type, etc.
503
	 */
504
	public function getSubManager( $manager, $name = null )
505
	{
506
		return $this->getSubManagerBase( 'common', 'lists/' . $manager, $name );
507
	}
508
509
510
	/**
511
	 * Returns the config path for retrieving the configuration values.
512
	 *
513
	 * @return string Configuration path
514
	 */
515
	abstract protected function getConfigPath();
516
517
518
	/**
519
	 * Returns the search configuration for searching items.
520
	 *
521
	 * @return array Associative list of search keys and search definitions
522
	 */
523
	abstract protected function getSearchConfig();
524
525
526
	/**
527
	 * Creates new common list item object.
528
	 *
529
	 * @see \Aimeos\MShop\Common\Item\Lists\Standard Default list item
530
	 * @param array $values Possible optional array keys can be given: id, parentid, refid, domain, pos, start, end
531
	 * @return \Aimeos\MShop\Common\Item\Lists\Standard New common list item object
532
	 */
533
	protected function createItemBase( array $values = array() )
534
	{
535
		return new \Aimeos\MShop\Common\Item\Lists\Standard( $this->prefix, $values );
536
	}
537
538
539
	/**
540
	 * Returns the domain prefix.
541
	 *
542
	 * @return string Domain prefix with sub-domains separated by "."
543
	 */
544
	protected function getPrefix()
545
	{
546
		return $this->prefix;
547
	}
548
}
549