Passed
Push — master ( b1a653...24fc04 )
by Aimeos
03:29
created

Base::batchBase()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 10
nc 2
nop 1
dl 0
loc 20
rs 9.9332
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2022
6
 * @package Admin
7
 * @subpackage JQAdm
8
 */
9
10
11
namespace Aimeos\Admin\JQAdm;
12
13
sprintf( 'type' ); // for translation
14
15
16
/**
17
 * Common abstract class for all admin client classes.
18
 *
19
 * @package Admin
20
 * @subpackage JQAdm
21
 */
22
abstract class Base
23
	implements \Aimeos\Admin\JQAdm\Iface, \Aimeos\Macro\Iface
24
{
25
	use \Aimeos\Macro\Macroable;
26
27
28
	private $view;
29
	private $aimeos;
30
	private $context;
31
	private $subclients;
32
	private $object;
33
34
35
	/**
36
	 * Initializes the class instance.
37
	 *
38
	 * @param \Aimeos\MShop\ContextIface $context Context object
39
	 */
40
	public function __construct( \Aimeos\MShop\ContextIface $context )
41
	{
42
		$this->context = $context;
43
	}
44
45
46
	/**
47
	 * Adds the required data used in the attribute template
48
	 *
49
	 * @param \Aimeos\Base\View\Iface $view View object
50
	 * @return \Aimeos\Base\View\Iface View object with assigned parameters
51
	 */
52
	public function data( \Aimeos\Base\View\Iface $view ) : \Aimeos\Base\View\Iface
53
	{
54
		return $view;
55
	}
56
57
58
	/**
59
	 * Returns the Aimeos bootstrap object
60
	 *
61
	 * @return \Aimeos\Bootstrap The Aimeos bootstrap object
62
	 */
63
	public function getAimeos() : \Aimeos\Bootstrap
64
	{
65
		if( !isset( $this->aimeos ) ) {
66
			throw new \Aimeos\Admin\JQAdm\Exception( $this->context->translate( 'admin', 'Aimeos object not available' ) );
67
		}
68
69
		return $this->aimeos;
70
	}
71
72
73
	/**
74
	 * Sets the Aimeos bootstrap object
75
	 *
76
	 * @param \Aimeos\Bootstrap $aimeos The Aimeos bootstrap object
77
	 * @return \Aimeos\Admin\JQAdm\Iface Reference to this object for fluent calls
78
	 */
79
	public function setAimeos( \Aimeos\Bootstrap $aimeos ) : \Aimeos\Admin\JQAdm\Iface
80
	{
81
		$this->aimeos = $aimeos;
82
		return $this;
83
	}
84
85
86
	/**
87
	 * Makes the outer decorator object available to inner objects
88
	 *
89
	 * @param \Aimeos\Admin\JQAdm\Iface $object Outmost object
90
	 * @return \Aimeos\Admin\JQAdm\Iface Same object for fluent interface
91
	 */
92
	public function setObject( \Aimeos\Admin\JQAdm\Iface $object ) : \Aimeos\Admin\JQAdm\Iface
93
	{
94
		$this->object = $object;
95
		return $this;
96
	}
97
98
99
	/**
100
	 * Returns the view object that will generate the admin output.
101
	 *
102
	 * @return \Aimeos\Base\View\Iface The view object which generates the admin output
103
	 */
104
	protected function view() : \Aimeos\Base\View\Iface
105
	{
106
		if( !isset( $this->view ) ) {
107
			throw new \Aimeos\Admin\JQAdm\Exception( $this->context->translate( 'admin', 'No view available' ) );
108
		}
109
110
		return $this->view;
111
	}
112
113
114
	/**
115
	 * Sets the view object that will generate the admin output.
116
	 *
117
	 * @param \Aimeos\Base\View\Iface $view The view object which generates the admin output
118
	 * @return \Aimeos\Admin\JQAdm\Iface Reference to this object for fluent calls
119
	 */
120
	public function setView( \Aimeos\Base\View\Iface $view ) : \Aimeos\Admin\JQAdm\Iface
121
	{
122
		$this->view = $view;
123
		return $this;
124
	}
125
126
127
	/**
128
	 * Batch update of a resource
129
	 *
130
	 * @return string|null Output to display
131
	 */
132
	public function batch() : ?string
133
	{
134
		return null;
135
	}
136
137
138
	/**
139
	 * Copies a resource
140
	 *
141
	 * @return string|null Output to display
142
	 */
143
	public function copy() : ?string
144
	{
145
		$body = null;
146
		$view = $this->view();
147
148
		foreach( $this->getSubClients() as $idx => $client )
149
		{
150
			$view->tabindex = ++$idx + 1;
151
			$body .= $client->copy();
152
		}
153
154
		return $body;
155
	}
156
157
158
	/**
159
	 * Creates a new resource
160
	 *
161
	 * @return string|null Output to display
162
	 */
163
	public function create() : ?string
164
	{
165
		$body = null;
166
		$view = $this->view();
167
168
		foreach( $this->getSubClients() as $idx => $client )
169
		{
170
			$view->tabindex = ++$idx + 1;
171
			$body .= $client->create();
172
		}
173
174
		return $body;
175
	}
176
177
178
	/**
179
	 * Deletes a resource
180
	 *
181
	 * @return string|null Output to display
182
	 */
183
	public function delete() : ?string
184
	{
185
		$body = null;
186
187
		foreach( $this->getSubClients() as $client ) {
188
			$body .= $client->delete();
189
		}
190
191
		return $body;
192
	}
193
194
195
	/**
196
	 * Exports a resource
197
	 *
198
	 * @return string|null Output to display
199
	 */
200
	public function export() : ?string
201
	{
202
		$body = null;
203
204
		foreach( $this->getSubClients() as $client ) {
205
			$body .= $client->export();
206
		}
207
208
		return $body;
209
	}
210
211
212
	/**
213
	 * Returns a resource
214
	 *
215
	 * @return string|null Output to display
216
	 */
217
	public function get() : ?string
218
	{
219
		$body = null;
220
		$view = $this->view();
221
222
		foreach( $this->getSubClients() as $idx => $client )
223
		{
224
			$view->tabindex = ++$idx + 1;
225
			$body .= $client->get();
226
		}
227
228
		return $body;
229
	}
230
231
232
	/**
233
	 * Imports a resource
234
	 *
235
	 * @return string|null Output to display
236
	 * @deprecated 2021.01
237
	 */
238
	public function import() : ?string
239
	{
240
		$body = null;
241
242
		foreach( $this->getSubClients() as $client ) {
243
			$body .= $client->import();
244
		}
245
246
		return null;
247
	}
248
249
250
	/**
251
	 * Saves the data
252
	 *
253
	 * @return string|null Output to display
254
	 */
255
	public function save() : ?string
256
	{
257
		$body = null;
258
259
		foreach( $this->getSubClients() as $client ) {
260
			$body .= $client->save();
261
		}
262
263
		return $body;
264
	}
265
266
267
	/**
268
	 * Returns a list of resource according to the conditions
269
	 *
270
	 * @return string|null Output to display
271
	 */
272
	public function search() : ?string
273
	{
274
		$body = null;
275
276
		foreach( $this->getSubClients() as $client ) {
277
			$body .= $client->search();
278
		}
279
280
		return $body;
281
	}
282
283
284
	/**
285
	 * Returns the PSR-7 response object for the request
286
	 *
287
	 * @return \Psr\Http\Message\ResponseInterface Response object
288
	 */
289
	public function response() : \Psr\Http\Message\ResponseInterface
290
	{
291
		return $this->view()->response();
292
	}
293
294
295
	/**
296
	 * Adds the decorators to the client object
297
	 *
298
	 * @param \Aimeos\Admin\JQAdm\Iface $client Admin object
299
	 * @param array $decorators List of decorator name that should be wrapped around the client
300
	 * @param string $classprefix Decorator class prefix, e.g. "\Aimeos\Admin\JQAdm\Catalog\Decorator\"
301
	 * @return \Aimeos\Admin\JQAdm\Iface Admin object
302
	 */
303
	protected function addDecorators( \Aimeos\Admin\JQAdm\Iface $client, array $decorators, string $classprefix ) : \Aimeos\Admin\JQAdm\Iface
304
	{
305
		foreach( $decorators as $name )
306
		{
307
			$classname = $classprefix . $name;
308
309
			if( ctype_alnum( $name ) === false )
310
			{
311
				$msg = $this->context->translate( 'admin', 'Invalid class name "%1$s"' );
312
				throw new \Aimeos\Admin\JQAdm\Exception( sprintf( $msg, $classname ) );
313
			}
314
315
			if( class_exists( $classname ) === false )
316
			{
317
				$msg = $this->context->translate( 'admin', 'Class "%1$s" not found' );
318
				throw new \Aimeos\Admin\JQAdm\Exception( sprintf( $msg, $classname ) );
319
			}
320
321
			$client = new $classname( $client, $this->context );
322
323
			\Aimeos\MW\Common\Base::checkClass( '\\Aimeos\\Admin\\JQAdm\\Common\\Decorator\\Iface', $client );
324
		}
325
326
		return $client;
327
	}
328
329
330
	/**
331
	 * Adds the decorators to the client object
332
	 *
333
	 * @param \Aimeos\Admin\JQAdm\Iface $client Admin object
334
	 * @param string $path Admin string in lower case, e.g. "catalog/detail/basic"
335
	 * @return \Aimeos\Admin\JQAdm\Iface Admin object
336
	 */
337
	protected function addClientDecorators( \Aimeos\Admin\JQAdm\Iface $client, string $path ) : \Aimeos\Admin\JQAdm\Iface
338
	{
339
		if( !is_string( $path ) || $path === '' )
0 ignored issues
show
introduced by
The condition is_string($path) is always true.
Loading history...
340
		{
341
			$msg = $this->context->translate( 'admin', 'Invalid domain "%1$s"' );
342
			throw new \Aimeos\Admin\JQAdm\Exception( sprintf( $msg, $path ) );
343
		}
344
345
		$localClass = str_replace( '/', '\\', ucwords( $path, '/' ) );
346
		$config = $this->context->config();
347
348
		$classprefix = '\\Aimeos\\Admin\\JQAdm\\Common\\Decorator\\';
349
		$decorators = $config->get( 'admin/jqadm/' . $path . '/decorators/global', [] );
350
		$client = $this->addDecorators( $client, $decorators, $classprefix );
351
352
		$classprefix = '\\Aimeos\\Admin\\JQAdm\\' . $localClass . '\\Decorator\\';
353
		$decorators = $config->get( 'admin/jqadm/' . $path . '/decorators/local', [] );
354
		$client = $this->addDecorators( $client, $decorators, $classprefix );
355
356
		return $client;
357
	}
358
359
360
	/**
361
	 * Modifiy several items at once
362
	 *
363
	 * @param string $domain Data domain of the items
364
	 * @return string|null Output to display
365
	 */
366
	protected function batchBase( string $domain ) : ?string
367
	{
368
		$view = $this->view();
369
370
		if( !empty( $ids = $view->param( 'id' ) ) )
371
		{
372
			$manager = \Aimeos\MShop::create( $this->context(), $domain );
373
			$filter = $manager->filter()->add( [$domain . '.id' => $ids] )->slice( 0, count( $ids ) );
374
			$items = $manager->search( $filter );
375
376
			$data = $view->param( 'item', [] );
377
378
			foreach( $items as $item ) {
379
				$temp = $data; $item->fromArray( $temp );
380
			}
381
382
			$manager->save( $items );
383
		}
384
385
		return $this->redirect( $domain, 'search', null, 'save' );
386
	}
387
388
389
	/**
390
	 * Returns the sub-client given by its name.
391
	 *
392
	 * @param string $path Name of the sub-part in lower case (can contain a path like catalog/filter/tree)
393
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
394
	 * @return \Aimeos\Admin\JQAdm\Iface Sub-part object
395
	 */
396
	protected function createSubClient( string $path, string $name = null ) : \Aimeos\Admin\JQAdm\Iface
397
	{
398
		$path = strtolower( $path );
399
400
		if( $name === null ) {
401
			$name = $this->context->config()->get( 'admin/jqadm/' . $path . '/name', 'Standard' );
402
		}
403
404
		if( empty( $name ) || ctype_alnum( $name ) === false )
405
		{
406
			$msg = $this->context->translate( 'admin', 'Invalid characters in client name "%1$s"' );
407
			throw new \Aimeos\Admin\JQAdm\Exception( sprintf( $msg, $name ) );
408
		}
409
410
		$subnames = str_replace( '/', '\\', ucwords( $path, '/' ) );
411
		$classname = '\\Aimeos\\Admin\\JQAdm\\' . $subnames . '\\' . $name;
412
413
		if( class_exists( $classname ) === false )
414
		{
415
			$msg = $this->context->translate( 'admin', 'Class "%1$s" not available' );
416
			throw new \Aimeos\Admin\JQAdm\Exception( sprintf( $msg, $classname ) );
417
		}
418
419
		$object = new $classname( $this->context );
420
		$object = \Aimeos\MW\Common\Base::checkClass( '\\Aimeos\\Admin\\JQAdm\\Iface', $object );
421
		$object = $this->addClientDecorators( $object, $path );
422
423
		return $object->setObject( $object )->setAimeos( $this->aimeos )->setView( $this->view );
0 ignored issues
show
Bug introduced by
The method setObject() does not exist on Aimeos\Admin\JQAdm\Iface. It seems like you code against a sub-type of said class. However, the method does not exist in Aimeos\Admin\JQAdm\Common\Admin\Factory\Iface or Aimeos\Admin\JQAdm\Common\Decorator\Iface. Are you sure you never get one of those? ( Ignorable by Annotation )

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

423
		return $object->/** @scrutinizer ignore-call */ setObject( $object )->setAimeos( $this->aimeos )->setView( $this->view );
Loading history...
424
	}
425
426
427
	/**
428
	 * Returns the value for the given key in the array
429
	 *
430
	 * @param array $values Multi-dimensional associative list of key/value pairs
431
	 * @param string $key Parameter key like "name" or "list/test" for associative arrays
432
	 * @param mixed $default Returned value if no one for key is available
433
	 * @return mixed Value from the array or default value if not present in array
434
	 */
435
	protected function val( array $values, $key, $default = null )
436
	{
437
		foreach( explode( '/', trim( $key, '/' ) ) as $part )
438
		{
439
			if( is_array( $values ) && isset( $values[$part] ) ) {
440
				$values = $values[$part];
441
			} else {
442
				return $default;
443
			}
444
		}
445
446
		return $values;
447
	}
448
449
450
	/**
451
	 * Returns the known client parameters and their values
452
	 *
453
	 * @param array $names List of parameter names
454
	 * @return array Associative list of parameters names as key and their values
455
	 */
456
	protected function getClientParams( $names = ['id', 'resource', 'site', 'locale'] ) : array
457
	{
458
		$list = [];
459
460
		foreach( $names as $name )
461
		{
462
			if( ( $val = $this->view->param( $name ) ) !== null && !is_array( $val ) ) {
463
				$list[$name] = $val;
464
			}
465
		}
466
467
		return $list;
468
	}
469
470
471
	/**
472
	 * Returns the context object.
473
	 *
474
	 * @return \Aimeos\MShop\ContextIface Context object
475
	 */
476
	protected function context() : \Aimeos\MShop\ContextIface
477
	{
478
		return $this->context;
479
	}
480
481
482
	/**
483
	 * Returns the available class names without namespace that are stored in the given path
484
	 *
485
	 * @param string $relpath Path relative to the include paths
486
	 * @param string[] $excludes List of file names to execlude
487
	 * @return string[] List of available class names
488
	 */
489
	protected function getClassNames( string $relpath, array $excludes = ['Base.php', 'Iface.php', 'Example.php', 'None.php'] ) : array
490
	{
491
		$list = [];
492
493
		foreach( $this->getAimeos()->getIncludePaths() as $path )
494
		{
495
			$path .= DIRECTORY_SEPARATOR . $relpath;
496
497
			if( is_dir( $path ) )
498
			{
499
				foreach( new \DirectoryIterator( $path ) as $entry )
500
				{
501
					if( $entry->isFile() && !in_array( $entry->getFileName(), $excludes ) ) {
502
						$list[] = pathinfo( $entry->getFileName(), PATHINFO_FILENAME );
503
					}
504
				}
505
			}
506
		}
507
508
		sort( $list );
509
		return $list;
510
	}
511
512
513
	/**
514
	 * Returns the array of criteria conditions based on the given parameters
515
	 *
516
	 * @param array $params List of criteria data with condition, sorting and paging
517
	 * @return array Multi-dimensional associative list of criteria conditions
518
	 */
519
	protected function getCriteriaConditions( array $params ) : array
520
	{
521
		$expr = [];
522
523
		if( isset( $params['key'] ) )
524
		{
525
			foreach( (array) $params['key'] as $idx => $key )
526
			{
527
				if( $key != '' && isset( $params['op'][$idx] ) && $params['op'][$idx] != ''
528
					&& isset( $params['val'][$idx] ) && $params['val'][$idx] != ''
529
				) {
530
					$expr[] = [$params['op'][$idx] => [$key => $params['val'][$idx]]];
531
				}
532
			}
533
534
			if( !empty( $expr ) ) {
535
				$expr = ['&&' => $expr];
536
			}
537
		}
538
539
		return $expr;
540
	}
541
542
543
	/**
544
	 * Returns the outer decoratorator of the object
545
	 *
546
	 * @return \Aimeos\Admin\JQAdm\Iface Outmost object
547
	 */
548
	protected function object() : Iface
549
	{
550
		if( isset( $this->object ) ) {
551
			return $this->object;
552
		}
553
554
		return $this;
555
	}
556
557
558
	/**
559
	 * Returns the sub-client given by its name.
560
	 *
561
	 * @param string $type Name of the client type
562
	 * @param string|null $name Name of the sub-client (Default if null)
563
	 * @return \Aimeos\Admin\JQAdm\Iface Sub-client object
564
	 */
565
	public function getSubClient( string $type, string $name = null ) : \Aimeos\Admin\JQAdm\Iface
566
	{
567
		$msg = $this->context()->translate( 'admin', 'Not implemented' );
568
		throw new \Aimeos\Admin\JQAdm\Exception( $msg );
569
	}
570
571
572
	/**
573
	 * Returns the configured sub-clients or the ones named in the default parameter if none are configured.
574
	 *
575
	 * @return array List of sub-clients implementing \Aimeos\Admin\JQAdm\Iface ordered in the same way as the names
576
	 */
577
	protected function getSubClients() : array
578
	{
579
		if( !isset( $this->subclients ) )
580
		{
581
			$this->subclients = [];
582
583
			foreach( $this->getSubClientNames() as $name ) {
584
				$this->subclients[] = $this->getSubClient( $name );
585
			}
586
		}
587
588
		return $this->subclients;
589
	}
590
591
592
	/**
593
	 * Returns the list of sub-client names configured for the client.
594
	 *
595
	 * @return array List of admin client names
596
	 */
597
	protected function getSubClientNames() : array
598
	{
599
		return [];
600
	}
601
602
603
	/**
604
	 * Initializes the criteria object based on the given parameter
605
	 *
606
	 * @param \Aimeos\Base\Criteria\Iface $criteria Criteria object
607
	 * @param array $params List of criteria data with condition, sorting and paging
608
	 * @return \Aimeos\Base\Criteria\Iface Initialized criteria object
609
	 */
610
	protected function initCriteria( \Aimeos\Base\Criteria\Iface $criteria, array $params ) : \Aimeos\Base\Criteria\Iface
611
	{
612
		if( isset( $params['sort'] ) && !empty( $params['sort'] ) ) {
613
			$criteria->order( $params['sort'] );
614
		}
615
616
		return $criteria->slice( $params['page']['offset'] ?? 0, $params['page']['limit'] ?? 25 )
617
			->add( $criteria->parse( $this->getCriteriaConditions( $params['filter'] ?? [] ) ) );
618
	}
619
620
621
	/**
622
	 * Flattens the nested configuration array
623
	 *
624
	 * @param array $config Multi-dimensional list of key/value pairs
625
	 * @param string $path Path of keys separated by slashes (/) to add new values for
626
	 * @return array List of arrays with "key" and "val" keys
627
	 */
628
	protected function flatten( array $config, string $path = '' ) : array
629
	{
630
		$list = [];
631
632
		foreach( $config as $key => $val )
633
		{
634
			if( is_array( $val ) ) {
635
				$list = array_merge( $list, $this->flatten( $val, $path . '/' . $key ) );
636
			} else {
637
				$list[] = ['key' => trim( $path . '/' . $key, '/' ), 'val' => $val];
638
			}
639
		}
640
641
		return $list;
642
	}
643
644
645
	/**
646
	 * Writes the exception details to the log
647
	 *
648
	 * @param \Exception $e Exception object
649
	 * @return \Aimeos\Admin\JQAdm\Iface Reference to this object for fluent calls
650
	 */
651
	protected function log( \Exception $e ) : Iface
652
	{
653
		$msg = $e->getMessage() . PHP_EOL;
654
655
		if( $e instanceof \Aimeos\Admin\JQAdm\Exception ) {
656
			$msg .= print_r( $e->getDetails(), true ) . PHP_EOL;
0 ignored issues
show
Bug introduced by
Are you sure print_r($e->getDetails(), true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

656
			$msg .= /** @scrutinizer ignore-type */ print_r( $e->getDetails(), true ) . PHP_EOL;
Loading history...
657
		}
658
659
		$this->context->logger()->error( $msg . $e->getTraceAsString(), 'admin/jqadm' );
660
661
		return $this;
662
	}
663
664
665
	/**
666
	 * Adds a redirect to the response for the next action
667
	 *
668
	 * @param string $resource Resource name
669
	 * @param string|null $action Next action
670
	 * @param string|null $id ID of the next resource item
671
	 * @param string|null $method Current method name
672
	 * @param array $params URL parameters to use
673
	 * @return string|null Returns value for the actions
674
	 */
675
	protected function redirect( string $resource, ?string $action, string $id = null,
676
		string $method = null, array $params = [] ) : ?string
677
	{
678
		$params += $this->getClientParams();
679
		$context = $this->context();
680
		$view = $this->view();
681
682
		$params['resource'] = $resource;
683
		unset( $params['id'] );
684
685
		switch( $action )
686
		{
687
			case 'search':
688
				$url = $view->link( 'admin/jqadm/url/search', $params ); break;
689
			case 'create':
690
				$url = $view->link( 'admin/jqadm/url/create', ['parentid' => $id] + $params ); break;
691
			case 'copy':
692
				$url = $view->link( 'admin/jqadm/url/copy', ['id' => $id] + $params ); break;
693
			default:
694
				$url = $view->link( 'admin/jqadm/url/get', ['id' => $id] + $params );
695
		}
696
697
		switch( $method )
698
		{
699
			case 'save':
700
				$context->session()->set( 'info', [$context->translate( 'admin', 'Item saved successfully' )] ); break;
701
			case 'delete':
702
				$context->session()->set( 'info', [$context->translate( 'admin', 'Item deleted successfully' )] ); break;
703
		}
704
705
		$view->response()->withStatus( 302 );
706
		$view->response()->withHeader( 'Location', $url );
707
		$view->response()->withHeader( 'Cache-Control', 'no-store' );
708
709
		return null;
710
	}
711
712
713
	/**
714
	 * Writes the exception details to the log
715
	 *
716
	 * @param \Exception $e Exception object
717
	 * @param string $method Method it's called from
718
	 * @return \Aimeos\Admin\JQAdm\Iface Reference to this object for fluent calls
719
	 */
720
	protected function report( \Exception $e, string $method ) : Iface
721
	{
722
		$view = $this->view;
723
		$i18n = $this->context->i18n();
724
725
		if( $e instanceof \Aimeos\Admin\JQAdm\Exception )
726
		{
727
			$view->errors = array_merge( $view->get( 'errors', [] ), [$e->getMessage()] );
728
			return $this->log( $e );
729
		}
730
		elseif( $e instanceof \Aimeos\MShop\Exception )
731
		{
732
			$view->errors = array_merge( $view->get( 'errors', [] ), [$i18n->dt( 'mshop', $e->getMessage() )] );
733
			return $this->log( $e );
734
		}
735
736
		switch( $method )
737
		{
738
			case 'save': $msg = $i18n->dt( 'admin', 'Error saving data' ); break;
739
			case 'delete': $msg = $i18n->dt( 'admin', 'Error deleting data' ); break;
740
			default: $msg = $i18n->dt( 'admin', 'Error retrieving data' ); break;
741
		}
742
743
		$view->errors = array_merge( $view->get( 'errors', [] ), [$msg] );
744
745
		return $this->log( $e );
746
	}
747
748
749
	/**
750
	 * Checks and returns the request parameter for the given name
751
	 *
752
	 * @param string $name Name of the request parameter, can be a path like 'page/limit'
753
	 * @return mixed Parameter value
754
	 * @throws \Aimeos\Admin\JQAdm\Exception If the parameter is missing
755
	 */
756
	protected function require( string $name )
757
	{
758
		if( ( $value = $this->view()->param( $name ) ) !== null ) {
759
			return $value;
760
		}
761
762
		$msg = $this->context->translate( 'admin', 'Required parameter "%1$s" is missing' );
763
		throw new \Aimeos\Admin\JQAdm\Exception( sprintf( $msg, $name ) );
764
	}
765
766
767
	/**
768
	 * Stores and returns the parameters used for searching items
769
	 *
770
	 * @param array $params GET/POST parameter set
771
	 * @param string $name Name of the panel/subpanel
772
	 * @return array Associative list of parameters for searching items
773
	 */
774
	protected function storeFilter( array $params, string $name ) : array
775
	{
776
		$key = 'aimeos/admin/jqadm/' . $name;
777
		$session = $this->context()->session();
778
779
		foreach( ['fields', 'filter', 'page', 'sort'] as $part )
780
		{
781
			if( isset( $params[$part] ) ) {
782
				$session->set( $key . '/' . $part, $params[$part] );
783
			}
784
		}
785
786
		return [
787
			'fields' => $session->get( $key . '/fields' ),
788
			'filter' => $session->get( $key . '/filter' ),
789
			'page' => $session->get( $key . '/page' ),
790
			'sort' => $session->get( $key . '/sort' ),
791
		];
792
	}
793
794
795
	/**
796
	 * Throws an exception with given details
797
	 *
798
	 * @param array $errors List of key/message pairs of errors
799
	 * @throws \Aimeos\Admin\JQAdm\Exception Exception with error details
800
	 */
801
	protected function notify( array $errors ) : Iface
802
	{
803
		$list = [];
804
		$i18n = $this->context->i18n();
805
806
		foreach( $errors as $key => $error )
807
		{
808
			if( $error ) {
809
				$list[] = $key . ': ' . $i18n->dt( 'mshop', $error );
810
			}
811
		}
812
813
		if( !empty( $list ) ) {
814
			throw new \Aimeos\Admin\JQAdm\Exception( join( "\n", $list ) );
815
		}
816
817
		return $this;
818
	}
819
}
820