Passed
Push — master ( 8d7206...a17893 )
by Aimeos
37:54 queued 24:55
created

src/MShop/Customer/Manager/Laravel.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2024
6
 * @package MShop
7
 * @subpackage Customer
8
 */
9
10
11
namespace Aimeos\MShop\Customer\Manager;
12
13
14
/**
15
 * Customer class implementation for Laravel.
16
 *
17
 * @package MShop
18
 * @subpackage Customer
19
 */
20
class Laravel
21
	extends \Aimeos\MShop\Customer\Manager\Standard
22
{
23
	private array $searchConfig = array(
24
		'customer.id' => array(
25
			'label' => 'Customer ID',
26
			'code' => 'customer.id',
27
			'internalcode' => 'mcus."id"',
28
			'type' => 'int',
29
			'public' => false,
30
		),
31
		'customer.siteid' => array(
32
			'code' =>'customer.siteid',
33
			'internalcode' =>'mcus."siteid"',
34
			'label' =>'Customer site ID',
35
			'type' => 'string',
36
			'public' => false,
37
		),
38
		'customer.code' => array(
39
			'label' => 'Customer username',
40
			'code' => 'customer.code',
41
			'internalcode' => 'mcus."email"',
42
			'type' => 'string',
43
		),
44
		'customer.label' => array(
45
			'label' => 'Customer label',
46
			'code' => 'customer.label',
47
			'internalcode' => 'mcus."name"',
48
			'type' => 'string',
49
		),
50
		'customer.salutation' => array(
51
			'label' => 'Customer salutation',
52
			'code' => 'customer.salutation',
53
			'internalcode' => 'mcus."salutation"',
54
			'type' => 'string',
55
		),
56
		'customer.company' => array(
57
			'label' => 'Customer company',
58
			'code' => 'customer.company',
59
			'internalcode' => 'mcus."company"',
60
			'type' => 'string',
61
		),
62
		'customer.vatid' => array(
63
			'label' => 'Customer VAT ID',
64
			'code' => 'customer.vatid',
65
			'internalcode' => 'mcus."vatid"',
66
			'type' => 'string',
67
		),
68
		'customer.title' => array(
69
			'label' => 'Customer title',
70
			'code' => 'customer.title',
71
			'internalcode' => 'mcus."title"',
72
			'type' => 'string',
73
		),
74
		'customer.firstname' => array(
75
			'label' => 'Customer firstname',
76
			'code' => 'customer.firstname',
77
			'internalcode' => 'mcus."firstname"',
78
			'type' => 'string',
79
		),
80
		'customer.lastname' => array(
81
			'label' => 'Customer lastname',
82
			'code' => 'customer.lastname',
83
			'internalcode' => 'mcus."lastname"',
84
			'type' => 'string',
85
		),
86
		'customer.address1' => array(
87
			'label' => 'Customer address part one',
88
			'code' => 'customer.address1',
89
			'internalcode' => 'mcus."address1"',
90
			'type' => 'string',
91
		),
92
		'customer.address2' => array(
93
			'label' => 'Customer address part two',
94
			'code' => 'customer.address2',
95
			'internalcode' => 'mcus."address2"',
96
			'type' => 'string',
97
		),
98
		'customer.address3' => array(
99
			'label' => 'Customer address part three',
100
			'code' => 'customer.address3',
101
			'internalcode' => 'mcus."address3"',
102
			'type' => 'string',
103
		),
104
		'customer.postal' => array(
105
			'label' => 'Customer postal',
106
			'code' => 'customer.postal',
107
			'internalcode' => 'mcus."postal"',
108
			'type' => 'string',
109
		),
110
		'customer.city' => array(
111
			'label' => 'Customer city',
112
			'code' => 'customer.city',
113
			'internalcode' => 'mcus."city"',
114
			'type' => 'string',
115
		),
116
		'customer.state' => array(
117
			'label' => 'Customer state',
118
			'code' => 'customer.state',
119
			'internalcode' => 'mcus."state"',
120
			'type' => 'string',
121
		),
122
		'customer.languageid' => array(
123
			'label' => 'Customer language',
124
			'code' => 'customer.languageid',
125
			'internalcode' => 'mcus."langid"',
126
			'type' => 'string',
127
		),
128
		'customer.countryid' => array(
129
			'label' => 'Customer country',
130
			'code' => 'customer.countryid',
131
			'internalcode' => 'mcus."countryid"',
132
			'type' => 'string',
133
		),
134
		'customer.telephone' => array(
135
			'label' => 'Customer telephone',
136
			'code' => 'customer.telephone',
137
			'internalcode' => 'mcus."telephone"',
138
			'type' => 'string',
139
		),
140
		'customer.telefax' => array(
141
			'label' => 'Customer telefax',
142
			'code' => 'customer.telefax',
143
			'internalcode' => 'mcus."telefax"',
144
			'type' => 'string',
145
		),
146
		'customer.mobile' => array(
147
			'label' => 'Customer mobile number',
148
			'code' => 'customer.mobile',
149
			'internalcode' => 'mcus."mobile"',
150
			'type' => 'string',
151
		),
152
		'customer.email' => array(
153
			'label' => 'Customer email',
154
			'code' => 'customer.email',
155
			'internalcode' => 'mcus."email"',
156
			'type' => 'string',
157
		),
158
		'customer.website' => array(
159
			'label' => 'Customer website',
160
			'code' => 'customer.website',
161
			'internalcode' => 'mcus."website"',
162
			'type' => 'string',
163
		),
164
		'customer.longitude' => array(
165
			'label' => 'Customer longitude',
166
			'code' => 'customer.longitude',
167
			'internalcode' => 'mcus."longitude"',
168
			'type' => 'float',
169
		),
170
		'customer.latitude' => array(
171
			'label' => 'Customer latitude',
172
			'code' => 'customer.latitude',
173
			'internalcode' => 'mcus."latitude"',
174
			'type' => 'float',
175
		),
176
		'customer.birthday' => array(
177
			'label' => 'Customer birthday',
178
			'code' => 'customer.birthday',
179
			'internalcode' => 'mcus."birthday"',
180
			'type' => 'string',
181
		),
182
		'customer.password' => array(
183
			'label' => 'Customer password',
184
			'code' => 'customer.password',
185
			'internalcode' => 'mcus."password"',
186
			'type' => 'string',
187
		),
188
		'customer.status' => array(
189
			'label' => 'Customer status',
190
			'code' => 'customer.status',
191
			'internalcode' => 'mcus."status"',
192
			'type' => 'int',
193
		),
194
		'customer.dateverified' => array(
195
			'label' => 'Customer verification date',
196
			'code' => 'customer.dateverified',
197
			'internalcode' => 'mcus."email_verified_at"',
198
			'type' => 'date',
199
		),
200
		'customer.ctime' => array(
201
			'label' => 'Customer creation time',
202
			'code' => 'customer.ctime',
203
			'internalcode' => 'mcus."created_at"',
204
			'type' => 'datetime',
205
		),
206
		'customer.mtime' => array(
207
			'label' => 'Customer modification time',
208
			'code' => 'customer.mtime',
209
			'internalcode' => 'mcus."updated_at"',
210
			'type' => 'datetime',
211
		),
212
		'customer.editor' => array(
213
			'label' =>'Customer editor',
214
			'code' =>'customer.editor',
215
			'internalcode' => 'mcus."editor"',
216
			'type' => 'string',
217
		),
218
		'customer:has' => array(
219
			'code' => 'customer:has()',
220
			'internalcode' => ':site AND :key AND mcusli."id"',
221
			'internaldeps' => ['LEFT JOIN "users_list" AS mcusli ON ( mcusli."parentid" = mcus."id" )'],
222
			'label' => 'Customer has list item, parameter(<domain>[,<list type>[,<reference ID>)]]',
223
			'type' => 'null',
224
			'public' => false,
225
		),
226
		'customer:prop' => array(
227
			'code' => 'customer:prop()',
228
			'internalcode' => ':site AND :key AND mcuspr."id"',
229
			'internaldeps' => ['LEFT JOIN "users_property" AS mcuspr ON ( mcuspr."parentid" = mcus."id" )'],
230
			'label' => 'Customer has property item, parameter(<property type>[,<language code>[,<property value>]])',
231
			'type' => 'null',
232
			'public' => false,
233
		),
234
	);
235
236
237
	/**
238
	 * Initializes the object.
239
	 *
240
	 * @param \Aimeos\MShop\ContextIface $context Context object
241
	 */
242
	public function __construct( \Aimeos\MShop\ContextIface $context )
243
	{
244
		parent::__construct( $context );
245
246
		$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
247
		$level = $context->config()->get( 'mshop/customer/manager/sitemode', $level );
248
249
250
		$this->searchConfig['customer:has']['function'] = function( &$source, array $params ) use ( $level ) {
251
252
			$keys = [];
253
254
			foreach( (array) ( $params[1] ?? '' ) as $type ) {
255
				foreach( (array) ( $params[2] ?? '' ) as $id ) {
256
					$keys[] = $params[0] . '|' . ( $type ? $type . '|' : '' ) . $id;
257
				}
258
			}
259
260
			$sitestr = $this->siteString( 'mcusli."siteid"', $level );
261
			$keystr = $this->toExpression( 'mcusli."key"', $keys, ( $params[2] ?? null ) ? '==' : '=~' );
262
			$source = str_replace( [':site', ':key'], [$sitestr, $keystr], $source );
263
264
			return $params;
265
		};
266
267
268
		$this->searchConfig['customer:prop']['function'] = function( &$source, array $params ) use ( $level ) {
269
270
			$keys = [];
271
			$langs = array_key_exists( 1, $params ) ? ( $params[1] ?? 'null' ) : '';
272
273
			foreach( (array) $langs as $lang ) {
274
				foreach( (array) ( $params[2] ?? '' ) as $val ) {
275
					$keys[] = substr( $params[0] . '|' . ( $lang === null ? 'null|' : ( $lang ? $lang . '|' : '' ) ) . $val, 0, 255 );
276
				}
277
			}
278
279
			$sitestr = $this->siteString( 'mcuspr."siteid"', $level );
280
			$keystr = $this->toExpression( 'mcuspr."key"', $keys, ( $params[2] ?? null ) ? '==' : '=~' );
281
			$source = str_replace( [':site', ':key'], [$sitestr, $keystr], $source );
282
283
			return $params;
284
		};
285
	}
286
287
288
	/**
289
	 * Counts the number items that are available for the values of the given key.
290
	 *
291
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria
292
	 * @param array|string $key Search key or list of key to aggregate items for
293
	 * @param string|null $value Search key for aggregating the value column
294
	 * @param string|null $type Type of the aggregation, empty string for count or "sum" or "avg" (average)
295
	 * @return \Aimeos\Map List of the search keys as key and the number of counted items as value
296
	 */
297
	public function aggregate( \Aimeos\Base\Criteria\Iface $search, $key, string $value = null, string $type = null ) : \Aimeos\Map
298
	{
299
		/** mshop/customer/manager/laravel//aggregate/mysql
300
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
301
		 *
302
		 * @see mshop/customer/manager/laravel//aggregate/ansi
303
		 */
304
305
		/** mshop/customer/manager/laravel//aggregate/ansi
306
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
307
		 *
308
		 * Groups all records by the values in the key column and counts their
309
		 * occurence. The matched records can be limited by the given criteria
310
		 * from the customer database. The records must be from one of the sites
311
		 * that are configured via the context item. If the current site is part
312
		 * of a tree of sites, the statement can count all records from the
313
		 * current site and the complete sub-tree of sites.
314
		 *
315
		 * As the records can normally be limited by criteria from sub-managers,
316
		 * their tables must be joined in the SQL context. This is done by
317
		 * using the "internaldeps" property from the definition of the ID
318
		 * column of the sub-managers. These internal dependencies specify
319
		 * the JOIN between the tables and the used columns for joining. The
320
		 * ":joins" placeholder is then replaced by the JOIN strings from
321
		 * the sub-managers.
322
		 *
323
		 * To limit the records matched, conditions can be added to the given
324
		 * criteria object. It can contain comparisons like column names that
325
		 * must match specific values which can be combined by AND, OR or NOT
326
		 * operators. The resulting string of SQL conditions replaces the
327
		 * ":cond" placeholder before the statement is sent to the database
328
		 * server.
329
		 *
330
		 * This statement doesn't return any records. Instead, it returns pairs
331
		 * of the different values found in the key column together with the
332
		 * number of records that have been found for that key values.
333
		 *
334
		 * The SQL statement should conform to the ANSI standard to be
335
		 * compatible with most relational database systems. This also
336
		 * includes using double quotes for table and column names.
337
		 *
338
		 * @param string SQL statement for aggregating customer items
339
		 * @since 2021.04
340
		 * @category Developer
341
		 * @see mshop/customer/manager/laravel//insert/ansi
342
		 * @see mshop/customer/manager/laravel//update/ansi
343
		 * @see mshop/customer/manager/laravel//newid/ansi
344
		 * @see mshop/customer/manager/laravel//delete/ansi
345
		 * @see mshop/customer/manager/laravel//search/ansi
346
		 * @see mshop/customer/manager/laravel//count/ansi
347
		 */
348
349
		$cfgkey = 'mshop/customer/manager/laravel/aggregate' . $type;
350
		return $this->aggregateBase( $search, $key, $cfgkey, ['customer'], $value );
351
	}
352
353
354
	/**
355
	 * Removes old entries from the storage.
356
	 *
357
	 * @param iterable $siteids List of IDs for sites whose entries should be deleted
358
	 * @return \Aimeos\MShop\Common\Manager\Iface Same object for fluent interface
359
	 */
360
	public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
361
	{
362
		$path = 'mshop/customer/manager/submanagers';
363
		$default = ['address', 'lists', 'property'];
364
365
		foreach( $this->context()->config()->get( $path, $default ) as $domain ) {
366
			$this->object()->getSubManager( $domain )->clear( $siteids );
367
		}
368
369
		return $this->clearBase( $siteids, 'mshop/customer/manager/laravel/clear' );
370
	}
371
372
373
	/**
374
	 * Removes multiple items.
375
	 *
376
	 * @param \Aimeos\MShop\Common\Item\Iface[]|string[] $itemIds List of item objects or IDs of the items
377
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
378
	 */
379
	public function delete( $itemIds ) : \Aimeos\MShop\Common\Manager\Iface
380
	{
381
		$path = 'mshop/customer/manager/laravel/delete';
382
		return $this->deleteItemsBase( $itemIds, $path )->deleteRefItems( $itemIds );
383
	}
384
385
386
	/**
387
	 * Returns the list attributes that can be used for searching.
388
	 *
389
	 * @param bool $withsub Return also attributes of sub-managers if true
390
	 * @return array List of attribute items implementing \Aimeos\Base\Criteria\Attribute\Iface
391
	 */
392
	public function getSearchAttributes( bool $withsub = true ) : array
393
	{
394
		$path = 'mshop/customer/manager/submanagers';
395
		return $this->getSearchAttributesBase( $this->searchConfig, $path, ['address'], $withsub );
396
	}
397
398
399
	/**
400
	 * Saves a customer item object.
401
	 *
402
	 * @param \Aimeos\MShop\Customer\Item\Iface $item Customer item object
403
	 * @param boolean $fetch True if the new ID should be returned in the item
404
	 * @return \Aimeos\MShop\Customer\Item\Iface $item Updated item including the generated ID
405
	 */
406
	protected function saveItem( \Aimeos\MShop\Customer\Item\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Customer\Item\Iface
407
	{
408
		$item = $this->addGroups( $item );
409
410
		if( !$item->isModified() )
411
		{
412
			$item = $this->savePropertyItems( $item, 'customer' );
413
			$item = $this->saveAddressItems( $item, 'customer' );
414
			return $this->saveListItems( $item, 'customer' );
415
		}
416
417
		$context = $this->context();
418
		$conn = $context->db( $this->getResourceName() );
419
420
		$id = $item->getId();
421
		$date = date( 'Y-m-d H:i:s' );
422
		$billingAddress = $item->getPaymentAddress();
423
		$columns = $this->object()->getSaveAttributes();
424
425
		if( $id === null )
426
		{
427
			/** mshop/customer/manager/laravel/insert
428
			 * Inserts a new customer record into the database table
429
			 *
430
			 * Items with no ID yet (i.e. the ID is NULL) will be created in
431
			 * the database and the newly created ID retrieved afterwards
432
			 * using the "newid" SQL statement.
433
			 *
434
			 * The SQL statement must be a string suitable for being used as
435
			 * prepared statement. It must include question marks for binding
436
			 * the values from the customer item to the statement before they are
437
			 * sent to the database server. The number of question marks must
438
			 * be the same as the number of columns listed in the INSERT
439
			 * statement. The order of the columns must correspond to the
440
			 * order in the save() method, so the correct values are
441
			 * bound to the columns.
442
			 *
443
			 * The SQL statement should conform to the ANSI standard to be
444
			 * compatible with most relational database systems. This also
445
			 * includes using double quotes for table and column names.
446
			 *
447
			 * @param string SQL statement for inserting records
448
			 * @since 2015.01
449
			 * @category Developer
450
			 * @see mshop/customer/manager/laravel/update
451
			 * @see mshop/customer/manager/laravel/newid
452
			 * @see mshop/customer/manager/laravel/delete
453
			 * @see mshop/customer/manager/laravel/search
454
			 * @see mshop/customer/manager/laravel/count
455
			 */
456
			$path = 'mshop/customer/manager/laravel/insert';
457
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ) );
0 ignored issues
show
It seems like $this->getSqlConfig($path) can also be of type array; however, parameter $sql of Aimeos\MShop\Common\Manager\Base::addSqlColumns() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

457
			$sql = $this->addSqlColumns( array_keys( $columns ), /** @scrutinizer ignore-type */ $this->getSqlConfig( $path ) );
Loading history...
458
		}
459
		else
460
		{
461
			/** mshop/customer/manager/laravel/update
462
			 * Updates an existing customer record in the database
463
			 *
464
			 * Items which already have an ID (i.e. the ID is not NULL) will
465
			 * be updated in the database.
466
			 *
467
			 * The SQL statement must be a string suitable for being used as
468
			 * prepared statement. It must include question marks for binding
469
			 * the values from the customer item to the statement before they are
470
			 * sent to the database server. The order of the columns must
471
			 * correspond to the order in the save() method, so the
472
			 * correct values are bound to the columns.
473
			 *
474
			 * The SQL statement should conform to the ANSI standard to be
475
			 * compatible with most relational database systems. This also
476
			 * includes using double quotes for table and column names.
477
			 *
478
			 * @param string SQL statement for updating records
479
			 * @since 2015.01
480
			 * @category Developer
481
			 * @see mshop/customer/manager/laravel/insert
482
			 * @see mshop/customer/manager/laravel/newid
483
			 * @see mshop/customer/manager/laravel/delete
484
			 * @see mshop/customer/manager/laravel/search
485
			 * @see mshop/customer/manager/laravel/count
486
			 */
487
			$path = 'mshop/customer/manager/laravel/update';
488
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ), false );
489
		}
490
491
		$idx = 1;
492
		$stmt = $this->getCachedStatement( $conn, $path, $sql );
493
494
		foreach( $columns as $name => $entry ) {
495
			$stmt->bind( $idx++, $item->get( $name ), \Aimeos\Base\Criteria\SQL::type( $entry->getType() ) );
496
		}
497
498
		$stmt->bind( $idx++, $item->getLabel() );
499
		$stmt->bind( $idx++, $item->getCode() );
500
		$stmt->bind( $idx++, $billingAddress->getCompany() );
501
		$stmt->bind( $idx++, $billingAddress->getVatID() );
502
		$stmt->bind( $idx++, $billingAddress->getSalutation() );
503
		$stmt->bind( $idx++, $billingAddress->getTitle() );
504
		$stmt->bind( $idx++, $billingAddress->getFirstname() );
505
		$stmt->bind( $idx++, $billingAddress->getLastname() );
506
		$stmt->bind( $idx++, $billingAddress->getAddress1() );
507
		$stmt->bind( $idx++, $billingAddress->getAddress2() );
508
		$stmt->bind( $idx++, $billingAddress->getAddress3() );
509
		$stmt->bind( $idx++, $billingAddress->getPostal() );
510
		$stmt->bind( $idx++, $billingAddress->getCity() );
511
		$stmt->bind( $idx++, $billingAddress->getState() );
512
		$stmt->bind( $idx++, $billingAddress->getCountryId() );
513
		$stmt->bind( $idx++, $billingAddress->getLanguageId() );
514
		$stmt->bind( $idx++, $billingAddress->getTelephone() );
515
		$stmt->bind( $idx++, $billingAddress->getTelefax() );
516
		$stmt->bind( $idx++, $billingAddress->getMobile() );
517
		$stmt->bind( $idx++, $billingAddress->getWebsite() );
518
		$stmt->bind( $idx++, $billingAddress->getLongitude(), \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT );
519
		$stmt->bind( $idx++, $billingAddress->getLatitude(), \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT );
520
		$stmt->bind( $idx++, $billingAddress->getBirthday() );
521
		$stmt->bind( $idx++, $item->getStatus(), \Aimeos\Base\DB\Statement\Base::PARAM_INT );
522
		$stmt->bind( $idx++, $item->getDateVerified() );
523
		$stmt->bind( $idx++, $item->getPassword() );
524
		$stmt->bind( $idx++, $date ); // Modification time
525
		$stmt->bind( $idx++, $context->editor() );
526
527
		if( $id !== null ) {
528
			$stmt->bind( $idx++, $context->locale()->getSiteId() . '%' );
529
			$stmt->bind( $idx++, $this->getUser()?->getSiteId() );
530
			$stmt->bind( $idx++, $id, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
531
			$item->setId( $id );
532
		} else {
533
			$stmt->bind( $idx++, $this->siteId( $item->getSiteId(), \Aimeos\MShop\Locale\Manager\Base::SITE_SUBTREE ) );
534
			$stmt->bind( $idx++, $date ); // Creation time
535
		}
536
537
		$stmt->execute()->finish();
538
539
		if( $id === null && $fetch === true )
540
		{
541
			/** mshop/customer/manager/laravel/newid
542
			 * Retrieves the ID generated by the database when inserting a new record
543
			 *
544
			 * As soon as a new record is inserted into the database table,
545
			 * the database server generates a new and unique identifier for
546
			 * that record. This ID can be used for retrieving, updating and
547
			 * deleting that specific record from the table again.
548
			 *
549
			 * For MySQL:
550
			 *  SELECT LAST_INSERT_ID()
551
			 * For PostgreSQL:
552
			 *  SELECT currval('seq_mcus_id')
553
			 * For SQL Server:
554
			 *  SELECT SCOPE_IDENTITY()
555
			 * For Oracle:
556
			 *  SELECT "seq_mcus_id".CURRVAL FROM DUAL
557
			 *
558
			 * There's no way to retrive the new ID by a SQL statements that
559
			 * fits for most database servers as they implement their own
560
			 * specific way.
561
			 *
562
			 * @param string SQL statement for retrieving the last inserted record ID
563
			 * @since 2015.01
564
			 * @category Developer
565
			 * @see mshop/customer/manager/laravel/insert
566
			 * @see mshop/customer/manager/laravel/update
567
			 * @see mshop/customer/manager/laravel/delete
568
			 * @see mshop/customer/manager/laravel/search
569
			 * @see mshop/customer/manager/laravel/count
570
			 */
571
			$path = 'mshop/customer/manager/laravel/newid';
572
			$item->setId( $this->newId( $conn, $path ) );
573
		}
574
575
		$item = $this->savePropertyItems( $item, 'customer' );
576
		$item = $this->saveAddressItems( $item, 'customer' );
577
		return $this->saveListItems( $item, 'customer' );
578
	}
579
580
581
	/**
582
	 * Returns the item objects matched by the given search criteria.
583
	 *
584
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria object
585
	 * @param integer &$total Number of items that are available in total
586
	 * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Customer\Item\Iface
587
	 * @throws \Aimeos\MShop\Customer\Exception If creating items failed
588
	 */
589
	public function search( \Aimeos\Base\Criteria\Iface $search, array $ref = [], int &$total = null ) : \Aimeos\Map
590
	{
591
		$conn = $this->context()->db( $this->getResourceName() );
592
		$map = [];
593
594
		$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
595
		$level = $this->context()->config()->get( 'mshop/customer/manager/sitemode', $level );
596
597
		$cfgPathSearch = 'mshop/customer/manager/laravel/search';
598
		$cfgPathCount = 'mshop/customer/manager/laravel/count';
599
		$required = ['customer'];
600
		$ref[] = 'group';
601
602
		$results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $level );
603
604
		while( ( $row = $results->fetch() ) !== null ) {
605
			$map[(string) $row['customer.id']] = $row;
606
		}
607
608
		$addrItems = [];
609
		if( in_array( 'customer/address', $ref, true ) ) {
610
			$addrItems = $this->getAddressItems( array_keys( $map ), 'customer' );
611
		}
612
613
		$propItems = []; $name = 'customer/property';
614
		if( isset( $ref[$name] ) || in_array( $name, $ref, true ) )
615
		{
616
			$propTypes = isset( $ref[$name] ) && is_array( $ref[$name] ) ? $ref[$name] : null;
617
			$propItems = $this->getPropertyItems( array_keys( $map ), 'customer', $propTypes );
618
		}
619
620
		return $this->buildItems( $map, $ref, 'customer', $addrItems, $propItems );
621
	}
622
623
624
	/**
625
	 * Returns a new manager for customer extensions
626
	 *
627
	 * @param string $manager Name of the sub manager type in lower case
628
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
629
	 * @return mixed Manager for different extensions, e.g stock, tags, locations, etc.
630
	 */
631
	public function getSubManager( string $manager, string $name = null ) : \Aimeos\MShop\Common\Manager\Iface
632
	{
633
		return $this->getSubManagerBase( 'customer', $manager, $name ?: 'Laravel' );
634
	}
635
}
636