Passed
Push — master ( 29d5f6...586595 )
by Aimeos
04:48
created

mshoplib/src/MShop/Attribute/Manager/Standard.php (1 issue)

Labels
Severity
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-2018
7
 * @package MShop
8
 * @subpackage Attribute
9
 */
10
11
12
namespace Aimeos\MShop\Attribute\Manager;
13
14
15
/**
16
 * Default attribute manager for creating and handling attributes.
17
 * @package MShop
18
 * @subpackage Attribute
19
 */
20
class Standard
21
	extends \Aimeos\MShop\Common\Manager\ListRef\Base
22
	implements \Aimeos\MShop\Attribute\Manager\Iface, \Aimeos\MShop\Common\Manager\Factory\Iface
23
{
24
	use \Aimeos\MShop\Common\Manager\PropertyRef\Traits;
25
26
27
	private $searchConfig = array(
28
		'attribute.id' => array(
29
			'code' => 'attribute.id',
30
			'internalcode' => 'matt."id"',
31
			'label' => 'ID',
32
			'type' => 'integer',
33
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
34
			'public' => false,
35
		),
36
		'attribute.siteid' => array(
37
			'code' => 'attribute.siteid',
38
			'internalcode' => 'matt."siteid"',
39
			'label' => 'Site ID',
40
			'type' => 'integer',
41
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
42
			'public' => false,
43
		),
44
		'attribute.typeid' => array(
45
			'code' => 'attribute.typeid',
46
			'internalcode' => 'matt."typeid"',
47
			'label' => 'Type',
48
			'type' => 'integer',
49
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
50
			'public' => false,
51
		),
52
		'attribute.label' => array(
53
			'code' => 'attribute.label',
54
			'internalcode' => 'matt."label"',
55
			'label' => 'Label',
56
			'type' => 'string',
57
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
58
		),
59
		'attribute.code' => array(
60
			'code' => 'attribute.code',
61
			'internalcode' => 'matt."code"',
62
			'label' => 'Code',
63
			'type' => 'string',
64
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
65
		),
66
		'attribute.domain' => array(
67
			'code' => 'attribute.domain',
68
			'internalcode' => 'matt."domain"',
69
			'label' => 'Domain',
70
			'type' => 'string',
71
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
72
		),
73
		'attribute.position' => array(
74
			'code' => 'attribute.position',
75
			'internalcode' => 'matt."pos"',
76
			'label' => 'Position',
77
			'type' => 'integer',
78
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
79
			'public' => false,
80
		),
81
		'attribute.status' => array(
82
			'code' => 'attribute.status',
83
			'internalcode' => 'matt."status"',
84
			'label' => 'Status',
85
			'type' => 'integer',
86
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
87
		),
88
		'attribute.ctime' => array(
89
			'code' => 'attribute.ctime',
90
			'internalcode' => 'matt."ctime"',
91
			'label' => 'Create date/time',
92
			'type' => 'datetime',
93
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
94
			'public' => false,
95
		),
96
		'attribute.mtime' => array(
97
			'code' => 'attribute.mtime',
98
			'internalcode' => 'matt."mtime"',
99
			'label' => 'Modification date/time',
100
			'type' => 'datetime',
101
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
102
			'public' => false,
103
		),
104
		'attribute.editor' => array(
105
			'code' => 'attribute.editor',
106
			'internalcode' => 'matt."editor"',
107
			'label' => 'Editor',
108
			'type' => 'string',
109
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
110
			'public' => false,
111
		),
112
	);
113
114
115
	/**
116
	 * Initializes the object.
117
	 *
118
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object
119
	 */
120
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
121
	{
122
		parent::__construct( $context );
123
		$this->setResourceName( 'db-attribute' );
124
	}
125
126
127
	/**
128
	 * Removes old entries from the storage.
129
	 *
130
	 * @param integer[] $siteids List of IDs for sites whose entries should be deleted
131
	 */
132
	public function cleanup( array $siteids )
133
	{
134
		$path = 'mshop/attribute/manager/submanagers';
135
		$default = ['lists', 'property', 'type'];
136
137
		foreach( $this->getContext()->getConfig()->get( $path, $default ) as $domain ) {
138
			$this->getObject()->getSubManager( $domain )->cleanup( $siteids );
139
		}
140
141
		$this->cleanupBase( $siteids, 'mshop/attribute/manager/standard/delete' );
142
	}
143
144
145
	/**
146
	 * Returns the available manager types
147
	 *
148
	 * @param boolean $withsub Return also the resource type of sub-managers if true
149
	 * @return array Type of the manager and submanagers, subtypes are separated by slashes
150
	 */
151
	public function getResourceType( $withsub = true )
152
	{
153
		$path = 'mshop/attribute/manager/submanagers';
154
		$default = ['lists', 'property', 'type'];
155
156
		return $this->getResourceTypeBase( 'attribute', $path, $default, $withsub );
157
	}
158
159
160
	/**
161
	 * Returns the attributes that can be used for searching.
162
	 *
163
	 * @param boolean $withsub Return also attributes of sub-managers if true
164
	 * @return array List of attribute items implementing \Aimeos\MW\Criteria\Attribute\Iface
165
	 */
166
	public function getSearchAttributes( $withsub = true )
167
	{
168
		/** mshop/attribute/manager/submanagers
169
		 * List of manager names that can be instantiated by the attribute manager
170
		 *
171
		 * Managers provide a generic interface to the underlying storage.
172
		 * Each manager has or can have sub-managers caring about particular
173
		 * aspects. Each of these sub-managers can be instantiated by its
174
		 * parent manager using the getSubManager() method.
175
		 *
176
		 * The search keys from sub-managers can be normally used in the
177
		 * manager as well. It allows you to search for items of the manager
178
		 * using the search keys of the sub-managers to further limit the
179
		 * retrieved list of items.
180
		 *
181
		 * @param array List of sub-manager names
182
		 * @since 2014.03
183
		 * @category Developer
184
		 */
185
		$path = 'mshop/attribute/manager/submanagers';
186
		$default = ['lists', 'property', 'type'];
187
188
		return $this->getSearchAttributesBase( $this->searchConfig, $path, $default, $withsub );
189
	}
190
191
192
	/**
193
	 * Creates a new empty item instance
194
	 *
195
	 * @param string|null Type the item should be created with
196
	 * @param string|null Domain of the type the item should be created with
197
	 * @param array $values Values the item should be initialized with
198
	 * @return \Aimeos\MShop\Attribute\Item\Iface New attribute item object
199
	 */
200
	public function createItem( $type = null, $domain = null, array $values = [] )
201
	{
202
		$values['attribute.siteid'] = $this->getContext()->getLocale()->getSiteId();
203
204
		if( $type !== null )
205
		{
206
			$values['attribute.typeid'] = $this->getTypeId( $type, $domain );
207
			$values['attribute.type'] = $type;
208
		}
209
210
		return $this->createItemBase( $values );
211
	}
212
213
214
	/**
215
	 * Returns the item specified by its code and domain/type if necessary
216
	 *
217
	 * @param string $code Code of the item
218
	 * @param string[] $ref List of domains to fetch list items and referenced items for
219
	 * @param string|null $domain Domain of the item if necessary to identify the item uniquely
220
	 * @param string|null $type Type code of the item if necessary to identify the item uniquely
221
	 * @param boolean $default True to add default criteria
222
	 * @return \Aimeos\MShop\Common\Item\Iface Item object
223
	 */
224
	public function findItem( $code, array $ref = [], $domain = null, $type = null, $default = false )
225
	{
226
		$find = array(
227
			'attribute.code' => $code,
228
			'attribute.domain' => $domain,
229
			'attribute.type.code' => $type,
230
			'attribute.type.domain' => $domain,
231
		);
232
		return $this->findItemBase( $find, $ref, $default );
233
	}
234
235
236
	/**
237
	 * Returns the attributes item specified by its ID.
238
	 *
239
	 * @param integer $id Unique ID of the attribute item in the storage
240
	 * @param string[] $ref List of domains to fetch list items and referenced items for
241
	 * @param boolean $default Add default criteria
242
	 * @return \Aimeos\MShop\Attribute\Item\Iface Returns the attribute item of the given id
243
	 * @throws \Aimeos\MShop\Exception If item couldn't be found
244
	 */
245
	public function getItem( $id, array $ref = [], $default = false )
246
	{
247
		return $this->getItemBase( 'attribute.id', $id, $ref, $default );
248
	}
249
250
251
	/**
252
	 * Saves an attribute item to the storage.
253
	 *
254
	 * @param \Aimeos\MShop\Common\Item\Iface $item Attribute item
255
	 * @param boolean $fetch True if the new ID should be returned in the item
256
	 * @return \Aimeos\MShop\Common\Item\Iface $item Updated item including the generated ID
257
	 * @throws \Aimeos\MShop\Attribute\Exception If Attribute couldn't be saved
258
	 */
259
	public function saveItem( \Aimeos\MShop\Common\Item\Iface $item, $fetch = true )
260
	{
261
		self::checkClass( '\\Aimeos\\MShop\\Attribute\\Item\\Iface', $item );
262
263
		if( !$item->isModified() )
264
		{
265
			$item = $this->savePropertyItems( $item, 'attribute', $fetch );
266
			return $this->saveListItems( $item, 'attribute', $fetch );
267
		}
268
269
		$context = $this->getContext();
270
271
		$dbm = $context->getDatabaseManager();
272
		$dbname = $this->getResourceName();
273
		$conn = $dbm->acquire( $dbname );
274
275
		try
276
		{
277
			$id = $item->getId();
278
			$date = date( 'Y-m-d H:i:s' );
279
280
			if( $id === null )
281
			{
282
				/** mshop/attribute/manager/standard/insert/mysql
283
				 * Inserts a new attribute record into the database table
284
				 *
285
				 * @see mshop/attribute/manager/standard/insert/ansi
286
				 */
287
288
				/** mshop/attribute/manager/standard/insert/ansi
289
				 * Inserts a new attribute record into the database table
290
				 *
291
				 * Items with no ID yet (i.e. the ID is NULL) will be created in
292
				 * the database and the newly created ID retrieved afterwards
293
				 * using the "newid" SQL statement.
294
				 *
295
				 * The SQL statement must be a string suitable for being used as
296
				 * prepared statement. It must include question marks for binding
297
				 * the values from the attribute item to the statement before they are
298
				 * sent to the database server. The number of question marks must
299
				 * be the same as the number of columns listed in the INSERT
300
				 * statement. The order of the columns must correspond to the
301
				 * order in the saveItems() method, so the correct values are
302
				 * bound to the columns.
303
				 *
304
				 * The SQL statement should conform to the ANSI standard to be
305
				 * compatible with most relational database systems. This also
306
				 * includes using double quotes for table and column names.
307
				 *
308
				 * @param string SQL statement for inserting records
309
				 * @since 2014.03
310
				 * @category Developer
311
				 * @see mshop/attribute/manager/standard/update/ansi
312
				 * @see mshop/attribute/manager/standard/newid/ansi
313
				 * @see mshop/attribute/manager/standard/delete/ansi
314
				 * @see mshop/attribute/manager/standard/search/ansi
315
				 * @see mshop/attribute/manager/standard/count/ansi
316
				 */
317
				$path = 'mshop/attribute/manager/standard/insert';
318
			}
319
			else
320
			{
321
				/** mshop/attribute/manager/standard/update/mysql
322
				 * Updates an existing attribute record in the database
323
				 *
324
				 * @see mshop/attribute/manager/standard/update/ansi
325
				 */
326
327
				/** mshop/attribute/manager/standard/update/ansi
328
				 * Updates an existing attribute record in the database
329
				 *
330
				 * Items which already have an ID (i.e. the ID is not NULL) will
331
				 * be updated in the database.
332
				 *
333
				 * The SQL statement must be a string suitable for being used as
334
				 * prepared statement. It must include question marks for binding
335
				 * the values from the attribute item to the statement before they are
336
				 * sent to the database server. The order of the columns must
337
				 * correspond to the order in the saveItems() method, so the
338
				 * correct values are bound to the columns.
339
				 *
340
				 * The SQL statement should conform to the ANSI standard to be
341
				 * compatible with most relational database systems. This also
342
				 * includes using double quotes for table and column names.
343
				 *
344
				 * @param string SQL statement for updating records
345
				 * @since 2014.03
346
				 * @category Developer
347
				 * @see mshop/attribute/manager/standard/insert/ansi
348
				 * @see mshop/attribute/manager/standard/newid/ansi
349
				 * @see mshop/attribute/manager/standard/delete/ansi
350
				 * @see mshop/attribute/manager/standard/search/ansi
351
				 * @see mshop/attribute/manager/standard/count/ansi
352
				 */
353
				$path = 'mshop/attribute/manager/standard/update';
354
			}
355
356
			$stmt = $this->getCachedStatement( $conn, $path );
357
358
			$stmt->bind( 1, $item->getTypeId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
359
			$stmt->bind( 2, $item->getDomain() );
360
			$stmt->bind( 3, $item->getCode() );
361
			$stmt->bind( 4, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
362
			$stmt->bind( 5, $item->getPosition(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
363
			$stmt->bind( 6, $item->getLabel() );
1 ignored issue
show
The method getLabel() does not exist on Aimeos\MShop\Common\Item\Iface. It seems like you code against a sub-type of Aimeos\MShop\Common\Item\Iface such as Aimeos\MShop\Product\Item\Iface or Aimeos\MShop\Service\Item\Iface or Aimeos\MShop\Locale\Item\Site\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MShop\Text\Item\Iface or Aimeos\MShop\Customer\Item\Group\Iface or Aimeos\MShop\Media\Item\Iface or Aimeos\MShop\Coupon\Item\Iface or Aimeos\MAdmin\Job\Item\Iface or Aimeos\MShop\Tag\Item\Iface or Aimeos\MShop\Common\Item\Type\Iface or Aimeos\MShop\Attribute\Item\Iface or Aimeos\MShop\Locale\Item\Language\Iface or Aimeos\MShop\Catalog\Item\Iface or Aimeos\MShop\Plugin\Item\Iface or Aimeos\MShop\Supplier\Item\Iface or Aimeos\MShop\Locale\Item\Currency\Iface or Aimeos\MShop\Attribute\Item\Standard or Aimeos\MShop\Catalog\Item\Standard or Aimeos\MShop\Customer\Item\Base or Aimeos\MShop\Plugin\Item\Standard or Aimeos\MShop\Tag\Item\Standard or Aimeos\MShop\Customer\Item\Group\Standard or Aimeos\MShop\Media\Item\Standard or Aimeos\MAdmin\Job\Item\Standard or Aimeos\MShop\Common\Item\Type\Standard or Aimeos\MShop\Locale\Item\Site\Standard or Aimeos\MShop\Locale\Item\Currency\Standard or Aimeos\MShop\Text\Item\Standard or Aimeos\MShop\Locale\Item\Language\Standard or Aimeos\MShop\Service\Item\Standard or Aimeos\MShop\Common\Item\ListRef\Base or Aimeos\MShop\Price\Item\Base or Aimeos\MShop\Supplier\Item\Standard or Aimeos\MShop\Coupon\Item\Standard or Aimeos\MShop\Product\Item\Standard or Aimeos\MShop\Product\Item\Iface or Aimeos\MShop\Service\Item\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MShop\Text\Item\Iface or Aimeos\MShop\Media\Item\Iface or Aimeos\MShop\Coupon\Item\Iface or Aimeos\MAdmin\Job\Item\Iface or Aimeos\MShop\Common\Item\Type\Iface or Aimeos\MShop\Attribute\Item\Iface or Aimeos\MShop\Locale\Item\Language\Iface or Aimeos\MShop\Common\Item\Tree\Iface or Aimeos\MShop\Plugin\Item\Iface or Aimeos\MShop\Supplier\Item\Iface or Aimeos\MShop\Locale\Item\Currency\Iface or Aimeos\MShop\Price\Item\Base or Aimeos\MShop\Price\Item\Base. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

363
			$stmt->bind( 6, $item->/** @scrutinizer ignore-call */ getLabel() );
Loading history...
364
			$stmt->bind( 7, $date ); // mtime
365
			$stmt->bind( 8, $context->getEditor() );
366
			$stmt->bind( 9, $context->getLocale()->getSiteId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
367
368
			if( $id !== null ) {
369
				$stmt->bind( 10, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
370
				$item->setId( $id );
371
			} else {
372
				$stmt->bind( 10, $date ); // ctime
373
			}
374
375
			$stmt->execute()->finish();
376
377
			if( $id === null )
378
			{
379
				/** mshop/attribute/manager/standard/newid/mysql
380
				 * Retrieves the ID generated by the database when inserting a new record
381
				 *
382
				 * @see mshop/attribute/manager/standard/newid/ansi
383
				 */
384
385
				/** mshop/attribute/manager/standard/newid/ansi
386
				 * Retrieves the ID generated by the database when inserting a new record
387
				 *
388
				 * As soon as a new record is inserted into the database table,
389
				 * the database server generates a new and unique identifier for
390
				 * that record. This ID can be used for retrieving, updating and
391
				 * deleting that specific record from the table again.
392
				 *
393
				 * For MySQL:
394
				 *  SELECT LAST_INSERT_ID()
395
				 * For PostgreSQL:
396
				 *  SELECT currval('seq_matt_id')
397
				 * For SQL Server:
398
				 *  SELECT SCOPE_IDENTITY()
399
				 * For Oracle:
400
				 *  SELECT "seq_matt_id".CURRVAL FROM DUAL
401
				 *
402
				 * There's no way to retrive the new ID by a SQL statements that
403
				 * fits for most database servers as they implement their own
404
				 * specific way.
405
				 *
406
				 * @param string SQL statement for retrieving the last inserted record ID
407
				 * @since 2014.03
408
				 * @category Developer
409
				 * @see mshop/attribute/manager/standard/insert/ansi
410
				 * @see mshop/attribute/manager/standard/update/ansi
411
				 * @see mshop/attribute/manager/standard/delete/ansi
412
				 * @see mshop/attribute/manager/standard/search/ansi
413
				 * @see mshop/attribute/manager/standard/count/ansi
414
				 */
415
				$path = 'mshop/attribute/manager/standard/newid';
416
				$item->setId( $this->newId( $conn, $path ) );
417
			}
418
419
			$dbm->release( $conn, $dbname );
420
		}
421
		catch( \Exception $e )
422
		{
423
			$dbm->release( $conn, $dbname );
424
			throw $e;
425
		}
426
427
		$item = $this->savePropertyItems( $item, 'attribute', $fetch );
428
		return $this->saveListItems( $item, 'attribute', $fetch );
429
	}
430
431
432
	/**
433
	 * Removes multiple items specified by ids in the array.
434
	 *
435
	 * @param array $ids List of IDs
436
	 */
437
	public function deleteItems( array $ids )
438
	{
439
		/** mshop/attribute/manager/standard/delete/mysql
440
		 * Deletes the items matched by the given IDs from the database
441
		 *
442
		 * @see mshop/attribute/manager/standard/delete/ansi
443
		 */
444
445
		/** mshop/attribute/manager/standard/delete/ansi
446
		 * Deletes the items matched by the given IDs from the database
447
		 *
448
		 * Removes the records specified by the given IDs from the attribute database.
449
		 * The records must be from the site that is configured via the
450
		 * context item.
451
		 *
452
		 * The ":cond" placeholder is replaced by the name of the ID column and
453
		 * the given ID or list of IDs while the site ID is bound to the question
454
		 * mark.
455
		 *
456
		 * The SQL statement should conform to the ANSI standard to be
457
		 * compatible with most relational database systems. This also
458
		 * includes using double quotes for table and column names.
459
		 *
460
		 * @param string SQL statement for deleting items
461
		 * @since 2014.03
462
		 * @category Developer
463
		 * @see mshop/attribute/manager/standard/insert/ansi
464
		 * @see mshop/attribute/manager/standard/update/ansi
465
		 * @see mshop/attribute/manager/standard/newid/ansi
466
		 * @see mshop/attribute/manager/standard/search/ansi
467
		 * @see mshop/attribute/manager/standard/count/ansi
468
		 */
469
		$path = 'mshop/attribute/manager/standard/delete';
470
		$this->deleteItemsBase( $ids, $path );
471
	}
472
473
474
	/**
475
	 * Searches for attribute items based on the given criteria.
476
	 *
477
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria object
478
	 * @param string[] $ref List of domains to fetch list items and referenced items for
479
	 * @param integer|null &$total Number of items that are available in total
480
	 * @return array List of attribute items implementing \Aimeos\MShop\Attribute\Item\Iface
481
	 */
482
	public function searchItems( \Aimeos\MW\Criteria\Iface $search, array $ref = [], &$total = null )
483
	{
484
		$map = $typeIds = [];
485
		$context = $this->getContext();
486
487
		$dbm = $context->getDatabaseManager();
488
		$dbname = $this->getResourceName();
489
		$conn = $dbm->acquire( $dbname );
490
491
		try
492
		{
493
			$required = array( 'attribute' );
494
495
			/** mshop/attribute/manager/sitemode
496
			 * Mode how items from levels below or above in the site tree are handled
497
			 *
498
			 * By default, only items from the current site are fetched from the
499
			 * storage. If the ai-sites extension is installed, you can create a
500
			 * tree of sites. Then, this setting allows you to define for the
501
			 * whole attribute domain if items from parent sites are inherited,
502
			 * sites from child sites are aggregated or both.
503
			 *
504
			 * Available constants for the site mode are:
505
			 * * 0 = only items from the current site
506
			 * * 1 = inherit items from parent sites
507
			 * * 2 = aggregate items from child sites
508
			 * * 3 = inherit and aggregate items at the same time
509
			 *
510
			 * You also need to set the mode in the locale manager
511
			 * (mshop/locale/manager/standard/sitelevel) to one of the constants.
512
			 * If you set it to the same value, it will work as described but you
513
			 * can also use different modes. For example, if inheritance and
514
			 * aggregation is configured the locale manager but only inheritance
515
			 * in the domain manager because aggregating items makes no sense in
516
			 * this domain, then items wil be only inherited. Thus, you have full
517
			 * control over inheritance and aggregation in each domain.
518
			 *
519
			 * @param integer Constant from Aimeos\MShop\Locale\Manager\Base class
520
			 * @category Developer
521
			 * @since 2018.01
522
			 * @see mshop/locale/manager/standard/sitelevel
523
			 */
524
			$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
525
			$level = $context->getConfig()->get( 'mshop/attribute/manager/sitemode', $level );
526
527
			/** mshop/attribute/manager/standard/search/mysql
528
			 * Retrieves the records matched by the given criteria in the database
529
			 *
530
			 * @see mshop/attribute/manager/standard/search/ansi
531
			 */
532
533
			/** mshop/attribute/manager/standard/search/ansi
534
			 * Retrieves the records matched by the given criteria in the database
535
			 *
536
			 * Fetches the records matched by the given criteria from the attribute
537
			 * database. The records must be from one of the sites that are
538
			 * configured via the context item. If the current site is part of
539
			 * a tree of sites, the SELECT statement can retrieve all records
540
			 * from the current site and the complete sub-tree of sites.
541
			 *
542
			 * As the records can normally be limited by criteria from sub-managers,
543
			 * their tables must be joined in the SQL context. This is done by
544
			 * using the "internaldeps" property from the definition of the ID
545
			 * column of the sub-managers. These internal dependencies specify
546
			 * the JOIN between the tables and the used columns for joining. The
547
			 * ":joins" placeholder is then replaced by the JOIN strings from
548
			 * the sub-managers.
549
			 *
550
			 * To limit the records matched, conditions can be added to the given
551
			 * criteria object. It can contain comparisons like column names that
552
			 * must match specific values which can be combined by AND, OR or NOT
553
			 * operators. The resulting string of SQL conditions replaces the
554
			 * ":cond" placeholder before the statement is sent to the database
555
			 * server.
556
			 *
557
			 * If the records that are retrieved should be ordered by one or more
558
			 * columns, the generated string of column / sort direction pairs
559
			 * replaces the ":order" placeholder. In case no ordering is required,
560
			 * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
561
			 * markers is removed to speed up retrieving the records. Columns of
562
			 * sub-managers can also be used for ordering the result set but then
563
			 * no index can be used.
564
			 *
565
			 * The number of returned records can be limited and can start at any
566
			 * number between the begining and the end of the result set. For that
567
			 * the ":size" and ":start" placeholders are replaced by the
568
			 * corresponding values from the criteria object. The default values
569
			 * are 0 for the start and 100 for the size value.
570
			 *
571
			 * The SQL statement should conform to the ANSI standard to be
572
			 * compatible with most relational database systems. This also
573
			 * includes using double quotes for table and column names.
574
			 *
575
			 * @param string SQL statement for searching items
576
			 * @since 2014.03
577
			 * @category Developer
578
			 * @see mshop/attribute/manager/standard/insert/ansi
579
			 * @see mshop/attribute/manager/standard/update/ansi
580
			 * @see mshop/attribute/manager/standard/newid/ansi
581
			 * @see mshop/attribute/manager/standard/delete/ansi
582
			 * @see mshop/attribute/manager/standard/count/ansi
583
			 */
584
			$cfgPathSearch = 'mshop/attribute/manager/standard/search';
585
586
			/** mshop/attribute/manager/standard/count/mysql
587
			 * Counts the number of records matched by the given criteria in the database
588
			 *
589
			 * @see mshop/attribute/manager/standard/count/ansi
590
			 */
591
592
			/** mshop/attribute/manager/standard/count/ansi
593
			 * Counts the number of records matched by the given criteria in the database
594
			 *
595
			 * Counts all records matched by the given criteria from the attribute
596
			 * database. The records must be from one of the sites that are
597
			 * configured via the context item. If the current site is part of
598
			 * a tree of sites, the statement can count all records from the
599
			 * current site and the complete sub-tree of sites.
600
			 *
601
			 * As the records can normally be limited by criteria from sub-managers,
602
			 * their tables must be joined in the SQL context. This is done by
603
			 * using the "internaldeps" property from the definition of the ID
604
			 * column of the sub-managers. These internal dependencies specify
605
			 * the JOIN between the tables and the used columns for joining. The
606
			 * ":joins" placeholder is then replaced by the JOIN strings from
607
			 * the sub-managers.
608
			 *
609
			 * To limit the records matched, conditions can be added to the given
610
			 * criteria object. It can contain comparisons like column names that
611
			 * must match specific values which can be combined by AND, OR or NOT
612
			 * operators. The resulting string of SQL conditions replaces the
613
			 * ":cond" placeholder before the statement is sent to the database
614
			 * server.
615
			 *
616
			 * Both, the strings for ":joins" and for ":cond" are the same as for
617
			 * the "search" SQL statement.
618
			 *
619
			 * Contrary to the "search" statement, it doesn't return any records
620
			 * but instead the number of records that have been found. As counting
621
			 * thousands of records can be a long running task, the maximum number
622
			 * of counted records is limited for performance reasons.
623
			 *
624
			 * The SQL statement should conform to the ANSI standard to be
625
			 * compatible with most relational database systems. This also
626
			 * includes using double quotes for table and column names.
627
			 *
628
			 * @param string SQL statement for counting items
629
			 * @since 2014.03
630
			 * @category Developer
631
			 * @see mshop/attribute/manager/standard/insert/ansi
632
			 * @see mshop/attribute/manager/standard/update/ansi
633
			 * @see mshop/attribute/manager/standard/newid/ansi
634
			 * @see mshop/attribute/manager/standard/delete/ansi
635
			 * @see mshop/attribute/manager/standard/search/ansi
636
			 */
637
			$cfgPathCount = 'mshop/attribute/manager/standard/count';
638
639
			$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $level );
640
641
			while( ( $row = $results->fetch() ) !== false )
642
			{
643
				$map[$row['attribute.id']] = $row;
644
				$typeIds[$row['attribute.typeid']] = null;
645
			}
646
647
			$dbm->release( $conn, $dbname );
648
		}
649
		catch( \Exception $e )
650
		{
651
			$dbm->release( $conn, $dbname );
652
			throw $e;
653
		}
654
655
		if( !empty( $typeIds ) )
656
		{
657
			$typeManager = $this->getObject()->getSubManager( 'type' );
658
			$typeSearch = $typeManager->createSearch();
659
			$typeSearch->setConditions( $typeSearch->compare( '==', 'attribute.type.id', array_keys( $typeIds ) ) );
660
			$typeSearch->setSlice( 0, $search->getSliceSize() );
661
			$typeItems = $typeManager->searchItems( $typeSearch );
662
663
			foreach( $map as $id => $row )
664
			{
665
				if( isset( $typeItems[$row['attribute.typeid']] ) )
666
				{
667
					$map[$id]['attribute.type'] = $typeItems[$row['attribute.typeid']]->getCode();
668
					$map[$id]['attribute.typename'] = $typeItems[$row['attribute.typeid']]->getName();
669
				}
670
			}
671
		}
672
673
		$propItems = $this->getPropertyItems( array_keys( $map ), 'attribute' );
674
675
		return $this->buildItems( $map, null, 'attribute', $propItems );
676
	}
677
678
679
	/**
680
	 * creates a search object and sets base criteria
681
	 *
682
	 * @param boolean $default
683
	 * @return \Aimeos\MW\Criteria\Iface
684
	 */
685
	public function createSearch( $default = false )
686
	{
687
		if( $default === true ) {
688
			return $this->createSearchBase( 'attribute' );
689
		}
690
691
		return parent::createSearch();
692
	}
693
694
695
	/**
696
	 * Returns a new manager for attribute extensions
697
	 *
698
	 * @param string $manager Name of the sub manager type in lower case
699
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
700
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager for different extensions, e.g Type, List's etc.
701
	 */
702
	public function getSubManager( $manager, $name = null )
703
	{
704
		return $this->getSubManagerBase( 'attribute', $manager, $name );
705
	}
706
707
708
	/**
709
	 * Creates a new attribute item instance.
710
	 *
711
	 * @param array $values Associative list of key/value pairs
712
	 * @param array $listItems List of items implementing \Aimeos\MShop\Common\Item\Lists\Iface
713
	 * @param array $refItems List of items implementing \Aimeos\MShop\Text\Item\Iface
714
	 * @param array $propertyItems List of items implementing \Aimeos\MShop\Common\Item\Property\Iface
715
	 * @return \Aimeos\MShop\Attribute\Item\Iface New attribute item
716
	 */
717
	protected function createItemBase( array $values = [], array $listItems = [],
718
		array $refItems = [], array $propertyItems = [] )
719
	{
720
		return new \Aimeos\MShop\Attribute\Item\Standard( $values, $listItems, $refItems, $propertyItems );
721
	}
722
}
723