Passed
Push — master ( 0f1828...ed6c8e )
by Aimeos
04:20
created

Standard::init()   B

Complexity

Conditions 11
Paths 45

Size

Total Lines 43
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 26
nc 45
nop 0
dl 0
loc 43
rs 7.3166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2014
6
 * @copyright Aimeos (aimeos.org), 2015-2021
7
 * @package Client
8
 * @subpackage Html
9
 */
10
11
12
namespace Aimeos\Client\Html\Account\Watch;
13
14
15
/**
16
 * Default implementation of account watch HTML client.
17
 *
18
 * @package Client
19
 * @subpackage Html
20
 */
21
class Standard
22
	extends \Aimeos\Client\Html\Common\Client\Factory\Base
23
	implements \Aimeos\Client\Html\Common\Client\Factory\Iface
24
{
25
	/** client/html/account/watch/subparts
26
	 * List of HTML sub-clients rendered within the account watch section
27
	 *
28
	 * The output of the frontend is composed of the code generated by the HTML
29
	 * clients. Each HTML client can consist of serveral (or none) sub-clients
30
	 * that are responsible for rendering certain sub-parts of the output. The
31
	 * sub-clients can contain HTML clients themselves and therefore a
32
	 * hierarchical tree of HTML clients is composed. Each HTML client creates
33
	 * the output that is placed inside the container of its parent.
34
	 *
35
	 * At first, always the HTML code generated by the parent is printed, then
36
	 * the HTML code of its sub-clients. The order of the HTML sub-clients
37
	 * determines the order of the output of these sub-clients inside the parent
38
	 * container. If the configured list of clients is
39
	 *
40
	 *  array( "subclient1", "subclient2" )
41
	 *
42
	 * you can easily change the order of the output by reordering the subparts:
43
	 *
44
	 *  client/html/<clients>/subparts = array( "subclient1", "subclient2" )
45
	 *
46
	 * You can also remove one or more parts if they shouldn't be rendered:
47
	 *
48
	 *  client/html/<clients>/subparts = array( "subclient1" )
49
	 *
50
	 * As the clients only generates structural HTML, the layout defined via CSS
51
	 * should support adding, removing or reordering content by a fluid like
52
	 * design.
53
	 *
54
	 * @param array List of sub-client names
55
	 * @since 2014.03
56
	 * @category Developer
57
	 */
58
	private $subPartPath = 'client/html/account/watch/subparts';
59
	private $subPartNames = [];
60
	private $view;
61
62
63
	/**
64
	 * Returns the HTML code for insertion into the body.
65
	 *
66
	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
67
	 * @return string HTML code
68
	 */
69
	public function body( string $uid = '' ) : string
70
	{
71
		$context = $this->getContext();
72
		$view = $this->getView();
73
74
		try
75
		{
76
			$view = $this->view = $this->view ?? $this->getObject()->data( $view );
77
78
			$html = '';
79
			foreach( $this->getSubClients() as $subclient ) {
80
				$html .= $subclient->setView( $view )->body( $uid );
81
			}
82
			$view->watchBody = $html;
83
		}
84
		catch( \Aimeos\Client\Html\Exception $e )
85
		{
86
			$error = array( $context->translate( 'client', $e->getMessage() ) );
87
			$view->watchErrorList = array_merge( $view->get( 'watchErrorList', [] ), $error );
88
		}
89
		catch( \Aimeos\Controller\Frontend\Exception $e )
90
		{
91
			$error = array( $context->translate( 'controller/frontend', $e->getMessage() ) );
92
			$view->watchErrorList = array_merge( $view->get( 'watchErrorList', [] ), $error );
93
		}
94
		catch( \Aimeos\MShop\Exception $e )
95
		{
96
			$error = array( $context->translate( 'mshop', $e->getMessage() ) );
97
			$view->watchErrorList = array_merge( $view->get( 'watchErrorList', [] ), $error );
98
		}
99
		catch( \Exception $e )
100
		{
101
			$error = array( $context->translate( 'client', 'A non-recoverable error occured' ) );
102
			$view->watchErrorList = array_merge( $view->get( 'watchErrorList', [] ), $error );
103
			$this->logException( $e );
104
		}
105
106
		/** client/html/account/watch/template-body
107
		 * Relative path to the HTML body template of the account watch client.
108
		 *
109
		 * The template file contains the HTML code and processing instructions
110
		 * to generate the result shown in the body of the frontend. The
111
		 * configuration string is the path to the template file relative
112
		 * to the templates directory (usually in client/html/templates).
113
		 *
114
		 * You can overwrite the template file configuration in extensions and
115
		 * provide alternative templates. These alternative templates should be
116
		 * named like the default one but with the string "standard" replaced by
117
		 * an unique name. You may use the name of your project for this. If
118
		 * you've implemented an alternative client class as well, "standard"
119
		 * should be replaced by the name of the new class.
120
		 *
121
		 * @param string Relative path to the template creating code for the HTML page body
122
		 * @since 2014.03
123
		 * @category Developer
124
		 * @see client/html/account/watch/template-header
125
		 */
126
		$tplconf = 'client/html/account/watch/template-body';
127
		$default = 'account/watch/body-standard';
128
129
		return $view->render( $view->config( $tplconf, $default ) );
130
	}
131
132
133
	/**
134
	 * Returns the HTML string for insertion into the header.
135
	 *
136
	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
137
	 * @return string|null String including HTML tags for the header on error
138
	 */
139
	public function header( string $uid = '' ) : ?string
140
	{
141
		$view = $this->getView();
142
143
		try
144
		{
145
			$view = $this->view = $this->view ?? $this->getObject()->data( $view );
146
147
			$html = '';
148
			foreach( $this->getSubClients() as $subclient ) {
149
				$html .= $subclient->setView( $view )->header( $uid );
150
			}
151
			$view->watchHeader = $html;
152
153
			/** client/html/account/watch/template-header
154
			 * Relative path to the HTML header template of the account watch client.
155
			 *
156
			 * The template file contains the HTML code and processing instructions
157
			 * to generate the HTML code that is inserted into the HTML page header
158
			 * of the rendered page in the frontend. The configuration string is the
159
			 * path to the template file relative to the templates directory (usually
160
			 * in client/html/templates).
161
			 *
162
			 * You can overwrite the template file configuration in extensions and
163
			 * provide alternative templates. These alternative templates should be
164
			 * named like the default one but with the string "standard" replaced by
165
			 * an unique name. You may use the name of your project for this. If
166
			 * you've implemented an alternative client class as well, "standard"
167
			 * should be replaced by the name of the new class.
168
			 *
169
			 * @param string Relative path to the template creating code for the HTML page head
170
			 * @since 2014.03
171
			 * @category Developer
172
			 * @see client/html/account/watch/template-body
173
			 */
174
			$tplconf = 'client/html/account/watch/template-header';
175
			$default = 'account/watch/header-standard';
176
177
			return $view->render( $view->config( $tplconf, $default ) );
178
		}
179
		catch( \Exception $e )
180
		{
181
			$this->logException( $e );
182
		}
183
184
		return null;
185
	}
186
187
188
	/**
189
	 * Returns the sub-client given by its name.
190
	 *
191
	 * @param string $type Name of the client type
192
	 * @param string|null $name Name of the sub-client (Default if null)
193
	 * @return \Aimeos\Client\Html\Iface Sub-client object
194
	 */
195
	public function getSubClient( string $type, string $name = null ) : \Aimeos\Client\Html\Iface
196
	{
197
		/** client/html/account/watch/decorators/excludes
198
		 * Excludes decorators added by the "common" option from the account watch html client
199
		 *
200
		 * Decorators extend the functionality of a class by adding new aspects
201
		 * (e.g. log what is currently done), executing the methods of the underlying
202
		 * class only in certain conditions (e.g. only for logged in users) or
203
		 * modify what is returned to the caller.
204
		 *
205
		 * This option allows you to remove a decorator added via
206
		 * "client/html/common/decorators/default" before they are wrapped
207
		 * around the html client.
208
		 *
209
		 *  client/html/account/watch/decorators/excludes = array( 'decorator1' )
210
		 *
211
		 * This would remove the decorator named "decorator1" from the list of
212
		 * common decorators ("\Aimeos\Client\Html\Common\Decorator\*") added via
213
		 * "client/html/common/decorators/default" to the html client.
214
		 *
215
		 * @param array List of decorator names
216
		 * @since 2014.05
217
		 * @category Developer
218
		 * @see client/html/common/decorators/default
219
		 * @see client/html/account/watch/decorators/global
220
		 * @see client/html/account/watch/decorators/local
221
		 */
222
223
		/** client/html/account/watch/decorators/global
224
		 * Adds a list of globally available decorators only to the account watch html client
225
		 *
226
		 * Decorators extend the functionality of a class by adding new aspects
227
		 * (e.g. log what is currently done), executing the methods of the underlying
228
		 * class only in certain conditions (e.g. only for logged in users) or
229
		 * modify what is returned to the caller.
230
		 *
231
		 * This option allows you to wrap global decorators
232
		 * ("\Aimeos\Client\Html\Common\Decorator\*") around the html client.
233
		 *
234
		 *  client/html/account/watch/decorators/global = array( 'decorator1' )
235
		 *
236
		 * This would add the decorator named "decorator1" defined by
237
		 * "\Aimeos\Client\Html\Common\Decorator\Decorator1" only to the html client.
238
		 *
239
		 * @param array List of decorator names
240
		 * @since 2014.05
241
		 * @category Developer
242
		 * @see client/html/common/decorators/default
243
		 * @see client/html/account/watch/decorators/excludes
244
		 * @see client/html/account/watch/decorators/local
245
		 */
246
247
		/** client/html/account/watch/decorators/local
248
		 * Adds a list of local decorators only to the account watch html client
249
		 *
250
		 * Decorators extend the functionality of a class by adding new aspects
251
		 * (e.g. log what is currently done), executing the methods of the underlying
252
		 * class only in certain conditions (e.g. only for logged in users) or
253
		 * modify what is returned to the caller.
254
		 *
255
		 * This option allows you to wrap local decorators
256
		 * ("\Aimeos\Client\Html\Account\Decorator\*") around the html client.
257
		 *
258
		 *  client/html/account/watch/decorators/local = array( 'decorator2' )
259
		 *
260
		 * This would add the decorator named "decorator2" defined by
261
		 * "\Aimeos\Client\Html\Account\Decorator\Decorator2" only to the html client.
262
		 *
263
		 * @param array List of decorator names
264
		 * @since 2014.05
265
		 * @category Developer
266
		 * @see client/html/common/decorators/default
267
		 * @see client/html/account/watch/decorators/excludes
268
		 * @see client/html/account/watch/decorators/global
269
		 */
270
271
		return $this->createSubClient( 'account/watch/' . $type, $name );
272
	}
273
274
275
	/**
276
	 * Processes the input, e.g. store given values.
277
	 *
278
	 * A view must be available and this method doesn't generate any output
279
	 * besides setting view variables if necessary.
280
	 */
281
	public function init()
282
	{
283
		$view = $this->getView();
284
		$context = $this->getContext();
285
		$ids = (array) $view->param( 'wat_id', [] );
286
287
		try
288
		{
289
			if( $context->getUserId() != null && !empty( $ids ) && $view->request()->getMethod() === 'POST' )
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $context->getUserId() of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
290
			{
291
				switch( $view->param( 'wat_action' ) )
292
				{
293
					case 'add':
294
						$this->addItems( $view, $ids ); break;
295
					case 'edit':
296
						$this->editItems( $view, $ids ); break;
297
					case 'delete':
298
						$this->deleteItems( $view, $ids ); break;
299
				}
300
			}
301
302
			parent::init();
303
		}
304
		catch( \Aimeos\MShop\Exception $e )
305
		{
306
			$error = array( $context->translate( 'mshop', $e->getMessage() ) );
307
			$view->watchErrorList = array_merge( $view->get( 'watchErrorList', [] ), $error );
308
		}
309
		catch( \Aimeos\Controller\Frontend\Exception $e )
310
		{
311
			$error = array( $context->translate( 'controller/frontend', $e->getMessage() ) );
312
			$view->watchErrorList = array_merge( $view->get( 'watchErrorList', [] ), $error );
313
		}
314
		catch( \Aimeos\Client\Html\Exception $e )
315
		{
316
			$error = array( $context->translate( 'client', $e->getMessage() ) );
317
			$view->watchErrorList = array_merge( $view->get( 'watchErrorList', [] ), $error );
318
		}
319
		catch( \Exception $e )
320
		{
321
			$error = array( $context->translate( 'client', 'A non-recoverable error occured' ) );
322
			$view->watchErrorList = array_merge( $view->get( 'watchErrorList', [] ), $error );
323
			$this->logException( $e );
324
		}
325
	}
326
327
328
	/**
329
	 * Adds one or more list items to the given customer item
330
	 *
331
	 * @param \Aimeos\MW\View\Iface $view View object
332
	 * @param array $ids List of referenced IDs
333
	 */
334
	protected function addItems( \Aimeos\MW\View\Iface $view, array $ids )
335
	{
336
		$context = $this->getContext();
337
338
		/** client/html/account/watch/maxitems
339
		 * Maximum number of products that can be watched in parallel
340
		 *
341
		 * This option limits the number of products that can be watched
342
		 * after the users added the products to their watch list.
343
		 * It must be a positive integer value greater than 0.
344
		 *
345
		 * Note: It's recommended to set this value not too high as this
346
		 * leads to a high memory consumption when the e-mails are generated
347
		 * to notify the customers. The memory used will up to 100*maxitems
348
		 * of the footprint of one product item including the associated
349
		 * texts, prices and media.
350
		 *
351
		 * @param integer Number of products
352
		 * @since 2014.09
353
		 * @category User
354
		 * @category Developer
355
		 */
356
		$max = $context->getConfig()->get( 'client/html/account/watch/maxitems', 100 );
357
358
		$cntl = \Aimeos\Controller\Frontend::create( $context, 'customer' );
359
		$item = $cntl->uses( ['product' => ['watch']] )->get();
360
361
		if( count( $item->getRefItems( 'product', null, 'watch' ) ) + count( $ids ) > $max )
362
		{
363
			$msg = sprintf( $context->translate( 'client', 'You can only watch up to %1$s products' ), $max );
364
			throw new \Aimeos\Client\Html\Exception( $msg );
365
		}
366
367
		foreach( $ids as $id )
368
		{
369
			if( ( $listItem = $item->getListItem( 'product', 'watch', $id ) ) === null ) {
370
				$listItem = $cntl->createListItem();
371
			}
372
			$cntl->addListItem( 'product', $listItem->setType( 'watch' )->setRefId( $id ) );
373
		}
374
375
		$cntl->store();
376
	}
377
378
379
	/**
380
	 * Removes the referencing list items from the given item
381
	 *
382
	 * @param \Aimeos\MW\View\Iface $view View object
383
	 * @param array $ids List of referenced IDs
384
	 */
385
	protected function deleteItems( \Aimeos\MW\View\Iface $view, array $ids )
386
	{
387
		$cntl = \Aimeos\Controller\Frontend::create( $this->getContext(), 'customer' );
388
		$item = $cntl->uses( ['product' => ['watch']] )->get();
389
390
		foreach( $ids as $id )
391
		{
392
			if( ( $listItem = $item->getListItem( 'product', 'watch', $id ) ) !== null ) {
393
				$cntl->deleteListItem( 'product', $listItem );
394
			}
395
		}
396
397
		$cntl->store();
398
	}
399
400
401
	/**
402
	 * Updates the item using the given reference IDs
403
	 *
404
	 * @param \Aimeos\MW\View\Iface $view View object
405
	 * @param array $ids List of referenced IDs
406
	 */
407
	protected function editItems( \Aimeos\MW\View\Iface $view, array $ids )
408
	{
409
		$context = $this->getContext();
410
		$cntl = \Aimeos\Controller\Frontend::create( $context, 'customer' );
411
		$item = $cntl->uses( ['product' => ['watch']] )->get();
412
413
		$config = [
414
			'timeframe' => $view->param( 'wat_timeframe', 7 ),
415
			'pricevalue' => $view->param( 'wat_pricevalue', '0.00' ),
416
			'price' => $view->param( 'wat_price', 0 ),
417
			'stock' => $view->param( 'wat_stock', 0 ),
418
			'currency' => $context->getLocale()->getCurrencyId(),
419
		];
420
421
		foreach( $ids as $id )
422
		{
423
			if( ( $listItem = $item->getListItem( 'product', 'watch', $id ) ) !== null )
424
			{
425
				$time = time() + ( $config['timeframe'] + 1 ) * 86400;
426
				$listItem = $listItem->setDateEnd( date( 'Y-m-d 00:00:00', $time ) )->setConfig( $config );
427
428
				$cntl->addListItem( 'product', $listItem );
429
			}
430
		}
431
432
		$cntl->store();
433
	}
434
435
436
	/**
437
	 * Returns the list of sub-client names configured for the client.
438
	 *
439
	 * @return array List of HTML client names
440
	 */
441
	protected function getSubClientNames() : array
442
	{
443
		return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
444
	}
445
446
447
	/**
448
	 * Returns the sanitized page from the parameters for the product list.
449
	 *
450
	 * @param \Aimeos\MW\View\Iface $view View instance with helper for retrieving the required parameters
451
	 * @return integer Page number starting from 1
452
	 */
453
	protected function getProductListPage( \Aimeos\MW\View\Iface $view ) : int
454
	{
455
		$page = (int) $view->param( 'wat_page', 1 );
456
		return ( $page < 1 ? 1 : $page );
457
	}
458
459
460
	/**
461
	 * Returns the sanitized page size from the parameters for the product list.
462
	 *
463
	 * @param \Aimeos\MW\View\Iface $view View instance with helper for retrieving the required parameters
464
	 * @return integer Page size
465
	 */
466
	protected function getProductListSize( \Aimeos\MW\View\Iface $view ) : int
467
	{
468
		/** client/html/account/watch/size
469
		 * The number of products shown in a list page for watch products
470
		 *
471
		 * Limits the number of products that is shown in the list pages to the
472
		 * given value. If more products are available, the products are split
473
		 * into bunches which will be shown on their own list page. The user is
474
		 * able to move to the next page (or previous one if it's not the first)
475
		 * to display the next (or previous) products.
476
		 *
477
		 * The value must be an integer number from 1 to 100. Negative values as
478
		 * well as values above 100 are not allowed. The value can be overwritten
479
		 * per request if the "l_size" parameter is part of the URL.
480
		 *
481
		 * @param integer Number of products
482
		 * @since 2014.09
483
		 * @category User
484
		 * @category Developer
485
		 * @see client/html/catalog/lists/size
486
		 */
487
		$defaultSize = $this->getContext()->getConfig()->get( 'client/html/account/watch/size', 48 );
488
489
		$size = (int) $view->param( 'watch-size', $defaultSize );
490
		return ( $size < 1 || $size > 100 ? $defaultSize : $size );
491
	}
492
493
494
	/**
495
	 * Sets the necessary parameter values in the view.
496
	 *
497
	 * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
498
	 * @param array &$tags Result array for the list of tags that are associated to the output
499
	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
500
	 * @return \Aimeos\MW\View\Iface Modified view object
501
	 */
502
	public function data( \Aimeos\MW\View\Iface $view, array &$tags = [], string &$expire = null ) : \Aimeos\MW\View\Iface
503
	{
504
		$context = $this->getContext();
505
506
		/** client/html/account/watch/domains
507
		 * A list of domain names whose items should be available in the account watch view template
508
		 *
509
		 * The templates rendering product details usually add the images,
510
		 * prices and texts associated to the product item. If you want to
511
		 * display additional or less content, you can configure your own
512
		 * list of domains (attribute, media, price, product, text, etc. are
513
		 * domains) whose items are fetched from the storage. Please keep
514
		 * in mind that the more domains you add to the configuration, the
515
		 * more time is required for fetching the content!
516
		 *
517
		 * @param array List of domain names
518
		 * @since 2014.09
519
		 * @category Developer
520
		 * @see client/html/catalog/domains
521
		 */
522
		$domains = $context->getConfig()->get( 'client/html/account/watch/domains', ['text', 'price', 'media'] );
523
		$domains['product'] = ['watch'];
524
525
		$cntl = \Aimeos\Controller\Frontend::create( $context, 'customer' );
526
		$listItems = $cntl->uses( $domains )->get()->getListItems( 'product', 'watch' );
527
		$total = count( $listItems );
528
529
		$size = $this->getProductListSize( $view );
530
		$current = $this->getProductListPage( $view );
531
		$last = ( $total != 0 ? ceil( $total / $size ) : 1 );
532
533
		$view->watchItems = $listItems;
534
		$view->watchPageFirst = 1;
535
		$view->watchPagePrev = ( $current > 1 ? $current - 1 : 1 );
536
		$view->watchPageNext = ( $current < $last ? $current + 1 : $last );
537
		$view->watchPageLast = $last;
538
		$view->watchPageCurr = $current;
539
540
		return parent::data( $view, $tags, $expire );
541
	}
542
}
543