Passed
Push — master ( c421f6...de9386 )
by Aimeos
03:07
created

Laravel::getUser()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 7
rs 10
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2023
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
	private ?\Aimeos\MShop\Customer\Item\Iface $user = null;
237
238
239
	/**
240
	 * Initializes the object.
241
	 *
242
	 * @param \Aimeos\MShop\ContextIface $context Context object
243
	 */
244
	public function __construct( \Aimeos\MShop\ContextIface $context )
245
	{
246
		parent::__construct( $context );
247
248
		$level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
249
		$level = $context->config()->get( 'mshop/customer/manager/sitemode', $level );
250
251
252
		$this->searchConfig['customer:has']['function'] = function( &$source, array $params ) use ( $level ) {
253
254
			$keys = [];
255
256
			foreach( (array) ( $params[1] ?? '' ) as $type ) {
257
				foreach( (array) ( $params[2] ?? '' ) as $id ) {
258
					$keys[] = $params[0] . '|' . ( $type ? $type . '|' : '' ) . $id;
259
				}
260
			}
261
262
			$sitestr = $this->siteString( 'mcusli."siteid"', $level );
263
			$keystr = $this->toExpression( 'mcusli."key"', $keys, ( $params[2] ?? null ) ? '==' : '=~' );
264
			$source = str_replace( [':site', ':key'], [$sitestr, $keystr], $source );
265
266
			return $params;
267
		};
268
269
270
		$this->searchConfig['customer:prop']['function'] = function( &$source, array $params ) use ( $level ) {
271
272
			$keys = [];
273
			$langs = array_key_exists( 1, $params ) ? ( $params[1] ?? 'null' ) : '';
274
275
			foreach( (array) $langs as $lang ) {
276
				foreach( (array) ( $params[2] ?? '' ) as $val ) {
277
					$keys[] = substr( $params[0] . '|' . ( $lang === null ? 'null|' : ( $lang ? $lang . '|' : '' ) ) . $val, 0, 255 );
278
				}
279
			}
280
281
			$sitestr = $this->siteString( 'mcuspr."siteid"', $level );
282
			$keystr = $this->toExpression( 'mcuspr."key"', $keys, ( $params[2] ?? null ) ? '==' : '=~' );
283
			$source = str_replace( [':site', ':key'], [$sitestr, $keystr], $source );
284
285
			return $params;
286
		};
287
	}
288
289
290
	/**
291
	 * Counts the number items that are available for the values of the given key.
292
	 *
293
	 * @param \Aimeos\Base\Criteria\Iface $search Search criteria
294
	 * @param array|string $key Search key or list of key to aggregate items for
295
	 * @param string|null $value Search key for aggregating the value column
296
	 * @param string|null $type Type of the aggregation, empty string for count or "sum" or "avg" (average)
297
	 * @return \Aimeos\Map List of the search keys as key and the number of counted items as value
298
	 */
299
	public function aggregate( \Aimeos\Base\Criteria\Iface $search, $key, string $value = null, string $type = null ) : \Aimeos\Map
300
	{
301
		/** mshop/customer/manager/laravel//aggregate/mysql
302
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
303
		 *
304
		 * @see mshop/customer/manager/laravel//aggregate/ansi
305
		 */
306
307
		/** mshop/customer/manager/laravel//aggregate/ansi
308
		 * Counts the number of records grouped by the values in the key column and matched by the given criteria
309
		 *
310
		 * Groups all records by the values in the key column and counts their
311
		 * occurence. The matched records can be limited by the given criteria
312
		 * from the customer database. The records must be from one of the sites
313
		 * that are configured via the context item. If the current site is part
314
		 * of a tree of sites, the statement can count all records from the
315
		 * current site and the complete sub-tree of sites.
316
		 *
317
		 * As the records can normally be limited by criteria from sub-managers,
318
		 * their tables must be joined in the SQL context. This is done by
319
		 * using the "internaldeps" property from the definition of the ID
320
		 * column of the sub-managers. These internal dependencies specify
321
		 * the JOIN between the tables and the used columns for joining. The
322
		 * ":joins" placeholder is then replaced by the JOIN strings from
323
		 * the sub-managers.
324
		 *
325
		 * To limit the records matched, conditions can be added to the given
326
		 * criteria object. It can contain comparisons like column names that
327
		 * must match specific values which can be combined by AND, OR or NOT
328
		 * operators. The resulting string of SQL conditions replaces the
329
		 * ":cond" placeholder before the statement is sent to the database
330
		 * server.
331
		 *
332
		 * This statement doesn't return any records. Instead, it returns pairs
333
		 * of the different values found in the key column together with the
334
		 * number of records that have been found for that key values.
335
		 *
336
		 * The SQL statement should conform to the ANSI standard to be
337
		 * compatible with most relational database systems. This also
338
		 * includes using double quotes for table and column names.
339
		 *
340
		 * @param string SQL statement for aggregating customer items
341
		 * @since 2021.04
342
		 * @category Developer
343
		 * @see mshop/customer/manager/laravel//insert/ansi
344
		 * @see mshop/customer/manager/laravel//update/ansi
345
		 * @see mshop/customer/manager/laravel//newid/ansi
346
		 * @see mshop/customer/manager/laravel//delete/ansi
347
		 * @see mshop/customer/manager/laravel//search/ansi
348
		 * @see mshop/customer/manager/laravel//count/ansi
349
		 */
350
351
		$cfgkey = 'mshop/customer/manager/laravel/aggregate' . $type;
352
		return $this->aggregateBase( $search, $key, $cfgkey, ['customer'], $value );
353
	}
354
355
356
	/**
357
	 * Removes old entries from the storage.
358
	 *
359
	 * @param iterable $siteids List of IDs for sites whose entries should be deleted
360
	 * @return \Aimeos\MShop\Common\Manager\Iface Same object for fluent interface
361
	 */
362
	public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
363
	{
364
		$path = 'mshop/customer/manager/submanagers';
365
		$default = ['address', 'lists', 'property'];
366
367
		foreach( $this->context()->config()->get( $path, $default ) as $domain ) {
368
			$this->object()->getSubManager( $domain )->clear( $siteids );
369
		}
370
371
		return $this->clearBase( $siteids, 'mshop/customer/manager/laravel/clear' );
372
	}
373
374
375
	/**
376
	 * Removes multiple items.
377
	 *
378
	 * @param \Aimeos\MShop\Common\Item\Iface[]|string[] $itemIds List of item objects or IDs of the items
379
	 * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
380
	 */
381
	public function delete( $itemIds ) : \Aimeos\MShop\Common\Manager\Iface
382
	{
383
		if( map( $itemIds )->isEmpty() ) {
384
			return $this;
385
		}
386
387
		$search = $this->object()->filter();
388
		$search->setConditions( $search->compare( '==', 'id', $itemIds ) );
389
390
		$types = array( 'id' => \Aimeos\Base\DB\Statement\Base::PARAM_STR );
391
		$translations = array( 'id' => '"id"' );
392
393
		$cond = $search->getConditionSource( $types, $translations );
394
		$sql = str_replace( ':cond', $cond, $this->getSqlConfig( 'mshop/customer/manager/laravel/delete' ) );
395
396
		$context = $this->context();
397
		$conn = $context->db( $this->getResourceName() );
398
399
		$stmt = $conn->create( $sql );
400
		$stmt->bind( 1, $context->locale()->getSiteId() . '%' );
401
		$stmt->bind( 2, $this->getUser()?->getSiteId() );
402
403
		$stmt->execute()->finish();
404
405
		return $this->deleteRefItems( $itemIds );
406
	}
407
408
409
	/**
410
	 * Returns the list attributes that can be used for searching.
411
	 *
412
	 * @param bool $withsub Return also attributes of sub-managers if true
413
	 * @return array List of attribute items implementing \Aimeos\Base\Criteria\Attribute\Iface
414
	 */
415
	public function getSearchAttributes( bool $withsub = true ) : array
416
	{
417
		$path = 'mshop/customer/manager/submanagers';
418
		return $this->getSearchAttributesBase( $this->searchConfig, $path, ['address'], $withsub );
419
	}
420
421
422
	/**
423
	 * Saves a customer item object.
424
	 *
425
	 * @param \Aimeos\MShop\Customer\Item\Iface $item Customer item object
426
	 * @param boolean $fetch True if the new ID should be returned in the item
427
	 * @return \Aimeos\MShop\Customer\Item\Iface $item Updated item including the generated ID
428
	 */
429
	protected function saveItem( \Aimeos\MShop\Customer\Item\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Customer\Item\Iface
430
	{
431
		$item = $this->addGroups( $item );
432
433
		if( !$item->isModified() )
434
		{
435
			$item = $this->savePropertyItems( $item, 'customer' );
436
			$item = $this->saveAddressItems( $item, 'customer' );
437
			return $this->saveListItems( $item, 'customer' );
438
		}
439
440
		$context = $this->context();
441
		$conn = $context->db( $this->getResourceName() );
442
443
		$id = $item->getId();
444
		$date = date( 'Y-m-d H:i:s' );
445
		$billingAddress = $item->getPaymentAddress();
446
		$columns = $this->object()->getSaveAttributes();
447
448
		if( $id === null )
449
		{
450
			/** mshop/customer/manager/laravel/insert
451
			 * Inserts a new customer record into the database table
452
			 *
453
			 * Items with no ID yet (i.e. the ID is NULL) will be created in
454
			 * the database and the newly created ID retrieved afterwards
455
			 * using the "newid" SQL statement.
456
			 *
457
			 * The SQL statement must be a string suitable for being used as
458
			 * prepared statement. It must include question marks for binding
459
			 * the values from the customer item to the statement before they are
460
			 * sent to the database server. The number of question marks must
461
			 * be the same as the number of columns listed in the INSERT
462
			 * statement. The order of the columns must correspond to the
463
			 * order in the save() method, so the correct values are
464
			 * bound to the columns.
465
			 *
466
			 * The SQL statement should conform to the ANSI standard to be
467
			 * compatible with most relational database systems. This also
468
			 * includes using double quotes for table and column names.
469
			 *
470
			 * @param string SQL statement for inserting records
471
			 * @since 2015.01
472
			 * @category Developer
473
			 * @see mshop/customer/manager/laravel/update
474
			 * @see mshop/customer/manager/laravel/newid
475
			 * @see mshop/customer/manager/laravel/delete
476
			 * @see mshop/customer/manager/laravel/search
477
			 * @see mshop/customer/manager/laravel/count
478
			 */
479
			$path = 'mshop/customer/manager/laravel/insert';
480
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ) );
0 ignored issues
show
Bug introduced by
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

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