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

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

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

721
			$stmt->bind( 8, $item->/** @scrutinizer ignore-call */ getName() );
Loading history...
722
			$stmt->bind( 9, $item->getMediaUrl() );
723
			$stmt->bind( 10, $item->getQuantity() );
724
			$stmt->bind( 11, $price->getCurrencyId() );
725
			$stmt->bind( 12, $price->getValue() );
726
			$stmt->bind( 13, $price->getCosts() );
727
			$stmt->bind( 14, $price->getRebate() );
728
			$stmt->bind( 15, $price->getTaxValue() );
729
			$stmt->bind( 16, $price->getTaxRate() );
730
			$stmt->bind( 17, $price->getTaxFlag(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
731
			$stmt->bind( 18, $item->getFlags(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
732
			$stmt->bind( 19, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
733
			$stmt->bind( 20, $item->getPosition(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
734
			$stmt->bind( 21, $date ); // mtime
735
			$stmt->bind( 22, $context->getEditor() );
736
			$stmt->bind( 23, $item->getTarget() );
737
			$stmt->bind( 24, $item->getSiteId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
738
739
			if( $id !== null ) {
740
				$stmt->bind( 25, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
741
				$item->setId( $id );
742
			} else {
743
				$stmt->bind( 25, $date ); // ctime
744
			}
745
746
			$stmt->execute()->finish();
747
748
			if( $id === null && $fetch === true )
749
			{
750
				/** mshop/order/manager/base/product/standard/newid/mysql
751
				 * Retrieves the ID generated by the database when inserting a new record
752
				 *
753
				 * @see mshop/order/manager/base/product/standard/newid/ansi
754
				 */
755
756
				/** mshop/order/manager/base/product/standard/newid/ansi
757
				 * Retrieves the ID generated by the database when inserting a new record
758
				 *
759
				 * As soon as a new record is inserted into the database table,
760
				 * the database server generates a new and unique identifier for
761
				 * that record. This ID can be used for retrieving, updating and
762
				 * deleting that specific record from the table again.
763
				 *
764
				 * For MySQL:
765
				 *  SELECT LAST_INSERT_ID()
766
				 * For PostgreSQL:
767
				 *  SELECT currval('seq_mord_id')
768
				 * For SQL Server:
769
				 *  SELECT SCOPE_IDENTITY()
770
				 * For Oracle:
771
				 *  SELECT "seq_mord_id".CURRVAL FROM DUAL
772
				 *
773
				 * There's no way to retrive the new ID by a SQL statements that
774
				 * fits for most database servers as they implement their own
775
				 * specific way.
776
				 *
777
				 * @param string SQL statement for retrieving the last inserted record ID
778
				 * @since 2014.03
779
				 * @category Developer
780
				 * @see mshop/order/manager/base/product/standard/insert/ansi
781
				 * @see mshop/order/manager/base/product/standard/update/ansi
782
				 * @see mshop/order/manager/base/product/standard/delete/ansi
783
				 * @see mshop/order/manager/base/product/standard/search/ansi
784
				 * @see mshop/order/manager/base/product/standard/count/ansi
785
				 */
786
				$path = 'mshop/order/manager/base/product/standard/newid';
787
				$item->setId( $this->newId( $conn, $path ) );
788
			}
789
790
			$dbm->release( $conn, $dbname );
791
		}
792
		catch( \Exception $e )
793
		{
794
			$dbm->release( $conn, $dbname );
795
			throw $e;
796
		}
797
798
		return $item;
799
	}
800
801
802
	/**
803
	 * Searches for order base products item based on the given criteria.
804
	 *
805
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria object
806
	 * @param string[] $ref List of domains to fetch list items and referenced items for
807
	 * @param integer|null &$total Number of items that are available in total
808
	 * @return array List of products implementing \Aimeos\MShop\Order\Item\Base\Product\Iface's
809
	 */
810
	public function searchItems( \Aimeos\MW\Criteria\Iface $search, array $ref = [], &$total = null )
811
	{
812
		$items = [];
813
		$context = $this->getContext();
814
		$priceManager = \Aimeos\MShop\Factory::createManager( $context, 'price' );
815
816
		$dbm = $context->getDatabaseManager();
817
		$dbname = $this->getResourceName();
818
		$conn = $dbm->acquire( $dbname );
819
820
		try
821
		{
822
			$required = array( 'order.base.product' );
823
824
			$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
825
			$level = $context->getConfig()->get( 'mshop/order/manager/sitemode', $level );
826
827
			/** mshop/order/manager/base/product/standard/search/mysql
828
			 * Retrieves the records matched by the given criteria in the database
829
			 *
830
			 * @see mshop/order/manager/base/product/standard/search/ansi
831
			 */
832
833
			/** mshop/order/manager/base/product/standard/search/ansi
834
			 * Retrieves the records matched by the given criteria in the database
835
			 *
836
			 * Fetches the records matched by the given criteria from the order
837
			 * database. The records must be from one of the sites that are
838
			 * configured via the context item. If the current site is part of
839
			 * a tree of sites, the SELECT statement can retrieve all records
840
			 * from the current site and the complete sub-tree of sites.
841
			 *
842
			 * As the records can normally be limited by criteria from sub-managers,
843
			 * their tables must be joined in the SQL context. This is done by
844
			 * using the "internaldeps" property from the definition of the ID
845
			 * column of the sub-managers. These internal dependencies specify
846
			 * the JOIN between the tables and the used columns for joining. The
847
			 * ":joins" placeholder is then replaced by the JOIN strings from
848
			 * the sub-managers.
849
			 *
850
			 * To limit the records matched, conditions can be added to the given
851
			 * criteria object. It can contain comparisons like column names that
852
			 * must match specific values which can be combined by AND, OR or NOT
853
			 * operators. The resulting string of SQL conditions replaces the
854
			 * ":cond" placeholder before the statement is sent to the database
855
			 * server.
856
			 *
857
			 * If the records that are retrieved should be ordered by one or more
858
			 * columns, the generated string of column / sort direction pairs
859
			 * replaces the ":order" placeholder. In case no ordering is required,
860
			 * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
861
			 * markers is removed to speed up retrieving the records. Columns of
862
			 * sub-managers can also be used for ordering the result set but then
863
			 * no index can be used.
864
			 *
865
			 * The number of returned records can be limited and can start at any
866
			 * number between the begining and the end of the result set. For that
867
			 * the ":size" and ":start" placeholders are replaced by the
868
			 * corresponding values from the criteria object. The default values
869
			 * are 0 for the start and 100 for the size value.
870
			 *
871
			 * The SQL statement should conform to the ANSI standard to be
872
			 * compatible with most relational database systems. This also
873
			 * includes using double quotes for table and column names.
874
			 *
875
			 * @param string SQL statement for searching items
876
			 * @since 2014.03
877
			 * @category Developer
878
			 * @see mshop/order/manager/base/product/standard/insert/ansi
879
			 * @see mshop/order/manager/base/product/standard/update/ansi
880
			 * @see mshop/order/manager/base/product/standard/newid/ansi
881
			 * @see mshop/order/manager/base/product/standard/delete/ansi
882
			 * @see mshop/order/manager/base/product/standard/count/ansi
883
			 */
884
			$cfgPathSearch = 'mshop/order/manager/base/product/standard/search';
885
886
			/** mshop/order/manager/base/product/standard/count/mysql
887
			 * Counts the number of records matched by the given criteria in the database
888
			 *
889
			 * @see mshop/order/manager/base/product/standard/count/ansi
890
			 */
891
892
			/** mshop/order/manager/base/product/standard/count/ansi
893
			 * Counts the number of records matched by the given criteria in the database
894
			 *
895
			 * Counts all records matched by the given criteria from the order
896
			 * database. The records must be from one of the sites that are
897
			 * configured via the context item. If the current site is part of
898
			 * a tree of sites, the statement can count all records from the
899
			 * current site and the complete sub-tree of sites.
900
			 *
901
			 * As the records can normally be limited by criteria from sub-managers,
902
			 * their tables must be joined in the SQL context. This is done by
903
			 * using the "internaldeps" property from the definition of the ID
904
			 * column of the sub-managers. These internal dependencies specify
905
			 * the JOIN between the tables and the used columns for joining. The
906
			 * ":joins" placeholder is then replaced by the JOIN strings from
907
			 * the sub-managers.
908
			 *
909
			 * To limit the records matched, conditions can be added to the given
910
			 * criteria object. It can contain comparisons like column names that
911
			 * must match specific values which can be combined by AND, OR or NOT
912
			 * operators. The resulting string of SQL conditions replaces the
913
			 * ":cond" placeholder before the statement is sent to the database
914
			 * server.
915
			 *
916
			 * Both, the strings for ":joins" and for ":cond" are the same as for
917
			 * the "search" SQL statement.
918
			 *
919
			 * Contrary to the "search" statement, it doesn't return any records
920
			 * but instead the number of records that have been found. As counting
921
			 * thousands of records can be a long running task, the maximum number
922
			 * of counted records is limited for performance reasons.
923
			 *
924
			 * The SQL statement should conform to the ANSI standard to be
925
			 * compatible with most relational database systems. This also
926
			 * includes using double quotes for table and column names.
927
			 *
928
			 * @param string SQL statement for counting items
929
			 * @since 2014.03
930
			 * @category Developer
931
			 * @see mshop/order/manager/base/product/standard/insert/ansi
932
			 * @see mshop/order/manager/base/product/standard/update/ansi
933
			 * @see mshop/order/manager/base/product/standard/newid/ansi
934
			 * @see mshop/order/manager/base/product/standard/delete/ansi
935
			 * @see mshop/order/manager/base/product/standard/search/ansi
936
			 */
937
			$cfgPathCount = 'mshop/order/manager/base/product/standard/count';
938
939
			$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount,
940
				$required, $total, $level );
941
942
			try
943
			{
944
				while( ( $row = $results->fetch() ) !== false )
945
				{
946
					$price = $priceManager->createItem();
947
					$price->setValue( $row['order.base.product.price'] );
948
					$price->setRebate( $row['order.base.product.rebate'] );
949
					$price->setCosts( $row['order.base.product.costs'] );
950
					$price->setTaxRate( $row['order.base.product.taxrate'] );
951
					$price->setTaxFlag( $row['order.base.product.taxflag'] );
952
					$price->setTaxValue( $row['order.base.product.taxvalue'] );
953
					$price->setCurrencyId( $row['order.base.product.currencyid'] );
954
955
					$items[$row['order.base.product.id']] = array( 'price' => $price, 'item' => $row );
956
				}
957
			}
958
			catch( \Exception $e )
959
			{
960
				$results->finish();
961
				throw $e;
962
			}
963
964
			$dbm->release( $conn, $dbname );
965
		}
966
		catch( \Exception $e )
967
		{
968
			$dbm->release( $conn, $dbname );
969
			throw $e;
970
		}
971
972
		$result = [];
973
		$attributes = $this->getAttributeItems( array_keys( $items ) );
974
975
		foreach( $items as $id => $row )
976
		{
977
			$attrList = ( isset( $attributes[$id] ) ? $attributes[$id] : [] );
978
			$result[$id] = $this->createItemBase( $row['price'], $row['item'], $attrList );
979
		}
980
981
		return $result;
982
	}
983
984
985
	/**
986
	 * Creates new order base product item object initialized with given parameters.
987
	 *
988
	 * @param \Aimeos\MShop\Price\Item\Iface $price Price item object with product price
989
	 * @param array $values Associative list of ordered product properties
990
	 * @param array $attributes List of order product attributes that belong to the ordered product
991
	 * @return \Aimeos\MShop\Order\Item\Base\Product\Iface
992
	 */
993
	protected function createItemBase( \Aimeos\MShop\Price\Item\Iface $price, array $values = [], array $attributes = [] )
994
	{
995
		return new \Aimeos\MShop\Order\Item\Base\Product\Standard( $price, $values, $attributes );
996
	}
997
998
999
	/**
1000
	 * Searches for attribute items connected with order product item.
1001
	 *
1002
	 * @param string[] $ids List of order product item IDs
1003
	 * @return array List of items implementing \Aimeos\MShop\Order\Item\Base\Product\Attribute\Iface
1004
	 */
1005
	protected function getAttributeItems( $ids )
1006
	{
1007
		$manager = $this->getSubmanager( 'attribute' );
1008
		$search = $manager->createSearch()->setSlice( 0, 0x7fffffff );
1009
		$search->setConditions( $search->compare( '==', 'order.base.product.attribute.parentid', $ids ) );
1010
		$search->setSortations( array( $search->sort( '+', 'order.base.product.attribute.code' ) ) );
1011
1012
		$result = [];
1013
		foreach( $manager->searchItems( $search ) as $item ) {
1014
			$result[$item->getParentId()][$item->getId()] = $item;
1015
		}
1016
1017
		return $result;
1018
	}
1019
}
1020