Passed
Push — master ( 022b5e...74faaa )
by Aimeos
04:45
created

Standard::searchItems()   B

Complexity

Conditions 7
Paths 19

Size

Total Lines 175
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 41
nc 19
nop 3
dl 0
loc 175
rs 8.3306
c 0
b 0
f 0

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

629
				$sql = $this->addSqlColumns( array_keys( $columns ), /** @scrutinizer ignore-type */ $this->getSqlConfig( $path ) );
Loading history...
630
			}
631
			else
632
			{
633
				/** mshop/order/manager/base/standard/update/mysql
634
				 * Updates an existing order record in the database
635
				 *
636
				 * @see mshop/order/manager/base/standard/update/ansi
637
				 */
638
639
				/** mshop/order/manager/base/standard/update/ansi
640
				 * Updates an existing order record in the database
641
				 *
642
				 * Items which already have an ID (i.e. the ID is not NULL) will
643
				 * be updated in the database.
644
				 *
645
				 * The SQL statement must be a string suitable for being used as
646
				 * prepared statement. It must include question marks for binding
647
				 * the values from the order item to the statement before they are
648
				 * sent to the database server. The order of the columns must
649
				 * correspond to the order in the saveItems() method, so the
650
				 * correct values are bound to the columns.
651
				 *
652
				 * The SQL statement should conform to the ANSI standard to be
653
				 * compatible with most relational database systems. This also
654
				 * includes using double quotes for table and column names.
655
				 *
656
				 * @param string SQL statement for updating records
657
				 * @since 2014.03
658
				 * @category Developer
659
				 * @see mshop/order/manager/base/standard/insert/ansi
660
				 * @see mshop/order/manager/base/standard/newid/ansi
661
				 * @see mshop/order/manager/base/standard/delete/ansi
662
				 * @see mshop/order/manager/base/standard/search/ansi
663
				 * @see mshop/order/manager/base/standard/count/ansi
664
				 */
665
				$path = 'mshop/order/manager/base/standard/update';
666
				$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ), false );
667
			}
668
669
			$priceItem = $item->getPrice();
670
			$localeItem = $context->getLocale();
671
672
			$idx = 1;
673
			$stmt = $this->getCachedStatement( $conn, $path, $sql );
674
675
			foreach( $columns as $name => $entry ) {
676
				$stmt->bind( $idx++, $item->get( $name ), $entry->getInternalType() );
677
			}
678
679
			$stmt->bind( $idx++, $item->getCustomerId() );
680
			$stmt->bind( $idx++, $localeItem->getSiteItem()->getCode() );
681
			$stmt->bind( $idx++, $item->getLocale()->getLanguageId() );
682
			$stmt->bind( $idx++, $priceItem->getCurrencyId() );
683
			$stmt->bind( $idx++, $priceItem->getValue() );
684
			$stmt->bind( $idx++, $priceItem->getCosts() );
685
			$stmt->bind( $idx++, $priceItem->getRebate() );
686
			$stmt->bind( $idx++, $priceItem->getTaxValue() );
687
			$stmt->bind( $idx++, $priceItem->getTaxFlag(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
688
			$stmt->bind( $idx++, $item->getCustomerReference() );
689
			$stmt->bind( $idx++, $item->getComment() );
690
			$stmt->bind( $idx++, $date ); // mtime
691
			$stmt->bind( $idx++, $context->getEditor() );
692
			$stmt->bind( $idx++, $localeItem->getSiteId() );
693
694
			if( $id !== null ) {
695
				$stmt->bind( $idx++, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
696
			} else {
697
				$stmt->bind( $idx++, $date ); // ctime
698
			}
699
700
			$stmt->execute()->finish();
701
702
			if( $id === null && $fetch === true )
703
			{
704
				/** mshop/order/manager/base/standard/newid/mysql
705
				 * Retrieves the ID generated by the database when inserting a new record
706
				 *
707
				 * @see mshop/order/manager/base/standard/newid/ansi
708
				 */
709
710
				/** mshop/order/manager/base/standard/newid/ansi
711
				 * Retrieves the ID generated by the database when inserting a new record
712
				 *
713
				 * As soon as a new record is inserted into the database table,
714
				 * the database server generates a new and unique identifier for
715
				 * that record. This ID can be used for retrieving, updating and
716
				 * deleting that specific record from the table again.
717
				 *
718
				 * For MySQL:
719
				 *  SELECT LAST_INSERT_ID()
720
				 * For PostgreSQL:
721
				 *  SELECT currval('seq_mord_id')
722
				 * For SQL Server:
723
				 *  SELECT SCOPE_IDENTITY()
724
				 * For Oracle:
725
				 *  SELECT "seq_mord_id".CURRVAL FROM DUAL
726
				 *
727
				 * There's no way to retrive the new ID by a SQL statements that
728
				 * fits for most database servers as they implement their own
729
				 * specific way.
730
				 *
731
				 * @param string SQL statement for retrieving the last inserted record ID
732
				 * @since 2014.03
733
				 * @category Developer
734
				 * @see mshop/order/manager/base/standard/insert/ansi
735
				 * @see mshop/order/manager/base/standard/update/ansi
736
				 * @see mshop/order/manager/base/standard/delete/ansi
737
				 * @see mshop/order/manager/base/standard/search/ansi
738
				 * @see mshop/order/manager/base/standard/count/ansi
739
				 */
740
				$path = 'mshop/order/manager/base/standard/newid';
741
				$id = $this->newId( $conn, $path );
742
			}
743
744
			$item->setId( $id );
745
746
			$dbm->release( $conn, $dbname );
747
		}
748
		catch( \Exception $e )
749
		{
750
			$dbm->release( $conn, $dbname );
751
			throw $e;
752
		}
753
754
		return $item;
755
	}
756
757
758
	/**
759
	 * Search for orders based on the given criteria.
760
	 *
761
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria object
762
	 * @param string[] $ref List of domains to fetch list items and referenced items for, e.g.
763
	 *	"order/base/address", "order/base/coupon", "order/base/product", "order/base/service"
764
	 * @param int|null &$total Number of items that are available in total
765
	 * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Order\Item\Base\Iface with ids as keys
766
	 */
767
	public function searchItems( \Aimeos\MW\Criteria\Iface $search, array $ref = [], int &$total = null ) : \Aimeos\Map
768
	{
769
		$context = $this->getContext();
770
		$priceManager = \Aimeos\MShop::create( $context, 'price' );
771
		$localeManager = \Aimeos\MShop::create( $context, 'locale' );
772
773
		$dbm = $context->getDatabaseManager();
774
		$dbname = $this->getResourceName();
775
		$conn = $dbm->acquire( $dbname );
776
777
		$map = $items = $custItems = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $items is dead and can be removed.
Loading history...
778
779
		try
780
		{
781
			$required = array( 'order.base' );
782
783
			$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
784
			$level = $context->getConfig()->get( 'mshop/order/manager/sitemode', $level );
785
786
			/** mshop/order/manager/base/standard/search/mysql
787
			 * Retrieves the records matched by the given criteria in the database
788
			 *
789
			 * @see mshop/order/manager/base/standard/search/ansi
790
			 */
791
792
			/** mshop/order/manager/base/standard/search/ansi
793
			 * Retrieves the records matched by the given criteria in the database
794
			 *
795
			 * Fetches the records matched by the given criteria from the order
796
			 * database. The records must be from one of the sites that are
797
			 * configured via the context item. If the current site is part of
798
			 * a tree of sites, the SELECT statement can retrieve all records
799
			 * from the current site and the complete sub-tree of sites.
800
			 *
801
			 * As the records can normally be limited by criteria from sub-managers,
802
			 * their tables must be joined in the SQL context. This is done by
803
			 * using the "internaldeps" property from the definition of the ID
804
			 * column of the sub-managers. These internal dependencies specify
805
			 * the JOIN between the tables and the used columns for joining. The
806
			 * ":joins" placeholder is then replaced by the JOIN strings from
807
			 * the sub-managers.
808
			 *
809
			 * To limit the records matched, conditions can be added to the given
810
			 * criteria object. It can contain comparisons like column names that
811
			 * must match specific values which can be combined by AND, OR or NOT
812
			 * operators. The resulting string of SQL conditions replaces the
813
			 * ":cond" placeholder before the statement is sent to the database
814
			 * server.
815
			 *
816
			 * If the records that are retrieved should be ordered by one or more
817
			 * columns, the generated string of column / sort direction pairs
818
			 * replaces the ":order" placeholder. In case no ordering is required,
819
			 * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
820
			 * markers is removed to speed up retrieving the records. Columns of
821
			 * sub-managers can also be used for ordering the result set but then
822
			 * no index can be used.
823
			 *
824
			 * The number of returned records can be limited and can start at any
825
			 * number between the begining and the end of the result set. For that
826
			 * the ":size" and ":start" placeholders are replaced by the
827
			 * corresponding values from the criteria object. The default values
828
			 * are 0 for the start and 100 for the size value.
829
			 *
830
			 * The SQL statement should conform to the ANSI standard to be
831
			 * compatible with most relational database systems. This also
832
			 * includes using double quotes for table and column names.
833
			 *
834
			 * @param string SQL statement for searching items
835
			 * @since 2014.03
836
			 * @category Developer
837
			 * @see mshop/order/manager/base/standard/insert/ansi
838
			 * @see mshop/order/manager/base/standard/update/ansi
839
			 * @see mshop/order/manager/base/standard/newid/ansi
840
			 * @see mshop/order/manager/base/standard/delete/ansi
841
			 * @see mshop/order/manager/base/standard/count/ansi
842
			 */
843
			$cfgPathSearch = 'mshop/order/manager/base/standard/search';
844
845
			/** mshop/order/manager/base/standard/count/mysql
846
			 * Counts the number of records matched by the given criteria in the database
847
			 *
848
			 * @see mshop/order/manager/base/standard/count/ansi
849
			 */
850
851
			/** mshop/order/manager/base/standard/count/ansi
852
			 * Counts the number of records matched by the given criteria in the database
853
			 *
854
			 * Counts all records matched by the given criteria from the order
855
			 * database. The records must be from one of the sites that are
856
			 * configured via the context item. If the current site is part of
857
			 * a tree of sites, the statement can count all records from the
858
			 * current site and the complete sub-tree of sites.
859
			 *
860
			 * As the records can normally be limited by criteria from sub-managers,
861
			 * their tables must be joined in the SQL context. This is done by
862
			 * using the "internaldeps" property from the definition of the ID
863
			 * column of the sub-managers. These internal dependencies specify
864
			 * the JOIN between the tables and the used columns for joining. The
865
			 * ":joins" placeholder is then replaced by the JOIN strings from
866
			 * the sub-managers.
867
			 *
868
			 * To limit the records matched, conditions can be added to the given
869
			 * criteria object. It can contain comparisons like column names that
870
			 * must match specific values which can be combined by AND, OR or NOT
871
			 * operators. The resulting string of SQL conditions replaces the
872
			 * ":cond" placeholder before the statement is sent to the database
873
			 * server.
874
			 *
875
			 * Both, the strings for ":joins" and for ":cond" are the same as for
876
			 * the "search" SQL statement.
877
			 *
878
			 * Contrary to the "search" statement, it doesn't return any records
879
			 * but instead the number of records that have been found. As counting
880
			 * thousands of records can be a long running task, the maximum number
881
			 * of counted records is limited for performance reasons.
882
			 *
883
			 * The SQL statement should conform to the ANSI standard to be
884
			 * compatible with most relational database systems. This also
885
			 * includes using double quotes for table and column names.
886
			 *
887
			 * @param string SQL statement for counting items
888
			 * @since 2014.03
889
			 * @category Developer
890
			 * @see mshop/order/manager/base/standard/insert/ansi
891
			 * @see mshop/order/manager/base/standard/update/ansi
892
			 * @see mshop/order/manager/base/standard/newid/ansi
893
			 * @see mshop/order/manager/base/standard/delete/ansi
894
			 * @see mshop/order/manager/base/standard/search/ansi
895
			 */
896
			$cfgPathCount = 'mshop/order/manager/base/standard/count';
897
898
			$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount,
899
				$required, $total, $level );
900
901
			while( ( $row = $results->fetch() ) !== null ) {
902
				$map[$row['order.base.id']] = $row;
903
			}
904
905
			$dbm->release( $conn, $dbname );
906
		}
907
		catch( \Exception $e )
908
		{
909
			$dbm->release( $conn, $dbname );
910
			throw $e;
911
		}
912
913
		if( ( isset( $ref['customer'] ) || in_array( 'customer', $ref ) )
914
			&& !( $ids = map( $map )->col( 'order.base.customerid' )->filter() )->empty()
915
		) {
916
			$manager = \Aimeos\MShop::create( $context, 'customer' );
917
			$search = $manager->createSearch()->setSlice( 0, count( $ids ) );
918
			$search->setConditions( $search->compare( '==', 'customer.id', $ids ) );
919
			$custItems = $manager->searchItems( $search, $ref );
920
		}
921
922
		foreach( $map as $id => $row )
923
		{
924
			$price = $priceManager->createItem();
925
			$price->setCurrencyId( $row['order.base.currencyid'] );
926
			$price->setValue( $row['order.base.price'] );
927
			$price->setCosts( $row['order.base.costs'] );
928
			$price->setRebate( $row['order.base.rebate'] );
929
			$price->setTaxValue( $row['order.base.taxvalue'] );
930
			$price->setTaxFlag( $row['order.base.taxflag'] );
931
932
			// you may need the site object! take care!
933
			$localeItem = $localeManager->createItem();
934
			$localeItem->setLanguageId( $row['order.base.languageid'] );
935
			$localeItem->setCurrencyId( $row['order.base.currencyid'] );
936
			$localeItem->setSiteId( $row['order.base.siteid'] );
937
938
			$map[$id] = [$price, $localeItem, $row, $custItems[$row['order.base.customerid'] ?? null] ?? null];
939
		}
940
941
		return $this->buildItems( $map, $ref );
942
	}
943
944
945
	/**
946
	 * Creates a new basket containing the items from the order excluding the coupons.
947
	 * If the last parameter is ture, the items will be marked as new and
948
	 * modified so an additional order is stored when the basket is saved.
949
	 *
950
	 * @param string $id Base ID of the order to load
951
	 * @param int $parts Bitmap of the basket parts that should be loaded
952
	 * @param bool $fresh Create a new basket by copying the existing one and remove IDs
953
	 * @param bool $default True to use default criteria, false for no limitation
954
	 * @return \Aimeos\MShop\Order\Item\Base\Iface Basket including all items
955
	 */
956
	public function load( string $id, int $parts = \Aimeos\MShop\Order\Item\Base\Base::PARTS_ALL, bool $fresh = false,
957
		bool $default = false ) : \Aimeos\MShop\Order\Item\Base\Iface
958
	{
959
		$search = $this->getObject()->createSearch( $default );
960
		$expr = [
961
			$search->compare( '==', 'order.base.id', $id ),
962
			$search->getConditions(),
963
		];
964
		$search->setConditions( $search->combine( '&&', $expr ) );
965
966
		$context = $this->getContext();
967
		$dbm = $context->getDatabaseManager();
968
		$dbname = $this->getResourceName();
969
		$conn = $dbm->acquire( $dbname );
970
971
		try
972
		{
973
			$sitelevel = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
974
			$sitelevel = $context->getConfig()->get( 'mshop/order/manager/sitemode', $sitelevel );
975
976
			$cfgPathSearch = 'mshop/order/manager/base/standard/search';
977
			$cfgPathCount = 'mshop/order/manager/base/standard/count';
978
			$required = array( 'order.base' );
979
			$total = null;
980
981
			$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $sitelevel );
982
983
			if( ( $row = $results->fetch() ) === null ) {
984
				throw new \Aimeos\MShop\Order\Exception( sprintf( 'Order base item with order ID "%1$s" not found', $id ) );
985
			}
986
			$results->finish();
987
988
			$dbm->release( $conn, $dbname );
989
		}
990
		catch( \Exception $e )
991
		{
992
			$dbm->release( $conn, $dbname );
993
			throw $e;
994
		}
995
996
		$priceManager = \Aimeos\MShop::create( $context, 'price' );
997
		$localeManager = \Aimeos\MShop::create( $context, 'locale' );
998
999
		$price = $priceManager->createItem( [
1000
			'price.currencyid' => $row['order.base.currencyid'],
1001
			'price.value' => $row['order.base.price'],
1002
			'price.costs' => $row['order.base.costs'],
1003
			'price.rebate' => $row['order.base.rebate'],
1004
			'price.taxflag' => $row['order.base.taxflag'],
1005
			'price.taxvalue' => $row['order.base.taxvalue'],
1006
		] );
1007
1008
		// you may need the site object! take care!
1009
		$localeItem = $localeManager->createItem( [
1010
			'locale.languageid' => $row['order.base.languageid'],
1011
			'locale.currencyid' => $row['order.base.currencyid'],
1012
			'locale.siteid' => $row['order.base.siteid'],
1013
		] );
1014
1015
		if( $fresh === false ) {
1016
			$basket = $this->loadItems( $id, $price, $localeItem, $row, $parts );
1017
		} else {
1018
			$basket = $this->loadFresh( $id, $price, $localeItem, $row, $parts );
1019
		}
1020
1021
		$pluginManager = \Aimeos\MShop::create( $this->getContext(), 'plugin' );
1022
		$pluginManager->register( $basket, 'order' );
1023
1024
		return $basket;
1025
	}
1026
1027
1028
	/**
1029
	 * Saves the complete basket to the storage including the items attached.
1030
	 *
1031
	 * @param \Aimeos\MShop\Order\Item\Base\Iface $basket Basket object containing all information
1032
	 * @param int $parts Bitmap of the basket parts that should be stored
1033
	 * @return \Aimeos\MShop\Order\Item\Base\Iface Stored order basket
1034
	 */
1035
	public function store( \Aimeos\MShop\Order\Item\Base\Iface $basket,
1036
		int $parts = \Aimeos\MShop\Order\Item\Base\Base::PARTS_ALL ) : \Aimeos\MShop\Order\Item\Base\Iface
1037
	{
1038
		$basket = $this->getObject()->saveItem( $basket );
1039
1040
		if( $parts & \Aimeos\MShop\Order\Item\Base\Base::PARTS_PRODUCT
1041
			|| $parts & \Aimeos\MShop\Order\Item\Base\Base::PARTS_COUPON
1042
		) {
1043
			$this->storeProducts( $basket );
1044
		}
1045
1046
		if( $parts & \Aimeos\MShop\Order\Item\Base\Base::PARTS_COUPON ) {
1047
			$this->storeCoupons( $basket );
1048
		}
1049
1050
		if( $parts & \Aimeos\MShop\Order\Item\Base\Base::PARTS_ADDRESS ) {
1051
			$this->storeAddresses( $basket );
1052
		}
1053
1054
		if( $parts & \Aimeos\MShop\Order\Item\Base\Base::PARTS_SERVICE ) {
1055
			$this->storeServices( $basket );
1056
		}
1057
1058
		return $basket;
1059
	}
1060
1061
1062
	/**
1063
	 * Creates the order base item objects from the map and adds the referenced items
1064
	 *
1065
	 * @param array $map Associative list of order base IDs as keys and list of price/locale/row as values
1066
	 * @param string[] $ref Domain items that should be added as well, e.g.
1067
	 *	"order/base/address", "order/base/coupon", "order/base/product", "order/base/service"
1068
	 * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Order\Item\Base\Iface with IDs as keys
1069
	 */
1070
	protected function buildItems( array $map, array $ref ) : \Aimeos\Map
1071
	{
1072
		$items = [];
1073
		$baseIds = array_keys( $map );
1074
		$addressMap = $couponMap = $productMap = $serviceMap = [];
1075
1076
		if( in_array( 'order/base/address', $ref ) ) {
1077
			$addressMap = $this->getAddresses( $baseIds );
1078
		}
1079
1080
		if( in_array( 'order/base/product', $ref ) ) {
1081
			$productMap = $this->getProducts( $baseIds );
1082
		}
1083
1084
		if( in_array( 'order/base/coupon', $ref ) ) {
1085
			$couponMap = $this->getCoupons( $baseIds, false, $productMap );
1086
		}
1087
1088
		if( in_array( 'order/base/service', $ref ) ) {
1089
			$serviceMap = $this->getServices( $baseIds );
1090
		}
1091
1092
		foreach( $map as $id => $list )
1093
		{
1094
			list( $price, $locale, $row, $custItem ) = $list;
1095
1096
			$addresses = $addressMap[$id] ?? [];
1097
			$coupons = $couponMap[$id] ?? [];
1098
			$products = $productMap[$id] ?? [];
1099
			$services = $serviceMap[$id] ?? [];
1100
1101
			$item = $this->createItemBase( $price, $locale, $row, $products, $addresses, $services, $coupons, $custItem );
1102
1103
			if( $item = $this->applyFilter( $item ) ) {
1104
				$items[$id] = $item;
1105
			}
1106
		}
1107
1108
		return map( $items );
1109
	}
1110
1111
1112
	/**
1113
	 * Returns a new and empty order base item (shopping basket).
1114
	 *
1115
	 * @param \Aimeos\MShop\Price\Item\Iface $price Default price of the basket (usually 0.00)
1116
	 * @param \Aimeos\MShop\Locale\Item\Iface $locale Locale item containing the site, language and currency
1117
	 * @param array $values Associative list of key/value pairs containing, e.g. the order or user ID
1118
	 * @param \Aimeos\MShop\Order\Item\Base\Product\Iface[] $products List of ordered product items
1119
	 * @param \Aimeos\MShop\Order\Item\Base\Address\Iface[] $addresses List of order address items
1120
	 * @param \Aimeos\MShop\Order\Item\Base\Service\Iface[] $services List of order serviceitems
1121
	 * @param \Aimeos\MShop\Order\Item\Base\Product\Iface[] $coupons Associative list of coupon codes as keys and items as values
1122
	 * @param \Aimeos\MShop\Customer\Item\Iface|null $custItem Customer item object if requested
1123
	 * @return \Aimeos\MShop\Order\Item\Base\Iface Order base object
1124
	 */
1125
	protected function createItemBase( \Aimeos\MShop\Price\Item\Iface $price, \Aimeos\MShop\Locale\Item\Iface $locale,
1126
		array $values = [], array $products = [], array $addresses = [], array $services = [], array $coupons = [],
1127
		?\Aimeos\MShop\Customer\Item\Iface $custItem = null ) : \Aimeos\MShop\Order\Item\Base\Iface
1128
	{
1129
		return new \Aimeos\MShop\Order\Item\Base\Standard( $price, $locale,
1130
			$values, $products, $addresses, $services, $coupons, $custItem );
1131
	}
1132
}
1133