Passed
Push — master ( 8f16ed...3311dc )
by Aimeos
10:04
created

src/MShop/Order/Manager/Base/Product/Standard.php (4 issues)

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.orderaddressid' => array(
52
			'code' => 'order.base.product.orderaddressid',
53
			'internalcode' => 'mordbapr."ordaddrid"',
54
			'label' => 'Address ID for the product',
55
			'type' => 'integer',
56
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
57
			'public' => false,
58
		),
59
		'order.base.product.orderproductid' => array(
60
			'code' => 'order.base.product.orderproductid',
61
			'internalcode' => 'mordbapr."ordprodid"',
62
			'label' => 'Product parent ID',
63
			'type' => 'integer',
64
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
65
			'public' => false,
66
		),
67
		'order.base.product.productid' => array(
68
			'code' => 'order.base.product.productid',
69
			'internalcode' => 'mordbapr."prodid"',
70
			'label' => 'Product original ID',
71
			'type' => 'integer',
72
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
73
			'public' => false,
74
		),
75
		'order.base.product.name' => array(
76
			'code' => 'order.base.product.name',
77
			'internalcode' => 'mordbapr."name"',
78
			'label' => 'Product name',
79
			'type' => 'string',
80
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
81
		),
82
		'order.base.product.prodcode' => array(
83
			'code' => 'order.base.product.prodcode',
84
			'internalcode' => 'mordbapr."prodcode"',
85
			'label' => 'Product code',
86
			'type' => 'string',
87
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
88
		),
89
		'order.base.product.type' => array(
90
			'code' => 'order.base.product.type',
91
			'internalcode' => 'mordbapr."type"',
92
			'label' => 'Product type',
93
			'type' => 'string',
94
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
95
		),
96
		'order.base.product.suppliercode' => array(
97
			'code' => 'order.base.product.suppliercode',
98
			'internalcode' => 'mordbapr."suppliercode"',
99
			'label' => 'Product supplier code',
100
			'type' => 'string',
101
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
102
		),
103
		'order.base.product.stocktype' => array(
104
			'code' => 'order.base.product.stocktype',
105
			'internalcode' => 'mordbapr."stocktype"',
106
			'label' => 'Product stock type',
107
			'type' => 'string',
108
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
109
		),
110
		'order.base.product.quantity' => array(
111
			'code' => 'order.base.product.quantity',
112
			'internalcode' => 'mordbapr."quantity"',
113
			'label' => 'Product quantity',
114
			'type' => 'integer',
115
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
116
		),
117
		'order.base.product.currencyid' => array(
118
			'code' => 'order.base.product.currencyid',
119
			'internalcode' => 'mordbapr."currencyid"',
120
			'label' => 'Product currencyid code',
121
			'type' => 'string',
122
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
123
		),
124
		'order.base.product.price' => array(
125
			'code' => 'order.base.product.price',
126
			'internalcode' => 'mordbapr."price"',
127
			'label' => 'Product price',
128
			'type' => 'decimal',
129
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
130
		),
131
		'order.base.product.costs' => array(
132
			'code' => 'order.base.product.costs',
133
			'internalcode' => 'mordbapr."costs"',
134
			'label' => 'Product shipping',
135
			'type' => 'decimal',
136
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
137
		),
138
		'order.base.product.rebate' => array(
139
			'code' => 'order.base.product.rebate',
140
			'internalcode' => 'mordbapr."rebate"',
141
			'label' => 'Product rebate',
142
			'type' => 'decimal',
143
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
144
		),
145
		'order.base.product.taxrate' => array(
146
			'code' => 'order.base.product.taxrate',
147
			'internalcode' => 'mordbapr."taxrate"',
148
			'label' => 'Product taxrate',
149
			'type' => 'decimal',
150
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
151
		),
152
		'order.base.product.taxvalue' => array(
153
			'code' => 'order.base.product.taxvalue',
154
			'internalcode' => 'mordbapr."tax"',
155
			'label' => 'Product tax value',
156
			'type' => 'decimal',
157
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
158
		),
159
		'order.base.product.taxflag' => array(
160
			'code' => 'order.base.product.taxflag',
161
			'internalcode' => 'mordbapr."taxflag"',
162
			'label' => 'Product tax flag (0=net, 1=gross)',
163
			'type' => 'integer',
164
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
165
		),
166
		'order.base.product.position' => array(
167
			'code' => 'order.base.product.position',
168
			'internalcode' => 'mordbapr."pos"',
169
			'label' => 'Product position',
170
			'type' => 'integer',
171
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
172
		),
173
		'order.base.product.status' => array(
174
			'code' => 'order.base.product.status',
175
			'internalcode' => 'mordbapr."status"',
176
			'label' => 'Product status',
177
			'type' => 'integer',
178
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
179
		),
180
		'order.base.product.mediaurl' => array(
181
			'code' => 'order.base.product.mediaurl',
182
			'internalcode' => 'mordbapr."mediaurl"',
183
			'label' => 'Product media url',
184
			'type' => 'string',
185
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
186
			'public' => false,
187
		),
188
		'order.base.product.target' => array(
189
			'code' => 'order.base.product.target',
190
			'internalcode' => 'mordbapr."target"',
191
			'label' => 'Product url target',
192
			'type' => 'string',
193
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
194
			'public' => false,
195
		),
196
		'order.base.product.flags' => array(
197
			'code' => 'order.base.product.flags',
198
			'internalcode' => 'mordbapr."flags"',
199
			'label' => 'Product flags',
200
			'type' => 'integer',
201
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
202
			'public' => false,
203
		),
204
		'order.base.product.ctime' => array(
205
			'code' => 'order.base.product.ctime',
206
			'internalcode' => 'mordbapr."ctime"',
207
			'label' => 'Product create date/time',
208
			'type' => 'datetime',
209
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
210
			'public' => false,
211
		),
212
		'order.base.product.mtime' => array(
213
			'code' => 'order.base.product.mtime',
214
			'internalcode' => 'mordbapr."mtime"',
215
			'label' => 'Order base product modify date/time',
216
			'type' => 'datetime',
217
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
218
			'public' => false,
219
		),
220
		'order.base.product.editor' => array(
221
			'code' => 'order.base.product.editor',
222
			'internalcode' => 'mordbapr."editor"',
223
			'label' => 'Product editor',
224
			'type' => 'string',
225
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
226
			'public' => false,
227
		),
228
		'order.base.product.count()' => array(
229
			'code' => 'order.base.product.count()',
230
			'internalcode' => '( SELECT COUNT(*) FROM mshop_order_base_product AS mordbapr_count
231
				WHERE mordbapr."baseid" = mordbapr_count."baseid" AND mordbapr_count."prodid" = $1 )',
232
			'label' => 'Order base product count, parameter(<product IDs>)',
233
			'type' => 'integer',
234
			'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
235
			'public' => false,
236
		),
237
	);
238
239
240
	/**
241
	 * Initializes the object.
242
	 *
243
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object
244
	 */
245
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
246
	{
247
		parent::__construct( $context );
248
		$this->setResourceName( 'db-order' );
249
	}
250
251
252
	/**
253
	 * Counts the number items that are available for the values of the given key.
254
	 *
255
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria
256
	 * @param string $key Search key to aggregate items for
257
	 * @return integer[] List of the search keys as key and the number of counted items as value
258
	 * @todo 2018.01 Add optional parameters to interface
259
	 */
260
	public function aggregate( \Aimeos\MW\Criteria\Iface $search, $key, $value = null, $type = null )
261
	{
262
		/** mshop/order/manager/base/product/standard/aggregate/mysql
263
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
264
		 *
265
		 * @see mshop/order/manager/base/product/standard/aggregate/ansi
266
		 */
267
268
		/** mshop/order/manager/base/product/standard/aggregate/ansi
269
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
270
		 *
271
		 * Groups all records by the values in the key column and counts their
272
		 * occurence. The matched records can be limited by the given criteria
273
		 * from the order database. The records must be from one of the sites
274
		 * that are configured via the context item. If the current site is part
275
		 * of a tree of sites, the statement can count all records from the
276
		 * current site and the complete sub-tree of sites.
277
		 *
278
		 * As the records can normally be limited by criteria from sub-managers,
279
		 * their tables must be joined in the SQL context. This is done by
280
		 * using the "internaldeps" property from the definition of the ID
281
		 * column of the sub-managers. These internal dependencies specify
282
		 * the JOIN between the tables and the used columns for joining. The
283
		 * ":joins" placeholder is then replaced by the JOIN strings from
284
		 * the sub-managers.
285
		 *
286
		 * To limit the records matched, conditions can be added to the given
287
		 * criteria object. It can contain comparisons like column names that
288
		 * must match specific values which can be combined by AND, OR or NOT
289
		 * operators. The resulting string of SQL conditions replaces the
290
		 * ":cond" placeholder before the statement is sent to the database
291
		 * server.
292
		 *
293
		 * This statement doesn't return any records. Instead, it returns pairs
294
		 * of the different values found in the key column together with the
295
		 * number of records that have been found for that key values.
296
		 *
297
		 * The SQL statement should conform to the ANSI standard to be
298
		 * compatible with most relational database systems. This also
299
		 * includes using double quotes for table and column names.
300
		 *
301
		 * @param string SQL statement for aggregating order items
302
		 * @since 2014.09
303
		 * @category Developer
304
		 * @see mshop/order/manager/base/product/standard/insert/ansi
305
		 * @see mshop/order/manager/base/product/standard/update/ansi
306
		 * @see mshop/order/manager/base/product/standard/newid/ansi
307
		 * @see mshop/order/manager/base/product/standard/delete/ansi
308
		 * @see mshop/order/manager/base/product/standard/search/ansi
309
		 * @see mshop/order/manager/base/product/standard/count/ansi
310
		 */
311
312
		/** mshop/order/manager/base/product/standard/aggregateavg/mysql
313
		 * Computes the average of all values grouped by the key column and matched by the given criteria
314
		 *
315
		 * @param string SQL statement for aggregating the order product items and computing the average value
316
		 * @since 2017.10
317
		 * @category Developer
318
		 * @see mshop/order/manager/base/product/standard/aggregateavg/ansi
319
		 * @see mshop/order/manager/base/product/standard/aggregate/mysql
320
		 */
321
322
		/** mshop/order/manager/base/product/standard/aggregateavg/ansi
323
		 * Computes the average of all values grouped by the key column and matched by the given criteria
324
		 *
325
		 * @param string SQL statement for aggregating the order product items and computing the average value
326
		 * @since 2017.10
327
		 * @category Developer
328
		 * @see mshop/order/manager/base/product/standard/aggregate/ansi
329
		 */
330
331
		/** mshop/order/manager/base/product/standard/aggregatesum/mysql
332
		 * Computes the sum of all values grouped by the key column and matched by the given criteria
333
		 *
334
		 * @param string SQL statement for aggregating the order product items and computing the sum
335
		 * @since 2017.10
336
		 * @category Developer
337
		 * @see mshop/order/manager/base/product/standard/aggregatesum/ansi
338
		 * @see mshop/order/manager/base/product/standard/aggregate/mysql
339
		 */
340
341
		/** mshop/order/manager/base/product/standard/aggregatesum/ansi
342
		 * Computes the sum of all values grouped by the key column and matched by the given criteria
343
		 *
344
		 * @param string SQL statement for aggregating the order product items and computing the sum
345
		 * @since 2017.10
346
		 * @category Developer
347
		 * @see mshop/order/manager/base/product/standard/aggregate/ansi
348
		 */
349
350
		$cfgkey = 'mshop/order/manager/base/product/standard/aggregate' . $type;
351
		return $this->aggregateBase( $search, $key, $cfgkey, array( 'order.base.product' ), $value );
352
	}
353
354
355
	/**
356
	 * Removes old entries from the storage.
357
	 *
358
	 * @param string[] $siteids List of IDs for sites whose entries should be deleted
359
	 * @return \Aimeos\MShop\Order\Manager\Base\Product\Iface Manager object for chaining method calls
360
	 */
361
	public function cleanup( array $siteids )
362
	{
363
		$path = 'mshop/order/manager/base/product/submanagers';
364
		foreach( $this->getContext()->getConfig()->get( $path, array( 'attribute' ) ) as $domain ) {
365
			$this->getObject()->getSubManager( $domain )->cleanup( $siteids );
366
		}
367
368
		return $this->cleanupBase( $siteids, 'mshop/order/manager/base/product/standard/delete' );
369
	}
370
371
372
	/**
373
	 * Creates a new empty item instance
374
	 *
375
	 * @param array $values Values the item should be initialized with
376
	 * @return \Aimeos\MShop\Order\Item\Base\Product\Iface New order product item object
377
	 */
378
	public function createItem( array $values = [] )
379
	{
380
		$context = $this->getContext();
381
		$priceManager = \Aimeos\MShop::create( $context, 'price' );
382
383
		$values['order.base.product.siteid'] = $context->getLocale()->getSiteId();
384
385
		return $this->createItemBase( $priceManager->createItem(), $values );
386
	}
387
388
389
	/**
390
	 * Returns order base product for the given product ID.
391
	 *
392
	 * @param string $id Product ids to create product object for
393
	 * @param string[] $ref List of domains to fetch list items and referenced items for
394
	 * @param boolean $default Add default criteria
395
	 * @return \Aimeos\MShop\Order\Item\Base\Product\Iface Returns order base product item of the given id
396
	 * @throws \Aimeos\MShop\Exception If item couldn't be found
397
	 */
398
	public function getItem( $id, array $ref = [], $default = false )
399
	{
400
		return $this->getItemBase( 'order.base.product.id', $id, $ref, $default );
401
	}
402
403
404
	/**
405
	 * Removes multiple items specified by ids in the array.
406
	 *
407
	 * @param string[] $ids List of IDs
408
	 * @return \Aimeos\MShop\Order\Manager\Base\Product\Iface Manager object for chaining method calls
409
	 */
410
	public function deleteItems( array $ids )
411
	{
412
		/** mshop/order/manager/base/product/standard/delete/mysql
413
		 * Deletes the items matched by the given IDs from the database
414
		 *
415
		 * @see mshop/order/manager/base/product/standard/delete/ansi
416
		 */
417
418
		/** mshop/order/manager/base/product/standard/delete/ansi
419
		 * Deletes the items matched by the given IDs from the database
420
		 *
421
		 * Removes the records specified by the given IDs from the order database.
422
		 * The records must be from the site that is configured via the
423
		 * context item.
424
		 *
425
		 * The ":cond" placeholder is replaced by the name of the ID column and
426
		 * the given ID or list of IDs while the site ID is bound to the question
427
		 * mark.
428
		 *
429
		 * The SQL statement should conform to the ANSI standard to be
430
		 * compatible with most relational database systems. This also
431
		 * includes using double quotes for table and column names.
432
		 *
433
		 * @param string SQL statement for deleting items
434
		 * @since 2014.03
435
		 * @category Developer
436
		 * @see mshop/order/manager/base/product/standard/insert/ansi
437
		 * @see mshop/order/manager/base/product/standard/update/ansi
438
		 * @see mshop/order/manager/base/product/standard/newid/ansi
439
		 * @see mshop/order/manager/base/product/standard/search/ansi
440
		 * @see mshop/order/manager/base/product/standard/count/ansi
441
		 */
442
		$path = 'mshop/order/manager/base/product/standard/delete';
443
444
		return $this->deleteItemsBase( $ids, $path );
445
	}
446
447
448
	/**
449
	 * Returns the available manager types
450
	 *
451
	 * @param boolean $withsub Return also the resource type of sub-managers if true
452
	 * @return string[] Type of the manager and submanagers, subtypes are separated by slashes
453
	 */
454
	public function getResourceType( $withsub = true )
455
	{
456
		$path = 'mshop/order/manager/base/product/submanagers';
457
		return $this->getResourceTypeBase( 'order/base/product', $path, array( 'attribute' ), $withsub );
458
	}
459
460
461
	/**
462
	 * Returns the attributes that can be used for searching.
463
	 *
464
	 * @param boolean $withsub Return also attributes of sub-managers if true
465
	 * @return \Aimeos\MW\Criteria\Attribute\Iface[] List of search attribute items
466
	 */
467
	public function getSearchAttributes( $withsub = true )
468
	{
469
		/** mshop/order/manager/base/product/submanagers
470
		 * List of manager names that can be instantiated by the order base product manager
471
		 *
472
		 * Managers provide a generic interface to the underlying storage.
473
		 * Each manager has or can have sub-managers caring about particular
474
		 * aspects. Each of these sub-managers can be instantiated by its
475
		 * parent manager using the getSubManager() method.
476
		 *
477
		 * The search keys from sub-managers can be normally used in the
478
		 * manager as well. It allows you to search for items of the manager
479
		 * using the search keys of the sub-managers to further limit the
480
		 * retrieved list of items.
481
		 *
482
		 * @param array List of sub-manager names
483
		 * @since 2014.03
484
		 * @category Developer
485
		 */
486
		$path = 'mshop/order/manager/base/product/submanagers';
487
488
		return $this->getSearchAttributesBase( $this->searchConfig, $path, array( 'attribute' ), $withsub );
489
	}
490
491
492
	/**
493
	 * Returns a new sub manager specified by its name.
494
	 *
495
	 * @param string $manager Name of the sub manager type in lower case
496
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
497
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object
498
	 */
499
	public function getSubManager( $manager, $name = null )
500
	{
501
		/** mshop/order/manager/base/product/name
502
		 * Class name of the used order base product manager implementation
503
		 *
504
		 * Each default order base product manager can be replaced by an alternative imlementation.
505
		 * To use this implementation, you have to set the last part of the class
506
		 * name as configuration value so the manager factory knows which class it
507
		 * has to instantiate.
508
		 *
509
		 * For example, if the name of the default class is
510
		 *
511
		 *  \Aimeos\MShop\Order\Manager\Base\Product\Standard
512
		 *
513
		 * and you want to replace it with your own version named
514
		 *
515
		 *  \Aimeos\MShop\Order\Manager\Base\Product\Myproduct
516
		 *
517
		 * then you have to set the this configuration option:
518
		 *
519
		 *  mshop/order/manager/base/product/name = Myproduct
520
		 *
521
		 * The value is the last part of your own class name and it's case sensitive,
522
		 * so take care that the configuration value is exactly named like the last
523
		 * part of the class name.
524
		 *
525
		 * The allowed characters of the class name are A-Z, a-z and 0-9. No other
526
		 * characters are possible! You should always start the last part of the class
527
		 * name with an upper case character and continue only with lower case characters
528
		 * or numbers. Avoid chamel case names like "MyProduct"!
529
		 *
530
		 * @param string Last part of the class name
531
		 * @since 2014.03
532
		 * @category Developer
533
		 */
534
535
		/** mshop/order/manager/base/product/decorators/excludes
536
		 * Excludes decorators added by the "common" option from the order base product manager
537
		 *
538
		 * Decorators extend the functionality of a class by adding new aspects
539
		 * (e.g. log what is currently done), executing the methods of the underlying
540
		 * class only in certain conditions (e.g. only for logged in users) or
541
		 * modify what is returned to the caller.
542
		 *
543
		 * This option allows you to remove a decorator added via
544
		 * "mshop/common/manager/decorators/default" before they are wrapped
545
		 * around the order base product manager.
546
		 *
547
		 *  mshop/order/manager/base/product/decorators/excludes = array( 'decorator1' )
548
		 *
549
		 * This would remove the decorator named "decorator1" from the list of
550
		 * common decorators ("\Aimeos\MShop\Common\Manager\Decorator\*") added via
551
		 * "mshop/common/manager/decorators/default" for the order base product manager.
552
		 *
553
		 * @param array List of decorator names
554
		 * @since 2014.03
555
		 * @category Developer
556
		 * @see mshop/common/manager/decorators/default
557
		 * @see mshop/order/manager/base/product/decorators/global
558
		 * @see mshop/order/manager/base/product/decorators/local
559
		 */
560
561
		/** mshop/order/manager/base/product/decorators/global
562
		 * Adds a list of globally available decorators only to the order base product manager
563
		 *
564
		 * Decorators extend the functionality of a class by adding new aspects
565
		 * (e.g. log what is currently done), executing the methods of the underlying
566
		 * class only in certain conditions (e.g. only for logged in users) or
567
		 * modify what is returned to the caller.
568
		 *
569
		 * This option allows you to wrap global decorators
570
		 * ("\Aimeos\MShop\Common\Manager\Decorator\*") around the order base
571
		 * product manager.
572
		 *
573
		 *  mshop/order/manager/base/product/decorators/global = array( 'decorator1' )
574
		 *
575
		 * This would add the decorator named "decorator1" defined by
576
		 * "\Aimeos\MShop\Common\Manager\Decorator\Decorator1" only to the order
577
		 * base product manager.
578
		 *
579
		 * @param array List of decorator names
580
		 * @since 2014.03
581
		 * @category Developer
582
		 * @see mshop/common/manager/decorators/default
583
		 * @see mshop/order/manager/base/product/decorators/excludes
584
		 * @see mshop/order/manager/base/product/decorators/local
585
		 */
586
587
		/** mshop/order/manager/base/product/decorators/local
588
		 * Adds a list of local decorators only to the order base product manager
589
		 *
590
		 * Decorators extend the functionality of a class by adding new aspects
591
		 * (e.g. log what is currently done), executing the methods of the underlying
592
		 * class only in certain conditions (e.g. only for logged in users) or
593
		 * modify what is returned to the caller.
594
		 *
595
		 * This option allows you to wrap local decorators
596
		 * ("\Aimeos\MShop\Order\Manager\Base\Product\Decorator\*") around the
597
		 * order base product manager.
598
		 *
599
		 *  mshop/order/manager/base/product/decorators/local = array( 'decorator2' )
600
		 *
601
		 * This would add the decorator named "decorator2" defined by
602
		 * "\Aimeos\MShop\Order\Manager\Base\Product\Decorator\Decorator2" only
603
		 * to the order base product manager.
604
		 *
605
		 * @param array List of decorator names
606
		 * @since 2014.03
607
		 * @category Developer
608
		 * @see mshop/common/manager/decorators/default
609
		 * @see mshop/order/manager/base/product/decorators/excludes
610
		 * @see mshop/order/manager/base/product/decorators/global
611
		 */
612
613
		return $this->getSubManagerBase( 'order', 'base/product/' . $manager, $name );
614
	}
615
616
617
	/**
618
	 * Adds or updates a order base product item to the storage.
619
	 *
620
	 * @param \Aimeos\MShop\Order\Item\Base\Product\Iface $item New or existing product item that should be saved to the storage
621
	 * @param boolean $fetch True if the new ID should be returned in the item
622
	 * @return \Aimeos\MShop\Order\Item\Base\Product\Iface $item Updated item including the generated ID
623
	 */
624
	public function saveItem( \Aimeos\MShop\Common\Item\Iface $item, $fetch = true )
625
	{
626
		self::checkClass( \Aimeos\MShop\Order\Item\Base\Product\Iface::class, $item );
627
628
		if( !$item->isModified() ) {
629
			return $item;
630
		}
631
632
		$context = $this->getContext();
633
634
		$dbm = $context->getDatabaseManager();
635
		$dbname = $this->getResourceName();
636
		$conn = $dbm->acquire( $dbname );
637
638
		try
639
		{
640
			$id = $item->getId();
641
			$price = $item->getPrice();
642
			$date = date( 'Y-m-d H:i:s' );
643
644
			if( $id === null )
645
			{
646
				/** mshop/order/manager/base/product/standard/insert/mysql
647
				 * Inserts a new order record into the database table
648
				 *
649
				 * @see mshop/order/manager/base/product/standard/insert/ansi
650
				 */
651
652
				/** mshop/order/manager/base/product/standard/insert/ansi
653
				 * Inserts a new order record into the database table
654
				 *
655
				 * Items with no ID yet (i.e. the ID is NULL) will be created in
656
				 * the database and the newly created ID retrieved afterwards
657
				 * using the "newid" SQL statement.
658
				 *
659
				 * The SQL statement must be a string suitable for being used as
660
				 * prepared statement. It must include question marks for binding
661
				 * the values from the order item to the statement before they are
662
				 * sent to the database server. The number of question marks must
663
				 * be the same as the number of columns listed in the INSERT
664
				 * statement. The order of the columns must correspond to the
665
				 * order in the saveItems() method, so the correct values are
666
				 * bound to the columns.
667
				 *
668
				 * The SQL statement should conform to the ANSI standard to be
669
				 * compatible with most relational database systems. This also
670
				 * includes using double quotes for table and column names.
671
				 *
672
				 * @param string SQL statement for inserting records
673
				 * @since 2014.03
674
				 * @category Developer
675
				 * @see mshop/order/manager/base/product/standard/update/ansi
676
				 * @see mshop/order/manager/base/product/standard/newid/ansi
677
				 * @see mshop/order/manager/base/product/standard/delete/ansi
678
				 * @see mshop/order/manager/base/product/standard/search/ansi
679
				 * @see mshop/order/manager/base/product/standard/count/ansi
680
				 */
681
				$path = 'mshop/order/manager/base/product/standard/insert';
682
			}
683
			else
684
			{
685
				/** mshop/order/manager/base/product/standard/update/mysql
686
				 * Updates an existing order record in the database
687
				 *
688
				 * @see mshop/order/manager/base/product/standard/update/ansi
689
				 */
690
691
				/** mshop/order/manager/base/product/standard/update/ansi
692
				 * Updates an existing order record in the database
693
				 *
694
				 * Items which already have an ID (i.e. the ID is not NULL) will
695
				 * be updated in the database.
696
				 *
697
				 * The SQL statement must be a string suitable for being used as
698
				 * prepared statement. It must include question marks for binding
699
				 * the values from the order item to the statement before they are
700
				 * sent to the database server. The order of the columns must
701
				 * correspond to the order in the saveItems() method, so the
702
				 * correct values are bound to the columns.
703
				 *
704
				 * The SQL statement should conform to the ANSI standard to be
705
				 * compatible with most relational database systems. This also
706
				 * includes using double quotes for table and column names.
707
				 *
708
				 * @param string SQL statement for updating records
709
				 * @since 2014.03
710
				 * @category Developer
711
				 * @see mshop/order/manager/base/product/standard/insert/ansi
712
				 * @see mshop/order/manager/base/product/standard/newid/ansi
713
				 * @see mshop/order/manager/base/product/standard/delete/ansi
714
				 * @see mshop/order/manager/base/product/standard/search/ansi
715
				 * @see mshop/order/manager/base/product/standard/count/ansi
716
				 */
717
				$path = 'mshop/order/manager/base/product/standard/update';
718
			}
719
720
			$stmt = $this->getCachedStatement( $conn, $path );
721
722
			$stmt->bind( 1, $item->getBaseId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
723
			$stmt->bind( 2, $item->getOrderProductId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
724
			$stmt->bind( 3, $item->getOrderAddressId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
725
			$stmt->bind( 4, $item->getType() );
726
			$stmt->bind( 5, $item->getProductId() );
727
			$stmt->bind( 6, $item->getProductCode() );
728
			$stmt->bind( 7, $item->getSupplierCode() );
729
			$stmt->bind( 8, $item->getStockType() );
730
			$stmt->bind( 9, $item->getName() );
731
			$stmt->bind( 10, $item->getMediaUrl() );
732
			$stmt->bind( 11, $item->getQuantity() );
733
			$stmt->bind( 12, $price->getCurrencyId() );
734
			$stmt->bind( 13, $price->getValue() );
735
			$stmt->bind( 14, $price->getCosts() );
736
			$stmt->bind( 15, $price->getRebate() );
737
			$stmt->bind( 16, $price->getTaxValue() );
738
			$stmt->bind( 17, $price->getTaxRate() );
739
			$stmt->bind( 18, $price->getTaxFlag(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
740
			$stmt->bind( 19, $item->getFlags(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
741
			$stmt->bind( 20, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
742
			$stmt->bind( 21, $item->getPosition(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
743
			$stmt->bind( 22, $date ); // mtime
744
			$stmt->bind( 23, $context->getEditor() );
745
			$stmt->bind( 24, $item->getTarget() );
746
			$stmt->bind( 25, $item->getSiteId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
747
748
			if( $id !== null ) {
749
				$stmt->bind( 26, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
750
				$item->setId( $id );
751
			} else {
752
				$stmt->bind( 26, $date ); // ctime
753
			}
754
755
			$stmt->execute()->finish();
756
757
			if( $id === null && $fetch === true )
758
			{
759
				/** mshop/order/manager/base/product/standard/newid/mysql
760
				 * Retrieves the ID generated by the database when inserting a new record
761
				 *
762
				 * @see mshop/order/manager/base/product/standard/newid/ansi
763
				 */
764
765
				/** mshop/order/manager/base/product/standard/newid/ansi
766
				 * Retrieves the ID generated by the database when inserting a new record
767
				 *
768
				 * As soon as a new record is inserted into the database table,
769
				 * the database server generates a new and unique identifier for
770
				 * that record. This ID can be used for retrieving, updating and
771
				 * deleting that specific record from the table again.
772
				 *
773
				 * For MySQL:
774
				 *  SELECT LAST_INSERT_ID()
775
				 * For PostgreSQL:
776
				 *  SELECT currval('seq_mord_id')
777
				 * For SQL Server:
778
				 *  SELECT SCOPE_IDENTITY()
779
				 * For Oracle:
780
				 *  SELECT "seq_mord_id".CURRVAL FROM DUAL
781
				 *
782
				 * There's no way to retrive the new ID by a SQL statements that
783
				 * fits for most database servers as they implement their own
784
				 * specific way.
785
				 *
786
				 * @param string SQL statement for retrieving the last inserted record ID
787
				 * @since 2014.03
788
				 * @category Developer
789
				 * @see mshop/order/manager/base/product/standard/insert/ansi
790
				 * @see mshop/order/manager/base/product/standard/update/ansi
791
				 * @see mshop/order/manager/base/product/standard/delete/ansi
792
				 * @see mshop/order/manager/base/product/standard/search/ansi
793
				 * @see mshop/order/manager/base/product/standard/count/ansi
794
				 */
795
				$path = 'mshop/order/manager/base/product/standard/newid';
796
				$item->setId( $this->newId( $conn, $path ) );
797
			}
798
799
			$dbm->release( $conn, $dbname );
800
		}
801
		catch( \Exception $e )
802
		{
803
			$dbm->release( $conn, $dbname );
804
			throw $e;
805
		}
806
807
		return $item;
808
	}
809
810
811
	/**
812
	 * Searches for order base products item based on the given criteria.
813
	 *
814
	 * @param \Aimeos\MW\Criteria\Iface $search Search criteria object
815
	 * @param string[] $ref List of domains to fetch list items and referenced items for
816
	 * @param integer|null &$total Number of items that are available in total
817
	 * @return array List of products implementing \Aimeos\MShop\Order\Item\Base\Product\Iface's
818
	 */
819
	public function searchItems( \Aimeos\MW\Criteria\Iface $search, array $ref = [], &$total = null )
820
	{
821
		$items = [];
822
		$context = $this->getContext();
823
		$priceManager = \Aimeos\MShop::create( $context, 'price' );
824
825
		$dbm = $context->getDatabaseManager();
826
		$dbname = $this->getResourceName();
827
		$conn = $dbm->acquire( $dbname );
828
829
		try
830
		{
831
			$required = array( 'order.base.product' );
832
833
			$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
834
			$level = $context->getConfig()->get( 'mshop/order/manager/sitemode', $level );
835
836
			/** mshop/order/manager/base/product/standard/search/mysql
837
			 * Retrieves the records matched by the given criteria in the database
838
			 *
839
			 * @see mshop/order/manager/base/product/standard/search/ansi
840
			 */
841
842
			/** mshop/order/manager/base/product/standard/search/ansi
843
			 * Retrieves the records matched by the given criteria in the database
844
			 *
845
			 * Fetches the records matched by the given criteria from the order
846
			 * database. The records must be from one of the sites that are
847
			 * configured via the context item. If the current site is part of
848
			 * a tree of sites, the SELECT statement can retrieve all records
849
			 * from the current site and the complete sub-tree of sites.
850
			 *
851
			 * As the records can normally be limited by criteria from sub-managers,
852
			 * their tables must be joined in the SQL context. This is done by
853
			 * using the "internaldeps" property from the definition of the ID
854
			 * column of the sub-managers. These internal dependencies specify
855
			 * the JOIN between the tables and the used columns for joining. The
856
			 * ":joins" placeholder is then replaced by the JOIN strings from
857
			 * the sub-managers.
858
			 *
859
			 * To limit the records matched, conditions can be added to the given
860
			 * criteria object. It can contain comparisons like column names that
861
			 * must match specific values which can be combined by AND, OR or NOT
862
			 * operators. The resulting string of SQL conditions replaces the
863
			 * ":cond" placeholder before the statement is sent to the database
864
			 * server.
865
			 *
866
			 * If the records that are retrieved should be ordered by one or more
867
			 * columns, the generated string of column / sort direction pairs
868
			 * replaces the ":order" placeholder. In case no ordering is required,
869
			 * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
870
			 * markers is removed to speed up retrieving the records. Columns of
871
			 * sub-managers can also be used for ordering the result set but then
872
			 * no index can be used.
873
			 *
874
			 * The number of returned records can be limited and can start at any
875
			 * number between the begining and the end of the result set. For that
876
			 * the ":size" and ":start" placeholders are replaced by the
877
			 * corresponding values from the criteria object. The default values
878
			 * are 0 for the start and 100 for the size value.
879
			 *
880
			 * The SQL statement should conform to the ANSI standard to be
881
			 * compatible with most relational database systems. This also
882
			 * includes using double quotes for table and column names.
883
			 *
884
			 * @param string SQL statement for searching items
885
			 * @since 2014.03
886
			 * @category Developer
887
			 * @see mshop/order/manager/base/product/standard/insert/ansi
888
			 * @see mshop/order/manager/base/product/standard/update/ansi
889
			 * @see mshop/order/manager/base/product/standard/newid/ansi
890
			 * @see mshop/order/manager/base/product/standard/delete/ansi
891
			 * @see mshop/order/manager/base/product/standard/count/ansi
892
			 */
893
			$cfgPathSearch = 'mshop/order/manager/base/product/standard/search';
894
895
			/** mshop/order/manager/base/product/standard/count/mysql
896
			 * Counts the number of records matched by the given criteria in the database
897
			 *
898
			 * @see mshop/order/manager/base/product/standard/count/ansi
899
			 */
900
901
			/** mshop/order/manager/base/product/standard/count/ansi
902
			 * Counts the number of records matched by the given criteria in the database
903
			 *
904
			 * Counts all records matched by the given criteria from the order
905
			 * database. The records must be from one of the sites that are
906
			 * configured via the context item. If the current site is part of
907
			 * a tree of sites, the statement can count all records from the
908
			 * current site and the complete sub-tree of sites.
909
			 *
910
			 * As the records can normally be limited by criteria from sub-managers,
911
			 * their tables must be joined in the SQL context. This is done by
912
			 * using the "internaldeps" property from the definition of the ID
913
			 * column of the sub-managers. These internal dependencies specify
914
			 * the JOIN between the tables and the used columns for joining. The
915
			 * ":joins" placeholder is then replaced by the JOIN strings from
916
			 * the sub-managers.
917
			 *
918
			 * To limit the records matched, conditions can be added to the given
919
			 * criteria object. It can contain comparisons like column names that
920
			 * must match specific values which can be combined by AND, OR or NOT
921
			 * operators. The resulting string of SQL conditions replaces the
922
			 * ":cond" placeholder before the statement is sent to the database
923
			 * server.
924
			 *
925
			 * Both, the strings for ":joins" and for ":cond" are the same as for
926
			 * the "search" SQL statement.
927
			 *
928
			 * Contrary to the "search" statement, it doesn't return any records
929
			 * but instead the number of records that have been found. As counting
930
			 * thousands of records can be a long running task, the maximum number
931
			 * of counted records is limited for performance reasons.
932
			 *
933
			 * The SQL statement should conform to the ANSI standard to be
934
			 * compatible with most relational database systems. This also
935
			 * includes using double quotes for table and column names.
936
			 *
937
			 * @param string SQL statement for counting items
938
			 * @since 2014.03
939
			 * @category Developer
940
			 * @see mshop/order/manager/base/product/standard/insert/ansi
941
			 * @see mshop/order/manager/base/product/standard/update/ansi
942
			 * @see mshop/order/manager/base/product/standard/newid/ansi
943
			 * @see mshop/order/manager/base/product/standard/delete/ansi
944
			 * @see mshop/order/manager/base/product/standard/search/ansi
945
			 */
946
			$cfgPathCount = 'mshop/order/manager/base/product/standard/count';
947
948
			$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount,
949
				$required, $total, $level );
950
951
			try
952
			{
953
				while( ( $row = $results->fetch() ) !== false )
954
				{
955
					$price = $priceManager->createItem();
956
					$price->setValue( $row['order.base.product.price'] );
0 ignored issues
show
The method setValue() does not exist on Aimeos\MShop\Attribute\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

956
					$price->/** @scrutinizer ignore-call */ 
957
             setValue( $row['order.base.product.price'] );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
957
					$price->setRebate( $row['order.base.product.rebate'] );
0 ignored issues
show
The method setRebate() does not exist on Aimeos\MShop\Attribute\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

957
					$price->/** @scrutinizer ignore-call */ 
958
             setRebate( $row['order.base.product.rebate'] );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
958
					$price->setCosts( $row['order.base.product.costs'] );
0 ignored issues
show
The method setCosts() does not exist on Aimeos\MShop\Attribute\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

958
					$price->/** @scrutinizer ignore-call */ 
959
             setCosts( $row['order.base.product.costs'] );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
959
					$price->setTaxRate( $row['order.base.product.taxrate'] );
0 ignored issues
show
The method setTaxRate() does not exist on Aimeos\MShop\Attribute\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

959
					$price->/** @scrutinizer ignore-call */ 
960
             setTaxRate( $row['order.base.product.taxrate'] );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
960
					$price->setTaxFlag( $row['order.base.product.taxflag'] );
961
					$price->setTaxValue( $row['order.base.product.taxvalue'] );
962
					$price->setCurrencyId( $row['order.base.product.currencyid'] );
963
964
					$items[$row['order.base.product.id']] = array( 'price' => $price, 'item' => $row );
965
				}
966
			}
967
			catch( \Exception $e )
968
			{
969
				$results->finish();
970
				throw $e;
971
			}
972
973
			$dbm->release( $conn, $dbname );
974
		}
975
		catch( \Exception $e )
976
		{
977
			$dbm->release( $conn, $dbname );
978
			throw $e;
979
		}
980
981
		$result = [];
982
		$attributes = $this->getAttributeItems( array_keys( $items ) );
983
984
		foreach( $items as $id => $row )
985
		{
986
			$attrList = ( isset( $attributes[$id] ) ? $attributes[$id] : [] );
987
			$result[$id] = $this->createItemBase( $row['price'], $row['item'], $attrList );
988
		}
989
990
		return $result;
991
	}
992
993
994
	/**
995
	 * Creates new order base product item object initialized with given parameters.
996
	 *
997
	 * @param \Aimeos\MShop\Price\Item\Iface $price Price item object with product price
998
	 * @param array $values Associative list of order product properties
999
	 * @param \Aimeos\MShop\Order\Item\Base\Product\Attribute\Iface[] $attributes List of order product attributes
1000
	 * @return \Aimeos\MShop\Order\Item\Base\Product\Iface Order product item
1001
	 */
1002
	protected function createItemBase( \Aimeos\MShop\Price\Item\Iface $price, array $values = [], array $attributes = [] )
1003
	{
1004
		return new \Aimeos\MShop\Order\Item\Base\Product\Standard( $price, $values, $attributes );
1005
	}
1006
1007
1008
	/**
1009
	 * Searches for attribute items connected with order product item.
1010
	 *
1011
	 * @param string[] $ids List of order product item IDs
1012
	 * @return array Associative list of order product IDs as keys and order product attribute items
1013
	 *  implementing \Aimeos\MShop\Order\Item\Base\Product\Attribute\Iface as values
1014
	 */
1015
	protected function getAttributeItems( $ids )
1016
	{
1017
		$manager = $this->getSubmanager( 'attribute' );
1018
		$search = $manager->createSearch()->setSlice( 0, 0x7fffffff );
1019
		$search->setConditions( $search->compare( '==', 'order.base.product.attribute.parentid', $ids ) );
1020
		$search->setSortations( array( $search->sort( '+', 'order.base.product.attribute.code' ) ) );
1021
1022
		$result = [];
1023
		foreach( $manager->searchItems( $search ) as $item ) {
1024
			$result[$item->getParentId()][$item->getId()] = $item;
1025
		}
1026
1027
		return $result;
1028
	}
1029
}
1030