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

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

871
					$price->/** @scrutinizer ignore-call */ 
872
             setValue( $row['order.base.service.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...
872
					$price->setRebate( $row['order.base.service.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

872
					$price->/** @scrutinizer ignore-call */ 
873
             setRebate( $row['order.base.service.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...
873
					$price->setCosts( $row['order.base.service.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

873
					$price->/** @scrutinizer ignore-call */ 
874
             setCosts( $row['order.base.service.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...
874
					$price->setTaxRate( $row['order.base.service.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

874
					$price->/** @scrutinizer ignore-call */ 
875
             setTaxRate( $row['order.base.service.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...
875
					$price->setTaxFlag( $row['order.base.service.taxflag'] );
876
					$price->setTaxValue( $row['order.base.service.taxvalue'] );
877
					$price->setCurrencyId( $row['order.base.service.currencyid'] );
878
879
					$items[$row['order.base.service.id']] = array( 'price' => $price, 'item' => $row );
880
				}
881
			}
882
			catch( \Exception $e )
883
			{
884
				$results->finish();
885
				throw $e;
886
			}
887
888
			$dbm->release( $conn, $dbname );
889
		}
890
		catch( \Exception $e )
891
		{
892
			$dbm->release( $conn, $dbname );
893
			throw $e;
894
		}
895
896
		$result = [];
897
		$attributes = $this->getAttributeItems( array_keys( $items ) );
898
899
		foreach( $items as $id => $row )
900
		{
901
			$attrList = [];
902
			if( isset( $attributes[$id] ) ) {
903
				$attrList = $attributes[$id];
904
			}
905
			$result[$id] = $this->createItemBase( $row['price'], $row['item'], $attrList );
906
		}
907
908
		return $result;
909
	}
910
911
912
	/**
913
	 * Creates a new order service item object initialized with given parameters.
914
	 *
915
	 * @param \Aimeos\MShop\Price\Item\Iface $price Price object
916
	 * @param array $values Associative list of values from the database
917
	 * @param \Aimeos\MShop\Order\Item\Base\Service\Attribute\Iface[] $attributes List of order service attribute items
918
	 * @return \Aimeos\MShop\Order\Item\Base\Service\Iface Order service item
919
	 */
920
	protected function createItemBase( \Aimeos\MShop\Price\Item\Iface $price,
921
		array $values = [], array $attributes = [] )
922
	{
923
		return new \Aimeos\MShop\Order\Item\Base\Service\Standard( $price, $values, $attributes );
924
	}
925
926
927
	/**
928
	 * Searches for attribute items connected with order service item.
929
	 *
930
	 * @param string[] $ids List of order service item IDs
931
	 * @return array Associative list of order service IDs as keys and order service attribute items
932
	 *  implementing \Aimeos\MShop\Order\Item\Base\Service\Attribute\Iface as values
933
	 */
934
	protected function getAttributeItems( $ids )
935
	{
936
		$manager = $this->getObject()->getSubManager( 'attribute' );
937
		$search = $manager->createSearch()->setSlice( 0, 0x7fffffff );
938
		$search->setConditions( $search->compare( '==', 'order.base.service.attribute.parentid', $ids ) );
939
		$search->setSortations( array( $search->sort( '+', 'order.base.service.attribute.code' ) ) );
940
941
		$result = [];
942
		foreach( $manager->searchItems( $search ) as $item ) {
943
			$result[$item->getParentId()][$item->getId()] = $item;
944
		}
945
946
		return $result;
947
	}
948
}
949