Passed
Push — master ( bcca11...81709a )
by Aimeos
05:21
created

Context::access()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2024
6
 * @package MShop
7
 */
8
9
10
namespace Aimeos\MShop;
11
12
13
/**
14
 * Common objects which must to be available for all manager objects.
15
 *
16
 * @package MShop
17
 */
18
class Context implements \Aimeos\MShop\ContextIface
19
{
20
	private ?\Aimeos\Base\Cache\Iface $cache = null;
21
	private ?\Aimeos\Base\Config\Iface $config = null;
22
	private ?\Aimeos\Base\DB\Manager\Iface $db = null;
23
	private ?\Aimeos\Base\Filesystem\Manager\Iface $fs = null;
24
	private ?\Aimeos\MShop\Locale\Item\Iface $locale = null;
25
	private ?\Aimeos\Base\Logger\Iface $logger = null;
26
	private ?\Aimeos\Base\Mail\Iface $mail = null;
27
	private ?\Aimeos\Base\MQueue\Manager\Iface $queue = null;
28
	private ?\Aimeos\Base\Password\Iface $password = null;
29
	private ?\Aimeos\Base\Process\Iface $process = null;
30
	private ?\Aimeos\Base\Session\Iface $session = null;
31
	private ?\Aimeos\Base\View\Iface $view = null;
32
	private ?string $datetime = null;
33
	private ?string $nonce = null;
34
	private ?string $token = null;
35
	private string $editor = '';
36
	private array $i18n = [];
37
	private $groups = null;
38
	private $user = null;
39
40
41
	/**
42
	 * Cleans up the stored resources
43
	 */
44
	public function __destruct()
45
	{
46
		$this->cache = null;
47
		$this->config = null;
48
		$this->db = null;
49
		$this->fs = null;
50
		$this->locale = null;
51
		$this->logger = null;
52
		$this->mail = null;
53
		$this->queue = null;
54
		$this->password = null;
55
		$this->process = null;
56
		$this->session = null;
57
		$this->view = null;
58
		$this->i18n = [];
59
	}
60
61
62
	/**
63
	 * Clones internal objects of the context item.
64
	 */
65
	public function __clone()
66
	{
67
		$this->cache = ( isset( $this->cache ) ? clone $this->cache : null );
68
		$this->config = ( isset( $this->config ) ? clone $this->config : null );
69
		$this->fs = ( isset( $this->fs ) ? clone $this->fs : null );
70
		$this->locale = ( isset( $this->locale ) ? clone $this->locale : null );
71
		$this->logger = ( isset( $this->logger ) ? clone $this->logger : null );
72
		$this->mail = ( isset( $this->mail ) ? clone $this->mail : null );
73
		$this->queue = ( isset( $this->queue ) ? clone $this->queue : null );
74
		$this->password = ( isset( $this->password ) ? clone $this->password : null );
75
		$this->process = ( isset( $this->process ) ? clone $this->process : null );
76
		$this->session = ( isset( $this->session ) ? clone $this->session : null );
77
		// view is always cloned
78
79
		foreach( $this->i18n as $locale => $object ) {
80
			$this->i18n[$locale] = clone $this->i18n[$locale];
81
		}
82
	}
83
84
85
	/**
86
	 * Cleans up internal objects of the context item
87
	 */
88
	public function __sleep() : array
89
	{
90
		$objects = array(
91
			$this->cache, $this->config, $this->db, $this->fs, $this->locale, $this->logger,
92
			$this->mail, $this->queue, $this->password, $this->process, $this->session, $this->view
93
		);
94
95
		foreach( $objects as $object )
96
		{
97
			if( is_object( $object ) && method_exists( $object, '__sleep' ) ) {
98
				$object->__sleep();
99
			}
100
		}
101
102
		return get_object_vars( $this );
103
	}
104
105
106
	/**
107
	 * Returns a hash identifying the context object.
108
	 *
109
	 * @return string Hash for identifying the context object
110
	 */
111
	public function __toString() : string
112
	{
113
		$objects = array(
114
			$this, $this->cache, $this->config, $this->db, $this->fs, $this->locale,
115
			$this->logger, $this->mail, $this->queue, $this->password, $this->process,
116
			$this->session, $this->view
117
		);
118
119
		return md5( $this->hash( $objects ) );
120
	}
121
122
123
	/**
124
	 * Checks the permissions of the currently logged in user.
125
	 *
126
	 * @param string|array $groups Group codes to check
127
	 * @return bool TRUE if access is allowed, FALSE if not
128
	 */
129
	public function access( $groups ) : bool
130
	{
131
		return $this->view ? $this->view->access( $groups ) : true;
132
	}
133
134
135
	/**
136
	 * Sets the cache object.
137
	 *
138
	 * @param \Aimeos\Base\Cache\Iface $cache Cache object
139
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
140
	 */
141
	public function setCache( \Aimeos\Base\Cache\Iface $cache ) : \Aimeos\MShop\ContextIface
142
	{
143
		$this->cache = $cache;
144
145
		return $this;
146
	}
147
148
149
	/**
150
	 * Returns the cache object.
151
	 *
152
	 * @return \Aimeos\Base\Cache\Iface Cache object
153
	 */
154
	public function cache() : \Aimeos\Base\Cache\Iface
155
	{
156
		if( !isset( $this->cache ) ) {
157
			throw new \Aimeos\MShop\Exception( sprintf( 'Cache object not available' ) );
158
		}
159
160
		return $this->cache;
161
	}
162
163
164
	/**
165
	 * Sets the configuration object.
166
	 *
167
	 * @param \Aimeos\Base\Config\Iface $config Configuration object
168
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
169
	 */
170
	public function setConfig( \Aimeos\Base\Config\Iface $config ) : \Aimeos\MShop\ContextIface
171
	{
172
		$this->config = $config;
173
174
		return $this;
175
	}
176
177
178
	/**
179
	 * Returns the configuration object.
180
	 *
181
	 * @return \Aimeos\Base\Config\Iface Configuration object
182
	 */
183
	public function config() : \Aimeos\Base\Config\Iface
184
	{
185
		if( !isset( $this->config ) ) {
186
			throw new \Aimeos\MShop\Exception( sprintf( 'Configuration object not available' ) );
187
		}
188
189
		return $this->config;
190
	}
191
192
193
	/**
194
	 * Sets the database connection manager object.
195
	 *
196
	 * @param \Aimeos\Base\DB\Manager\Iface $manager Database manager object
197
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
198
	 */
199
	public function setDatabaseManager( \Aimeos\Base\DB\Manager\Iface $manager ) : \Aimeos\MShop\ContextIface
200
	{
201
		$this->db = $manager;
202
203
		return $this;
204
	}
205
206
207
	/**
208
	 * Returns the database connection object.
209
	 *
210
	 * @param string $resource Database resource name
211
	 * @param bool $new Create a new database connection
212
	 * @return \Aimeos\Base\DB\Manager\Iface Database manager object
213
	 */
214
	public function db( string $resource = 'db', bool $new = false ) : \Aimeos\Base\DB\Connection\Iface
215
	{
216
		if( !isset( $this->db ) ) {
217
			throw new \Aimeos\MShop\Exception( sprintf( 'Database manager object not available' ) );
218
		}
219
220
		return $this->db->get( $resource, $new );
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

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

220
		return $this->db->/** @scrutinizer ignore-call */ get( $resource, $new );

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...
221
	}
222
223
224
	/**
225
	 * Sets the current date and time
226
	 *
227
	 * @param string $datetime Date and time as ISO string (YYYY-MM-DD HH:mm:ss)
228
	 */
229
	public function setDateTime( string $datetime ) : \Aimeos\MShop\ContextIface
230
	{
231
		$regex = '/^[0-9]{4}-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]$/';
232
233
		if( preg_match( $regex, (string) $datetime ) !== 1 ) {
234
			throw new \Aimeos\MShop\Exception( sprintf( 'Invalid characters in date "%1$s". ISO format "YYYY-MM-DD hh:mm:ss" expected.', $datetime ) );
235
		}
236
237
		$this->datetime = $datetime;
238
239
		return $this;
240
	}
241
242
243
	/**
244
	 * Returns the current date and time
245
	 * This is especially useful to share the same request time or if applications
246
	 * allow to travel in time.
247
	 *
248
	 * @return string Current date and time as ISO string (YYYY-MM-DD HH:mm:ss)
249
	 */
250
	public function datetime() : string
251
	{
252
		if( $this->datetime === null ) {
253
			$this->datetime = date( 'Y-m-d H:i:s' );
254
		}
255
256
		return $this->datetime;
257
	}
258
259
260
	/**
261
	 * Sets the file system manager object.
262
	 *
263
	 * @param \Aimeos\Base\Filesystem\Manager\Iface $manager File system object
264
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
265
	 */
266
	public function setFilesystemManager( \Aimeos\Base\Filesystem\Manager\Iface $manager ) : \Aimeos\MShop\ContextIface
267
	{
268
		$this->fs = $manager;
269
		return $this;
270
	}
271
272
273
	/**
274
	 * Returns the file system object for the given resource name.
275
	 *
276
	 * @param string $resource Resource name, e.g. "fs-admin"
277
	 * @return \Aimeos\Base\Filesystem\Iface File system object
278
	 */
279
	public function fs( string $resource = 'fs' ) : \Aimeos\Base\Filesystem\Iface
280
	{
281
		if( !isset( $this->fs ) ) {
282
			throw new \Aimeos\MShop\Exception( sprintf( 'File system manager object not available' ) );
283
		}
284
285
		return $this->fs->get( $resource );
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

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

285
		return $this->fs->/** @scrutinizer ignore-call */ get( $resource );

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...
286
	}
287
288
289
	/**
290
	 * Sets the translation/internationalization objects.
291
	 *
292
	 * @param array $translations Associative list of internationalization objects implementing
293
	 * 	\Aimeos\Base\Translation\Iface with locale as key
294
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
295
	 */
296
	public function setI18n( array $translations ) : \Aimeos\MShop\ContextIface
297
	{
298
		$this->i18n = $translations;
299
300
		return $this;
301
	}
302
303
304
	/**
305
	 * Returns the translation/internationalization object for the given locale (null for default one).
306
	 *
307
	 * @param string|null $locale Two letter language ISO code for specific language instead of default one
308
	 * @return \Aimeos\Base\Translation\Iface Internationalization object
309
	 */
310
	public function i18n( string $locale = null ) : \Aimeos\Base\Translation\Iface
311
	{
312
		if( isset( $this->locale ) && $locale === null ) {
313
			$locale = $this->locale()->getLanguageId();
314
		}
315
316
		if( isset( $this->locale ) && $locale === null && reset( $this->i18n ) !== false ) {
317
			$locale = key( $this->i18n );
318
		}
319
320
		if( isset( $this->i18n[$locale] ) ) {
321
			return $this->i18n[$locale];
322
		}
323
324
		if( isset( $this->i18n['en'] ) ) {
325
			return $this->i18n['en'];
326
		}
327
328
		/// Locale ID %1$s
329
		throw new \Aimeos\MShop\Exception( sprintf( 'Internationalization object not available for "%1$s"', $locale ) );
330
	}
331
332
333
	/**
334
	 * Translates a string if possible
335
	 *
336
	 * @param string $name Name of the translation domain
337
	 * @param string $singular Singular string to translate
338
	 * @param string $plural Plural string to translate if count is not one
339
	 * @param int $number Number for plural translations
340
	 * @param string|null $locale Locale (e.g. en, en_US, de, etc.) or NULL for current locale
341
	 * @return string Translated string if possible
342
	 */
343
	public function translate( string $domain, string $singular, string $plural = null, int $number = 1, string $locale = null ) : string
344
	{
345
		if( empty( $this->i18n ) ) {
346
			return $number === 1 ? $singular : $plural;
347
		}
348
349
		if( $plural ) {
350
			return $this->i18n( $locale )->dn( $domain, $singular, $plural, $number );
351
		}
352
353
		return $this->i18n( $locale )->dt( $domain, $singular );
354
	}
355
356
357
	/**
358
	 * Sets the localization object.
359
	 *
360
	 * @param \Aimeos\MShop\Locale\Item\Iface $locale Localization object
361
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
362
	 */
363
	public function setLocale( \Aimeos\MShop\Locale\Item\Iface $locale ) : \Aimeos\MShop\ContextIface
364
	{
365
		$this->locale = $locale;
366
367
		return $this;
368
	}
369
370
371
	/**
372
	 * Returns the localization object.
373
	 *
374
	 * @return \Aimeos\MShop\Locale\Item\Iface Localization object
375
	 */
376
	public function locale() : \Aimeos\MShop\Locale\Item\Iface
377
	{
378
		if( !isset( $this->locale ) ) {
379
			throw new \Aimeos\MShop\Exception( sprintf( 'Locale object not available' ) );
380
		}
381
382
		return $this->locale;
383
	}
384
385
386
	/**
387
	 * Sets the logger object.
388
	 *
389
	 * @param \Aimeos\Base\Logger\Iface $logger Logger object
390
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
391
	 */
392
	public function setLogger( \Aimeos\Base\Logger\Iface $logger ) : \Aimeos\MShop\ContextIface
393
	{
394
		$this->logger = $logger;
395
396
		return $this;
397
	}
398
399
400
	/**
401
	 * Returns the logger object.
402
	 *
403
	 * @return \Aimeos\Base\Logger\Iface Logger object
404
	 */
405
	public function logger() : \Aimeos\Base\Logger\Iface
406
	{
407
		if( !isset( $this->logger ) ) {
408
			throw new \Aimeos\MShop\Exception( sprintf( 'Log manager object not available' ) );
409
		}
410
411
		return $this->logger;
412
	}
413
414
415
	/**
416
	 * Sets the mail object.
417
	 *
418
	 * @param \Aimeos\Base\Mail\Iface $mail Mail object
419
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
420
	 */
421
	public function setMail( \Aimeos\Base\Mail\Iface $mail ) : \Aimeos\MShop\ContextIface
422
	{
423
		$this->mail = $mail;
424
425
		return $this;
426
	}
427
428
429
	/**
430
	 * Returns the mail object.
431
	 *
432
	 * @return \Aimeos\Base\Mail\Iface Mail object
433
	 */
434
	public function mail() : \Aimeos\Base\Mail\Iface
435
	{
436
		if( !isset( $this->mail ) ) {
437
			throw new \Aimeos\MShop\Exception( sprintf( 'Mail object not available' ) );
438
		}
439
440
		return $this->mail;
441
	}
442
443
444
	/**
445
	 * Sets the message queue manager object.
446
	 *
447
	 * @param \Aimeos\Base\MQueue\Manager\Iface $mqManager Message queue manager object
448
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
449
	 */
450
	public function setMessageQueueManager( \Aimeos\Base\MQueue\Manager\Iface $mqManager ) : \Aimeos\MShop\ContextIface
451
	{
452
		$this->queue = $mqManager;
453
454
		return $this;
455
	}
456
457
458
	/**
459
	 * Returns the message queue object.
460
	 *
461
	 * @param string $resource Resource name, e.g. "mq-email"
462
	 * @param string $queue Message queue name, e.g. "order/email/payment"
463
	 * @return \Aimeos\Base\MQueue\Queue\Iface Message queue object
464
	 */
465
	public function queue( string $resource, string $queue ) : \Aimeos\Base\MQueue\Queue\Iface
466
	{
467
		if( !isset( $this->queue ) ) {
468
			throw new \Aimeos\MShop\Exception( sprintf( 'Message queue object not available' ) );
469
		}
470
471
		return $this->queue->get( $resource )->getQueue( $queue );
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

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

471
		return $this->queue->/** @scrutinizer ignore-call */ get( $resource )->getQueue( $queue );

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...
472
	}
473
474
475
	/**
476
	 * Returns the nonce value for inline Javascript
477
	 *
478
	 * @return string|null Nonce value
479
	 */
480
	public function nonce() : ?string
481
	{
482
		return $this->nonce;
483
	}
484
485
486
	/**
487
	 * Sets the nonce value for inline Javascript
488
	 *
489
	 * @param string $value Nonce value
490
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
491
	 */
492
	public function setNonce( ?string $value ) : \Aimeos\MShop\ContextIface
493
	{
494
		$this->nonce = $value;
495
		return $this;
496
	}
497
498
499
	/**
500
	 * Returns the password adapter object.
501
	 *
502
	 * @return \Aimeos\Base\Password\Iface Password adapter
503
	 */
504
	public function password() : \Aimeos\Base\Password\Iface
505
	{
506
		if( !isset( $this->password ) ) {
507
			throw new \Aimeos\MShop\Exception( sprintf( 'Password object not available' ) );
508
		}
509
510
		return $this->password;
511
	}
512
513
514
	/**
515
	 * Sets the password adapter object.
516
	 *
517
	 * @param \Aimeos\Base\Password\Iface $password Password adapter
518
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
519
	 */
520
	public function setPassword( \Aimeos\Base\Password\Iface $password ) : \Aimeos\MShop\ContextIface
521
	{
522
		$this->password = $password;
523
		return $this;
524
	}
525
526
527
	/**
528
	 * Sets the process object.
529
	 *
530
	 * @param \Aimeos\Base\Process\Iface $process Process object
531
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
532
	 */
533
	public function setProcess( \Aimeos\Base\Process\Iface $process ) : \Aimeos\MShop\ContextIface
534
	{
535
		$this->process = $process;
536
537
		return $this;
538
	}
539
540
541
	/**
542
	 * Returns the process object.
543
	 *
544
	 * @return \Aimeos\Base\Process\Iface Process object
545
	 */
546
	public function process() : \Aimeos\Base\Process\Iface
547
	{
548
		if( !isset( $this->process ) ) {
549
			throw new \Aimeos\MShop\Exception( sprintf( 'Process object not available' ) );
550
		}
551
552
		return $this->process;
553
	}
554
555
556
	/**
557
	 * Sets the session object.
558
	 *
559
	 * @param \Aimeos\Base\Session\Iface $session Session object
560
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
561
	 */
562
	public function setSession( \Aimeos\Base\Session\Iface $session ) : \Aimeos\MShop\ContextIface
563
	{
564
		$this->session = $session;
565
566
		return $this;
567
	}
568
569
570
	/**
571
	 * Returns the session object.
572
	 *
573
	 * @return \Aimeos\Base\Session\Iface Session object
574
	 */
575
	public function session() : \Aimeos\Base\Session\Iface
576
	{
577
		if( !isset( $this->session ) ) {
578
			throw new \Aimeos\MShop\Exception( sprintf( 'Session object not available' ) );
579
		}
580
581
		return $this->session;
582
	}
583
584
	/**
585
	 * Returns the session token.
586
	 *
587
	 * @return string|null Session token
588
	 */
589
	public function token() : ?string
590
	{
591
		return $this->token;
592
	}
593
594
595
	/**
596
	 * Sets the ion token.
597
	 *
598
	 * @param string $token Session token
599
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
600
	 */
601
	public function setToken( string $token ) : \Aimeos\MShop\ContextIface
602
	{
603
		$this->token = $token;
604
		return $this;
605
	}
606
607
608
	/**
609
	 * Sets the view object.
610
	 *
611
	 * @param \Aimeos\Base\View\Iface $view View object
612
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
613
	 */
614
	public function setView( \Aimeos\Base\View\Iface $view ) : \Aimeos\MShop\ContextIface
615
	{
616
		$this->view = $view;
617
618
		return $this;
619
	}
620
621
622
	/**
623
	 * Returns the view object.
624
	 *
625
	 * @return \Aimeos\Base\View\Iface View object
626
	 */
627
	public function view() : \Aimeos\Base\View\Iface
628
	{
629
		if( !isset( $this->view ) ) {
630
			throw new \Aimeos\MShop\Exception( sprintf( 'View object not available' ) );
631
		}
632
633
		return clone $this->view;
634
	}
635
636
637
	/**
638
	 * Sets the account name of the user/editor.
639
	 *
640
	 * @param string $name Account name of the user/editor
641
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
642
	 */
643
	public function setEditor( string $name ) : \Aimeos\MShop\ContextIface
644
	{
645
		$this->editor = $name;
646
647
		return $this;
648
	}
649
650
651
	/**
652
	 * Returns the account name of the user/editor.
653
	 *
654
	 * @return string Account name of the user/editor
655
	 */
656
	public function editor() : string
657
	{
658
		return $this->editor;
659
	}
660
661
662
	/**
663
	 * Returns the user/customer item of the logged in user.
664
	 *
665
	 * @return \Aimeos\MShop\Customer\Item\Iface|null User/customer item of the logged in user
666
	 */
667
	public function user() : ?\Aimeos\MShop\Customer\Item\Iface
668
	{
669
		if( $this->user instanceof \Closure )
670
		{
671
			$fcn = $this->user;
672
			$this->user = $fcn();
673
		}
674
675
		return $this->user;
676
	}
677
678
679
	/**
680
	 * Sets the user/customer item of the logged in user.
681
	 *
682
	 * @param \Closure|string|null $user User/customer item of the logged in user or closure to retrieve them
683
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
684
	 */
685
	public function setUser( $user ) : \Aimeos\MShop\ContextIface
686
	{
687
		$this->user = $user;
688
689
		return $this;
690
	}
691
692
693
	/**
694
	 * Returns the group ID/code pairs of the logged in user.
695
	 *
696
	 * @return array Group ID/code pairs of the logged in user
697
	 */
698
	public function groups() : array
699
	{
700
		if( $this->groups instanceof \Closure )
701
		{
702
			$fcn = $this->groups;
703
			$this->groups = $fcn();
704
		}
705
706
		return (array) $this->groups;
707
	}
708
709
710
	/**
711
	 * Sets the group IDs of the logged in user.
712
	 *
713
	 * @param \Closure|array $groups Group ID/code pairs of the logged in user or closure to retrieve them
714
	 * @return \Aimeos\MShop\ContextIface Context item for chaining method calls
715
	 */
716
	public function setGroups( $groups ) : \Aimeos\MShop\ContextIface
717
	{
718
		$this->groups = $groups;
719
720
		return $this;
721
	}
722
723
724
	/**
725
	 * Returns a hash for the given objects
726
	 *
727
	 * @param array $list List of objects
728
	 * @return string Hash for the objects
729
	 */
730
	private function hash( array $list ) : string
731
	{
732
		$hash = '';
733
734
		foreach( $list as $item )
735
		{
736
			if( is_object( $item ) ) {
737
				$hash .= spl_object_hash( $item );
738
			}
739
		}
740
741
		return $hash;
742
	}
743
}
744