[BUGFIX] Adapt glitches of context patch
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Context / Context.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Core\Context;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use TYPO3\CMS\Core\Context\Exception\AspectNotFoundException;
19 use TYPO3\CMS\Core\Context\Exception\AspectPropertyNotFoundException;
20 use TYPO3\CMS\Core\SingletonInterface;
21
22 /**
23 * Contains the state of a current page request, to be used when reading
24 * information of the current request in which configuration/context
25 * it is used.
26 *
27 * Typically, the current main context is initialized very early within each entry-point application,
28 * and is then modified overridden in e.g. PSR-15 middlewares (e.g. authentication, preview settings etc).
29 *
30 * For most use-cases, the current main context is fetched via GeneralUtility::makeInstance(Context::class),
31 * however, if custom settings for a single use-case is necessary, it is recommended to clone the base context:
32 *
33 * $mainContext = GeneralUtility::makeInstance(Context::class);
34 * $customContext = clone $mainContext;
35 * $customContext->setAspect(GeneralUtility::makeInstance(VisibilityAspect::class, true, true, false))
36 *
37 * ... which in turn can be injected in the various places where TYPO3 uses contexts.
38 *
39 *
40 * Classic aspect names to be used are:
41 * - date (DateTimeAspect)
42 * - workspace
43 * - visibility
44 * - frontend.user
45 * - backend.user
46 */
47 class Context implements SingletonInterface
48 {
49 /**
50 * @var AspectInterface[]
51 */
52 protected $aspects = [];
53
54 /**
55 * Sets up the context with pre-defined aspects
56 *
57 * @param array|null $defaultAspects
58 */
59 public function __construct(array $defaultAspects = [])
60 {
61 foreach ($defaultAspects as $name => $defaultAspect) {
62 if ($defaultAspect instanceof AspectInterface) {
63 $this->aspects[$name] = $defaultAspect;
64 }
65 }
66 // Ensure the default aspects are set, this is mostly necessary for tests to not set up everything
67 if (!$this->hasAspect('date')) {
68 $this->setAspect('date', new DateTimeAspect(new \DateTimeImmutable('@' . $GLOBALS['EXEC_TIME'])));
69 }
70 if (!$this->hasAspect('visibility')) {
71 $this->setAspect('visibility', new VisibilityAspect());
72 }
73 if (!$this->hasAspect('backend.user')) {
74 $this->setAspect('backend.user', new UserAspect());
75 }
76 if (!$this->hasAspect('frontend.user')) {
77 $this->setAspect('frontend.user', new UserAspect());
78 }
79 if (!$this->hasAspect('workspace')) {
80 $this->setAspect('workspace', new WorkspaceAspect());
81 }
82 }
83
84 /**
85 * Checks if an aspect exists in the context
86 *
87 * @param string $name
88 * @return bool
89 */
90 public function hasAspect(string $name): bool
91 {
92 return isset($this->aspects[$name]);
93 }
94
95 /**
96 * Returns an aspect, if it is set
97 *
98 * @param string $name
99 * @return AspectInterface
100 * @throws AspectNotFoundException
101 */
102 public function getAspect(string $name): AspectInterface
103 {
104 if (!$this->hasAspect($name)) {
105 throw new AspectNotFoundException('No aspect named "' . $name . '" found.', 1527777641);
106 }
107 return $this->aspects[$name];
108 }
109
110 /**
111 * Returns a property from the aspect, but only if the property is found.
112 *
113 * @param string $name
114 * @param string $property
115 * @param mixed $default
116 * @return mixed|null
117 * @throws AspectNotFoundException
118 */
119 public function getPropertyFromAspect(string $name, string $property, $default = null)
120 {
121 if (!$this->hasAspect($name)) {
122 throw new AspectNotFoundException('No aspect named "' . $name . '" found.', 1527777868);
123 }
124 try {
125 return $this->aspects[$name]->get($property);
126 } catch (AspectPropertyNotFoundException $e) {
127 return $default;
128 }
129 }
130
131 /**
132 * Sets an aspect, or overrides an existing aspect if an aspect is already set
133 *
134 * @param string $name
135 * @param AspectInterface $aspect
136 */
137 public function setAspect(string $name, AspectInterface $aspect): void
138 {
139 $this->aspects[$name] = $aspect;
140 }
141 }