Completed
Push — master ( 626216...e78c82 )
by Aimeos
03:45
created

Standard::get()   A

Complexity

Conditions 4
Paths 12

Size

Total Lines 29
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 12
nop 0
dl 0
loc 29
rs 9.7666
c 0
b 0
f 0
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\Service;
12
13
sprintf( 'service' ); // for translation
14
15
16
/**
17
 * Default implementation of service 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
	 * Adds the required data used in the template
28
	 *
29
	 * @param \Aimeos\MW\View\Iface $view View object
30
	 * @return \Aimeos\MW\View\Iface View object with assigned parameters
31
	 */
32
	public function addData( \Aimeos\MW\View\Iface $view ) : \Aimeos\MW\View\Iface
33
	{
34
		$ds = DIRECTORY_SEPARATOR;
35
36
		$view->itemDecorators = $this->getClassNames( 'MShop' . $ds . 'Service' . $ds . 'Provider' . $ds . 'Decorator' );
37
		$view->itemProviders = [
38
			'delivery' => $this->getClassNames( 'MShop' . $ds . 'Service' . $ds . 'Provider' . $ds . 'Delivery' ),
39
			'payment' => $this->getClassNames( 'MShop' . $ds . 'Service' . $ds . 'Provider' . $ds . 'Payment' ),
40
		];
41
42
		$view->itemSubparts = $this->getSubClientNames();
43
		$view->itemTypes = $this->getTypeItems();
44
45
		return $view;
46
	}
47
48
49
	/**
50
	 * Copies a resource
51
	 *
52
	 * @return string|null HTML output
53
	 */
54
	public function copy() : ?string
55
	{
56
		$view = $this->getObject()->addData( $this->getView() );
57
58
		try
59
		{
60
			if( ( $id = $view->param( 'id' ) ) === null ) {
61
				throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Required parameter "%1$s" is missing', 'id' ) );
62
			}
63
64
			$manager = \Aimeos\MShop::create( $this->getContext(), 'service' );
65
66
			$view->item = $manager->getItem( $id, $this->getDomains() );
67
			$view->itemAttributes = $this->getConfigAttributes( $view->item );
68
			$view->itemData = $this->toArray( $view->item, true );
69
			$view->itemBody = '';
70
71
			foreach( $this->getSubClients() as $idx => $client )
72
			{
73
				$view->tabindex = ++$idx + 1;
74
				$view->itemBody .= $client->copy();
75
			}
76
		}
77
		catch( \Exception $e )
78
		{
79
			$this->report( $e, 'copy' );
80
		}
81
82
		return $this->render( $view );
83
	}
84
85
86
	/**
87
	 * Creates a new resource
88
	 *
89
	 * @return string|null HTML output
90
	 */
91
	public function create() : ?string
92
	{
93
		$view = $this->getObject()->addData( $this->getView() );
94
95
		try
96
		{
97
			$data = $view->param( 'item', [] );
98
99
			if( !isset( $view->item ) ) {
100
				$view->item = \Aimeos\MShop::create( $this->getContext(), 'service' )->createItem();
101
			}
102
103
			$data['service.siteid'] = $view->item->getSiteId();
104
105
			$view->itemData = $data;
106
			$view->itemBody = '';
107
108
			foreach( $this->getSubClients() as $idx => $client )
109
			{
110
				$view->tabindex = ++$idx + 1;
111
				$view->itemBody .= $client->create();
112
			}
113
		}
114
		catch( \Exception $e )
115
		{
116
			$this->report( $e, 'create' );
117
		}
118
119
		return $this->render( $view );
120
	}
121
122
123
	/**
124
	 * Deletes a resource
125
	 *
126
	 * @return string|null HTML output
127
	 */
128
	public function delete() : ?string
129
	{
130
		$view = $this->getView();
131
132
		$manager = \Aimeos\MShop::create( $this->getContext(), 'service' );
133
		$manager->begin();
134
135
		try
136
		{
137
			if( ( $ids = $view->param( 'id' ) ) === null ) {
138
				throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Required parameter "%1$s" is missing', 'id' ) );
139
			}
140
141
			$search = $manager->createSearch()->setSlice( 0, count( (array) $ids ) );
142
			$search->setConditions( $search->compare( '==', 'service.id', $ids ) );
143
			$items = $manager->searchItems( $search, $this->getDomains() );
144
145
			foreach( $items as $item )
146
			{
147
				$view->item = $item;
148
149
				foreach( $this->getSubClients() as $client ) {
150
					$client->delete();
151
				}
152
			}
153
154
			$manager->deleteItems( $items->toArray() );
155
			$manager->commit();
156
157
			$this->nextAction( $view, 'search', 'service', null, 'delete' );
158
			return null;
159
		}
160
		catch( \Exception $e )
161
		{
162
			$manager->rollback();
163
			$this->report( $e, 'delete' );
164
		}
165
166
		return $this->search();
167
	}
168
169
170
	/**
171
	 * Returns a single resource
172
	 *
173
	 * @return string|null HTML output
174
	 */
175
	public function get() : ?string
176
	{
177
		$view = $this->getObject()->addData( $this->getView() );
178
179
		try
180
		{
181
			if( ( $id = $view->param( 'id' ) ) === null ) {
182
				throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Required parameter "%1$s" is missing', 'id' ) );
183
			}
184
185
			$manager = \Aimeos\MShop::create( $this->getContext(), 'service' );
186
187
			$view->item = $manager->getItem( $id, $this->getDomains() );
188
			$view->itemAttributes = $this->getConfigAttributes( $view->item );
189
			$view->itemData = $this->toArray( $view->item );
190
			$view->itemBody = '';
191
192
			foreach( $this->getSubClients() as $idx => $client )
193
			{
194
				$view->tabindex = ++$idx + 1;
195
				$view->itemBody .= $client->get();
196
			}
197
		}
198
		catch( \Exception $e )
199
		{
200
			$this->report( $e, 'get' );
201
		}
202
203
		return $this->render( $view );
204
	}
205
206
207
	/**
208
	 * Saves the data
209
	 *
210
	 * @return string|null HTML output
211
	 */
212
	public function save() : ?string
213
	{
214
		$view = $this->getView();
215
216
		$manager = \Aimeos\MShop::create( $this->getContext(), 'service' );
217
		$manager->begin();
218
219
		try
220
		{
221
			$item = $this->fromArray( $view->param( 'item', [] ) );
222
			$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

222
			$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...
223
			$view->itemBody = '';
224
225
			foreach( $this->getSubClients() as $client ) {
226
				$view->itemBody .= $client->save();
227
			}
228
229
			$manager->saveItem( clone $view->item );
230
			$manager->commit();
231
232
			$this->nextAction( $view, $view->param( 'next' ), 'service', $view->item->getId(), 'save' );
233
			return null;
234
		}
235
		catch( \Exception $e )
236
		{
237
			$manager->rollback();
238
			$this->report( $e, 'save' );
239
		}
240
241
		return $this->create();
242
	}
243
244
245
	/**
246
	 * Returns a list of resource according to the conditions
247
	 *
248
	 * @return string|null HTML output
249
	 */
250
	public function search() : ?string
251
	{
252
		$view = $this->getView();
253
254
		try
255
		{
256
			$total = 0;
257
			$params = $this->storeSearchParams( $view->param(), 'service' );
258
			$manager = \Aimeos\MShop::create( $this->getContext(), 'service' );
259
260
			$search = $manager->createSearch();
261
			$search->setSortations( [$search->sort( '+', 'service.type' ), $search->sort( '+', 'service.position' )] );
262
			$search = $this->initCriteria( $search, $params );
263
264
			$view->items = $manager->searchItems( $search, $this->getDomains(), $total );
265
			$view->filterAttributes = $manager->getSearchAttributes( true );
266
			$view->filterOperators = $search->getOperators();
267
			$view->itemTypes = $this->getTypeItems();
268
			$view->total = $total;
269
			$view->itemBody = '';
270
271
			foreach( $this->getSubClients() as $client ) {
272
				$view->itemBody .= $client->search();
273
			}
274
		}
275
		catch( \Exception $e )
276
		{
277
			$this->report( $e, 'search' );
278
		}
279
280
		/** admin/jqadm/service/template-list
281
		 * Relative path to the HTML body template for the service list.
282
		 *
283
		 * The template file contains the HTML code and processing instructions
284
		 * to generate the result shown in the body of the frontend. The
285
		 * configuration string is the path to the template file relative
286
		 * to the templates directory (usually in admin/jqadm/templates).
287
		 *
288
		 * You can overwrite the template file configuration in extensions and
289
		 * provide alternative templates. These alternative templates should be
290
		 * named like the default one but with the string "default" replaced by
291
		 * an unique name. You may use the name of your project for this. If
292
		 * you've implemented an alternative client class as well, "default"
293
		 * should be replaced by the name of the new class.
294
		 *
295
		 * @param string Relative path to the template creating the HTML code
296
		 * @since 2016.04
297
		 * @category Developer
298
		 */
299
		$tplconf = 'admin/jqadm/service/template-list';
300
		$default = 'service/list-standard';
301
302
		return $view->render( $view->config( $tplconf, $default ) );
303
	}
304
305
306
	/**
307
	 * Returns the sub-client given by its name.
308
	 *
309
	 * @param string $type Name of the client type
310
	 * @param string|null $name Name of the sub-client (Default if null)
311
	 * @return \Aimeos\Admin\JQAdm\Iface Sub-client object
312
	 */
313
	public function getSubClient( string $type, string $name = null ) : \Aimeos\Admin\JQAdm\Iface
314
	{
315
		/** admin/jqadm/service/decorators/excludes
316
		 * Excludes decorators added by the "common" option from the service JQAdm client
317
		 *
318
		 * Decorators extend the functionality of a class by adding new aspects
319
		 * (e.g. log what is currently done), executing the methods of the underlying
320
		 * class only in certain conditions (e.g. only for logged in users) or
321
		 * modify what is returned to the caller.
322
		 *
323
		 * This option allows you to remove a decorator added via
324
		 * "client/jqadm/common/decorators/default" before they are wrapped
325
		 * around the JQAdm client.
326
		 *
327
		 *  admin/jqadm/service/decorators/excludes = array( 'decorator1' )
328
		 *
329
		 * This would remove the decorator named "decorator1" from the list of
330
		 * common decorators ("\Aimeos\Admin\JQAdm\Common\Decorator\*") added via
331
		 * "client/jqadm/common/decorators/default" to the JQAdm client.
332
		 *
333
		 * @param array List of decorator names
334
		 * @since 2017.10
335
		 * @category Developer
336
		 * @see admin/jqadm/common/decorators/default
337
		 * @see admin/jqadm/service/decorators/global
338
		 * @see admin/jqadm/service/decorators/local
339
		 */
340
341
		/** admin/jqadm/service/decorators/global
342
		 * Adds a list of globally available decorators only to the service JQAdm client
343
		 *
344
		 * Decorators extend the functionality of a class by adding new aspects
345
		 * (e.g. log what is currently done), executing the methods of the underlying
346
		 * class only in certain conditions (e.g. only for logged in users) or
347
		 * modify what is returned to the caller.
348
		 *
349
		 * This option allows you to wrap global decorators
350
		 * ("\Aimeos\Admin\JQAdm\Common\Decorator\*") around the JQAdm client.
351
		 *
352
		 *  admin/jqadm/service/decorators/global = array( 'decorator1' )
353
		 *
354
		 * This would add the decorator named "decorator1" defined by
355
		 * "\Aimeos\Admin\JQAdm\Common\Decorator\Decorator1" only to the JQAdm client.
356
		 *
357
		 * @param array List of decorator names
358
		 * @since 2017.10
359
		 * @category Developer
360
		 * @see admin/jqadm/common/decorators/default
361
		 * @see admin/jqadm/service/decorators/excludes
362
		 * @see admin/jqadm/service/decorators/local
363
		 */
364
365
		/** admin/jqadm/service/decorators/local
366
		 * Adds a list of local decorators only to the service JQAdm client
367
		 *
368
		 * Decorators extend the functionality of a class by adding new aspects
369
		 * (e.g. log what is currently done), executing the methods of the underlying
370
		 * class only in certain conditions (e.g. only for logged in users) or
371
		 * modify what is returned to the caller.
372
		 *
373
		 * This option allows you to wrap local decorators
374
		 * ("\Aimeos\Admin\JQAdm\Service\Decorator\*") around the JQAdm client.
375
		 *
376
		 *  admin/jqadm/service/decorators/local = array( 'decorator2' )
377
		 *
378
		 * This would add the decorator named "decorator2" defined by
379
		 * "\Aimeos\Admin\JQAdm\Service\Decorator\Decorator2" only to the JQAdm client.
380
		 *
381
		 * @param array List of decorator names
382
		 * @since 2017.10
383
		 * @category Developer
384
		 * @see admin/jqadm/common/decorators/default
385
		 * @see admin/jqadm/service/decorators/excludes
386
		 * @see admin/jqadm/service/decorators/global
387
		 */
388
		return $this->createSubClient( 'service/' . $type, $name );
389
	}
390
391
392
	/**
393
	 * Returns the backend configuration attributes of the provider and decorators
394
	 *
395
	 * @param \Aimeos\MShop\Service\Item\Iface $item Service item incl. provider/decorator property
396
	 * @return \Aimeos\MW\Common\Critera\Attribute\Iface[] List of configuration attributes
397
	 */
398
	public function getConfigAttributes( \Aimeos\MShop\Service\Item\Iface $item ) : array
399
	{
400
		$manager = \Aimeos\MShop::create( $this->getContext(), 'service' );
401
402
		try {
403
			return $manager->getProvider( $item, $item->getType() )->getConfigBE();
404
		} catch( \Aimeos\MShop\Exception $e ) {
405
			return [];
406
		}
407
	}
408
409
410
	/**
411
	 * Returns the domain names whose items should be fetched too
412
	 *
413
	 * @return string[] List of domain names
414
	 */
415
	protected function getDomains() : array
416
	{
417
		/** admin/jqadm/service/domains
418
		 * List of domain items that should be fetched along with the service
419
		 *
420
		 * If you need to display additional content, you can configure your own
421
		 * list of domains (attribute, media, price, service, text, etc. are
422
		 * domains) whose items are fetched from the storage.
423
		 *
424
		 * @param array List of domain names
425
		 * @since 2017.10
426
		 * @category Developer
427
		 */
428
		return $this->getContext()->getConfig()->get( 'admin/jqadm/service/domains', [] );
429
	}
430
431
432
	/**
433
	 * Returns the list of sub-client names configured for the client.
434
	 *
435
	 * @return array List of JQAdm client names
436
	 */
437
	protected function getSubClientNames() : array
438
	{
439
		/** admin/jqadm/service/standard/subparts
440
		 * List of JQAdm sub-clients rendered within the service section
441
		 *
442
		 * The output of the frontend is composed of the code generated by the JQAdm
443
		 * clients. Each JQAdm client can consist of serveral (or none) sub-clients
444
		 * that are responsible for rendering certain sub-parts of the output. The
445
		 * sub-clients can contain JQAdm clients themselves and therefore a
446
		 * hierarchical tree of JQAdm clients is composed. Each JQAdm client creates
447
		 * the output that is placed inside the container of its parent.
448
		 *
449
		 * At first, always the JQAdm code generated by the parent is printed, then
450
		 * the JQAdm code of its sub-clients. The order of the JQAdm sub-clients
451
		 * determines the order of the output of these sub-clients inside the parent
452
		 * container. If the configured list of clients is
453
		 *
454
		 *  array( "subclient1", "subclient2" )
455
		 *
456
		 * you can easily change the order of the output by reordering the subparts:
457
		 *
458
		 *  admin/jqadm/<clients>/subparts = array( "subclient1", "subclient2" )
459
		 *
460
		 * You can also remove one or more parts if they shouldn't be rendered:
461
		 *
462
		 *  admin/jqadm/<clients>/subparts = array( "subclient1" )
463
		 *
464
		 * As the clients only generates structural JQAdm, the layout defined via CSS
465
		 * should support adding, removing or reordering content by a fluid like
466
		 * design.
467
		 *
468
		 * @param array List of sub-client names
469
		 * @since 2017.10
470
		 * @category Developer
471
		 */
472
		return $this->getContext()->getConfig()->get( 'admin/jqadm/service/standard/subparts', [] );
473
	}
474
475
476
	/**
477
	 * Returns the available service type items
478
	 *
479
	 * @return \Aimeos\Map List of item implementing \Aimeos\MShop\Common\Type\Iface
480
	 */
481
	protected function getTypeItems() : \Aimeos\Map
482
	{
483
		$typeManager = \Aimeos\MShop::create( $this->getContext(), 'service/type' );
484
485
		$search = $typeManager->createSearch( true )->setSlice( 0, 10000 );
486
		$search->setSortations( [$search->sort( '+', 'service.type.position' )] );
487
488
		return $typeManager->searchItems( $search );
489
	}
490
491
492
	/**
493
	 * Creates new and updates existing items using the data array
494
	 *
495
	 * @param array $data Data array
496
	 * @return \Aimeos\MShop\Service\Item\Iface New service item object
497
	 */
498
	protected function fromArray( array $data ) : \Aimeos\MShop\Service\Item\Iface
499
	{
500
		$conf = [];
501
502
		if( isset( $data['config']['key'] ) )
503
		{
504
			foreach( (array) $data['config']['key'] as $idx => $key )
505
			{
506
				if( trim( $key ) !== '' && isset( $data['config']['val'][$idx] ) )
507
				{
508
					if( ( $val = json_decode( $data['config']['val'][$idx] ) ) === null ) {
509
						$conf[$key] = $data['config']['val'][$idx];
510
					} else {
511
						$conf[$key] = $val;
512
					}
513
				}
514
			}
515
		}
516
517
		$manager = \Aimeos\MShop::create( $this->getContext(), 'service' );
518
519
		if( isset( $data['service.id'] ) && $data['service.id'] != '' ) {
520
			$item = $manager->getItem( $data['service.id'], $this->getDomains() );
521
		} else {
522
			$item = $manager->createItem();
523
		}
524
525
		$item->fromArray( $data, true );
526
		$item->setConfig( $conf );
527
528
		return $item;
529
	}
530
531
532
	/**
533
	 * Constructs the data array for the view from the given item
534
	 *
535
	 * @param \Aimeos\MShop\Service\Item\Iface $item Service item object
536
	 * @return string[] Multi-dimensional associative list of item data
537
	 */
538
	protected function toArray( \Aimeos\MShop\Service\Item\Iface $item, bool $copy = false ) : array
539
	{
540
		$config = $item->getConfig();
541
		$data = $item->toArray( true );
542
		$data['config'] = [];
543
544
		if( $copy === true )
545
		{
546
			$data['service.siteid'] = $this->getContext()->getLocale()->getSiteId();
547
			$data['service.code'] = $data['service.code'] . '_copy';
548
			$data['service.id'] = '';
549
		}
550
551
		ksort( $config );
552
553
		foreach( $config as $key => $value )
554
		{
555
			$data['config']['key'][] = $key;
556
			$data['config']['val'][] = $value;
557
		}
558
559
		return $data;
560
	}
561
562
563
	/**
564
	 * Returns the rendered template including the view data
565
	 *
566
	 * @param \Aimeos\MW\View\Iface $view View object with data assigned
567
	 * @return string|null HTML output
568
	 */
569
	protected function render( \Aimeos\MW\View\Iface $view ) : string
570
	{
571
		/** admin/jqadm/service/template-item
572
		 * Relative path to the HTML body template for the service item.
573
		 *
574
		 * The template file contains the HTML code and processing instructions
575
		 * to generate the result shown in the body of the frontend. The
576
		 * configuration string is the path to the template file relative
577
		 * to the templates directory (usually in admin/jqadm/templates).
578
		 *
579
		 * You can overwrite the template file configuration in extensions and
580
		 * provide alternative templates. These alternative templates should be
581
		 * named like the default one but with the string "default" replaced by
582
		 * an unique name. You may use the name of your project for this. If
583
		 * you've implemented an alternative client class as well, "default"
584
		 * should be replaced by the name of the new class.
585
		 *
586
		 * @param string Relative path to the template creating the HTML code
587
		 * @since 2016.04
588
		 * @category Developer
589
		 */
590
		$tplconf = 'admin/jqadm/service/template-item';
591
		$default = 'service/item-standard';
592
593
		return $view->render( $view->config( $tplconf, $default ) );
594
	}
595
}
596