Completed
Push — master ( 8b8334...2005c2 )
by Aimeos
07:11
created

Base::replaceSection()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 17
rs 9.4285
cc 3
eloc 9
nc 3
nop 3
1
<?php
2
3
/**
4
 * @copyright Metaways Infosystems GmbH, 2012
5
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
6
 * @copyright Aimeos (aimeos.org), 2015
7
 * @package Client
8
 * @subpackage Html
9
 */
10
11
12
namespace Aimeos\Client\Html;
13
14
15
/**
16
 * Common abstract class for all HTML client classes.
17
 *
18
 * @package Client
19
 * @subpackage Html
20
 */
21
abstract class Base
22
	implements \Aimeos\Client\Html\Iface
23
{
24
	private $view;
25
	private $cache;
26
	private $context;
27
	private $subclients;
28
	private $templatePaths;
29
30
31
	/**
32
	 * Initializes the class instance.
33
	 *
34
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object
35
	 * @param array $templatePaths Associative list of the file system paths to the core or the extensions as key
36
	 * 	and a list of relative paths inside the core or the extension as values
37
	 */
38
	public function __construct( \Aimeos\MShop\Context\Item\Iface $context, array $templatePaths )
39
	{
40
		$this->context = $context;
41
		$this->templatePaths = $templatePaths;
42
	}
43
44
45
	/**
46
	 * Returns the view object that will generate the HTML output.
47
	 *
48
	 * @return \Aimeos\MW\View\Iface $view The view object which generates the HTML output
49
	 */
50
	public function getView()
51
	{
52
		if( !isset( $this->view ) ) {
53
			throw new \Aimeos\Client\Html\Exception( sprintf( 'No view available' ) );
54
		}
55
56
		return $this->view;
57
	}
58
59
60
	/**
61
	 * Modifies the cached body content to replace content based on sessions or cookies.
62
	 *
63
	 * @param string $content Cached content
64
	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
65
	 * @return string Modified body content
66
	 */
67
	public function modifyBody( $content, $uid )
68
	{
69
		$view = $this->getView();
70
71
		foreach( $this->getSubClients() as $subclient )
72
		{
73
			$subclient->setView( $view );
74
			$content = $subclient->modifyBody( $content, $uid );
75
		}
76
77
		return $content;
78
	}
79
80
81
	/**
82
	 * Modifies the cached header content to replace content based on sessions or cookies.
83
	 *
84
	 * @param string $content Cached content
85
	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
86
	 * @return string Modified header content
87
	 */
88
	public function modifyHeader( $content, $uid )
89
	{
90
		$view = $this->getView();
91
92
		foreach( $this->getSubClients() as $subclient )
93
		{
94
			$subclient->setView( $view );
95
			$content = $subclient->modifyHeader( $content, $uid );
96
		}
97
98
		return $content;
99
	}
100
101
102
	/**
103
	 * Processes the input, e.g. store given values.
104
	 * A view must be available and this method doesn't generate any output
105
	 * besides setting view variables.
106
	 *
107
	 * @return boolean False if processing is stopped, otherwise all processing was completed successfully
108
	 */
109
	public function process()
110
	{
111
		$view = $this->getView();
112
113
		foreach( $this->getSubClients() as $subclient )
114
		{
115
			$subclient->setView( $view );
116
117
			if( $subclient->process() === false ) {
118
				return false;
119
			}
120
		}
121
122
		return true;
123
	}
124
125
126
	/**
127
	 * Sets the view object that will generate the HTML output.
128
	 *
129
	 * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
130
	 * @return \Aimeos\Client\Html\Iface Reference to this object for fluent calls
131
	 */
132
	public function setView( \Aimeos\MW\View\Iface $view )
133
	{
134
		$this->view = $view;
135
		return $this;
136
	}
137
138
139
	/**
140
	 * Adds the decorators to the client object
141
	 *
142
	 * @param \Aimeos\Client\Html\Iface $client Client object
143
	 * @param array $templatePaths List of file system paths where the templates are stored
144
	 * @param array $decorators List of decorator name that should be wrapped around the client
145
	 * @param string $classprefix Decorator class prefix, e.g. "\Aimeos\Client\Html\Catalog\Decorator\"
146
	 * @return \Aimeos\Client\Html\Iface Client object
147
	 */
148
	protected function addDecorators( \Aimeos\Client\Html\Iface $client, array $templatePaths,
149
		array $decorators, $classprefix )
150
	{
151
		$iface = '\\Aimeos\\Client\\Html\\Common\\Decorator\\Iface';
152
153
		foreach( $decorators as $name )
154
		{
155
			if( ctype_alnum( $name ) === false )
156
			{
157
				$classname = is_string( $name ) ? $classprefix . $name : '<not a string>';
158
				throw new \Aimeos\Client\Html\Exception( sprintf( 'Invalid class name "%1$s"', $classname ) );
159
			}
160
161
			$classname = $classprefix . $name;
162
163
			if( class_exists( $classname ) === false ) {
164
				throw new \Aimeos\Client\Html\Exception( sprintf( 'Class "%1$s" not found', $classname ) );
165
			}
166
167
			$client = new $classname( $client, $this->context, $this->templatePaths );
168
169
			if( !( $client instanceof $iface ) ) {
170
				throw new \Aimeos\Client\Html\Exception( sprintf( 'Class "%1$s" does not implement "%2$s"', $classname, $iface ) );
171
			}
172
		}
173
174
		return $client;
175
	}
176
177
178
	/**
179
	 * Adds the decorators to the client object
180
	 *
181
	 * @param \Aimeos\Client\Html\Iface $client Client object
182
	 * @param array $templatePaths List of file system paths where the templates are stored
183
	 * @param string $path Client string in lower case, e.g. "catalog/detail/basic"
184
	 * @return \Aimeos\Client\Html\Iface Client object
185
	 */
186
	protected function addClientDecorators( \Aimeos\Client\Html\Iface $client, array $templatePaths, $path )
187
	{
188
		if( !is_string( $path ) || $path === '' ) {
189
			throw new \Aimeos\Client\Html\Exception( sprintf( 'Invalid domain "%1$s"', $path ) );
190
		}
191
192
		$localClass = str_replace( ' ', '\\', ucwords( str_replace( '/', ' ', $path ) ) );
193
		$config = $this->context->getConfig();
194
195
		$decorators = $config->get( 'client/html/common/decorators/default', array() );
196
		$excludes = $config->get( 'client/html/' . $path . '/decorators/excludes', array() );
197
198
		foreach( $decorators as $key => $name )
199
		{
200
			if( in_array( $name, $excludes ) ) {
201
				unset( $decorators[$key] );
202
			}
203
		}
204
205
		$classprefix = '\\Aimeos\\Client\\Html\\Common\\Decorator\\';
206
		$client = $this->addDecorators( $client, $templatePaths, $decorators, $classprefix );
207
208
		$classprefix = '\\Aimeos\\Client\\Html\\Common\\Decorator\\';
209
		$decorators = $config->get( 'client/html/' . $path . '/decorators/global', array() );
210
		$client = $this->addDecorators( $client, $templatePaths, $decorators, $classprefix );
211
212
		$classprefix = '\\Aimeos\\Client\\Html\\' . $localClass . '\\Decorator\\';
213
		$decorators = $config->get( 'client/html/' . $path . '/decorators/local', array() );
214
		$client = $this->addDecorators( $client, $templatePaths, $decorators, $classprefix );
215
216
		return $client;
217
	}
218
219
220
	/**
221
	 * Adds the cache tags to the given list and sets a new expiration date if necessary based on the given item.
222
	 *
223
	 * @param array|\Aimeos\MShop\Common\Item\Iface $items Item or list of items, maybe with associated list items
224
	 * @param string $domain Name of the domain the item is from
225
	 * @param string|null &$expire Expiration date that will be overwritten if an earlier date is found
226
	 * @param array &$tags List of tags the new tags will be added to
227
	 */
228
	protected function addMetaItem( $items, $domain, &$expire, array &$tags )
229
	{
230
		/** client/html/common/cache/tag-all
231
		 * Adds tags for all items used in a cache entry
232
		 *
233
		 * Each cache entry storing rendered parts for the HTML header or body
234
		 * can be tagged with information which items like texts, media, etc.
235
		 * are used in the HTML. This allows removing only those cache entries
236
		 * whose content has really changed and only that entries have to be
237
		 * rebuild the next time.
238
		 *
239
		 * The standard behavior stores only tags for each used domain, e.g. if
240
		 * a text is used, only the tag "text" is added. If you change a text
241
		 * in the administration interface, all cache entries with the tag
242
		 * "text" will be removed from the cache. This effectively wipes out
243
		 * almost all cached entries, which have to be rebuild with the next
244
		 * request.
245
		 *
246
		 * Important: As a list or detail view can use several hundred items,
247
		 * this configuration option will also add this number of tags to the
248
		 * cache entry. When using a cache adapter that can't insert all tags
249
		 * at once, this slows down the initial cache insert (and therefore the
250
		 * page speed) drastically! It's only recommended to enable this option
251
		 * if you use the DB, Mysql or Redis adapter that can insert all tags
252
		 * at once.
253
		 *
254
		 * @param boolean True to add tags for all items, false to use only a domain tag
255
		 * @since 2014.07
256
		 * @category Developer
257
		 * @category User
258
		 * @see client/html/common/cache/force
259
		 * @see madmin/cache/manager/name
260
		 * @see madmin/cache/name
261
		 */
262
		$tagAll = $this->context->getConfig()->get( 'client/html/common/cache/tag-all', false );
263
264
		if( !is_array( $items ) ) {
265
			$items = array( $items );
266
		}
267
268
		if( $tagAll !== true && !empty( $items ) ) {
269
			$tags[] = $domain;
270
		}
271
272
		foreach( $items as $item ) {
273
			$this->addMetaItemSingle( $item, $domain, $expire, $tags, $tagAll );
274
		}
275
	}
276
277
278
	/**
279
	 * Adds expire date and tags for a single item.
280
	 *
281
	 * @param \Aimeos\MShop\Common\Item\Iface $item Item, maybe with associated list items
282
	 * @param string $domain Name of the domain the item is from
283
	 * @param string|null &$expire Expiration date that will be overwritten if an earlier date is found
284
	 * @param array &$tags List of tags the new tags will be added to
285
	 * @param boolean $tagAll True of tags for all items should be added, false if only for the main item
286
	 */
287
	private function addMetaItemSingle( \Aimeos\MShop\Common\Item\Iface $item, $domain, &$expire, array &$tags, $tagAll )
288
	{
289
		$expires = array();
290
		$domain = str_replace( '/', '_', $domain ); // maximum compatiblity
291
292
		if( $tagAll === true ) {
293
			$tags[] = $domain . '-' . $item->getId();
294
		}
295
296
		if( $item instanceof \Aimeos\MShop\Common\Item\Time\Iface && ( $date = $item->getDateEnd() ) !== null ) {
297
			$expires[] = $date;
298
		}
299
300
		if( $item instanceof \Aimeos\MShop\Common\Item\ListRef\Iface ) {
301
			$this->addMetaItemRef( $item, $expires, $tags, $tagAll );
302
		}
303
304
		if( !empty( $expires ) ) {
305
			$expire = min( $expires );
306
		}
307
	}
308
309
310
	/**
311
	 * Adds expire date and tags for referenced items
312
	 *
313
	 * @param \Aimeos\MShop\Common\Item\ListRef\Iface $item Item with associated list items
314
	 * @param array &$expire Expiration date that will be overwritten if an earlier date is found
315
	 * @param array &$tags List of tags the new tags will be added to
316
	 * @param boolean $tagAll True of tags for all items should be added, false if only for the main item
317
	 */
318
	private function addMetaItemRef( \Aimeos\MShop\Common\Item\ListRef\Iface $item, array &$expires, array &$tags, $tagAll )
319
	{
320
		foreach( $item->getListItems() as $listitem )
321
		{
322
			if( $tagAll === true ) {
323
				$tags[] = str_replace( '/', '_', $listitem->getDomain() ) . '-' . $listitem->getRefId();
324
			}
325
326
			if( ( $date = $listitem->getDateEnd() ) !== null ) {
327
				$expires[] = $date;
328
			}
329
		}
330
	}
331
332
333
	/**
334
	 * Adds a new expiration date if a list item is activated in the future.
335
	 *
336
	 * @param array|string $ids Item ID or list of item IDs from the given domain
337
	 * @param string $domain Name of the domain the item IDs are from
338
	 * @param string|null &$expire Expiration date that will be overwritten if an start date in the future is available
339
	 */
340
	protected function addMetaList( $ids, $domain, &$expire )
341
	{
342
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), $domain . '/lists' );
343
344
		$search = $manager->createSearch();
345
		$expr = array(
346
			$search->compare( '==', $domain . '.lists.parentid', $ids ),
347
			$search->compare( '>', $domain . '.lists.datestart', date( 'Y-m-d H:i:00' ) ),
348
		);
349
		$search->setConditions( $search->combine( '&&', $expr ) );
350
		$search->setSortations( array( $search->sort( '+', $domain . '.lists.datestart' ) ) );
351
		$search->setSlice( 0, 1 );
352
353
		foreach( $manager->searchItems( $search ) as $listItem ) {
354
			$expire = $this->expires( $expire, $listItem->getDateStart() );
355
		}
356
	}
357
358
359
	/**
360
	 * Returns the sub-client given by its name.
361
	 *
362
	 * @param string $path Name of the sub-part in lower case (can contain a path like catalog/filter/tree)
363
	 * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
364
	 * @return \Aimeos\Client\Html\Iface Sub-part object
365
	 */
366
	protected function createSubClient( $path, $name )
367
	{
368
		$path = strtolower( $path );
369
370
		if( $name === null ) {
371
			$name = $this->context->getConfig()->get( 'client/html/' . $path . '/name', 'Standard' );
372
		}
373
374
		if( empty( $name ) || ctype_alnum( $name ) === false ) {
375
			throw new \Aimeos\Client\Html\Exception( sprintf( 'Invalid characters in client name "%1$s"', $name ) );
376
		}
377
378
		$subnames = str_replace( ' ', '\\', ucwords( str_replace( '/', ' ', $path ) ) );
379
380
		$classname = '\\Aimeos\\Client\\Html\\' . $subnames . '\\' . $name;
381
		$interface = '\\Aimeos\\Client\\Html\\Iface';
382
383
		if( class_exists( $classname ) === false ) {
384
			throw new \Aimeos\Client\Html\Exception( sprintf( 'Class "%1$s" not available', $classname ) );
385
		}
386
387
		$object = new $classname( $this->context, $this->templatePaths );
388
389
		if( ( $object instanceof $interface ) === false ) {
390
			throw new \Aimeos\Client\Html\Exception( sprintf( 'Class "%1$s" does not implement interface "%2$s"', $classname, $interface ) );
391
		}
392
393
		return $this->addClientDecorators( $object, $this->templatePaths, $path );
394
	}
395
396
397
	/**
398
	 * Returns the minimal expiration date.
399
	 *
400
	 * @param string|null $first First expiration date or null
401
	 * @param string|null $second Second expiration date or null
402
	 * @return string|null Expiration date
403
	 */
404
	protected function expires( $first, $second )
405
	{
406
		return ( $first !== null ? ( $second !== null ? min( $first, $second ) : $first ) : $second );
407
	}
408
409
410
	/**
411
	 * Returns the parameters used by the html client.
412
	 *
413
	 * @param array $params Associative list of all parameters
414
	 * @param array $prefixes List of prefixes the parameters must start with
415
	 * @return array Associative list of parameters used by the html client
416
	 */
417
	protected function getClientParams( array $params, array $prefixes = array( 'f', 'l', 'd', 'a' ) )
418
	{
419
		$list = array();
420
421
		foreach( $params as $key => $value )
422
		{
423
			if( in_array( $key[0], $prefixes ) && $key[1] === '_' ) {
424
				$list[$key] = $value;
425
			}
426
		}
427
428
		return $list;
429
	}
430
431
432
	/**
433
	 * Returns the context object.
434
	 *
435
	 * @return \Aimeos\MShop\Context\Item\Iface Context object
436
	 */
437
	protected function getContext()
438
	{
439
		return $this->context;
440
	}
441
442
443
	/**
444
	 * Generates an unique hash from based on the input suitable to be used as part of the cache key
445
	 *
446
	 * @param array $prefixes List of prefixes the parameters must start with
447
	 * @param string $key Unique identifier if the content is placed more than once on the same page
448
	 * @param array $config Multi-dimensional array of configuration options used by the client and sub-clients
449
	 * @return string Unique hash
450
	 */
451
	protected function getParamHash( array $prefixes = array( 'f', 'l', 'd' ), $key = '', array $config = array() )
452
	{
453
		$locale = $this->getContext()->getLocale();
454
		$params = $this->getClientParams( $this->getView()->param(), $prefixes );
455
		ksort( $params );
456
457
		if( ( $pstr = json_encode( $params ) ) === false || ( $cstr = json_encode( $config ) ) === false ) {
458
			throw new \Aimeos\Client\Html\Exception( 'Unable to encode parameters or configuration options' );
459
		}
460
461
		return md5( $key . $pstr . $cstr . $locale->getLanguageId() . $locale->getCurrencyId() );
462
	}
463
464
465
	/**
466
	 * Returns the list of sub-client names configured for the client.
467
	 *
468
	 * @return array List of HTML client names
469
	 */
470
	abstract protected function getSubClientNames();
471
472
473
	/**
474
	 * Returns the configured sub-clients or the ones named in the default parameter if none are configured.
475
	 *
476
	 * @return array List of sub-clients implementing \Aimeos\Client\Html\Iface	ordered in the same way as the names
477
	 */
478
	protected function getSubClients()
479
	{
480
		if( !isset( $this->subclients ) )
481
		{
482
			$this->subclients = array();
483
484
			foreach( $this->getSubClientNames() as $name ) {
485
				$this->subclients[] = $this->getSubClient( $name );
486
			}
487
		}
488
489
		return $this->subclients;
490
	}
491
492
493
	/**
494
	 * Returns the paths where the layout templates can be found
495
	 *
496
	 * @return array List of template paths
497
	 * @since 2015.09
498
	 */
499
	protected function getTemplatePaths()
500
	{
501
		return $this->templatePaths;
502
	}
503
504
505
	/**
506
	 * Returns the attribute type item specified by the code.
507
	 *
508
	 * @param string $prefix Domain prefix for the manager, e.g. "media/type"
509
	 * @param string $domain Domain of the type item
510
	 * @param string $code Code of the type item
511
	 * @return \Aimeos\MShop\Common\Item\Type\Iface Type item
512
	 * @throws \Aimeos\Controller\Jobs\Exception If no item is found
513
	 */
514
	protected function getTypeItem( $prefix, $domain, $code )
515
	{
516
		$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), $prefix );
517
		$prefix = str_replace( '/', '.', $prefix );
518
519
		$search = $manager->createSearch();
520
		$expr = array(
521
				$search->compare( '==', $prefix . '.domain', $domain ),
522
				$search->compare( '==', $prefix . '.code', $code ),
523
		);
524
		$search->setConditions( $search->combine( '&&', $expr ) );
525
		$result = $manager->searchItems( $search );
526
527
		if( ( $item = reset( $result ) ) === false )
528
		{
529
			$msg = sprintf( 'No type item for "%1$s/%2$s" in "%3$s" found', $domain, $code, $prefix );
530
			throw new \Aimeos\Controller\Jobs\Exception( $msg );
531
		}
532
533
		return $item;
534
	}
535
536
537
	/**
538
	 * Returns the cache entry for the given unique ID and type.
539
	 *
540
	 * @param string $type Type of the cache entry, i.e. "body" or "header"
541
	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
542
	 * @param string[] $prefixes List of prefixes of all parameters that are relevant for generating the output
543
	 * @param string $confkey Configuration key prefix that matches all relevant settings for the component
544
	 * @return string Cached entry or empty string if not available
545
	 */
546
	protected function getCached( $type, $uid, array $prefixes, $confkey )
547
	{
548
		if( !isset( $this->cache ) )
549
		{
550
			$context = $this->getContext();
551
			$config = $context->getConfig();
552
553
			/** client/html/common/cache/force
554
			 * Enforces content caching regardless of user logins
555
			 *
556
			 * Caching the component output is normally disabled as soon as the
557
			 * user has logged in. This enables displaying user or user group
558
			 * specific content without mixing standard and user specific output.
559
			 *
560
			 * If you don't have any user or user group specific content
561
			 * (products, categories, attributes, media, prices, texts, etc.),
562
			 * you can enforce content caching nevertheless to keep response
563
			 * times as low as possible.
564
			 *
565
			 * @param boolean True to cache output regardless of login, false for no caching
566
			 * @since 2015.08
567
			 * @category Developer
568
			 * @category User
569
			 * @see client/html/common/cache/tag-all
570
			 */
571
			$force = $config->get( 'client/html/common/cache/force', false );
572
573
			if( $force == false && $context->getUserId() !== null ) {
574
				return null;
575
			}
576
577
			$cfg = $config->get( $confkey, array() );
578
579
			$keys = array(
580
				'body' => $this->getParamHash( $prefixes, $uid . ':' . $confkey . ':body', $cfg ),
581
				'header' => $this->getParamHash( $prefixes, $uid . ':' . $confkey . ':header', $cfg ),
582
			);
583
584
			$entries = $context->getCache()->getList( $keys );
585
			$this->cache = array();
586
587
			foreach( $keys as $key => $hash ) {
588
				$this->cache[$key] = ( array_key_exists( $hash, $entries ) ? $entries[$hash] : null );
589
			}
590
		}
591
592
		return ( array_key_exists( $type, $this->cache ) ? $this->cache[$type] : null );
593
	}
594
595
596
	/**
597
	 * Returns the cache entry for the given type and unique ID.
598
	 *
599
	 * @param string $type Type of the cache entry, i.e. "body" or "header"
600
	 * @param string $uid Unique identifier for the output if the content is placed more than once on the same page
601
	 * @param string[] $prefixes List of prefixes of all parameters that are relevant for generating the output
602
	 * @param string $confkey Configuration key prefix that matches all relevant settings for the component
603
	 * @param string $value Value string that should be stored for the given key
604
	 * @param array $tags List of tag strings that should be assoicated to the
605
	 * 	given value in the cache
606
	 * @param string|null $expire Date/time string in "YYYY-MM-DD HH:mm:ss"
607
	 * 	format when the cache entry expires
608
	 */
609
	protected function setCached( $type, $uid, array $prefixes, $confkey, $value, array $tags, $expire )
610
	{
611
		$context = $this->getContext();
612
		$config = $context->getConfig();
613
614
		$force = $config->get( 'client/html/common/cache/force', false );
615
616
		if( $force == false && $context->getUserId() !== null ) {
617
			return;
618
		}
619
620
		try
621
		{
622
			$cfg = $config->get( $confkey, array() );
623
			$key = $this->getParamHash( $prefixes, $uid . ':' . $confkey . ':' . $type, $cfg );
624
625
			$context->getCache()->set( $key, $value, array_unique( $tags ), $expire );
626
		}
627
		catch( \Exception $e )
628
		{
629
			$msg = sprintf( 'Unable to set cache entry: %1$s', $e->getMessage() );
630
			$context->getLogger()->log( $msg, \Aimeos\MW\Logger\Base::NOTICE );
631
		}
632
	}
633
634
635
	/**
636
	 * Replaces the section in the content that is enclosed by the marker.
637
	 *
638
	 * @param string $content Cached content
639
	 * @param string $section New section content
640
	 * @param string $marker Name of the section marker without "<!-- " and " -->" parts
641
	 */
642
	protected function replaceSection( $content, $section, $marker )
643
	{
644
		$start = 0;
645
		$len = strlen( $section );
646
		$marker = '<!-- ' . $marker . ' -->';
647
648
		while( ( $start = @strpos( $content, $marker, $start ) ) !== false )
649
		{
650
			if( ( $end = strpos( $content, $marker, $start + 1 ) ) !== false ) {
651
				$content = substr_replace( $content, $section, $start, $end - $start + strlen( $marker ) );
652
			}
653
654
			$start += 2 * strlen( $marker ) + $len;
655
		}
656
657
		return $content;
658
	}
659
660
661
	/**
662
	 * Sets the necessary parameter values in the view.
663
	 *
664
	 * @param \Aimeos\MW\View\Iface $view The view object which generates the HTML output
665
	 * @param array &$tags Result array for the list of tags that are associated to the output
666
	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
667
	 * @return \Aimeos\MW\View\Iface Modified view object
668
	 */
669
	protected function setViewParams( \Aimeos\MW\View\Iface $view, array &$tags = array(), &$expire = null )
670
	{
671
		return $view;
672
	}
673
674
675
	/**
676
	 * Translates the plugin error codes to human readable error strings.
677
	 *
678
	 * @param array $codes Associative list of scope and object as key and error code as value
679
	 * @return array List of translated error messages
680
	 */
681
	protected function translatePluginErrorCodes( array $codes )
682
	{
683
		$errors = array();
684
		$i18n = $this->context->getI18n();
685
686
		foreach( $codes as $scope => $list )
687
		{
688
			foreach( $list as $object => $errcode )
689
			{
690
				$key = $scope . ( $scope !== 'product' ? '.' . $object : '' ) . '.' . $errcode;
691
				$errors[] = $i18n->dt( 'mshop/code', $key );
692
			}
693
		}
694
695
		return $errors;
696
	}
697
}
698