Standard   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 409
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 100
dl 0
loc 409
rs 10
c 0
b 0
f 0
wmc 27

11 Methods

Rating   Name   Duplication   Size   Complexity  
B fromArray() 0 41 7
B data() 0 43 6
A toArray() 0 33 5
A copy() 0 7 1
A create() 0 16 2
A getSubClientNames() 0 36 1
A render() 0 25 1
A delete() 0 8 1
A get() 0 7 1
A getSubClient() 0 76 1
A save() 0 8 1
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
267
		$listSearch = $listTypeManager->filter( true )->slice( 0, 10000 );
268
		$listSearch->setConditions( $listSearch->compare( '==', 'cms.lists.type.domain', 'text' ) );
269
		$listSearch->setSortations( [$listSearch->sort( '+', 'cms.lists.type.position' )] );
270
271
		$view->contentListTypes = $listTypeManager->search( $listSearch );
272
273
		$theme = $locale->getSiteItem()->getTheme() ?: 'default';
274
		$rtl = in_array( $view->param( 'locale' ), ['ar', 'az', 'dv', 'fa', 'he', 'ku', 'ur'] );
275
		$view->config = [
276
			'canvas' => [
277
				'styles' => [
278
					$view->content( $theme . '/app.' . ( $rtl ? 'rtl.' : '' ) . 'css', 'fs-theme', true ),
279
					$view->content( $theme . '/aimeos.css', 'fs-theme', true ),
280
					$view->content( $theme . '/cms-page.css', 'fs-theme', true ),
281
				]
282
			],
283
			'langDir' => $rtl ? 'rtl' : ''
284
		];
285
286
		foreach( $view->item->getRefItems( 'media' ) as $mediaItem )
287
		{
288
			$srcset = [];
289
290
			foreach( $mediaItem->getPreviews() as $width => $path ) {
291
				$srcset[] = $view->content( $path ) . ' ' . $width . 'w';
292
			}
293
294
			$media[] = [
295
				'name' => $mediaItem->getLabel(),
296
				'src' => $view->content( $mediaItem->getPreview( true ) ),
297
				'srcset' => join( ', ', $srcset ),
298
				'type' => 'image'
299
			];
300
		}
301
302
		return $view->set( 'contentMedia', $media );
303
	}
304
305
306
	/**
307
	 * Creates new and updates existing items using the data array
308
	 *
309
	 * @param \Aimeos\MShop\Cms\Item\Iface $item Cms item object without referenced domain items
310
	 * @param array $data Data array
311
	 * @return \Aimeos\MShop\Cms\Item\Iface Modified cms item
312
	 */
313
	protected function fromArray( \Aimeos\MShop\Cms\Item\Iface $item, array $data ) : \Aimeos\MShop\Cms\Item\Iface
314
	{
315
		$context = $this->context();
316
317
		$textManager = \Aimeos\MShop::create( $context, 'text' );
318
		$manager = \Aimeos\MShop::create( $context, 'cms' );
319
320
		$listItems = $item->getListItems( 'text', null, 'content', false );
321
322
		foreach( $data as $idx => $entry )
323
		{
324
			if( trim( $this->val( $entry, 'text.content', '' ) ) === '' ) {
325
				continue;
326
			}
327
328
			$id = $this->val( $entry, 'text.id', '' );
329
			$type = $this->val( $entry, 'cms.lists.type', 'default' );
330
331
			$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

331
			$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...
332
			$refItem = $listItem->getRefItem() ?: $textManager->create();
333
334
			$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

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