Completed
Push — master ( a13539...bd1b6d )
by Aimeos
04:27
created

Standard   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 535
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 152
dl 0
loc 535
rs 9.1199
c 0
b 0
f 0
wmc 41

13 Methods

Rating   Name   Duplication   Size   Complexity  
A fromArray() 0 32 6
A checkSite() 0 7 3
A toArray() 0 16 3
A render() 0 25 1
A get() 0 32 4
A search() 0 58 4
A getUserSiteId() 0 6 1
A getSubClient() 0 76 1
A getSubClientNames() 0 36 1
A create() 0 31 4
A copy() 0 32 4
A delete() 0 41 5
A save() 0 31 4

How to fix   Complexity   

Complex Class

Complex classes like Standard often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Standard, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2017-2020
6
 * @package Admin
7
 * @subpackage JQAdm
8
 */
9
10
11
namespace Aimeos\Admin\JQAdm\Locale\Site;
12
13
sprintf( 'locale/site' ); // for translation
14
15
16
/**
17
 * Default implementation of locale site JQAdm client.
18
 *
19
 * @package Admin
20
 * @subpackage JQAdm
21
 */
22
class Standard
23
	extends \Aimeos\Admin\JQAdm\Common\Admin\Factory\Base
24
	implements \Aimeos\Admin\JQAdm\Common\Admin\Factory\Iface
25
{
26
	/**
27
	 * Copies a resource
28
	 *
29
	 * @return string|null HTML output
30
	 */
31
	public function copy() : ?string
32
	{
33
		$view = $this->getView();
34
		$context = $this->getContext();
35
36
		try
37
		{
38
			if( ( $id = $view->param( 'id' ) ) === null ) {
39
				throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Required parameter "%1$s" is missing', 'id' ) );
40
			}
41
42
			$this->checkSite( $view->access( 'super' ), $id );
43
44
			$manager = \Aimeos\MShop::create( $context, 'locale/site' );
45
			$view->item = $manager->getItem( $id );
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type null; however, parameter $id of Aimeos\MShop\Common\Manager\Iface::getItem() 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

45
			$view->item = $manager->getItem( /** @scrutinizer ignore-type */ $id );
Loading history...
46
47
			$view->itemData = $this->toArray( $view->item, true );
48
			$view->itemSubparts = $this->getSubClientNames();
49
			$view->itemBody = '';
50
51
			foreach( $this->getSubClients() as $idx => $client )
52
			{
53
				$view->tabindex = ++$idx + 1;
54
				$view->itemBody .= $client->copy();
55
			}
56
		}
57
		catch( \Exception $e )
58
		{
59
			$this->report( $e, 'copy' );
60
		}
61
62
		return $this->render( $view );
63
	}
64
65
66
	/**
67
	 * Creates a new resource
68
	 *
69
	 * @return string|null HTML output
70
	 */
71
	public function create() : ?string
72
	{
73
		$view = $this->getView();
74
		$context = $this->getContext();
75
76
		try
77
		{
78
			$this->checkSite( $view->access( 'super' ) );
79
80
			$data = $view->param( 'item', [] );
81
82
			if( !isset( $view->item ) ) {
83
				$view->item = \Aimeos\MShop::create( $context, 'locale/site' )->createItem();
84
			}
85
86
			$view->itemSubparts = $this->getSubClientNames();
87
			$view->itemData = $data;
88
			$view->itemBody = '';
89
90
			foreach( $this->getSubClients() as $idx => $client )
91
			{
92
				$view->tabindex = ++$idx + 1;
93
				$view->itemBody .= $client->create();
94
			}
95
		}
96
		catch( \Exception $e )
97
		{
98
			$this->report( $e, 'create' );
99
		}
100
101
		return $this->render( $view );
102
	}
103
104
105
	/**
106
	 * Deletes a resource
107
	 *
108
	 * @return string|null HTML output
109
	 */
110
	public function delete() : ?string
111
	{
112
		$view = $this->getView();
113
		$context = $this->getContext();
114
115
		$manager = \Aimeos\MShop::create( $context, 'locale/site' );
116
		$manager->begin();
117
118
		try
119
		{
120
			if( ( $ids = $view->param( 'id' ) ) === null ) {
121
				throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Required parameter "%1$s" is missing', 'id' ) );
122
			}
123
124
			$search = $manager->createSearch()->setSlice( 0, count( (array) $ids ) );
125
			$search->setConditions( $search->compare( '==', 'locale.site.id', $ids ) );
126
			$items = $manager->searchItems( $search );
127
128
			foreach( $items as $id => $item )
129
			{
130
				$this->checkSite( $view->access( 'super' ), $id );
131
				$view->item = $item;
132
133
				foreach( $this->getSubClients() as $client ) {
134
					$client->delete();
135
				}
136
			}
137
138
			$manager->deleteItems( $items->toArray() );
139
			$manager->commit();
140
141
			$this->nextAction( $view, 'search', 'locale/site', null, 'delete' );
142
			return null;
143
		}
144
		catch( \Exception $e )
145
		{
146
			$manager->rollback();
147
			$this->report( $e, 'delete' );
148
		}
149
150
		return $this->search();
151
	}
152
153
154
	/**
155
	 * Returns a single resource
156
	 *
157
	 * @return string|null HTML output
158
	 */
159
	public function get() : ?string
160
	{
161
		$view = $this->getView();
162
		$context = $this->getContext();
163
164
		try
165
		{
166
			if( ( $id = $view->param( 'id' ) ) === null ) {
167
				throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Required parameter "%1$s" is missing', 'id' ) );
168
			}
169
170
			$this->checkSite( $view->access( 'super' ), $id );
171
172
			$manager = \Aimeos\MShop::create( $context, 'locale/site' );
173
174
			$view->item = $manager->getItem( $id );
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type null; however, parameter $id of Aimeos\MShop\Common\Manager\Iface::getItem() 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

174
			$view->item = $manager->getItem( /** @scrutinizer ignore-type */ $id );
Loading history...
175
			$view->itemSubparts = $this->getSubClientNames();
176
			$view->itemData = $this->toArray( $view->item );
177
			$view->itemBody = '';
178
179
			foreach( $this->getSubClients() as $idx => $client )
180
			{
181
				$view->tabindex = ++$idx + 1;
182
				$view->itemBody .= $client->get();
183
			}
184
		}
185
		catch( \Exception $e )
186
		{
187
			$this->report( $e, 'get' );
188
		}
189
190
		return $this->render( $view );
191
	}
192
193
194
	/**
195
	 * Saves the data
196
	 *
197
	 * @return string|null HTML output
198
	 */
199
	public function save() : ?string
200
	{
201
		$view = $this->getView();
202
		$context = $this->getContext();
203
204
		$manager = \Aimeos\MShop::create( $context, 'locale/site' );
205
		$manager->begin();
206
207
		try
208
		{
209
			$item = $this->fromArray( $view->param( 'item', [] ), $view->access( 'super' ) );
210
			$view->item = $item->getId() ? $item : $manager->saveItem( $item );
0 ignored issues
show
Bug introduced by
The method saveItem() does not exist on Aimeos\MShop\Common\Manager\Iface. Did you maybe mean saveItems()? ( Ignorable by Annotation )

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

210
			$view->item = $item->getId() ? $item : $manager->/** @scrutinizer ignore-call */ saveItem( $item );

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...
211
			$view->itemBody = '';
212
213
			foreach( $this->getSubClients() as $client ) {
214
				$view->itemBody .= $client->save();
215
			}
216
217
			$manager->saveItem( clone $view->item );
218
			$manager->commit();
219
220
			$this->nextAction( $view, $view->param( 'next' ), 'locale/site', $view->item->getId(), 'save' );
221
			return null;
222
		}
223
		catch( \Exception $e )
224
		{
225
			$manager->rollback();
226
			$this->report( $e, 'save' );
227
		}
228
229
		return $this->create();
230
	}
231
232
233
	/**
234
	 * Returns a list of resource according to the conditions
235
	 *
236
	 * @return string|null HTML output
237
	 */
238
	public function search() : ?string
239
	{
240
		$view = $this->getView();
241
		$context = $this->getContext();
242
243
		try
244
		{
245
			$total = 0;
246
			$params = $this->storeSearchParams( $view->param(), 'locale/site' );
247
			$manager = \Aimeos\MShop::create( $context, 'locale/site' );
248
			$search = $this->initCriteria( $manager->createSearch(), $params );
249
250
			if( $view->access( 'super' ) === false )
251
			{
252
				$search->setConditions( $search->combine( '&&', [
253
					$search->compare( '==', 'locale.site.id', $this->getUserSiteId() ),
254
					$search->getConditions(),
255
				] ) );
256
			}
257
258
			$view->items = $manager->searchItems( $search, [], $total );
259
			$view->filterAttributes = $manager->getSearchAttributes( true );
260
			$view->filterOperators = $search->getOperators();
261
			$view->total = $total;
262
			$view->itemBody = '';
263
264
			foreach( $this->getSubClients() as $client ) {
265
				$view->itemBody .= $client->search();
266
			}
267
		}
268
		catch( \Exception $e )
269
		{
270
			$this->report( $e, 'search' );
271
		}
272
273
		/** admin/jqadm/locale/site/template-list
274
		 * Relative path to the HTML body template for the locale list.
275
		 *
276
		 * The template file contains the HTML code and processing instructions
277
		 * to generate the result shown in the body of the frontend. The
278
		 * configuration string is the path to the template file relative
279
		 * to the templates directory (usually in admin/jqadm/templates).
280
		 *
281
		 * You can overwrite the template file configuration in extensions and
282
		 * provide alternative templates. These alternative templates should be
283
		 * named like the default one but with the string "default" replaced by
284
		 * an unique name. You may use the name of your project for this. If
285
		 * you've implemented an alternative client class as well, "default"
286
		 * should be replaced by the name of the new class.
287
		 *
288
		 * @param string Relative path to the template creating the HTML code
289
		 * @since 2016.04
290
		 * @category Developer
291
		 */
292
		$tplconf = 'admin/jqadm/locale/site/template-list';
293
		$default = 'locale/site/list-standard';
294
295
		return $view->render( $view->config( $tplconf, $default ) );
296
	}
297
298
299
	/**
300
	 * Returns the sub-client given by its name.
301
	 *
302
	 * @param string $type Name of the client type
303
	 * @param string|null $name Name of the sub-client (Default if null)
304
	 * @return \Aimeos\Admin\JQAdm\Iface Sub-client object
305
	 */
306
	public function getSubClient( string $type, string $name = null ) : \Aimeos\Admin\JQAdm\Iface
307
	{
308
		/** admin/jqadm/locale/site/decorators/excludes
309
		 * Excludes decorators added by the "common" option from the locale JQAdm client
310
		 *
311
		 * Decorators extend the functionality of a class by adding new aspects
312
		 * (e.g. log what is currently done), executing the methods of the underlying
313
		 * class only in certain conditions (e.g. only for logged in users) or
314
		 * modify what is returned to the caller.
315
		 *
316
		 * This option allows you to remove a decorator added via
317
		 * "client/jqadm/common/decorators/default" before they are wrapped
318
		 * around the JQAdm client.
319
		 *
320
		 *  admin/jqadm/locale/site/decorators/excludes = array( 'decorator1' )
321
		 *
322
		 * This would remove the decorator named "decorator1" from the list of
323
		 * common decorators ("\Aimeos\Admin\JQAdm\Common\Decorator\*") added via
324
		 * "client/jqadm/common/decorators/default" to the JQAdm client.
325
		 *
326
		 * @param array List of decorator names
327
		 * @since 2017.10
328
		 * @category Developer
329
		 * @see admin/jqadm/common/decorators/default
330
		 * @see admin/jqadm/locale/site/decorators/global
331
		 * @see admin/jqadm/locale/site/decorators/local
332
		 */
333
334
		/** admin/jqadm/locale/site/decorators/global
335
		 * Adds a list of globally available decorators only to the locale JQAdm client
336
		 *
337
		 * Decorators extend the functionality of a class by adding new aspects
338
		 * (e.g. log what is currently done), executing the methods of the underlying
339
		 * class only in certain conditions (e.g. only for logged in users) or
340
		 * modify what is returned to the caller.
341
		 *
342
		 * This option allows you to wrap global decorators
343
		 * ("\Aimeos\Admin\JQAdm\Common\Decorator\*") around the JQAdm client.
344
		 *
345
		 *  admin/jqadm/locale/site/decorators/global = array( 'decorator1' )
346
		 *
347
		 * This would add the decorator named "decorator1" defined by
348
		 * "\Aimeos\Admin\JQAdm\Common\Decorator\Decorator1" only to the JQAdm client.
349
		 *
350
		 * @param array List of decorator names
351
		 * @since 2017.10
352
		 * @category Developer
353
		 * @see admin/jqadm/common/decorators/default
354
		 * @see admin/jqadm/locale/site/decorators/excludes
355
		 * @see admin/jqadm/locale/site/decorators/local
356
		 */
357
358
		/** admin/jqadm/locale/site/decorators/local
359
		 * Adds a list of local decorators only to the locale JQAdm client
360
		 *
361
		 * Decorators extend the functionality of a class by adding new aspects
362
		 * (e.g. log what is currently done), executing the methods of the underlying
363
		 * class only in certain conditions (e.g. only for logged in users) or
364
		 * modify what is returned to the caller.
365
		 *
366
		 * This option allows you to wrap local decorators
367
		 * ("\Aimeos\Admin\JQAdm\Locale\Site\Decorator\*") around the JQAdm client.
368
		 *
369
		 *  admin/jqadm/locale/site/decorators/local = array( 'decorator2' )
370
		 *
371
		 * This would add the decorator named "decorator2" defined by
372
		 * "\Aimeos\Admin\JQAdm\Locale\Site\Decorator\Decorator2" only to the JQAdm client.
373
		 *
374
		 * @param array List of decorator names
375
		 * @since 2017.10
376
		 * @category Developer
377
		 * @see admin/jqadm/common/decorators/default
378
		 * @see admin/jqadm/locale/site/decorators/excludes
379
		 * @see admin/jqadm/locale/site/decorators/global
380
		 */
381
		return $this->createSubClient( 'locale/site' . $type, $name );
382
	}
383
384
385
	/**
386
	 * Checks if the user is allowed to access the site item
387
	 *
388
	 * @param bool $super True if user is a super user
389
	 * @param string $id ID of the site to access
390
	 * @throws \Aimeos\Admin\JQAdm\Exception If user isn't allowed to access the site
391
	 */
392
	protected function checkSite( bool $super, string $id = null )
393
	{
394
		if( $super === true || (string) $this->getUserSiteId() === (string) $id ) {
395
			return;
396
		}
397
398
		throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Permission denied' ) );
399
	}
400
401
402
	/**
403
	 * Returns the site ID of the current user
404
	 *
405
	 * @return string|null Site ID of the current user
406
	 */
407
	protected function getUserSiteId() : ?string
408
	{
409
		$context = $this->getContext();
410
		$manager = \Aimeos\MShop::create( $context, 'customer' );
411
412
		return $manager->getItem( $context->getUserId() )->getSiteId();
0 ignored issues
show
Bug introduced by
It seems like $context->getUserId() can also be of type null; however, parameter $id of Aimeos\MShop\Common\Manager\Iface::getItem() 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

412
		return $manager->getItem( /** @scrutinizer ignore-type */ $context->getUserId() )->getSiteId();
Loading history...
413
	}
414
415
416
	/**
417
	 * Returns the list of sub-client names configured for the client.
418
	 *
419
	 * @return array List of JQAdm client names
420
	 */
421
	protected function getSubClientNames() : array
422
	{
423
		/** admin/jqadm/locale/site/standard/subparts
424
		 * List of JQAdm sub-clients rendered within the locale section
425
		 *
426
		 * The output of the frontend is composed of the code generated by the JQAdm
427
		 * clients. Each JQAdm client can consist of serveral (or none) sub-clients
428
		 * that are responsible for rendering certain sub-parts of the output. The
429
		 * sub-clients can contain JQAdm clients themselves and therefore a
430
		 * hierarchical tree of JQAdm clients is composed. Each JQAdm client creates
431
		 * the output that is placed inside the container of its parent.
432
		 *
433
		 * At first, always the JQAdm code generated by the parent is printed, then
434
		 * the JQAdm code of its sub-clients. The order of the JQAdm sub-clients
435
		 * determines the order of the output of these sub-clients inside the parent
436
		 * container. If the configured list of clients is
437
		 *
438
		 *  array( "subclient1", "subclient2" )
439
		 *
440
		 * you can easily change the order of the output by reordering the subparts:
441
		 *
442
		 *  admin/jqadm/<clients>/subparts = array( "subclient1", "subclient2" )
443
		 *
444
		 * You can also remove one or more parts if they shouldn't be rendered:
445
		 *
446
		 *  admin/jqadm/<clients>/subparts = array( "subclient1" )
447
		 *
448
		 * As the clients only generates structural JQAdm, the layout defined via CSS
449
		 * should support adding, removing or reordering content by a fluid like
450
		 * design.
451
		 *
452
		 * @param array List of sub-client names
453
		 * @since 2017.10
454
		 * @category Developer
455
		 */
456
		return $this->getContext()->getConfig()->get( 'admin/jqadm/locale/site/standard/subparts', [] );
457
	}
458
459
460
	/**
461
	 * Creates new and updates existing items using the data array
462
	 *
463
	 * @param array $data Data array
464
	 * @param bool $super If current user is a super user
465
	 * @return \Aimeos\MShop\Locale\Item\Site\Iface New locale site item object
466
	 */
467
	protected function fromArray( array $data, bool $super ) : \Aimeos\MShop\Locale\Item\Site\Iface
468
	{
469
		$conf = [];
470
471
		foreach( (array) $this->getValue( $data, 'config', [] ) as $idx => $entry )
472
		{
473
			if( trim( $entry['key'] ?? '' ) !== '' ) {
474
				$conf[$entry['key']] = $entry['val'] ?? null;
475
			}
476
		}
477
478
		$manager = \Aimeos\MShop::create( $this->getContext(), 'locale/site' );
479
480
		if( isset( $data['locale.site.id'] ) && $data['locale.site.id'] != '' )
481
		{
482
			$this->checkSite( $super, $data['locale.site.id'] );
483
			$item = $manager->getItem( $data['locale.site.id'] );
0 ignored issues
show
Bug introduced by
It seems like $data['locale.site.id'] can also be of type null; however, parameter $id of Aimeos\MShop\Common\Manager\Iface::getItem() 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

483
			$item = $manager->getItem( /** @scrutinizer ignore-type */ $data['locale.site.id'] );
Loading history...
484
		}
485
		else
486
		{
487
			$this->checkSite( $super );
488
			$item = $manager->createItem();
489
		}
490
491
		$item->fromArray( $data, true );
492
		$item->setConfig( $conf );
493
494
		if( $item->getId() == null ) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $item->getId() of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
495
			return $manager->insertItem( $item );
496
		}
497
498
		return $item;
499
	}
500
501
502
	/**
503
	 * Constructs the data array for the view from the given item
504
	 *
505
	 * @param \Aimeos\MShop\Locale\Item\Site\Iface $item Locale site item object
506
	 * @return string[] Multi-dimensional associative list of item data
507
	 */
508
	protected function toArray( \Aimeos\MShop\Locale\Item\Site\Iface $item, bool $copy = false ) : array
509
	{
510
		$data = $item->toArray( true );
511
		$data['config'] = [];
512
513
		if( $copy === true )
514
		{
515
			$data['locale.site.code'] = $data['locale.site.code'] . '_copy';
516
			$data['locale.site.id'] = '';
517
		}
518
519
		foreach( $item->getConfig() as $key => $value ) {
520
			$data['config'][] = ['key' => $key, 'val' => $value];
521
		}
522
523
		return $data;
524
	}
525
526
527
	/**
528
	 * Returns the rendered template including the view data
529
	 *
530
	 * @return string|null HTML output
531
	 */
532
	protected function render( \Aimeos\MW\View\Iface $view ) : string
533
	{
534
		/** admin/jqadm/locale/site/template-item
535
		 * Relative path to the HTML body template for the locale item.
536
		 *
537
		 * The template file contains the HTML code and processing instructions
538
		 * to generate the result shown in the body of the frontend. The
539
		 * configuration string is the path to the template file relative
540
		 * to the templates directory (usually in admin/jqadm/templates).
541
		 *
542
		 * You can overwrite the template file configuration in extensions and
543
		 * provide alternative templates. These alternative templates should be
544
		 * named like the default one but with the string "default" replaced by
545
		 * an unique name. You may use the name of your project for this. If
546
		 * you've implemented an alternative client class as well, "default"
547
		 * should be replaced by the name of the new class.
548
		 *
549
		 * @param string Relative path to the template creating the HTML code
550
		 * @since 2017.10
551
		 * @category Developer
552
		 */
553
		$tplconf = 'admin/jqadm/locale/site/template-item';
554
		$default = 'locale/site/item-standard';
555
556
		return $view->render( $view->config( $tplconf, $default ) );
557
	}
558
}
559