Passed
Push — master ( c9dfc7...a4ce90 )
by Aimeos
01:38
created

Standard::use()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
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
	private $domains = [];
25
	private $manager;
26
	private $item;
27
28
29
	/**
30
	 * Initializes the controller
31
	 *
32
	 * @param \Aimeos\MShop\Context\Item\Iface $context Common MShop context object
33
	 */
34
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
35
	{
36
		parent::__construct( $context );
37
38
		/** controller/frontend/customer/groupids
39
		 * List of groups new customers should be assigned to
40
		 *
41
		 * Newly created customers will be assigned automatically to the groups
42
		 * given by their IDs. This is especially useful if those groups limit
43
		 * functionality for those users.
44
		 *
45
		 * @param array List of group IDs
46
		 * @since 2017.07
47
		 * @category User
48
		 * @category Developer
49
		 */
50
		$groupIds = (array) $context->getConfig()->get( 'controller/frontend/customer/groupids', [] );
51
52
		$this->manager = \Aimeos\MShop::create( $context, 'customer' );
53
		$this->item = $this->manager->createItem()->setGroups( $groupIds );
0 ignored issues
show
Bug introduced by
The method setGroups() does not exist on Aimeos\MShop\Attribute\Item\Iface. ( Ignorable by Annotation )

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

53
		$this->item = $this->manager->createItem()->/** @scrutinizer ignore-call */ setGroups( $groupIds );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
54
	}
55
56
57
	/**
58
	 * Clones objects in controller and resets values
59
	 */
60
	public function __clone()
61
	{
62
		$this->item = clone $this->item;
63
	}
64
65
66
	/**
67
	 * Creates a new customer item object pre-filled with the given values but not yet stored
68
	 *
69
	 * @param array $values Values added to the customer item (new or existing) like "customer.code"
70
	 * @return \Aimeos\Controller\Frontend\Customer\Iface Customer controller for fluent interface
71
	 * @since 2019.04
72
	 */
73
	public function add( array $values )
74
	{
75
		$item = $this->item->fromArray( $values );
76
		$addrItem = $item->getPaymentAddress();
77
78
		if( $item->getLabel() === '' )
79
		{
80
			$label = $addrItem->getLastname();
81
82
			if( ( $firstName = $addrItem->getFirstname() ) !== '' ) {
83
				$label = $firstName . ' ' . $label;
84
			}
85
86
			if( ( $company = $addrItem->getCompany() ) !== '' ) {
87
				$label .= ' (' . $company . ')';
88
			}
89
90
			$item = $item->setLabel( $label );
91
		}
92
93
		if( $item->getCode() === '' ) {
94
			$item = $item->setCode( $addrItem->getEmail() );
95
		}
96
97
		$this->item = $item;
98
		return $this;
99
	}
100
101
102
	/**
103
	 * Adds the given address item to the customer object (not yet stored)
104
	 *
105
	 * @param \Aimeos\MShop\Common\Item\Address\Iface $item Address item to add
106
	 * @param integer|null $idx Key in the list of address items or null to add the item at the end
107
	 * @return \Aimeos\Controller\Frontend\Customer\Iface Customer controller for fluent interface
108
	 * @since 2019.04
109
	 */
110
	public function addAddressItem( \Aimeos\MShop\Common\Item\Address\Iface $item, $idx = null )
111
	{
112
		$this->item = $this->item->addAddressItem( $item, $idx );
113
		return $this;
114
	}
115
116
117
	/**
118
	 * Adds the given list item to the customer object (not yet stored)
119
	 *
120
	 * @param string $domain Domain name the referenced item belongs to
121
	 * @param \Aimeos\MShop\Common\Item\Lists\Iface $item List item to add
122
	 * @param \Aimeos\MShop\Common\Item\Iface|null $refItem Referenced item to add or null if list item contains refid value
123
	 * @return \Aimeos\Controller\Frontend\Customer\Iface Customer controller for fluent interface
124
	 * @since 2019.04
125
	 */
126
	public function addListItem( $domain, \Aimeos\MShop\Common\Item\Lists\Iface $item, \Aimeos\MShop\Common\Item\Iface $refItem = null )
127
	{
128
		$this->item = $this->item->addListItem( $domain, $item, $refItem );
129
		return $this;
130
	}
131
132
133
	/**
134
	 * Adds the given property item to the customer object (not yet stored)
135
	 *
136
	 * @param \Aimeos\MShop\Common\Item\Property\Iface $item Property item to add
137
	 * @return \Aimeos\Controller\Frontend\Customer\Iface Customer controller for fluent interface
138
	 * @since 2019.04
139
	 */
140
	public function addPropertyItem( \Aimeos\MShop\Common\Item\Property\Iface $item )
141
	{
142
		$this->item = $this->item->addPropertyItem( $item );
143
		return $this;
144
	}
145
146
147
	/**
148
	 * Creates a new address item object pre-filled with the given values
149
	 *
150
	 * @return \Aimeos\MShop\Customer\Item\Address\Iface Address item
151
	 * @since 2019.04
152
	 */
153
	public function createAddressItem( array $values = [] )
154
	{
155
		$manager = \Aimeos\MShop::create( $this->getContext(), 'customer/address' );
156
		return $manager->createItem()->fromArray( $values );
157
	}
158
159
160
	/**
161
	 * Creates a new list item object pre-filled with the given values
162
	 *
163
	 * @return \Aimeos\MShop\Common\Item\Lists\Iface List item
164
	 * @since 2019.04
165
	 */
166
	public function createListItem( array $values = [] )
167
	{
168
		$manager = \Aimeos\MShop::create( $this->getContext(), 'customer/lists' );
169
		return $manager->createItem()->fromArray( $values );
170
	}
171
172
173
	/**
174
	 * Creates a new property item object pre-filled with the given values
175
	 *
176
	 * @return \Aimeos\MShop\Common\Item\Property\Iface Property item
177
	 * @since 2019.04
178
	 */
179
	public function createPropertyItem( array $values = [] )
180
	{
181
		$manager = \Aimeos\MShop::create( $this->getContext(), 'customer/property' );
182
		return $manager->createItem()->fromArray( $values );
183
	}
184
185
186
	/**
187
	 * Deletes a customer item that belongs to the current authenticated user
188
	 *
189
	 * @return \Aimeos\MShop\Customer\Item\Iface Customer item including the referenced domains items
190
	 * @since 2019.04
191
	 */
192
	public function delete()
193
	{
194
		if( $this->item && $this->item->getId() ) {
195
			\Aimeos\MShop::create( $this->getContext(), 'customer' )->deleteItem( $this->item->getId() );
196
		}
197
198
		return $this;
199
	}
200
201
202
	/**
203
	 * Removes the given address item from the customer object (not yet stored)
204
	 *
205
	 * @param \Aimeos\MShop\Common\Item\Address\Iface $item Address item to remove
206
	 * @return \Aimeos\Controller\Frontend\Customer\Iface Customer controller for fluent interface
207
	 */
208
	public function deleteAddressItem( \Aimeos\MShop\Common\Item\Address\Iface $item )
209
	{
210
		$this->item = $this->item->deleteAddressItem( $item );
211
		return $this;
212
	}
213
214
215
	/**
216
	 * Removes the given list item from the customer object (not yet stored)
217
	 *
218
	 * @param string $domain Domain name the referenced item belongs to
219
	 * @param \Aimeos\MShop\Common\Item\Lists\Iface $item List item to remove
220
	 * @param \Aimeos\MShop\Common\Item\Iface|null $refItem Referenced item to remove or null if only list item should be removed
221
	 * @return \Aimeos\Controller\Frontend\Customer\Iface Customer controller for fluent interface
222
	 */
223
	public function deleteListItem( $domain, \Aimeos\MShop\Common\Item\Lists\Iface $listItem, \Aimeos\MShop\Common\Item\Iface $refItem = null )
224
	{
225
		$this->item = $this->item->deleteListItem( $domain, $listItem, $refItem );
226
		return $this;
227
	}
228
229
230
	/**
231
	 * Removes the given property item from the customer object (not yet stored)
232
	 *
233
	 * @param \Aimeos\MShop\Common\Item\Property\Iface $item Property item to remove
234
	 * @return \Aimeos\Controller\Frontend\Customer\Iface Customer controller for fluent interface
235
	 */
236
	public function deletePropertyItem( \Aimeos\MShop\Common\Item\Property\Iface $item )
237
	{
238
		$this->item = $this->item->deletePropertyItem( $item );
239
		return $this;
240
	}
241
242
243
	/**
244
	 * Returns the customer item for the given customer code (usually e-mail address)
245
	 *
246
	 * This method doesn't check if the customer item belongs to the logged in user!
247
	 *
248
	 * @param string $code Unique customer code
249
	 * @return \Aimeos\MShop\Customer\Item\Iface Customer item including the referenced domains items
250
	 * @since 2019.04
251
	 */
252
	public function find( $code )
253
	{
254
		return $this->manager->findItem( $code, $this->domains, true );
255
	}
256
257
258
	/**
259
	 * Returns the customer item for the current authenticated user
260
	 *
261
	 * @return \Aimeos\MShop\Customer\Item\Iface Customer item including the referenced domains items
262
	 * @since 2019.04
263
	 */
264
	public function get()
265
	{
266
		return $this->item;
267
	}
268
269
270
	/**
271
	 * Adds or updates a modified customer item in the storage
272
	 *
273
	 * @return \Aimeos\Controller\Frontend\Customer\Iface Customer controller for fluent interface
274
	 * @since 2019.04
275
	 */
276
	public function store()
277
	{
278
		( $id = $this->item->getId() ) !== null ? $this->checkId( $id ) : $this->checkLimit();
279
		$context = $this->getContext();
280
281
		if( $id === null )
282
		{
283
			$msg = $this->item->toArray();
284
			$msg['customer.password'] = null;
285
286
			// Show only generated passwords in account creation e-mails
287
			if( $this->item->getPassword() === '' ) {
288
				$msg['customer.password'] = substr( sha1( microtime( true ) . getmypid() . rand() ), -8 );
289
			}
290
291
			$context->getMessageQueue( 'mq-email', 'customer/email/account' )->add( json_encode( $msg ) );
292
		}
293
294
		$this->item = $this->manager->saveItem( $this->item );
295
		return $this;
296
	}
297
298
299
	/**
300
	 * Sets the domains that will be used when working with the customer item
301
	 *
302
	 * @param array $domains Domain names of the referenced items that should be fetched too
303
	 * @return \Aimeos\Controller\Frontend\Customer\Iface Customer controller for fluent interface
304
	 * @since 2019.04
305
	 */
306
	public function uses( array $domains )
307
	{
308
		$this->domains = $domains;
309
310
		if( ( $id = $this->getContext()->getUserId() ) !== null ) {
0 ignored issues
show
introduced by
The condition $id = $this->getContext()->getUserId() !== null is always true.
Loading history...
311
			$this->item = $this->manager->getItem( $id, $domains, true );
312
		}
313
314
		return $this;
315
	}
316
317
318
	/**
319
	 * Checks if the current user is allowed to create more customer accounts
320
	 *
321
	 * @throws \Aimeos\Controller\Frontend\Customer\Exception If access isn't allowed
322
	 */
323
	protected function checkLimit()
324
	{
325
		$total = 0;
326
		$context = $this->getContext();
327
		$config = $context->getConfig();
328
329
		/** controller/frontend/customer/limit-count
330
		 * Maximum number of customers within the time frame
331
		 *
332
		 * Creating new customers is limited to avoid abuse and mitigate denial of
333
		 * service attacks. The number of customer accountss created within the
334
		 * time frame configured by "controller/frontend/customer/limit-seconds"
335
		 * are counted before a new customer account (identified by the IP address)
336
		 * is created. If the number of accounts is higher than the configured value,
337
		 * an error message will be shown to the user instead of creating a new account.
338
		 *
339
		 * @param integer Number of customer accounts allowed within the time frame
340
		 * @since 2017.07
341
		 * @category Developer
342
		 * @see controller/frontend/customer/limit-seconds
343
		 */
344
		$count = $config->get( 'controller/frontend/customer/limit-count', 5 );
345
346
		/** controller/frontend/customer/limit-seconds
347
		 * Customer account limitation time frame in seconds
348
		 *
349
		 * Creating new customer accounts is limited to avoid abuse and mitigate
350
		 * denial of service attacks. Within the configured time frame, only a
351
		 * limited number of customer accounts can be created. All accounts from
352
		 * the same source (identified by the IP address) within the last X
353
		 * seconds are counted. If the total value is higher then the number
354
		 * configured in "controller/frontend/customer/limit-count", an error
355
		 * message will be shown to the user instead of creating a new account.
356
		 *
357
		 * @param integer Number of seconds to check customer accounts within
358
		 * @since 2017.07
359
		 * @category Developer
360
		 * @see controller/frontend/customer/limit-count
361
		 */
362
		$seconds = $config->get( 'controller/frontend/customer/limit-seconds', 300 );
363
364
		$search = $this->manager->createSearch()->setSlice( 0, 0 );
365
		$expr = [
366
			$search->compare( '==', 'customer.editor', $context->getEditor() ),
367
			$search->compare( '>=', 'customer.ctime', date( 'Y-m-d H:i:s', time() - $seconds ) ),
368
		];
369
		$search->setConditions( $search->combine( '&&', $expr ) );
370
371
		$this->manager->searchItems( $search, [], $total );
372
373
		if( $total > $count ) {
374
			throw new \Aimeos\Controller\Frontend\Customer\Exception( sprintf( 'Temporary limit reached' ) );
375
		}
376
	}
377
378
379
	/**
380
	 * Checks if the current user is allowed to retrieve the customer data for the given ID
381
	 *
382
	 * @param string $id Unique customer ID
383
	 * @return string Unique customer ID
384
	 * @throws \Aimeos\Controller\Frontend\Customer\Exception If access isn't allowed
385
	 */
386
	protected function checkId( $id )
387
	{
388
		if( $id != $this->getContext()->getUserId() )
389
		{
390
			$msg = sprintf( 'Not allowed to access customer data for ID "%1$s"', $id );
391
			throw new \Aimeos\Controller\Frontend\Customer\Exception( $msg );
392
		}
393
394
		return $id;
395
	}
396
}
397