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

aimeos / aimeos-core / cb23f6d9-6d38-4cc2-8b6a-1de073eff86c

11 Oct 2024 12:43PM UTC coverage: 91.626% (-0.009%) from 91.635%
cb23f6d9-6d38-4cc2-8b6a-1de073eff86c

push

circleci

aimeos
Alias columns for ordering results in index manager

1 of 1 new or added line in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

9552 of 10425 relevant lines covered (91.63%)

80.02 hits per line

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

88.54
/src/MShop/Index/Manager/DBBase.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 Index
8
 */
9

10

11
namespace Aimeos\MShop\Index\Manager;
12

13

14
/**
15
 * Base class for all database based index managers
16
 *
17
 * @package MShop
18
 * @subpackage Index
19
 */
20
abstract class DBBase
21
        extends \Aimeos\MShop\Common\Manager\Base
22
        implements \Aimeos\MShop\Product\Manager\Iface
23
{
24
        private \Aimeos\MShop\Common\Manager\Iface $manager;
25

26

27
        /**
28
         * Initializes the manager object
29
         *
30
         * @param \Aimeos\MShop\ContextIface $context Context object
31
         */
32
        public function __construct( \Aimeos\MShop\ContextIface $context )
33
        {
34
                parent::__construct( $context );
109✔
35

36
                /** mshop/index/manager/resource
37
                 * Name of the database connection resource to use
38
                 *
39
                 * You can configure a different database connection for each data domain
40
                 * and if no such connection name exists, the "db" connection will be used.
41
                 * It's also possible to use the same database connection for different
42
                 * data domains by configuring the same connection name using this setting.
43
                 *
44
                 * @param string Database connection name
45
                 * @since 2023.04
46
                 */
47
                $this->setResourceName( $context->config()->get( 'mshop/index/manager/resource', 'db-product' ) );
109✔
48
                $this->manager = \Aimeos\MShop::create( $this->context(), 'product' );
109✔
49
        }
50

51

52
        /**
53
         * Removes old entries from the storage.
54
         *
55
         * @param iterable $siteids List of IDs for sites whose entries should be deleted
56
         * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
57
         */
58
        public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
59
        {
60
                foreach( $this->getSubManagers() as $submanager ) {
8✔
61
                        $submanager->clear( $siteids );
×
62
                }
63

64
                return $this;
8✔
65
        }
66

67

68
        /**
69
         * Creates a new empty item instance
70
         *
71
         * @param array $values Values the item should be initialized with
72
         * @return \Aimeos\MShop\Product\Item\Iface New product item object
73
         */
74
        public function create( array $values = [] ) : \Aimeos\MShop\Common\Item\Iface
75
        {
76
                return $this->manager->create( $values );
1✔
77
        }
78

79

80
        /**
81
         * Creates a new lists item object
82
         *
83
         * @param array $values Values the item should be initialized with
84
         * @return \Aimeos\MShop\Common\Item\Lists\Iface New list items object
85
         */
86
        public function createListItem( array $values = [] ) : \Aimeos\MShop\Common\Item\Lists\Iface
87
        {
88
                return $this->manager->createListItem( $values );
1✔
89
        }
90

91

92
        /**
93
         * Creates a new property item object
94
         *
95
         * @param array $values Values the item should be initialized with
96
         * @return \Aimeos\MShop\Common\Item\Property\Iface New property items object
97
         */
98
        public function createPropertyItem( array $values = [] ) : \Aimeos\MShop\Common\Item\Property\Iface
99
        {
100
                return $this->manager->createPropertyItem( $values );
1✔
101
        }
102

103

104
        /**
105
         * Removes multiple items.
106
         *
107
         * @param \Aimeos\MShop\Common\Item\Iface|\Aimeos\Map|array|string $items Item object, ID or a list of them
108
         * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
109
         */
110
        public function delete( $itemIds ) : \Aimeos\MShop\Common\Manager\Iface
111
        {
112
                foreach( $this->getSubManagers() as $submanager ) {
1✔
113
                        $submanager->delete( $itemIds );
1✔
114
                }
115

116
                return $this;
1✔
117
        }
118

119

120
        /**
121
         * Creates a filter object.
122
         *
123
         * @param bool|null $default Add default criteria or NULL for relaxed default criteria
124
         * @param bool $site TRUE for adding site criteria to limit items by the site of related items
125
         * @return \Aimeos\Base\Criteria\Iface Returns the filter object
126
         */
127
        public function filter( ?bool $default = false, bool $site = false ) : \Aimeos\Base\Criteria\Iface
128
        {
129
                return $this->manager->filter( $default );
96✔
130
        }
131

132

133
        /**
134
         * Returns the item specified by its code and domain/type if necessary
135
         *
136
         * @param string $code Code of the item
137
         * @param string[] $ref List of domains to fetch list items and referenced items for
138
         * @param string|null $domain Domain of the item if necessary to identify the item uniquely
139
         * @param string|null $type Type code of the item if necessary to identify the item uniquely
140
         * @param bool|null $default Add default criteria or NULL for relaxed default criteria
141
         * @return \Aimeos\MShop\Common\Item\Iface Item object
142
         */
143
        public function find( string $code, array $ref = [], ?string $domain = 'product', string $type = null,
144
                ?bool $default = false ) : \Aimeos\MShop\Common\Item\Iface
145
        {
146
                return $this->manager->find( $code, $ref, $domain, $type, $default );
1✔
147
        }
148

149

150
        /**
151
         * Returns the product item for the given ID
152
         *
153
         * @param string $id Id of item
154
         * @param string[] $ref List of domains to fetch list items and referenced items for
155
         * @param bool|null $default Add default criteria or NULL for relaxed default criteria
156
         * @return \Aimeos\MShop\Product\Item\Iface Product item object
157
         */
158
        public function get( string $id, array $ref = [], ?bool $default = false ) : \Aimeos\MShop\Common\Item\Iface
159
        {
160
                return $this->manager->get( $id, $ref, $default );
1✔
161
        }
162

163

164
        /**
165
         * Returns a list of attribute objects describing the available criteria for searching
166
         *
167
         * @param bool $withsub True to return attributes of sub-managers too
168
         * @return array List of items implementing \Aimeos\Base\Criteria\Attribute\Iface
169
         */
170
        public function getSearchAttributes( bool $withsub = true ) : array
171
        {
172
                return $this->manager->getSearchAttributes( $withsub );
63✔
173
        }
174

175

176
        /**
177
         * Iterates over all matched items and returns the found ones
178
         *
179
         * @param \Aimeos\MShop\Common\Cursor\Iface $cursor Cursor object with filter, domains and cursor
180
         * @param string[] $ref List of domains whose items should be fetched too
181
         * @return \Aimeos\Map|null List of items implementing \Aimeos\MShop\Common\Item\Iface with ids as keys
182
         */
183
        public function iterate( \Aimeos\MShop\Common\Cursor\Iface $cursor, array $ref = [] ) : ?\Aimeos\Map
184
        {
185
                if( $cursor->value() === '' ) {
6✔
186
                        return null;
×
187
                }
188

189
                $filter = $cursor->filter()->add( 'product.id', '>', (int) $cursor->value() )->order( 'product.id' );
6✔
190
                $items = $this->search( $filter, $ref );
6✔
191

192
                $cursor->setValue( $items->lastKey() ?: '' );
6✔
193
                return $items;
6✔
194
        }
195

196

197
        /**
198
         * Updates the rating of the item
199
         *
200
         * @param string $id ID of the item
201
         * @param string $rating Decimal value of the rating
202
         * @param int $ratings Total number of ratings for the item
203
         * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
204
         */
205
        public function rate( string $id, string $rating, int $ratings ) : \Aimeos\MShop\Common\Manager\Iface
206
        {
207
                $this->manager->rate( $id, $rating, $ratings );
1✔
208
                return $this;
1✔
209
        }
210

211

212
        /**
213
         * Rebuilds the customer index
214
         *
215
         * @param \Aimeos\MShop\Product\Item\Iface[] $items Associative list of product IDs and items values
216
         * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
217
         */
218
        public function rebuild( iterable $items = [] ) : \Aimeos\MShop\Index\Manager\Iface
219
        {
220
                foreach( $this->getSubManagers() as $submanager ) {
×
221
                        $submanager->rebuild( $items );
×
222
                }
223

224
                return $this;
×
225
        }
226

227

228
        /**
229
         * Removes the products from the product index.
230
         *
231
         * @param iterable|string $ids Product ID or list of IDs
232
         * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
233
         */
234
         public function remove( $ids ) : \Aimeos\MShop\Index\Manager\Iface
235
         {
236
                foreach( $this->getSubManagers() as $submanager ) {
10✔
237
                        $submanager->remove( $ids );
5✔
238
                }
239

240
                return $this;
10✔
241
        }
242

243

244
        /**
245
         * Adds or updates an item object or a list of them.
246
         *
247
         * @param \Aimeos\Map|\Aimeos\MShop\Common\Item\Iface[]|\Aimeos\MShop\Common\Item\Iface $items Item or list of items whose data should be saved
248
         * @param bool $fetch True if the new ID should be returned in the item
249
         * @return \Aimeos\Map|\Aimeos\MShop\Common\Item\Iface Saved item or items
250
         */
251
        public function save( $items, bool $fetch = true )
252
        {
253
                $this->rebuild( map( $this->manager->save( $items, true ) ) );
8✔
254
                return $items;
8✔
255
        }
256

257

258
        /**
259
         * Updates if the product is in stock
260
         *
261
         * @param string $id ID of the procuct item
262
         * @param int $value "0" or "1" if product is in stock or not
263
         * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
264
         */
265
        public function stock( string $id, int $value ) : \Aimeos\MShop\Common\Manager\Iface
266
        {
267
                $this->manager->stock( $id, $value );
1✔
268
                return $this;
1✔
269
        }
270

271

272
        /**
273
         * Removes all entries not touched after the given timestamp
274
         *
275
         * @param string $timestamp Timestamp in ISO format (YYYY-MM-DD HH:mm:ss)
276
         * @param string $path Configuration path to the SQL statement to execute
277
         * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
278
         */
279
        protected function cleanupBase( string $timestamp, string $path ) : \Aimeos\MShop\Index\Manager\Iface
280
        {
281
                $context = $this->context();
8✔
282
                $siteid = $context->locale()->getSiteId();
8✔
283

284
                $this->begin();
8✔
285
                $conn = $context->db( $this->getResourceName() );
8✔
286

287
                try
288
                {
289
                        $stmt = $this->getCachedStatement( $conn, $path );
8✔
290

291
                        $stmt->bind( 1, $timestamp ); // ctime
8✔
292
                        $stmt->bind( 2, $siteid );
8✔
293

294
                        $stmt->execute()->finish();
8✔
295
                }
296
                catch( \Exception $e )
×
297
                {
298
                        $this->rollback();
×
299
                        throw $e;
×
300
                }
301

302
                $this->commit();
8✔
303

304
                foreach( $this->getSubManagers() as $submanager ) {
8✔
305
                        $submanager->cleanup( $timestamp );
×
306
                }
307

308
                return $this;
8✔
309
        }
310

311

312
        /**
313
         * Removes several items from the index
314
         *
315
         * @param string[] $ids List of product IDs
316
         * @param string $path Configuration path to the SQL statement to execute
317
         * @param bool $siteidcheck If siteid should be used in the statement
318
         * @param string $name Name of the ID column
319
         * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
320
         */
321
        protected function deleteItemsBase( $ids, string $path, bool $siteidcheck = true,
322
                string $name = 'prodid' ) : \Aimeos\MShop\Common\Manager\Iface
323
        {
324
                foreach( $this->getSubManagers() as $submanager ) {
17✔
325
                        $submanager->delete( $ids );
×
326
                }
327

328
                return parent::deleteItemsBase( $ids, $path, $siteidcheck, $name );
17✔
329
        }
330

331

332
        /**
333
         * Returns the product manager instance
334
         *
335
         * @return \Aimeos\MShop\Product\Manager\Iface Product manager object
336
         */
337
        protected function getManager() : \Aimeos\MShop\Common\Manager\Iface
338
        {
339
                return $this->manager;
1✔
340
        }
341

342

343
        /**
344
         * Returns the string replacements for the SQL statements
345
         *
346
         * @param \Aimeos\Base\Criteria\Iface $search Search critera object
347
         * @param \Aimeos\Base\Criteria\Attribute\Iface[] $attributes Associative list of search keys and criteria attribute items as values
348
         * @param \Aimeos\Base\Criteria\Attribute\Iface[] $attronly Associative list of search keys and criteria attribute items as values for the base table
349
         * @param \Aimeos\Base\Criteria\Plugin\Iface[] $plugins Associative list of search keys and criteria plugin items as values
350
         * @param string[] $joins Associative list of SQL joins
351
         * @param \Aimeos\Base\Criteria\Attribute\Iface[] $columns Additional columns to retrieve values from
352
         * @return array Array of keys, find and replace arrays
353
         */
354
        protected function getSQLReplacements( \Aimeos\Base\Criteria\Iface $search, array $attributes, array $attronly, array $plugins, array $joins ) : array
355
        {
356
                $types = $this->getSearchTypes( $attributes );
52✔
357
                $funcs = $this->getSearchFunctions( $attributes );
52✔
358
                $translations = $this->getSearchTranslations( $attributes );
52✔
359
                $translations = $this->aliasTranslations( $translations );
52✔
360

361
                if( !empty( $sorts = $search->getSortations() ) )
52✔
362
                {
363
                        $names = $search->translate( $sorts, [], $funcs );
26✔
364
                        $cols = $search->translate( $sorts, $translations, $funcs );
26✔
365
                        $ops = map( $sorts )->getOperator();
26✔
366

367
                        $list = $translations = [];
26✔
368
                        foreach( $cols as $idx => $col )
26✔
369
                        {
370
                                if( strpos( $col, '"' ) === false ) {
26✔
UNCOV
371
                                        $col = $this->alias( $names[$idx] ) . '."' . $col . '"';
×
372
                                }
373

374
                                $list[] = ( $ops[$idx] === '-' ? 'MAX' : 'MIN' ) . '(' . $col . ') AS "s' . $idx . '"';
26✔
375
                                $translations[$names[$idx]] = '"s' . $idx . '"';
26✔
376
                        }
377
                }
378

379
                $map = parent::getSQLReplacements( $search, $attributes, $attronly, $plugins, $joins );
52✔
380

381
                $map[':mincols'] = !empty( $list ) ? ', ' . implode( ', ', $list ) : '';
52✔
382
                $map[':order'] = $search->getSortationSource( $types, $translations, $funcs );
52✔
383

384
                return $map;
52✔
385
        }
386

387

388
        /**
389
         * Optimizes the catalog customer index if necessary
390
         *
391
         * @param string $path Configuration path to the SQL statements to execute
392
         * @return \Aimeos\MShop\Index\Manager\Iface Manager object for chaining method calls
393
         */
394
        protected function optimizeBase( string $path ) : \Aimeos\MShop\Index\Manager\Iface
395
        {
396
                $context = $this->context();
1✔
397
                $conn = $context->db( $this->getResourceName() );
1✔
398

399
                foreach( (array) $this->getSqlConfig( $path ) as $sql ) {
1✔
400
                        $conn->create( $sql )->execute()->finish();
1✔
401
                }
402

403
                foreach( $this->getSubManagers() as $submanager ) {
1✔
404
                        $submanager->optimize();
1✔
405
                }
406

407
                return $this;
1✔
408
        }
409

410

411
        /**
412
         * Searches for items matching the given criteria.
413
         *
414
         * @param \Aimeos\Base\Criteria\Iface $search Search criteria
415
         * @param string[] $ref List of domains to fetch list items and referenced items for
416
         * @param int &$total Total number of items matched by the given criteria
417
         * @param string $cfgPathSearch Configuration path to the search SQL statement
418
         * @param string $cfgPathCount Configuration path to the count SQL statement
419
         * @return \Aimeos\MShop\Product\Item\Iface[] List of product items
420
         */
421
        protected function searchItemsIndexBase( \Aimeos\Base\Criteria\Iface $search,
422
                array $ref, int &$total = null, string $cfgPathSearch, string $cfgPathCount ) : \Aimeos\Map
423
        {
424
                $list = $ids = [];
44✔
425
                $context = $this->context();
44✔
426
                $conn = $context->db( $this->getResourceName() );
44✔
427

428
                $required = array( 'product' );
44✔
429

430
                /** mshop/index/manager/sitemode
431
                 * Mode how items from levels below or above in the site tree are handled
432
                 *
433
                 * By default, only items from the current site are fetched from the
434
                 * storage. If the ai-sites extension is installed, you can create a
435
                 * tree of sites. Then, this setting allows you to define for the
436
                 * whole index domain if items from parent sites are inherited,
437
                 * sites from child sites are aggregated or both.
438
                 *
439
                 * Available constants for the site mode are:
440
                 * * 0 = only items from the current site
441
                 * * 1 = inherit items from parent sites
442
                 * * 2 = aggregate items from child sites
443
                 * * 3 = inherit and aggregate items at the same time
444
                 *
445
                 * You also need to set the mode in the locale manager
446
                 * (mshop/locale/manager/sitelevel) to one of the constants.
447
                 * If you set it to the same value, it will work as described but you
448
                 * can also use different modes. For example, if inheritance and
449
                 * aggregation is configured the locale manager but only inheritance
450
                 * in the domain manager because aggregating items makes no sense in
451
                 * this domain, then items wil be only inherited. Thus, you have full
452
                 * control over inheritance and aggregation in each domain.
453
                 *
454
                 * @param int Constant from Aimeos\MShop\Locale\Manager\Base class
455
                 * @since 2018.01
456
                 * @see mshop/locale/manager/sitelevel
457
                 */
458
                $level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
44✔
459
                $level = $context->config()->get( 'mshop/index/manager/sitemode', $level );
44✔
460

461
                $results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $level );
44✔
462

463
                while( $row = $results->fetch() ) {
44✔
464
                        $ids[] = $row['id'];
43✔
465
                }
466

467
                $manager = \Aimeos\MShop::create( $context, 'product' );
44✔
468
                $prodSearch = $manager->filter();
44✔
469
                $prodSearch->setConditions( $prodSearch->compare( '==', 'product.id', $ids ) );
44✔
470
                $prodSearch->slice( 0, $search->getLimit() );
44✔
471
                $items = $manager->search( $prodSearch, $ref );
44✔
472

473
                foreach( $ids as $id )
44✔
474
                {
475
                        if( isset( $items[$id] ) ) {
43✔
476
                                $list[$id] = $items[$id];
43✔
477
                        }
478
                }
479

480
                return map( $list );
44✔
481
        }
482
}
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

© 2025 Coveralls, Inc