Completed
Push — master ( 830d97...474f8e )
by Aimeos
01:45
created

Standard::checkUser()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2017-2018
6
 * @package Controller
7
 * @subpackage Frontend
8
 */
9
10
11
namespace Aimeos\Controller\Frontend\Customer;
12
13
14
/**
15
 * Default implementation of the customer frontend controller
16
 *
17
 * @package Controller
18
 * @subpackage Frontend
19
 */
20
class Standard
21
	extends \Aimeos\Controller\Frontend\Base
22
	implements Iface, \Aimeos\Controller\Frontend\Common\Iface
23
{
24
	/**
25
	 * Adds and returns a new customer item object
26
	 *
27
	 * @param array $values Values added to the newly created customer item like "customer.birthday"
28
	 * @return \Aimeos\MShop\Customer\Item\Iface Customer item
29
	 * @since 2017.04
30
	 */
31
	public function addItem( array $values )
32
	{
33
		$list = [];
34
		$context = $this->getContext();
35
		$config = $context->getConfig();
36
37
		foreach( $values as $key => $val ) {
38
			$list[str_replace( 'order.base.address', 'customer', $key )] = $val;
39
		}
40
41
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer' );
42
		$list = $this->addItemDefaults( $list );
43
		$passwd = $list['customer.password'];
44
45
		try
46
		{
47
			$item = $manager->findItem( $list['customer.code'], [], true );
48
		}
49
		catch( \Aimeos\MShop\Exception $e )
50
		{
51
			$this->checkLimit( $list );
52
53
			$item = $manager->createItem()->fromArray( $list )->setId( null );
0 ignored issues
show
Bug introduced by
The method setId cannot be called on $manager->createItem()->fromArray($list) (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
54
55
			/** controller/frontend/customer/groupids
56
			 * List of groups new customers should be assigned to
57
			 *
58
			 * Newly created customers will be assigned automatically to the groups
59
			 * given by their IDs. This is especially useful if those groups limit
60
			 * functionality for those users.
61
			 *
62
			 * @param array List of group IDs
63
			 * @since 2017.07
64
			 * @category User
65
			 * @category Developer
66
			 */
67
			$item->setGroups( (array) $config->get( 'controller/frontend/customer/groupids', [] ) );
68
69
			$item = $manager->saveItem( $item );
70
71
			$msg = $item->toArray();
72
			// Show only generated passwords in account creation e-mails
73
			$msg['customer.password'] = ( isset( $values['customer.password'] ) ? null : $passwd );
74
			$context->getMessageQueue( 'mq-email', 'customer/email/account' )->add( json_encode( $msg ) );
75
		}
76
77
		return $item;
78
	}
79
80
81
	/**
82
	 * Creates a new customer item object pre-filled with the given values but not yet stored
83
	 *
84
	 * @return \Aimeos\MShop\Customer\Item\Iface Customer item
85
	 */
86
	public function createItem( array $values = [] )
87
	{
88
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer' );
89
		return $manager->createItem()->fromArray( $values )->setId( null );
0 ignored issues
show
Bug introduced by
The method setId cannot be called on $manager->createItem()->fromArray($values) (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
90
	}
91
92
93
	/**
94
	 * Deletes a customer item that belongs to the current authenticated user
95
	 *
96
	 * @param string $id Unique customer ID
97
	 * @since 2017.04
98
	 */
99
	public function deleteItem( $id )
100
	{
101
		$this->checkUser( $id );
102
103
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer' );
104
		$manager->deleteItem( $id );
105
	}
106
107
108
	/**
109
	 * Updates the customer item identified by its ID
110
	 *
111
	 * @param string $id Unique customer ID
112
	 * @param array $values Values added to the customer item like "customer.birthday" or "customer.city"
113
	 * @return \Aimeos\MShop\Customer\Item\Iface Customer item
114
	 * @since 2017.04
115
	 */
116
	public function editItem( $id, array $values )
117
	{
118
		$this->checkUser( $id );
119
		unset( $values['customer.id'] );
120
121
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer' );
122
		$item = $manager->getItem( $id, ['customer/group'], true )->fromArray( $values );
123
124
		return $manager->saveItem( $item );
0 ignored issues
show
Documentation introduced by
$item is of type array, but the function expects a object<Aimeos\MShop\Common\Item\Iface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
125
	}
126
127
128
	/**
129
	 * Returns the customer item for the given customer ID
130
	 *
131
	 * @param string|null $id Unique customer ID or null for current customer item
132
	 * @param string[] $domains Domain names of items that are associated with the customers and that should be fetched too
133
	 * @return \Aimeos\MShop\Customer\Item\Iface Customer item including the referenced domains items
134
	 * @since 2017.04
135
	 */
136
	public function getItem( $id = null, array $domains = [] )
137
	{
138
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer' );
139
140
		if( $id == null ) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $id of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
141
			return $manager->getItem( $this->getContext()->getUserId(), $domains, true );
142
		}
143
144
		$this->checkUser( $id );
145
146
		return $manager->getItem( $id, $domains, true );
147
	}
148
149
150
	/**
151
	 * Returns the customer item for the given customer code (usually e-mail address)
152
	 *
153
	 * This method doesn't check if the customer item belongs to the logged in user!
154
	 *
155
	 * @param string $code Unique customer code
156
	 * @param string[] $domains Domain names of items that are associated with the customers and that should be fetched too
157
	 * @return \Aimeos\MShop\Customer\Item\Iface Customer item including the referenced domains items
158
	 * @since 2017.04
159
	 */
160
	public function findItem( $code, array $domains = [] )
161
	{
162
		return \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer' )->findItem( $code, $domains, true );
163
	}
164
165
166
	/**
167
	 * Stores a modified customer item
168
	 *
169
	 * @param \Aimeos\MShop\Customer\Item\Iface $item Customer item
170
	 * @return \Aimeos\MShop\Customer\Item\Address\Iface Customer address item including the generated ID
171
	 */
172
	public function saveItem( \Aimeos\MShop\Customer\Item\Iface $item )
173
	{
174
		return \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer' )->saveItem( $item );
175
	}
176
177
178
	/**
179
	 * Creates and returns a new item object
180
	 *
181
	 * @param array $values Values added to the newly created customer item like "customer.birthday"
182
	 * @return \Aimeos\MShop\Customer\Item\Address\Iface Customer address item
183
	 * @since 2017.04
184
	 */
185
	public function addAddressItem( array $values )
186
	{
187
		$context = $this->getContext();
188
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer/address' );
189
190
		$item = $manager->createItem()->fromArray( $values )->setId( null )->setParentId( $context->getUserId() );
0 ignored issues
show
Bug introduced by
The method setId cannot be called on $manager->createItem()->fromArray($values) (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
191
		return $manager->saveItem( $item );
192
	}
193
194
195
	/**
196
	 * Creates a new customer address item object pre-filled with the given values but not yet stored
197
	 *
198
	 * @return \Aimeos\MShop\Customer\Item\Address\Iface Customer address item
199
	 */
200
	public function createAddressItem( array $values = [] )
201
	{
202
		$context = $this->getContext();
203
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer/address' );
204
205
		return $manager->createItem()->fromArray( $values )->setId( null )->setParentId( $context->getUserId() );
0 ignored issues
show
Bug introduced by
The method setId cannot be called on $manager->createItem()->fromArray($values) (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
206
	}
207
208
209
	/**
210
	 * Deletes a customer item that belongs to the current authenticated user
211
	 *
212
	 * @param string $id Unique customer address ID
213
	 * @since 2017.04
214
	 */
215
	public function deleteAddressItem( $id )
216
	{
217
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer/address' );
218
219
		$this->checkUser( $manager->getItem( $id, [], true )->getParentId() );
220
221
		$manager->deleteItem( $id );
222
	}
223
224
225
	/**
226
	 * Saves a modified customer item object
227
	 *
228
	 * @param string $id Unique customer address ID
229
	 * @param array $values Values added to the customer item like "customer.address.city"
230
	 * @return \Aimeos\MShop\Customer\Item\Address\Iface Customer address item
231
	 * @since 2017.04
232
	 */
233
	public function editAddressItem( $id, array $values )
234
	{
235
		unset( $values['customer.address.id'] );
236
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer/address' );
237
238
		$item = $manager->getItem( $id, [], true );
239
		$this->checkUser( $item->getParentId() );
240
241
		return $manager->saveItem( $item->fromArray( $values ) );
0 ignored issues
show
Documentation introduced by
$item->fromArray($values) is of type array, but the function expects a object<Aimeos\MShop\Common\Item\Iface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
242
	}
243
244
245
	/**
246
	 * Returns the customer item for the given customer ID
247
	 *
248
	 * @param string $id Unique customer address ID
249
	 * @return \Aimeos\MShop\Customer\Item\Address\Iface Customer address item
250
	 * @since 2017.04
251
	 */
252
	public function getAddressItem( $id )
253
	{
254
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer/address' );
255
256
		$item = $manager->getItem( $id );
257
		$this->checkUser( $item->getParentId() );
258
259
		return $item;
260
	}
261
262
263
	/**
264
	 * Stores a modified customer address item
265
	 *
266
	 * @param \Aimeos\MShop\Customer\Item\Address\Iface $item Customer address item
267
	 * @return \Aimeos\MShop\Customer\Item\Address\Iface Customer address item including the generated ID
268
	 */
269
	public function saveAddressItem( \Aimeos\MShop\Customer\Item\Address\Iface $item )
270
	{
271
		return \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer/address' )->saveItem( $item );
272
	}
273
274
275
	/**
276
	 * Creates and returns a new list item object
277
	 *
278
	 * @param array $values Values added to the newly created customer item like "customer.lists.refid"
279
	 * @return \Aimeos\MShop\Common\Item\Lists\Iface Customer lists item
280
	 * @since 2017.06
281
	 */
282
	public function addListItem( array $values )
283
	{
284
		$context = $this->getContext();
285
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer/lists' );
286
287
		if( !isset( $values['customer.lists.typeid'] ) )
288
		{
289
			if( !isset( $values['customer.lists.type'] ) ) {
290
				throw new \Aimeos\Controller\Frontend\Customer\Exception( sprintf( 'No customer lists type code' ) );
291
			}
292
293
			if( !isset( $values['customer.lists.domain'] ) ) {
294
				throw new \Aimeos\Controller\Frontend\Customer\Exception( sprintf( 'No customer lists domain' ) );
295
			}
296
297
			$typeManager = \Aimeos\MShop\Factory::createManager( $context, 'customer/lists/type' );
298
			$typeItem = $typeManager->findItem( $values['customer.lists.type'], [], $values['customer.lists.domain'] );
299
			$values['customer.lists.typeid'] = $typeItem->getId();
300
		}
301
302
		$item = $manager->createItem()->fromArray( $values )->setId( null )->setParentId( $context->getUserId() );
0 ignored issues
show
Bug introduced by
The method setId cannot be called on $manager->createItem()->fromArray($values) (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
303
		return $manager->saveItem( $item );
304
	}
305
306
307
	/**
308
	 * Returns a new customer lists filter criteria object
309
	 *
310
	 * @return \Aimeos\MW\Criteria\Iface New filter object
311
	 * @since 2017.06
312
	 */
313
	public function createListsFilter()
314
	{
315
		$context = $this->getContext();
316
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer/lists' );
317
318
		$filter = $manager->createSearch();
319
		$filter->setConditions( $filter->compare( '==', 'customer.lists.parentid', $context->getUserId() ) );
320
321
		return $filter;
322
	}
323
324
325
	/**
326
	 * Deletes a customer item that belongs to the current authenticated user
327
	 *
328
	 * @param string $id Unique customer address ID
329
	 * @since 2017.06
330
	 */
331
	public function deleteListItem( $id )
332
	{
333
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer/lists' );
334
335
		$this->checkUser( $manager->getItem( $id )->getParentId() );
336
337
		$manager->deleteItem( $id );
338
	}
339
340
341
	/**
342
	 * Saves a modified customer lists item object
343
	 *
344
	 * @param string $id Unique customer lists ID
345
	 * @param array $values Values added to the customer lists item like "customer.lists.refid"
346
	 * @return \Aimeos\MShop\Common\Item\Lists\Iface Customer lists item
347
	 * @since 2017.06
348
	 */
349
	public function editListItem( $id, array $values )
350
	{
351
		$context = $this->getContext();
352
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer/lists' );
353
354
		$item = $manager->getItem( $id, [], true );
355
		$this->checkUser( $item->getParentId() );
356
		unset( $values['customer.lists.id'] );
357
358
		if( !isset( $values['customer.lists.typeid'] ) )
359
		{
360
			if( !isset( $values['customer.lists.type'] ) ) {
361
				throw new \Aimeos\Controller\Frontend\Customer\Exception( sprintf( 'No customer lists type code' ) );
362
			}
363
364
			if( !isset( $values['customer.lists.domain'] ) ) {
365
				throw new \Aimeos\Controller\Frontend\Customer\Exception( sprintf( 'No customer lists domain' ) );
366
			}
367
368
			$typeManager = \Aimeos\MShop\Factory::createManager( $context, 'customer/lists/type' );
369
			$typeItem = $typeManager->findItem( $values['customer.lists.type'], [], $values['customer.lists.domain'], true );
370
			$values['customer.lists.typeid'] = $typeItem->getId();
371
		}
372
373
		return $manager->saveItem( $item->fromArray( $values ) );
0 ignored issues
show
Documentation introduced by
$item->fromArray($values) is of type array, but the function expects a object<Aimeos\MShop\Common\Item\Iface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
374
	}
375
376
377
	/**
378
	 * Returns the customer item for the given customer ID
379
	 *
380
	 * @param string $id Unique customer address ID
381
	 * @return \Aimeos\MShop\Customer\Item\Address\Iface Customer address item
382
	 * @since 2017.06
383
	 */
384
	public function getListItem( $id )
385
	{
386
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer/lists' );
387
		$item = $manager->getItem( $id );
388
389
		$this->checkUser( $item->getParentId() );
390
391
		return $item;
392
	}
393
394
395
	/**
396
	 * Returns the customer lists items filtered by the given criteria
397
	 *
398
	 * @param \Aimeos\MW\Criteria\Iface $filter Criteria object which contains the filter conditions
399
	 * @param integer &$total Parameter where the total number of found attributes will be stored in
400
	 * @return \Aimeos\MShop\Common\Item\Lists\Iface[] Customer list items
401
	 * @since 2017.06
402
	 */
403
	public function searchListItems( \Aimeos\MW\Criteria\Iface $filter, &$total = null )
404
	{
405
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'customer/lists' );
406
407
		return $manager->searchItems( $filter, [], $total );
408
	}
409
410
411
	/**
412
	 * Adds the default values for customer items if not yet available
413
	 *
414
	 * @param string[] $values Associative list of customer keys (e.g. "customer.label") and their values
415
	 * @return string[] Associative list of customer key/value pairs with default values set
416
	 */
417
	protected function addItemDefaults( array $values )
418
	{
419
		if( !isset( $values['customer.label'] ) || $values['customer.label'] == '' )
420
		{
421
			$label = '';
422
423
			if( isset( $values['customer.lastname'] ) ) {
424
				$label = $values['customer.lastname'];
425
			}
426
427
			if( isset( $values['customer.firstname'] ) && $values['customer.firstname'] != '' ) {
428
				$label = $values['customer.firstname'] . ' ' . $label;
429
			}
430
431
			if( isset( $values['customer.company'] ) && $values['customer.company'] != '' ) {
432
				$label .= ' (' . $values['customer.company'] . ')';
433
			}
434
435
			$values['customer.label'] = $label;
436
		}
437
438
		if( !isset( $values['customer.code'] ) && isset( $values['customer.email'] ) ) {
439
			$values['customer.code'] = $values['customer.email'];
440
		}
441
442
		if( !isset( $values['customer.password'] ) ) {
443
			$values['customer.password'] = substr( md5( microtime( true ) . getmypid() . rand() ), -8 );
444
		}
445
446
		return $values;
447
	}
448
449
450
	/**
451
	 * Checks if the current user is allowed to create more customer accounts
452
	 *
453
	 * @param string[] $values Associative list of customer keys (e.g. "customer.label") and their values
454
	 * @throws \Aimeos\Controller\Frontend\Customer\Exception If access isn't allowed
455
	 */
456
	protected function checkLimit( array $values )
0 ignored issues
show
Unused Code introduced by
The parameter $values is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
457
	{
458
		$total = 0;
459
		$context = $this->getContext();
460
		$config = $context->getConfig();
461
462
		/** controller/frontend/customer/limit-count
463
		 * Maximum number of customers within the time frame
464
		 *
465
		 * Creating new customers is limited to avoid abuse and mitigate denial of
466
		 * service attacks. The number of customer accountss created within the
467
		 * time frame configured by "controller/frontend/customer/limit-seconds"
468
		 * are counted before a new customer account (identified by the IP address)
469
		 * is created. If the number of accounts is higher than the configured value,
470
		 * an error message will be shown to the user instead of creating a new account.
471
		 *
472
		 * @param integer Number of customer accounts allowed within the time frame
473
		 * @since 2017.07
474
		 * @category Developer
475
		 * @see controller/frontend/customer/limit-seconds
476
		 */
477
		$count = $config->get( 'controller/frontend/customer/limit-count', 5 );
478
479
		/** controller/frontend/customer/limit-seconds
480
		 * Customer account limitation time frame in seconds
481
		 *
482
		 * Creating new customer accounts is limited to avoid abuse and mitigate
483
		 * denial of service attacks. Within the configured time frame, only a
484
		 * limited number of customer accounts can be created. All accounts from
485
		 * the same source (identified by the IP address) within the last X
486
		 * seconds are counted. If the total value is higher then the number
487
		 * configured in "controller/frontend/customer/limit-count", an error
488
		 * message will be shown to the user instead of creating a new account.
489
		 *
490
		 * @param integer Number of seconds to check customer accounts within
491
		 * @since 2017.07
492
		 * @category Developer
493
		 * @see controller/frontend/customer/limit-count
494
		 */
495
		$seconds = $config->get( 'controller/frontend/customer/limit-seconds', 300 );
496
497
		$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer' );
498
499
		$search = $manager->createSearch();
500
		$expr = [
501
			$search->compare( '==', 'customer.editor', $context->getEditor() ),
502
			$search->compare( '>=', 'customer.ctime', date( 'Y-m-d H:i:s', time() - $seconds ) ),
503
		];
504
		$search->setConditions( $search->combine( '&&', $expr ) );
505
		$search->setSlice( 0, 0 );
506
507
		$manager->searchItems( $search, [], $total );
508
509
		if( $total > $count ) {
510
			throw new \Aimeos\Controller\Frontend\Basket\Exception( sprintf( 'Temporary limit reached' ) );
511
		}
512
	}
513
514
515
	/**
516
	 * Checks if the current user is allowed to retrieve the customer data for the given ID
517
	 *
518
	 * @param string $id Unique customer ID
519
	 * @throws \Aimeos\Controller\Frontend\Customer\Exception If access isn't allowed
520
	 */
521
	protected function checkUser( $id )
522
	{
523
		if( $id != $this->getContext()->getUserId() )
524
		{
525
			$msg = sprintf( 'Not allowed to access customer data for ID "%1$s"', $id );
526
			throw new \Aimeos\Controller\Frontend\Customer\Exception( $msg );
527
		}
528
	}
529
}
530