Passed
Push — master ( 5b5d82...0b20e6 )
by Aimeos
05:27
created

Standard::search()   A

Complexity

Conditions 5
Paths 16

Size

Total Lines 146
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 146
rs 9.2888
c 0
b 0
f 0
cc 5
nc 16
nop 3

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2011
6
 * @copyright Aimeos (aimeos.org), 2015-2023
7
 * @package MShop
8
 * @subpackage Order
9
 */
10
11
12
namespace Aimeos\MShop\Order\Manager\Service\Attribute;
13
14
15
/**
16
 * Order base service manager.
17
 *
18
 * @package MShop
19
 * @subpackage Order
20
 */
21
class Standard
22
	extends \Aimeos\MShop\Common\Manager\Base
23
	implements \Aimeos\MShop\Order\Manager\Service\Attribute\Iface, \Aimeos\MShop\Common\Manager\Factory\Iface
24
{
25
	private array $searchConfig = array(
26
		'order.service.attribute.id' => array(
27
			'code' => 'order.service.attribute.id',
28
			'internalcode' => 'mordseat."id"',
29
			'internaldeps' => array( 'LEFT JOIN "mshop_order_service_attr" AS mordseat ON ( mordse."id" = mordseat."parentid" )' ),
30
			'label' => 'Service attribute ID',
31
			'type' => 'int',
32
			'public' => false,
33
		),
34
		'order.service.attribute.siteid' => array(
35
			'code' => 'order.service.attribute.siteid',
36
			'internalcode' => 'mordseat."siteid"',
37
			'label' => 'Service attribute site ID',
38
			'public' => false,
39
		),
40
		'order.service.attribute.attributeid' => array(
41
			'code' => 'order.service.attribute.attributeid',
42
			'internalcode' => 'mordseat."attrid"',
43
			'label' => 'Service attribute original ID',
44
			'public' => false,
45
		),
46
		'order.service.attribute.parentid' => array(
47
			'code' => 'order.service.attribute.parentid',
48
			'internalcode' => 'mordseat."parentid"',
49
			'label' => 'Service ID',
50
			'type' => 'int',
51
			'public' => false,
52
		),
53
		'order.service.attribute.name' => array(
54
			'code' => 'order.service.attribute.name',
55
			'internalcode' => 'mordseat."name"',
56
			'label' => 'Service attribute name',
57
		),
58
		'order.service.attribute.value' => array(
59
			'code' => 'order.service.attribute.value',
60
			'internalcode' => 'mordseat."value"',
61
			'label' => 'Service attribute value',
62
		),
63
		'order.service.attribute.code' => array(
64
			'code' => 'order.service.attribute.code',
65
			'internalcode' => 'mordseat."code"',
66
			'label' => 'Service attribute code',
67
		),
68
		'order.service.attribute.type' => array(
69
			'code' => 'order.service.attribute.type',
70
			'internalcode' => 'mordseat."type"',
71
			'label' => 'Service attribute type',
72
		),
73
		'order.service.attribute.quantity' => array(
74
			'code' => 'order.service.attribute.quantity',
75
			'internalcode' => 'mordseat."quantity"',
76
			'label' => 'Service attribute quantity',
77
			'type' => 'int',
78
		),
79
		'order.service.attribute.price' => array(
80
			'code' => 'order.service.attribute.price',
81
			'internalcode' => 'mordseat."price"',
82
			'label' => 'Service attribute price',
83
			'type' => 'int',
84
		),
85
		'order.service.attribute.ctime' => array(
86
			'code' => 'order.service.attribute.ctime',
87
			'internalcode' => 'mordseat."ctime"',
88
			'label' => 'Service attribute create date/time',
89
			'type' => 'datetime',
90
			'public' => false,
91
		),
92
		'order.service.attribute.mtime' => array(
93
			'code' => 'order.service.attribute.mtime',
94
			'internalcode' => 'mordseat."mtime"',
95
			'label' => 'Service attribute modify date/time',
96
			'type' => 'datetime',
97
			'public' => false,
98
		),
99
		'order.service.attribute.editor' => array(
100
			'code' => 'order.service.attribute.editor',
101
			'internalcode' => 'mordseat."editor"',
102
			'label' => 'Service attribute editor',
103
			'public' => false,
104
		),
105
	);
106
107
108
	/**
109
	 * Initializes the object.
110
	 *
111
	 * @param \Aimeos\MShop\ContextIface $context Context object
112
	 */
113
	public function __construct( \Aimeos\MShop\ContextIface $context )
114
	{
115
		parent::__construct( $context );
116
117
		/** mshop/order/manager/resource
118
		 * Name of the database connection resource to use
119
		 *
120
		 * You can configure a different database connection for each data domain
121
		 * and if no such connection name exists, the "db" connection will be used.
122
		 * It's also possible to use the same database connection for different
123
		 * data domains by configuring the same connection name using this setting.
124
		 *
125
		 * @param string Database connection name
126
		 * @since 2023.04
127
		 */
128
		$this->setResourceName( $context->config()->get( 'mshop/order/manager/resource', 'db-order' ) );
129
	}
130
131
132
	/**
133
	 * Counts the number items that are available for the values of the given key.
134
	 *
135
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria
136
	 * @param array|string $key Search key or list of keys to aggregate items for
137
	 * @param string|null $value Search key for aggregating the value column
138
	 * @param string|null $type Type of the aggregation, empty string for count or "sum" or "avg" (average)
139
	 * @return \Aimeos\Map List of the search keys as key and the number of counted items as value
140
	 */
141
	public function aggregate( \Aimeos\Base\Criteria\Iface $search, $key, string $value = null, string $type = null ) : \Aimeos\Map
142
	{
143
		/** mshop/order/manager/service/attribute/aggregate/mysql
144
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
145
		 *
146
		 * @see mshop/order/manager/service/attribute/aggregate/ansi
147
		 */
148
149
		/** mshop/order/manager/service/attribute/aggregate/ansi
150
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
151
		 *
152
		 * Groups all records by the values in the key column and counts their
153
		 * occurence. The matched records can be limited by the given criteria
154
		 * from the order database. The records must be from one of the sites
155
		 * that are configured via the context item. If the current site is part
156
		 * of a tree of sites, the statement can count all records from the
157
		 * current site and the complete sub-tree of sites.
158
		 *
159
		 * As the records can normally be limited by criteria from sub-managers,
160
		 * their tables must be joined in the SQL context. This is done by
161
		 * using the "internaldeps" property from the definition of the ID
162
		 * column of the sub-managers. These internal dependencies specify
163
		 * the JOIN between the tables and the used columns for joining. The
164
		 * ":joins" placeholder is then replaced by the JOIN strings from
165
		 * the sub-managers.
166
		 *
167
		 * To limit the records matched, conditions can be added to the given
168
		 * criteria object. It can contain comparisons like column names that
169
		 * must match specific values which can be combined by AND, OR or NOT
170
		 * operators. The resulting string of SQL conditions replaces the
171
		 * ":cond" placeholder before the statement is sent to the database
172
		 * server.
173
		 *
174
		 * This statement doesn't return any records. Instead, it returns pairs
175
		 * of the different values found in the key column together with the
176
		 * number of records that have been found for that key values.
177
		 *
178
		 * The SQL statement should conform to the ANSI standard to be
179
		 * compatible with most relational database systems. This also
180
		 * includes using double quotes for table and column names.
181
		 *
182
		 * @param string SQL statement for aggregating order items
183
		 * @since 2014.09
184
		 * @category Developer
185
		 * @see mshop/order/manager/service/attribute/insert/ansi
186
		 * @see mshop/order/manager/service/attribute/update/ansi
187
		 * @see mshop/order/manager/service/attribute/newid/ansi
188
		 * @see mshop/order/manager/service/attribute/delete/ansi
189
		 * @see mshop/order/manager/service/attribute/search/ansi
190
		 * @see mshop/order/manager/service/attribute/count/ansi
191
		 */
192
		$cfgkey = 'mshop/order/manager/service/attribute/aggregate';
193
		return $this->aggregateBase( $search, $key, $cfgkey, ['order.service.attribute'], $value, $type );
194
	}
195
196
197
	/**
198
	 * Removes old entries from the storage.
199
	 *
200
	 * @param iterable $siteids List of IDs for sites whose entries should be deleted
201
	 * @return \Aimeos\MShop\Order\Manager\Service\Attribute\Iface Manager object for chaining method calls
202
	 */
203
	public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
204
	{
205
		$path = 'mshop/order/manager/service/attribute/submanagers';
206
		foreach( $this->context()->config()->get( $path, [] ) as $domain ) {
207
			$this->object()->getSubManager( $domain )->clear( $siteids );
208
		}
209
210
		return $this->clearBase( $siteids, 'mshop/order/manager/service/attribute/delete' );
211
	}
212
213
214
	/**
215
	 * Creates a new empty item instance
216
	 *
217
	 * @param array $values Values the item should be initialized with
218
	 * @return \Aimeos\MShop\Order\Item\Service\Attribute\Iface New order service attribute item object
219
	 */
220
	public function create( array $values = [] ) : \Aimeos\MShop\Common\Item\Iface
221
	{
222
		$values['order.service.attribute.siteid'] = $values['order.service.attribute.siteid'] ?? $this->context()->locale()->getSiteId();
223
		return $this->createItemBase( $values );
224
	}
225
226
227
	/**
228
	 * Creates a filter object.
229
	 *
230
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
231
	 * @param bool $site TRUE for adding site criteria to limit items by the site of related items
232
	 * @return \Aimeos\Base\Criteria\Iface Returns the filter object
233
	 */
234
	public function filter( ?bool $default = false, bool $site = false ) : \Aimeos\Base\Criteria\Iface
235
	{
236
		$search = parent::filter( $default );
237
		$search->setSortations( [$search->sort( '+', 'order.service.attribute.id' )] );
238
239
		return $search;
240
	}
241
242
243
	/**
244
	 * Returns the attribute object for the given ID.
245
	 *
246
	 * @param string $id Order service attribute ID
247
	 * @param string[] $ref List of domains to fetch list items and referenced items for
248
	 * @param bool|null $default Add default criteria or NULL for relaxed default criteria
249
	 * @return \Aimeos\MShop\Order\Item\Service\Attribute\Iface Order base service attribute item of the given ID
250
	 * @throws \Aimeos\MShop\Exception If item couldn't be found
251
	 */
252
	public function get( string $id, array $ref = [], ?bool $default = false ) : \Aimeos\MShop\Common\Item\Iface
253
	{
254
		return $this->getItemBase( 'order.service.attribute.id', $id, $ref, $default );
255
	}
256
257
258
	/**
259
	 * Removes multiple items.
260
	 *
261
	 * @param \Aimeos\MShop\Common\Item\Iface[]|string[] $itemIds List of item objects or IDs of the items
262
	 * @return \Aimeos\MShop\Order\Manager\Service\Attribute\Iface Manager object for chaining method calls
263
	 */
264
	public function delete( $itemIds ) : \Aimeos\MShop\Common\Manager\Iface
265
	{
266
		/** mshop/order/manager/service/attribute/delete/mysql
267
		 * Deletes the items matched by the given IDs from the database
268
		 *
269
		 * @see mshop/order/manager/service/attribute/delete/ansi
270
		 */
271
272
		/** mshop/order/manager/service/attribute/delete/ansi
273
		 * Deletes the items matched by the given IDs from the database
274
		 *
275
		 * Removes the records specified by the given IDs from the order database.
276
		 * The records must be from the site that is configured via the
277
		 * context item.
278
		 *
279
		 * The ":cond" placeholder is replaced by the name of the ID column and
280
		 * the given ID or list of IDs while the site ID is bound to the question
281
		 * mark.
282
		 *
283
		 * The SQL statement should conform to the ANSI standard to be
284
		 * compatible with most relational database systems. This also
285
		 * includes using double quotes for table and column names.
286
		 *
287
		 * @param string SQL statement for deleting items
288
		 * @since 2014.03
289
		 * @category Developer
290
		 * @see mshop/order/manager/service/attribute/insert/ansi
291
		 * @see mshop/order/manager/service/attribute/update/ansi
292
		 * @see mshop/order/manager/service/attribute/newid/ansi
293
		 * @see mshop/order/manager/service/attribute/search/ansi
294
		 * @see mshop/order/manager/service/attribute/count/ansi
295
		 */
296
		$path = 'mshop/order/manager/service/attribute/delete';
297
298
		return $this->deleteItemsBase( $itemIds, $path );
299
	}
300
301
302
	/**
303
	 * Returns the available manager types
304
	 *
305
	 * @param bool $withsub Return also the resource type of sub-managers if true
306
	 * @return string[] Type of the manager and submanagers, subtypes are separated by slashes
307
	 */
308
	public function getResourceType( bool $withsub = true ) : array
309
	{
310
		$path = 'mshop/order/manager/service/attribute/submanagers';
311
		return $this->getResourceTypeBase( 'order/service/attribute', $path, [], $withsub );
312
	}
313
314
315
	/**
316
	 * Returns the attributes that can be used for searching.
317
	 *
318
	 * @param bool $withsub Return also attributes of sub-managers if true
319
	 * @return \Aimeos\Base\Criteria\Attribute\Iface[] List of search attribute items
320
	 */
321
	public function getSearchAttributes( bool $withsub = true ) : array
322
	{
323
		/** mshop/order/manager/service/attribute/submanagers
324
		 * List of manager names that can be instantiated by the order base service attribute manager
325
		 *
326
		 * Managers provide a generic interface to the underlying storage.
327
		 * Each manager has or can have sub-managers caring about particular
328
		 * aspects. Each of these sub-managers can be instantiated by its
329
		 * parent manager using the getSubManager() method.
330
		 *
331
		 * The search keys from sub-managers can be normally used in the
332
		 * manager as well. It allows you to search for items of the manager
333
		 * using the search keys of the sub-managers to further limit the
334
		 * retrieved list of items.
335
		 *
336
		 * @param array List of sub-manager names
337
		 * @since 2014.03
338
		 * @category Developer
339
		 */
340
		$path = 'mshop/order/manager/service/attribute/submanagers';
341
342
		return $this->getSearchAttributesBase( $this->searchConfig, $path, [], $withsub );
343
	}
344
345
346
	/**
347
	 * Returns a new manager for order service extensions.
348
	 *
349
	 * @param string $manager Name of the sub manager type in lower case
350
	 * @param string|null $name Name of the implementation (from configuration or "Standard" if null)
351
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager for different extensions, e.g attribute
352
	 */
353
	public function getSubManager( string $manager, string $name = null ) : \Aimeos\MShop\Common\Manager\Iface
354
	{
355
		/** mshop/order/manager/service/attribute/name
356
		 * Class name of the used order base service attribute manager implementation
357
		 *
358
		 * Each default order base service attribute manager can be replaced by an alternative imlementation.
359
		 * To use this implementation, you have to set the last part of the class
360
		 * name as configuration value so the manager factory knows which class it
361
		 * has to instantiate.
362
		 *
363
		 * For example, if the name of the default class is
364
		 *
365
		 *  \Aimeos\MShop\Order\Manager\Service\Attribute\Standard
366
		 *
367
		 * and you want to replace it with your own version named
368
		 *
369
		 *  \Aimeos\MShop\Order\Manager\Service\Attribute\Myattribute
370
		 *
371
		 * then you have to set the this configuration option:
372
		 *
373
		 *  mshop/order/manager/service/attribute/name = Myattribute
374
		 *
375
		 * The value is the last part of your own class name and it's case sensitive,
376
		 * so take care that the configuration value is exactly named like the last
377
		 * part of the class name.
378
		 *
379
		 * The allowed characters of the class name are A-Z, a-z and 0-9. No other
380
		 * characters are possible! You should always start the last part of the class
381
		 * name with an upper case character and continue only with lower case characters
382
		 * or numbers. Avoid chamel case names like "MyAttribute"!
383
		 *
384
		 * @param string Last part of the class name
385
		 * @since 2014.03
386
		 * @category Developer
387
		 */
388
389
		/** mshop/order/manager/service/attribute/decorators/excludes
390
		 * Excludes decorators added by the "common" option from the order base service attribute manager
391
		 *
392
		 * Decorators extend the functionality of a class by adding new aspects
393
		 * (e.g. log what is currently done), executing the methods of the underlying
394
		 * class only in certain conditions (e.g. only for logged in users) or
395
		 * modify what is returned to the caller.
396
		 *
397
		 * This option allows you to remove a decorator added via
398
		 * "mshop/common/manager/decorators/default" before they are wrapped
399
		 * around the order base service attribute manager.
400
		 *
401
		 *  mshop/order/manager/service/attribute/decorators/excludes = array( 'decorator1' )
402
		 *
403
		 * This would remove the decorator named "decorator1" from the list of
404
		 * common decorators ("\Aimeos\MShop\Common\Manager\Decorator\*") added via
405
		 * "mshop/common/manager/decorators/default" for the order base service attribute manager.
406
		 *
407
		 * @param array List of decorator names
408
		 * @since 2014.03
409
		 * @category Developer
410
		 * @see mshop/common/manager/decorators/default
411
		 * @see mshop/order/manager/service/attribute/decorators/global
412
		 * @see mshop/order/manager/service/attribute/decorators/local
413
		 */
414
415
		/** mshop/order/manager/service/attribute/decorators/global
416
		 * Adds a list of globally available decorators only to the order base service attribute manager
417
		 *
418
		 * Decorators extend the functionality of a class by adding new aspects
419
		 * (e.g. log what is currently done), executing the methods of the underlying
420
		 * class only in certain conditions (e.g. only for logged in users) or
421
		 * modify what is returned to the caller.
422
		 *
423
		 * This option allows you to wrap global decorators
424
		 * ("\Aimeos\MShop\Common\Manager\Decorator\*") around the order base
425
		 * service attribute manager.
426
		 *
427
		 *  mshop/order/manager/service/attribute/decorators/global = array( 'decorator1' )
428
		 *
429
		 * This would add the decorator named "decorator1" defined by
430
		 * "\Aimeos\MShop\Common\Manager\Decorator\Decorator1" only to the order
431
		 * base service attribute manager.
432
		 *
433
		 * @param array List of decorator names
434
		 * @since 2014.03
435
		 * @category Developer
436
		 * @see mshop/common/manager/decorators/default
437
		 * @see mshop/order/manager/service/attribute/decorators/excludes
438
		 * @see mshop/order/manager/service/attribute/decorators/local
439
		 */
440
441
		/** mshop/order/manager/service/attribute/decorators/local
442
		 * Adds a list of local decorators only to the order base service attribute manager
443
		 *
444
		 * Decorators extend the functionality of a class by adding new aspects
445
		 * (e.g. log what is currently done), executing the methods of the underlying
446
		 * class only in certain conditions (e.g. only for logged in users) or
447
		 * modify what is returned to the caller.
448
		 *
449
		 * This option allows you to wrap local decorators
450
		 * ("\Aimeos\MShop\Order\Manager\Service\Attribute\Decorator\*")
451
		 * around the order base service attribute manager.
452
		 *
453
		 *  mshop/order/manager/service/attribute/decorators/local = array( 'decorator2' )
454
		 *
455
		 * This would add the decorator named "decorator2" defined by
456
		 * "\Aimeos\MShop\Order\Manager\Service\Attribute\Decorator\Decorator2"
457
		 * only to the order base service attribute manager.
458
		 *
459
		 * @param array List of decorator names
460
		 * @since 2014.03
461
		 * @category Developer
462
		 * @see mshop/common/manager/decorators/default
463
		 * @see mshop/order/manager/service/attribute/decorators/excludes
464
		 * @see mshop/order/manager/service/attribute/decorators/global
465
		 */
466
467
		return $this->getSubManagerBase( 'order', 'service/attribute/' . $manager, $name );
468
	}
469
470
471
	/**
472
	 * Adds or updates an order service attribute item to the storage.
473
	 *
474
	 * @param \Aimeos\MShop\Order\Item\Service\Attribute\Iface $item Order service attribute object
475
	 * @param bool $fetch True if the new ID should be returned in the item
476
	 * @return \Aimeos\MShop\Order\Item\Service\Attribute\Iface $item Updated item including the generated ID
477
	 */
478
	protected function saveItem( \Aimeos\MShop\Order\Item\Service\Attribute\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Order\Item\Service\Attribute\Iface
479
	{
480
		if( !$item->isModified() ) {
481
			return $item;
482
		}
483
484
		$context = $this->context();
485
		$conn = $context->db( $this->getResourceName() );
486
487
		$id = $item->getId();
488
		$date = date( 'Y-m-d H:i:s' );
489
		$columns = $this->object()->getSaveAttributes();
490
491
		if( $id === null )
492
		{
493
			/** mshop/order/manager/service/attribute/insert/mysql
494
			 * Inserts a new order record into the database table
495
			 *
496
			 * @see mshop/order/manager/service/attribute/insert/ansi
497
			 */
498
499
			/** mshop/order/manager/service/attribute/insert/ansi
500
			 * Inserts a new order record into the database table
501
			 *
502
			 * Items with no ID yet (i.e. the ID is NULL) will be created in
503
			 * the database and the newly created ID retrieved afterwards
504
			 * using the "newid" SQL statement.
505
			 *
506
			 * The SQL statement must be a string suitable for being used as
507
			 * prepared statement. It must include question marks for binding
508
			 * the values from the order item to the statement before they are
509
			 * sent to the database server. The number of question marks must
510
			 * be the same as the number of columns listed in the INSERT
511
			 * statement. The order of the columns must correspond to the
512
			 * order in the save() method, so the correct values are
513
			 * bound to the columns.
514
			 *
515
			 * The SQL statement should conform to the ANSI standard to be
516
			 * compatible with most relational database systems. This also
517
			 * includes using double quotes for table and column names.
518
			 *
519
			 * @param string SQL statement for inserting records
520
			 * @since 2014.03
521
			 * @category Developer
522
			 * @see mshop/order/manager/service/attribute/update/ansi
523
			 * @see mshop/order/manager/service/attribute/newid/ansi
524
			 * @see mshop/order/manager/service/attribute/delete/ansi
525
			 * @see mshop/order/manager/service/attribute/search/ansi
526
			 * @see mshop/order/manager/service/attribute/count/ansi
527
			 */
528
			$path = 'mshop/order/manager/service/attribute/insert';
529
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ) );
0 ignored issues
show
Bug introduced by
It seems like $this->getSqlConfig($path) can also be of type array; however, parameter $sql of Aimeos\MShop\Common\Manager\Base::addSqlColumns() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

529
			$sql = $this->addSqlColumns( array_keys( $columns ), /** @scrutinizer ignore-type */ $this->getSqlConfig( $path ) );
Loading history...
530
		}
531
		else
532
		{
533
			/** mshop/order/manager/service/attribute/update/mysql
534
			 * Updates an existing order record in the database
535
			 *
536
			 * @see mshop/order/manager/service/attribute/update/ansi
537
			 */
538
539
			/** mshop/order/manager/service/attribute/update/ansi
540
			 * Updates an existing order record in the database
541
			 *
542
			 * Items which already have an ID (i.e. the ID is not NULL) will
543
			 * be updated in the database.
544
			 *
545
			 * The SQL statement must be a string suitable for being used as
546
			 * prepared statement. It must include question marks for binding
547
			 * the values from the order item to the statement before they are
548
			 * sent to the database server. The order of the columns must
549
			 * correspond to the order in the save() method, so the
550
			 * correct values are bound to the columns.
551
			 *
552
			 * The SQL statement should conform to the ANSI standard to be
553
			 * compatible with most relational database systems. This also
554
			 * includes using double quotes for table and column names.
555
			 *
556
			 * @param string SQL statement for updating records
557
			 * @since 2014.03
558
			 * @category Developer
559
			 * @see mshop/order/manager/service/attribute/insert/ansi
560
			 * @see mshop/order/manager/service/attribute/newid/ansi
561
			 * @see mshop/order/manager/service/attribute/delete/ansi
562
			 * @see mshop/order/manager/service/attribute/search/ansi
563
			 * @see mshop/order/manager/service/attribute/count/ansi
564
			 */
565
			$path = 'mshop/order/manager/service/attribute/update';
566
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ), false );
567
		}
568
569
		$idx = 1;
570
		$stmt = $this->getCachedStatement( $conn, $path, $sql );
571
572
		foreach( $columns as $name => $entry ) {
573
			$stmt->bind( $idx++, $item->get( $name ), \Aimeos\Base\Criteria\SQL::type( $entry->getType() ) );
574
		}
575
576
		$stmt->bind( $idx++, $item->getAttributeId() );
577
		$stmt->bind( $idx++, $item->getParentId(), \Aimeos\Base\DB\Statement\Base::PARAM_INT );
578
		$stmt->bind( $idx++, $item->getType() );
579
		$stmt->bind( $idx++, $item->getCode() );
580
		$stmt->bind( $idx++, json_encode( $item->getValue() ) );
581
		$stmt->bind( $idx++, $item->getQuantity(), \Aimeos\Base\DB\Statement\Base::PARAM_INT );
582
		$stmt->bind( $idx++, $item->getPrice() );
583
		$stmt->bind( $idx++, $item->getName() );
584
		$stmt->bind( $idx++, $date ); // mtime
585
		$stmt->bind( $idx++, $context->editor() );
586
587
		if( $id !== null ) {
588
			$stmt->bind( $idx++, $context->locale()->getSiteId() . '%' );
589
			$stmt->bind( $idx++, $id, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
590
		} else {
591
			$stmt->bind( $idx++, $this->siteId( $item->getSiteId(), \Aimeos\MShop\Locale\Manager\Base::SITE_SUBTREE ) );
592
			$stmt->bind( $idx++, $date ); // ctime
593
		}
594
595
		$stmt->execute()->finish();
596
597
		if( $id === null && $fetch === true )
598
		{
599
			/** mshop/order/manager/service/attribute/newid/mysql
600
			 * Retrieves the ID generated by the database when inserting a new record
601
			 *
602
			 * @see mshop/order/manager/service/attribute/newid/ansi
603
			 */
604
605
			/** mshop/order/manager/service/attribute/newid/ansi
606
			 * Retrieves the ID generated by the database when inserting a new record
607
			 *
608
			 * As soon as a new record is inserted into the database table,
609
			 * the database server generates a new and unique identifier for
610
			 * that record. This ID can be used for retrieving, updating and
611
			 * deleting that specific record from the table again.
612
			 *
613
			 * For MySQL:
614
			 *  SELECT LAST_INSERT_ID()
615
			 * For PostgreSQL:
616
			 *  SELECT currval('seq_mord_id')
617
			 * For SQL Server:
618
			 *  SELECT SCOPE_IDENTITY()
619
			 * For Oracle:
620
			 *  SELECT "seq_mord_id".CURRVAL FROM DUAL
621
			 *
622
			 * There's no way to retrive the new ID by a SQL statements that
623
			 * fits for most database servers as they implement their own
624
			 * specific way.
625
			 *
626
			 * @param string SQL statement for retrieving the last inserted record ID
627
			 * @since 2014.03
628
			 * @category Developer
629
			 * @see mshop/order/manager/service/attribute/insert/ansi
630
			 * @see mshop/order/manager/service/attribute/update/ansi
631
			 * @see mshop/order/manager/service/attribute/delete/ansi
632
			 * @see mshop/order/manager/service/attribute/search/ansi
633
			 * @see mshop/order/manager/service/attribute/count/ansi
634
			 */
635
			$path = 'mshop/order/manager/service/attribute/newid';
636
			$id = $this->newId( $conn, $path );
637
		}
638
639
		$item->setId( $id );
640
641
		return $item;
642
	}
643
644
645
	/**
646
	 * Searches for order service attribute items based on the given criteria.
647
	 *
648
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria object
649
	 * @param string[] $ref List of domains to fetch list items and referenced items for
650
	 * @param int|null &$total Number of items that are available in total
651
	 * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Order\Item\Service\Attribute\Iface with ids as keys
652
	 */
653
	public function search( \Aimeos\Base\Criteria\Iface $search, array $ref = [], int &$total = null ) : \Aimeos\Map
654
	{
655
		$context = $this->context();
656
		$conn = $context->db( $this->getResourceName() );
657
		$items = [];
658
659
			$required = array( 'order.service.attribute' );
660
661
			$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
662
			$level = $context->config()->get( 'mshop/order/manager/sitemode', $level );
663
664
			/** mshop/order/manager/service/attribute/search/mysql
665
			 * Retrieves the records matched by the given criteria in the database
666
			 *
667
			 * @see mshop/order/manager/service/attribute/search/ansi
668
			 */
669
670
			/** mshop/order/manager/service/attribute/search/ansi
671
			 * Retrieves the records matched by the given criteria in the database
672
			 *
673
			 * Fetches the records matched by the given criteria from the order
674
			 * database. The records must be from one of the sites that are
675
			 * configured via the context item. If the current site is part of
676
			 * a tree of sites, the SELECT statement can retrieve all records
677
			 * from the current site and the complete sub-tree of sites.
678
			 *
679
			 * As the records can normally be limited by criteria from sub-managers,
680
			 * their tables must be joined in the SQL context. This is done by
681
			 * using the "internaldeps" property from the definition of the ID
682
			 * column of the sub-managers. These internal dependencies specify
683
			 * the JOIN between the tables and the used columns for joining. The
684
			 * ":joins" placeholder is then replaced by the JOIN strings from
685
			 * the sub-managers.
686
			 *
687
			 * To limit the records matched, conditions can be added to the given
688
			 * criteria object. It can contain comparisons like column names that
689
			 * must match specific values which can be combined by AND, OR or NOT
690
			 * operators. The resulting string of SQL conditions replaces the
691
			 * ":cond" placeholder before the statement is sent to the database
692
			 * server.
693
			 *
694
			 * If the records that are retrieved should be ordered by one or more
695
			 * columns, the generated string of column / sort direction pairs
696
			 * replaces the ":order" placeholder. In case no ordering is required,
697
			 * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
698
			 * markers is removed to speed up retrieving the records. Columns of
699
			 * sub-managers can also be used for ordering the result set but then
700
			 * no index can be used.
701
			 *
702
			 * The number of returned records can be limited and can start at any
703
			 * number between the begining and the end of the result set. For that
704
			 * the ":size" and ":start" placeholders are replaced by the
705
			 * corresponding values from the criteria object. The default values
706
			 * are 0 for the start and 100 for the size value.
707
			 *
708
			 * The SQL statement should conform to the ANSI standard to be
709
			 * compatible with most relational database systems. This also
710
			 * includes using double quotes for table and column names.
711
			 *
712
			 * @param string SQL statement for searching items
713
			 * @since 2014.03
714
			 * @category Developer
715
			 * @see mshop/order/manager/service/attribute/insert/ansi
716
			 * @see mshop/order/manager/service/attribute/update/ansi
717
			 * @see mshop/order/manager/service/attribute/newid/ansi
718
			 * @see mshop/order/manager/service/attribute/delete/ansi
719
			 * @see mshop/order/manager/service/attribute/count/ansi
720
			 */
721
			$cfgPathSearch = 'mshop/order/manager/service/attribute/search';
722
723
			/** mshop/order/manager/service/attribute/count/mysql
724
			 * Counts the number of records matched by the given criteria in the database
725
			 *
726
			 * @see mshop/order/manager/service/attribute/count/ansi
727
			 */
728
729
			/** mshop/order/manager/service/attribute/count/ansi
730
			 * Counts the number of records matched by the given criteria in the database
731
			 *
732
			 * Counts all records matched by the given criteria from the order
733
			 * database. The records must be from one of the sites that are
734
			 * configured via the context item. If the current site is part of
735
			 * a tree of sites, the statement can count all records from the
736
			 * current site and the complete sub-tree of sites.
737
			 *
738
			 * As the records can normally be limited by criteria from sub-managers,
739
			 * their tables must be joined in the SQL context. This is done by
740
			 * using the "internaldeps" property from the definition of the ID
741
			 * column of the sub-managers. These internal dependencies specify
742
			 * the JOIN between the tables and the used columns for joining. The
743
			 * ":joins" placeholder is then replaced by the JOIN strings from
744
			 * the sub-managers.
745
			 *
746
			 * To limit the records matched, conditions can be added to the given
747
			 * criteria object. It can contain comparisons like column names that
748
			 * must match specific values which can be combined by AND, OR or NOT
749
			 * operators. The resulting string of SQL conditions replaces the
750
			 * ":cond" placeholder before the statement is sent to the database
751
			 * server.
752
			 *
753
			 * Both, the strings for ":joins" and for ":cond" are the same as for
754
			 * the "search" SQL statement.
755
			 *
756
			 * Contrary to the "search" statement, it doesn't return any records
757
			 * but instead the number of records that have been found. As counting
758
			 * thousands of records can be a long running task, the maximum number
759
			 * of counted records is limited for performance reasons.
760
			 *
761
			 * The SQL statement should conform to the ANSI standard to be
762
			 * compatible with most relational database systems. This also
763
			 * includes using double quotes for table and column names.
764
			 *
765
			 * @param string SQL statement for counting items
766
			 * @since 2014.03
767
			 * @category Developer
768
			 * @see mshop/order/manager/service/attribute/insert/ansi
769
			 * @see mshop/order/manager/service/attribute/update/ansi
770
			 * @see mshop/order/manager/service/attribute/newid/ansi
771
			 * @see mshop/order/manager/service/attribute/delete/ansi
772
			 * @see mshop/order/manager/service/attribute/search/ansi
773
			 */
774
			$cfgPathCount = 'mshop/order/manager/service/attribute/count';
775
776
			$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount,
777
				$required, $total, $level );
778
779
			try
780
			{
781
				while( $row = $results->fetch() )
782
				{
783
					if( ( $row['order.service.attribute.value'] = json_decode( $row['order.service.attribute.value'], true ) ) === null ) {
784
						$row['order.service.attribute.value'] = [];
785
					}
786
787
					if( $item = $this->applyFilter( $this->createItemBase( $row ) ) ) {
788
						$items[$row['order.service.attribute.id']] = $item;
789
					}
790
				}
791
			}
792
			catch( \Exception $e )
793
			{
794
				$results->finish();
795
				throw $e;
796
			}
797
798
		return map( $items );
799
	}
800
801
802
	/**
803
	 * Creates a new order service attribute item object initialized with given parameters.
804
	 *
805
	 * @param array $values Associative list of order service attribute key/value pairs
806
	 * @return \Aimeos\MShop\Order\Item\Service\Attribute\Standard New order service attribute item
807
	 */
808
	protected function createItemBase( array $values = [] ) : \Aimeos\MShop\Order\Item\Service\Attribute\Iface
809
	{
810
		return new \Aimeos\MShop\Order\Item\Service\Attribute\Standard( $values );
811
	}
812
}
813