Standard::fromArray()   B
last analyzed

Complexity

Conditions 7
Paths 5

Size

Total Lines 41
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 22
nc 5
nop 2
dl 0
loc 41
rs 8.6346
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), 2021-2025
6
 * @package Admin
7
 * @subpackage JQAdm
8
 */
9
10
11
namespace Aimeos\Admin\JQAdm\Cms\Content;
12
13
sprintf( 'content' ); // for translation
14
15
16
/**
17
 * Default implementation of cms SEO 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
	/** admin/jqadm/cms/content/name
27
	 * Name of the SEO subpart used by the JQAdm cms implementation
28
	 *
29
	 * Use "Myname" if your class is named "\Aimeos\Admin\Jqadm\Cms\Text\Myname".
30
	 * The name is case-sensitive and you should avoid camel case names like "MyName".
31
	 *
32
	 * @param string Last part of the JQAdm class name
33
	 * @since 2020.10
34
	 * @category Developer
35
	 */
36
37
38
	/**
39
	 * Copies a resource
40
	 *
41
	 * @return string|null HTML output
42
	 */
43
	public function copy() : ?string
44
	{
45
		$view = $this->object()->data( $this->view() );
46
		$view->contentData = $this->toArray( $view->item, true );
47
		$view->contentBody = parent::copy();
48
49
		return $this->render( $view );
50
	}
51
52
53
	/**
54
	 * Creates a new resource
55
	 *
56
	 * @return string|null HTML output
57
	 */
58
	public function create() : ?string
59
	{
60
		$view = $this->object()->data( $this->view() );
61
		$siteid = $this->context()->locale()->getSiteId();
62
		$data = $view->param( 'content', [] );
63
64
		foreach( $data as $idx => $entry )
65
		{
66
			$data[$idx]['cms.lists.siteid'] = $siteid;
67
			$data[$idx]['text.siteid'] = $siteid;
68
		}
69
70
		$view->contentData = $data;
71
		$view->contentBody = parent::create();
72
73
		return $this->render( $view );
74
	}
75
76
77
	/**
78
	 * Deletes a resource
79
	 *
80
	 * @return string|null HTML output
81
	 */
82
	public function delete() : ?string
83
	{
84
		parent::delete();
85
86
		$item = $this->view()->item;
87
		$item->deleteListItems( $item->getListItems( 'text', null, 'content', false )->toArray(), true );
88
89
		return null;
90
	}
91
92
93
	/**
94
	 * Returns a single resource
95
	 *
96
	 * @return string|null HTML output
97
	 */
98
	public function get() : ?string
99
	{
100
		$view = $this->object()->data( $this->view() );
101
		$view->contentData = $this->toArray( $view->item );
102
		$view->contentBody = parent::get();
103
104
		return $this->render( $view );
105
	}
106
107
108
	/**
109
	 * Saves the data
110
	 *
111
	 * @return string|null HTML output
112
	 */
113
	public function save() : ?string
114
	{
115
		$view = $this->view();
116
117
		$view->item = $this->fromArray( $view->item, $view->param( 'content', [] ) );
118
		$view->contentBody = parent::save();
119
120
		return null;
121
	}
122
123
124
	/**
125
	 * Returns the sub-client given by its name.
126
	 *
127
	 * @param string $type Name of the client type
128
	 * @param string|null $name Name of the sub-client (Default if null)
129
	 * @return \Aimeos\Admin\JQAdm\Iface Sub-client object
130
	 */
131
	public function getSubClient( string $type, ?string $name = null ) : \Aimeos\Admin\JQAdm\Iface
132
	{
133
		/** admin/jqadm/cms/content/decorators/excludes
134
		 * Excludes decorators added by the "common" option from the cms JQAdm client
135
		 *
136
		 * Decorators extend the functionality of a class by adding new aspects
137
		 * (e.g. log what is currently done), executing the methods of the underlying
138
		 * class only in certain conditions (e.g. only for logged in users) or
139
		 * modify what is returned to the caller.
140
		 *
141
		 * This option allows you to remove a decorator added via
142
		 * "admin/jqadm/common/decorators/default" before they are wrapped
143
		 * around the JQAdm client.
144
		 *
145
		 *  admin/jqadm/cms/content/decorators/excludes = array( 'decorator1' )
146
		 *
147
		 * This would remove the decorator named "decorator1" from the list of
148
		 * common decorators ("\Aimeos\Admin\JQAdm\Common\Decorator\*") added via
149
		 * "admin/jqadm/common/decorators/default" to the JQAdm client.
150
		 *
151
		 * @param array List of decorator names
152
		 * @since 2020.10
153
		 * @category Developer
154
		 * @see admin/jqadm/common/decorators/default
155
		 * @see admin/jqadm/cms/content/decorators/global
156
		 * @see admin/jqadm/cms/content/decorators/local
157
		 */
158
159
		/** admin/jqadm/cms/content/decorators/global
160
		 * Adds a list of globally available decorators only to the cms JQAdm client
161
		 *
162
		 * Decorators extend the functionality of a class by adding new aspects
163
		 * (e.g. log what is currently done), executing the methods of the underlying
164
		 * class only in certain conditions (e.g. only for logged in users) or
165
		 * modify what is returned to the caller.
166
		 *
167
		 * This option allows you to wrap global decorators
168
		 * ("\Aimeos\Admin\JQAdm\Common\Decorator\*") around the JQAdm client.
169
		 *
170
		 *  admin/jqadm/cms/content/decorators/global = array( 'decorator1' )
171
		 *
172
		 * This would add the decorator named "decorator1" defined by
173
		 * "\Aimeos\Admin\JQAdm\Common\Decorator\Decorator1" only to the JQAdm client.
174
		 *
175
		 * @param array List of decorator names
176
		 * @since 2020.10
177
		 * @category Developer
178
		 * @see admin/jqadm/common/decorators/default
179
		 * @see admin/jqadm/cms/content/decorators/excludes
180
		 * @see admin/jqadm/cms/content/decorators/local
181
		 */
182
183
		/** admin/jqadm/cms/content/decorators/local
184
		 * Adds a list of local decorators only to the cms JQAdm client
185
		 *
186
		 * Decorators extend the functionality of a class by adding new aspects
187
		 * (e.g. log what is currently done), executing the methods of the underlying
188
		 * class only in certain conditions (e.g. only for logged in users) or
189
		 * modify what is returned to the caller.
190
		 *
191
		 * This option allows you to wrap local decorators
192
		 * ("\Aimeos\Admin\JQAdm\Cms\Decorator\*") around the JQAdm client.
193
		 *
194
		 *  admin/jqadm/cms/content/decorators/local = array( 'decorator2' )
195
		 *
196
		 * This would add the decorator named "decorator2" defined by
197
		 * "\Aimeos\Admin\JQAdm\Cms\Decorator\Decorator2" only to the JQAdm client.
198
		 *
199
		 * @param array List of decorator names
200
		 * @since 2020.10
201
		 * @category Developer
202
		 * @see admin/jqadm/common/decorators/default
203
		 * @see admin/jqadm/cms/content/decorators/excludes
204
		 * @see admin/jqadm/cms/content/decorators/global
205
		 */
206
		return $this->createSubClient( 'cms/content/' . $type, $name );
207
	}
208
209
210
	/**
211
	 * Returns the list of sub-client names configured for the client.
212
	 *
213
	 * @return array List of JQAdm client names
214
	 */
215
	protected function getSubClientNames() : array
216
	{
217
		/** admin/jqadm/cms/content/subparts
218
		 * List of JQAdm sub-clients rendered within the cms content section
219
		 *
220
		 * The output of the frontend is composed of the code generated by the JQAdm
221
		 * clients. Each JQAdm client can consist of serveral (or none) sub-clients
222
		 * that are responsible for rendering certain sub-parts of the output. The
223
		 * sub-clients can contain JQAdm clients themselves and therefore a
224
		 * hierarchical tree of JQAdm clients is composed. Each JQAdm client creates
225
		 * the output that is placed inside the container of its parent.
226
		 *
227
		 * At first, always the JQAdm code generated by the parent is printed, then
228
		 * the JQAdm code of its sub-clients. The order of the JQAdm sub-clients
229
		 * determines the order of the output of these sub-clients inside the parent
230
		 * container. If the configured list of clients is
231
		 *
232
		 *  array( "subclient1", "subclient2" )
233
		 *
234
		 * you can easily change the order of the output by reordering the subparts:
235
		 *
236
		 *  admin/jqadm/<clients>/subparts = array( "subclient1", "subclient2" )
237
		 *
238
		 * You can also remove one or more parts if they shouldn't be rendered:
239
		 *
240
		 *  admin/jqadm/<clients>/subparts = array( "subclient1" )
241
		 *
242
		 * As the clients only generates structural JQAdm, the layout defined via CSS
243
		 * should support adding, removing or reordering content by a fluid like
244
		 * design.
245
		 *
246
		 * @param array List of sub-client names
247
		 * @since 2020.10
248
		 * @category Developer
249
		 */
250
		return $this->context()->config()->get( 'admin/jqadm/cms/content/subparts', [] );
251
	}
252
253
254
	/**
255
	 * Adds the required data used in the content template
256
	 *
257
	 * @param \Aimeos\Base\View\Iface $view View object
258
	 * @return \Aimeos\Base\View\Iface View object with assigned parameters
259
	 */
260
	public function data( \Aimeos\Base\View\Iface $view ) : \Aimeos\Base\View\Iface
261
	{
262
		$media = [];
263
		$context = $this->context();
264
		$locale = $context->locale();
265
		$listTypeManager = \Aimeos\MShop::create( $context, 'cms/lists/type' );
266
		$listSearch = $listTypeManager->filter( true )->order( 'cms.lists.type.code' )->slice( 0, 10000 );
267
268
		$view->contentListTypes = $listTypeManager->search( $listSearch );
269
270
		$theme = $locale->getSiteItem()->getTheme() ?: 'default';
271
		$rtl = in_array( $view->param( 'locale' ), ['ar', 'az', 'dv', 'fa', 'he', 'ku', 'ur'] );
272
		$view->config = [
273
			'canvas' => [
274
				'styles' => [
275
					$view->content( $theme . '/app.' . ( $rtl ? 'rtl.' : '' ) . 'css', 'fs-theme', true ),
276
					$view->content( $theme . '/aimeos.css', 'fs-theme', true ),
277
					$view->content( $theme . '/cms-page.css', 'fs-theme', true ),
278
				]
279
			],
280
			'langDir' => $rtl ? 'rtl' : ''
281
		];
282
283
		foreach( $view->item->getRefItems( 'media' ) as $mediaItem )
284
		{
285
			$srcset = [];
286
287
			foreach( $mediaItem->getPreviews() as $width => $path ) {
288
				$srcset[] = $view->content( $path ) . ' ' . $width . 'w';
289
			}
290
291
			$media[] = [
292
				'name' => $mediaItem->getLabel(),
293
				'src' => $view->content( $mediaItem->getPreview( true ) ),
294
				'srcset' => join( ', ', $srcset ),
295
				'type' => 'image'
296
			];
297
		}
298
299
		return $view->set( 'contentMedia', $media );
300
	}
301
302
303
	/**
304
	 * Creates new and updates existing items using the data array
305
	 *
306
	 * @param \Aimeos\MShop\Cms\Item\Iface $item Cms item object without referenced domain items
307
	 * @param array $data Data array
308
	 * @return \Aimeos\MShop\Cms\Item\Iface Modified cms item
309
	 */
310
	protected function fromArray( \Aimeos\MShop\Cms\Item\Iface $item, array $data ) : \Aimeos\MShop\Cms\Item\Iface
311
	{
312
		$context = $this->context();
313
314
		$textManager = \Aimeos\MShop::create( $context, 'text' );
315
		$manager = \Aimeos\MShop::create( $context, 'cms' );
316
317
		$listItems = $item->getListItems( 'text', null, 'content', false );
318
319
		foreach( $data as $idx => $entry )
320
		{
321
			if( trim( $this->val( $entry, 'text.content', '' ) ) === '' ) {
322
				continue;
323
			}
324
325
			$id = $this->val( $entry, 'text.id', '' );
326
			$type = $this->val( $entry, 'cms.lists.type', 'default' );
327
328
			$listItem = $item->getListItem( 'text', $type, $id, false ) ?: $manager->createListItem();
0 ignored issues
show
Bug introduced by
The method createListItem() does not exist on Aimeos\MShop\Common\Manager\Iface. Did you maybe mean create()? ( Ignorable by Annotation )

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

328
			$listItem = $item->getListItem( 'text', $type, $id, false ) ?: $manager->/** @scrutinizer ignore-call */ createListItem();

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...
329
			$refItem = $listItem->getRefItem() ?: $textManager->create();
330
331
			$refItem->fromArray( $entry, true )->setType( 'content' );
0 ignored issues
show
Bug introduced by
The method setType() does not exist on Aimeos\MShop\Common\Item\Iface. It seems like you code against a sub-type of said class. However, the method does not exist in Aimeos\MAdmin\Log\Item\Iface or Aimeos\MShop\Group\Item\Iface or Aimeos\MShop\Basket\Item\Iface or Aimeos\MShop\Locale\Item\Site\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MAdmin\Cache\Item\Iface or Aimeos\MShop\Common\Item\ListsRef\Iface or Aimeos\MShop\Order\Item\Iface or Aimeos\MShop\Subscription\Item\Iface or Aimeos\MShop\Coupon\Item\Iface or Aimeos\MShop\Review\Item\Iface or Aimeos\MAdmin\Job\Item\Iface or Aimeos\MShop\Locale\Item\Iface or Aimeos\MShop\Common\Item\PropertyRef\Iface or Aimeos\MShop\Locale\Item\Language\Iface or Aimeos\MShop\Cms\Item\Iface or Aimeos\MShop\Catalog\Item\Iface or Aimeos\MShop\Common\Item\AddressRef\Iface or Aimeos\MShop\Coupon\Item\Code\Iface or Aimeos\MShop\Supplier\Item\Iface or Aimeos\MShop\Type\Item\Iface or Aimeos\MShop\Locale\Item\Currency\Iface or Aimeos\MShop\Order\Item\Coupon\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MShop\Cms\Item\Iface or Aimeos\MShop\Catalog\Item\Iface or Aimeos\MShop\Supplier\Item\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MShop\Customer\Item\Iface or Aimeos\MShop\Supplier\Item\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

331
			$refItem->fromArray( $entry, true )->/** @scrutinizer ignore-call */ setType( 'content' );
Loading history...
332
			$conf = [];
333
334
			foreach( (array) $this->val( $entry, 'config', [] ) as $cfg )
335
			{
336
				if( ( $key = trim( $cfg['key'] ?? '' ) ) !== '' ) {
337
					$conf[$key] = trim( $cfg['val'] ?? '' );
338
				}
339
			}
340
341
			$listItem->fromArray( $entry, true );
342
			$listItem->setPosition( $idx );
343
			$listItem->setConfig( $conf );
344
345
			$item->addListItem( 'text', $listItem, $refItem );
346
347
			unset( $listItems[$listItem->getId()] );
348
		}
349
350
		return $item->deleteListItems( $listItems->toArray(), true );
351
	}
352
353
354
	/**
355
	 * Constructs the data array for the view from the given item
356
	 *
357
	 * @param \Aimeos\MShop\Cms\Item\Iface $item Cms item object including referenced domain items
358
	 * @param bool $copy True if items should be copied, false if not
359
	 * @return string[] Multi-dimensional associative list of item data
360
	 */
361
	protected function toArray( \Aimeos\MShop\Cms\Item\Iface $item, bool $copy = false ) : array
362
	{
363
		$data = [];
364
		$siteId = $this->context()->locale()->getSiteId();
365
366
		foreach( $item->getListItems( 'text', null, 'content', false ) as $listItem )
367
		{
368
			if( ( $refItem = $listItem->getRefItem() ) === null ) {
369
				continue;
370
			}
371
372
			$list = $listItem->toArray( true ) + $refItem->toArray( true );
373
374
			if( $copy === true )
375
			{
376
				$list['cms.lists.siteid'] = $siteId;
377
				$list['cms.lists.id'] = '';
378
				$list['text.siteid'] = $siteId;
379
				$list['text.id'] = null;
380
			}
381
382
			$list['cms.lists.datestart'] = str_replace( ' ', 'T', $list['cms.lists.datestart'] ?? '' );
383
			$list['cms.lists.dateend'] = str_replace( ' ', 'T', $list['cms.lists.dateend'] ?? '' );
384
			$list['config'] = [];
385
386
			foreach( $listItem->getConfig() as $key => $value ) {
387
				$list['config'][] = ['key' => $key, 'val' => $value];
388
			}
389
390
			$data[] = $list;
391
		}
392
393
		return $data;
394
	}
395
396
397
	/**
398
	 * Returns the rendered template including the view data
399
	 *
400
	 * @param \Aimeos\Base\View\Iface $view View object with data assigned
401
	 * @return string HTML output
402
	 */
403
	protected function render( \Aimeos\Base\View\Iface $view ) : string
404
	{
405
		/** admin/jqadm/cms/content/template-item
406
		 * Relative path to the HTML body template of the content subpart for cmss.
407
		 *
408
		 * The template file contains the HTML code and processing instructions
409
		 * to generate the result shown in the body of the frontend. The
410
		 * configuration string is the path to the template file relative
411
		 * to the templates directory (usually in admin/jqadm/templates).
412
		 *
413
		 * You can overwrite the template file configuration in extensions and
414
		 * provide alternative templates. These alternative templates should be
415
		 * named like the default one but with the string "default" replaced by
416
		 * an unique name. You may use the name of your project for this. If
417
		 * you've implemented an alternative client class as well, "default"
418
		 * should be replaced by the name of the new class.
419
		 *
420
		 * @param string Relative path to the template creating the HTML code
421
		 * @since 2020.10
422
		 * @category Developer
423
		 */
424
		$tplconf = 'admin/jqadm/cms/content/template-item';
425
		$default = 'cms/item-content';
426
427
		return $view->render( $view->config( $tplconf, $default ) );
428
	}
429
}
430