• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aimeos / aimeos-core / e67a5171-b485-4a8f-9441-93d8ff5aa19b

15 Aug 2024 11:37AM UTC coverage: 91.967% (+0.03%) from 91.933%
e67a5171-b485-4a8f-9441-93d8ff5aa19b

push

circleci

aimeos
Simplified order service manager

111 of 117 new or added lines in 4 files covered. (94.87%)

5 existing lines in 3 files now uncovered.

10246 of 11141 relevant lines covered (91.97%)

61.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.83
/src/MShop/Order/Manager/Service/Standard.php
1
<?php
2

3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2024
6
 * @package MShop
7
 * @subpackage Order
8
 */
9

10

11
namespace Aimeos\MShop\Order\Manager\Service;
12

13

14
/**
15
 * Default order service manager implementation.
16
 *
17
 * @package MShop
18
 * @subpackage Order
19
 */
20
class Standard
21
        extends \Aimeos\MShop\Common\Manager\Base
22
        implements \Aimeos\MShop\Order\Manager\Service\Iface, \Aimeos\MShop\Common\Manager\Factory\Iface
23
{
24
        private array $searchConfig = [
25
                'order.service.parentid' => [
26
                        'label' => 'Order ID',
27
                        'internalcode' => 'parentid',
28
                        'type' => 'int',
29
                        'public' => false,
30
                ],
31
                'order.service.serviceid' => [
32
                        'label' => 'Service original service ID',
33
                        'internalcode' => 'servid',
34
                        'public' => false,
35
                ],
36
                'order.service.name' => [
37
                        'label' => 'Service name',
38
                        'internalcode' => 'name',
39
                ],
40
                'order.service.code' => [
41
                        'label' => 'Service code',
42
                        'internalcode' => 'code',
43
                ],
44
                'order.service.type' => [
45
                        'label' => 'Service type',
46
                        'internalcode' => 'type',
47
                ],
48
                'order.service.mediaurl' => [
49
                        'label' => 'Service media url',
50
                        'internalcode' => 'mediaurl',
51
                        'public' => false,
52
                ],
53
                'order.service.position' => [
54
                        'label' => 'Service position',
55
                        'internalcode' => 'pos',
56
                        'type' => 'int',
57
                        'public' => false,
58
                ],
59
        ];
60

61

62
        /**
63
         * Counts the number items that are available for the values of the given key.
64
         *
65
         * @param \Aimeos\Base\Criteria\Iface $search Search criteria
66
         * @param array|string $key Search key or list of keys to aggregate items for
67
         * @param string|null $value Search key for aggregating the value column
68
         * @param string|null $type Type of the aggregation, empty string for count or "sum" or "avg" (average)
69
         * @return \Aimeos\Map List of the search keys as key and the number of counted items as value
70
         */
71
        public function aggregate( \Aimeos\Base\Criteria\Iface $search, $key, string $value = null, string $type = null ) : \Aimeos\Map
72
        {
73
                /** mshop/order/manager/service/aggregate/mysql
74
                 * Counts the number of records grouped by the values in the key column and matched by the given criteria
75
                 *
76
                 * @see mshop/order/manager/service/aggregate/ansi
77
                 */
78

79
                /** mshop/order/manager/service/aggregate/ansi
80
                 * Counts the number of records grouped by the values in the key column and matched by the given criteria
81
                 *
82
                 * Groups all records by the values in the key column and counts their
83
                 * occurence. The matched records can be limited by the given criteria
84
                 * from the order database. The records must be from one of the sites
85
                 * that are configured via the context item. If the current site is part
86
                 * of a tree of sites, the statement can count all records from the
87
                 * current site and the complete sub-tree of sites.
88
                 *
89
                 * As the records can normally be limited by criteria from sub-managers,
90
                 * their tables must be joined in the SQL context. This is done by
91
                 * using the "internaldeps" property from the definition of the ID
92
                 * column of the sub-managers. These internal dependencies specify
93
                 * the JOIN between the tables and the used columns for joining. The
94
                 * ":joins" placeholder is then replaced by the JOIN strings from
95
                 * the sub-managers.
96
                 *
97
                 * To limit the records matched, conditions can be added to the given
98
                 * criteria object. It can contain comparisons like column names that
99
                 * must match specific values which can be combined by AND, OR or NOT
100
                 * operators. The resulting string of SQL conditions replaces the
101
                 * ":cond" placeholder before the statement is sent to the database
102
                 * server.
103
                 *
104
                 * This statement doesn't return any records. Instead, it returns pairs
105
                 * of the different values found in the key column together with the
106
                 * number of records that have been found for that key values.
107
                 *
108
                 * The SQL statement should conform to the ANSI standard to be
109
                 * compatible with most relational database systems. This also
110
                 * includes using double quotes for table and column names.
111
                 *
112
                 * @param string SQL statement for aggregating order items
113
                 * @since 2014.09
114
                 * @see mshop/order/manager/service/insert/ansi
115
                 * @see mshop/order/manager/service/update/ansi
116
                 * @see mshop/order/manager/service/newid/ansi
117
                 * @see mshop/order/manager/service/delete/ansi
118
                 * @see mshop/order/manager/service/search/ansi
119
                 * @see mshop/order/manager/service/count/ansi
120
                 */
121

122
                /** mshop/order/manager/service/aggregateavg/mysql
123
                 * Computes the average of all values grouped by the key column and matched by the given criteria
124
                 *
125
                 * @param string SQL statement for aggregating the order service items and computing the average value
126
                 * @since 2017.10
127
                 * @see mshop/order/manager/service/aggregateavg/ansi
128
                 * @see mshop/order/manager/service/aggregate/mysql
129
                 */
130

131
                /** mshop/order/manager/service/aggregateavg/ansi
132
                 * Computes the average of all values grouped by the key column and matched by the given criteria
133
                 *
134
                 * @param string SQL statement for aggregating the order service items and computing the average value
135
                 * @since 2017.10
136
                 * @see mshop/order/manager/service/aggregate/ansi
137
                 */
138

139
                /** mshop/order/manager/service/aggregatesum/mysql
140
                 * Computes the sum of all values grouped by the key column and matched by the given criteria
141
                 *
142
                 * @param string SQL statement for aggregating the order service items and computing the sum
143
                 * @since 2017.10
144
                 * @see mshop/order/manager/service/aggregatesum/ansi
145
                 * @see mshop/order/manager/service/aggregate/mysql
146
                 */
147

148
                /** mshop/order/manager/service/aggregatesum/ansi
149
                 * Computes the sum of all values grouped by the key column and matched by the given criteria
150
                 *
151
                 * @param string SQL statement for aggregating the order service items and computing the sum
152
                 * @since 2017.10
153
                 * @see mshop/order/manager/service/aggregate/ansi
154
                 */
155

156
                $cfgkey = 'mshop/order/manager/service/aggregate';
3✔
157
                return $this->aggregateBase( $search, $key, $cfgkey, ['order.service'], $value, $type );
3✔
158
        }
159

160

161
        /**
162
         * Creates a new empty item instance
163
         *
164
         * @param array $values Values the item should be initialized with
165
         * @return \Aimeos\MShop\Order\Item\Service\Iface New order service item object
166
         */
167
        public function create( array $values = [] ) : \Aimeos\MShop\Common\Item\Iface
168
        {
169
                $context = $this->context();
117✔
170

171
                $values['.price'] = $values['.price'] ?? \Aimeos\MShop::create( $context, 'price' )->create();
117✔
172
                $values['order.service.siteid'] = $values['order.service.siteid'] ?? $context->locale()->getSiteId();
117✔
173

174
                return new \Aimeos\MShop\Order\Item\Service\Standard( 'order.service.', $values );
117✔
175
        }
176

177

178
        /**
179
         * Creates a new order service attribute item instance
180
         *
181
         * @param array $values Values the item should be initialized with
182
         * @return \Aimeos\MShop\Order\Item\Service\Attribute\Iface New order service attribute item object
183
         */
184
        public function createAttributeItem( array $values = [] ) : \Aimeos\MShop\Common\Item\Iface
185
        {
186
                return $this->object()->getSubManager( 'attribute' )->create( $values );
23✔
187
        }
188

189

190
        /**
191
         * Creates a new order service transaction item instance
192
         *
193
         * @param array $values Values the item should be initialized with
194
         * @return \Aimeos\MShop\Order\Item\Service\Transaction\Iface New order service transaction item object
195
         */
196
        public function createTransaction( array $values = [] ) : \Aimeos\MShop\Common\Item\Iface
197
        {
198
                return $this->object()->getSubManager( 'transaction' )->create( $values );
1✔
199
        }
200

201

202
        /**
203
         * Creates a filter object.
204
         *
205
         * @param bool|null $default Add default criteria or NULL for relaxed default criteria
206
         * @param bool $site TRUE for adding site criteria to limit items by the site of related items
207
         * @return \Aimeos\Base\Criteria\Iface Returns the filter object
208
         */
209
        public function filter( ?bool $default = false, bool $site = false ) : \Aimeos\Base\Criteria\Iface
210
        {
211
                return parent::filter( $default )->order( 'order.service.id' );
46✔
212
        }
213

214

215
        /**
216
         * Returns the additional column/search definitions
217
         *
218
         * @return array Associative list of column names as keys and items implementing \Aimeos\Base\Criteria\Attribute\Iface
219
         */
220
        public function getSaveAttributes() : array
221
        {
222
                return $this->createAttributes( $this->searchConfig );
94✔
223
        }
224

225

226
        /**
227
         * Returns the attributes that can be used for searching.
228
         *
229
         * @param bool $withsub Return also attributes of sub-managers if true
230
         * @return \Aimeos\Base\Criteria\Attribute\Iface[] List of search attribute items
231
         */
232
        public function getSearchAttributes( bool $withsub = true ) : array
233
        {
234
                return array_replace( parent::getSearchAttributes( $withsub ), $this->createAttributes( [
94✔
235
                        'order.service.id' => [
94✔
236
                                'label' => 'Service ID',
94✔
237
                                'internaldeps' => [ 'LEFT JOIN "mshop_order_service" AS mordse ON ( mord."id" = mordse."parentid" )' ],
94✔
238
                                'internalcode' => 'id',
94✔
239
                                'type' => 'int',
94✔
240
                                'public' => false,
94✔
241
                        ],
94✔
242
                        'order.service.currencyid' => [
94✔
243
                                'label' => 'Service currencyid code',
94✔
244
                                'internalcode' => 'currencyid',
94✔
245
                        ],
94✔
246
                        'order.service.price' => [
94✔
247
                                'label' => 'Service price',
94✔
248
                                'internalcode' => 'price',
94✔
249
                                'type' => 'decimal',
94✔
250
                        ],
94✔
251
                        'order.service.costs' => [
94✔
252
                                'label' => 'Service shipping',
94✔
253
                                'internalcode' => 'costs',
94✔
254
                                'type' => 'decimal',
94✔
255
                        ],
94✔
256
                        'order.service.rebate' => [
94✔
257
                                'label' => 'Service rebate',
94✔
258
                                'internalcode' => 'rebate',
94✔
259
                                'type' => 'decimal',
94✔
260
                        ],
94✔
261
                        'order.service.taxrates' => [
94✔
262
                                'label' => 'Service taxrates',
94✔
263
                                'internalcode' => 'taxrate',
94✔
264
                                'type' => 'json',
94✔
265
                        ],
94✔
266
                        'order.service.taxvalue' => [
94✔
267
                                'label' => 'Service tax value',
94✔
268
                                'internalcode' => 'tax',
94✔
269
                                'type' => 'decimal',
94✔
270
                        ],
94✔
271
                        'order.service.taxflag' => [
94✔
272
                                'label' => 'Service tax flag (0=net, 1=gross)',
94✔
273
                                'internalcode' => 'taxflag',
94✔
274
                                'type' => 'int',
94✔
275
                        ],
94✔
276
                ] ) );
94✔
277
        }
278

279

280
        /**
281
         * Binds additional values to the statement before execution.
282
         *
283
         * @param \Aimeos\MShop\Common\Item\Iface $item Item object
284
         * @param \Aimeos\Base\DB\Statement\Iface $stmt Database statement object
285
         * @param int $idx Current bind index
286
         * @return \Aimeos\Base\DB\Statement\Iface Database statement object with bound values
287
         */
288
        protected function bind( \Aimeos\MShop\Common\Item\Iface $item, \Aimeos\Base\DB\Statement\Iface $stmt, int &$idx ) : \Aimeos\Base\DB\Statement\Iface
289
        {
290
                $price = $item->getPrice();
6✔
291

292
                $stmt->bind( $idx++, $price->getCurrencyId() );
6✔
293
                $stmt->bind( $idx++, $price->getValue() );
6✔
294
                $stmt->bind( $idx++, $price->getCosts() );
6✔
295
                $stmt->bind( $idx++, $price->getRebate() );
6✔
296
                $stmt->bind( $idx++, $price->getTaxValue() );
6✔
297
                $stmt->bind( $idx++, json_encode( $price->getTaxRates(), JSON_FORCE_OBJECT ) );
6✔
298
                $stmt->bind( $idx++, $price->getTaxFlag(), \Aimeos\Base\DB\Statement\Base::PARAM_INT );
6✔
299

300
                return $stmt;
6✔
301
        }
302

303

304
        /**
305
         * Fetches the rows from the database statement and returns the list of items.
306
         *
307
         * @param \Aimeos\Base\DB\Result\Iface $stmt Database statement object
308
         * @param array $ref List of domains whose items should be fetched too
309
         * @param string $prefix Prefix for the property names
310
         * @param array $attrs List of attributes that should be decoded
311
         * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Common\Item\Iface
312
         */
313
        protected function fetch( \Aimeos\Base\DB\Result\Iface $results, array $ref, string $prefix = '', array $attrs = [] ) : \Aimeos\Map
314
        {
315
                $ids = $map = [];
41✔
316
                $priceManager = \Aimeos\MShop::create( $this->context(), 'price' );
41✔
317

318
                while( $row = $results->fetch() )
41✔
319
                {
320
                        $row['order.service.taxrates'] = json_decode( $row['order.service.taxrates'], true ) ?? [];
39✔
321

322
                        $row['.price'] = $priceManager->create( [
39✔
323
                                'price.currencyid' => $row['order.service.currencyid'],
39✔
324
                                'price.taxrates' => $row['order.service.taxrates'],
39✔
325
                                'price.value' => $row['order.service.price'],
39✔
326
                                'price.costs' => $row['order.service.costs'],
39✔
327
                                'price.rebate' => $row['order.service.rebate'],
39✔
328
                                'price.taxflag' => $row['order.service.taxflag'],
39✔
329
                                'price.taxvalue' => $row['order.service.taxvalue'],
39✔
330
                                'price.siteid' => $row['order.service.siteid'],
39✔
331
                        ] );
39✔
332

333
                        $ids[] = $row['order.service.serviceid'];
39✔
334

335
                        $map[$row['order.service.id']] = $row;
39✔
336
                }
337

338
                $items = [];
41✔
339
                $attributes = $this->getAttributeItems( array_keys( $map ) );
41✔
340
                $transactions = $this->getTransactions( array_keys( $map ) );
41✔
341
                $servItems = $this->hasRef( $ref, 'service' ) ? $this->getServiceItems( array_filter( $ids ), $ref ) : [];
41✔
342

343
                foreach( $map as $id => $row )
41✔
344
                {
345
                        $row['.service'] = $servItems[$row['order.service.serviceid']] ?? null;
39✔
346
                        $row['.transactions'] = $transactions[$id] ?? map();
39✔
347
                        $row['.attributes'] = $attributes[$id] ?? map();
39✔
348

349
                        if( $item = $this->applyFilter( $this->create( $row ) ) ) {
39✔
350
                                $items[$id] = $item;
39✔
351
                        }
352
                }
353

354
                return map( $items );
41✔
355
        }
356

357

358
        /**
359
         * Searches for attribute items connected with order service item.
360
         *
361
         * @param string[] $ids List of order service item IDs
362
         * @return \Aimeos\Map Associative list of order service IDs as keys and order service attribute items
363
         *  implementing \Aimeos\MShop\Order\Item\Service\Attribute\Iface as values
364
         */
365
        protected function getAttributeItems( array $ids ) : \Aimeos\Map
366
        {
367
                $manager = $this->object()->getSubManager( 'attribute' );
41✔
368
                $filter = $manager->filter()->add( 'order.service.attribute.parentid', '==', $ids )->slice( 0, 0x7fffffff );
41✔
369

370
                return $manager->search( $filter )->groupBy( 'order.service.attribute.parentid' );
41✔
371
        }
372

373

374
        /**
375
         * Fetches service items connected with order service item.
376
         *
377
         * @param string[] $ids List of order service item IDs
378
         * @return \Aimeos\Map Associative list of order service IDs as keys and order service attribute items
379
         *  implementing \Aimeos\MShop\Order\Item\Service\Attribute\Iface as values
380
         */
381
        protected function getServiceItems( array $ids, array $ref ) : \Aimeos\Map
382
        {
383
                $manager = \Aimeos\MShop::create( $this->context(), 'service' );
4✔
384
                $search = $manager->filter()->add( 'service.id', '==', array_unique( $ids ) )->slice( 0, 0x7fffffff );
4✔
385

386
                return $manager->search( $search, $ref );
4✔
387
        }
388

389

390
        /**
391
         * Searches for transaction items connected with order service item.
392
         *
393
         * @param string[] $ids List of order service item IDs
394
         * @return \Aimeos\Map Associative list of order service IDs as keys and order service transaction items
395
         *  implementing \Aimeos\MShop\Order\Item\Service\Transaction\Iface as values
396
         */
397
        protected function getTransactions( array $ids ) : \Aimeos\Map
398
        {
399
                $manager = $this->object()->getSubManager( 'transaction' );
41✔
400
                $filter = $manager->filter()->add( 'order.service.transaction.parentid', '==', $ids )->slice( 0, 0x7fffffff );
41✔
401

402
                return $manager->search( $filter )->groupBy( 'order.service.attribute.parentid' );
41✔
403
        }
404

405

406
        /**
407
         * Checks if the item is modified
408
         *
409
         * @param \Aimeos\MShop\Common\Item\Iface $item Item object
410
         * @return bool True if the item is modified, false if not
411
         */
412
        protected function isModified( \Aimeos\MShop\Common\Item\Iface $item ) : bool
413
        {
414
                return $item->isModified() || $item->getPrice()->isModified();
6✔
415
        }
416

417

418
        /**
419
         * Returns the prefix for the item properties and search keys.
420
         *
421
         * @return string Prefix for the item properties and search keys
422
         */
423
        protected function prefix() : string
424
        {
425
                return 'order.service.';
94✔
426
        }
427

428

429
        /**
430
         * Saves the dependent items of the item
431
         *
432
         * @param \Aimeos\MShop\Common\Item\Iface $item Item object
433
         * @param bool $fetch True if the new ID should be returned in the item
434
         * @return \Aimeos\MShop\Common\Item\Iface Updated item
435
         */
436
        protected function saveDeps( \Aimeos\MShop\Common\Item\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Common\Item\Iface
437
        {
438
                $this->saveAttributeItems( $item, $fetch );
6✔
439
                $this->saveTransactions( $item, $fetch );
6✔
440

441
                return $item;
6✔
442
        }
443

444

445
        /**
446
         * Saves the attribute items included in the order service item
447
         *
448
         * @param \Aimeos\MShop\Order\Item\Service\Iface $item Order service item with attribute items
449
         * @param bool $fetch True if the new ID should be set in the attribute item
450
         * @return \Aimeos\MShop\Order\Item\Service\Iface Object with saved attribute items and IDs
451
         */
452
        protected function saveAttributeItems( \Aimeos\MShop\Order\Item\Service\Iface $item, bool $fetch ) : \Aimeos\MShop\Order\Item\Service\Iface
453
        {
454
                $attrItems = $item->getAttributeItems();
6✔
455

456
                foreach( $attrItems as $key => $attrItem )
6✔
457
                {
458
                        if( $attrItem->getType() === 'session' )
5✔
459
                        {
460
                                unset( $attrItems[$key] );
×
461
                                continue;
×
462
                        }
463

464
                        if( $attrItem->getParentId() != $item->getId() ) {
5✔
465
                                $attrItem->setId( null ); // create new property item if copied
5✔
466
                        }
467

468
                        $attrItem->setParentId( $item->getId() );
5✔
469
                }
470

471
                $this->object()->getSubManager( 'attribute' )->save( $attrItems, $fetch );
6✔
472
                return $item;
6✔
473
        }
474

475

476
        /**
477
         * Saves the transaction items included in the order service item
478
         *
479
         * @param \Aimeos\MShop\Order\Item\Service\Iface $item Order service item with transaction items
480
         * @param bool $fetch True if the new ID should be set in the transaction item
481
         * @return \Aimeos\MShop\Order\Item\Service\Iface Object with saved transaction items and IDs
482
         */
483
        protected function saveTransactions( \Aimeos\MShop\Order\Item\Service\Iface $item, bool $fetch ) : \Aimeos\MShop\Order\Item\Service\Iface
484
        {
485
                $list = $item->getTransactions();
6✔
486

487
                foreach( $list as $key => $txItem )
6✔
488
                {
UNCOV
489
                        if( $txItem->getParentId() != $item->getId() ) {
×
UNCOV
490
                                $txItem->setId( null ); // create new property item if copied
×
491
                        }
492

UNCOV
493
                        $txItem->setParentId( $item->getId() );
×
494
                }
495

496
                $this->object()->getSubManager( 'transaction' )->save( $list, $fetch );
6✔
497
                return $item;
6✔
498
        }
499
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc