1 | <?php |
||||||
2 | |||||||
3 | namespace Backend\Core\Engine; |
||||||
4 | |||||||
5 | use Backend\Core\Language\Language as BL; |
||||||
6 | use Common\Core\Twig\BaseTwigTemplate; |
||||||
7 | use Common\Core\Twig\Extensions\TwigFilters; |
||||||
8 | use Frontend\Core\Engine\FormExtension; |
||||||
9 | use ReflectionClass; |
||||||
10 | use Symfony\Bridge\Twig\AppVariable; |
||||||
11 | use Symfony\Bridge\Twig\Extension\FormExtension as SymfonyFormExtension; |
||||||
12 | use Symfony\Bridge\Twig\Extension\TranslationExtension; |
||||||
13 | use Symfony\Bridge\Twig\Form\TwigRendererEngine; |
||||||
14 | use Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator; |
||||||
15 | use Symfony\Component\DependencyInjection\ContainerInterface; |
||||||
16 | use Symfony\Component\Form\FormRenderer; |
||||||
17 | use Twig\Environment; |
||||||
18 | use Twig\Extension\DebugExtension; |
||||||
19 | use Twig\Loader\FilesystemLoader; |
||||||
20 | use Twig\RuntimeLoader\FactoryRuntimeLoader; |
||||||
21 | |||||||
22 | /** |
||||||
23 | * This is a twig template wrapper |
||||||
24 | * that glues spoon libraries and code standards with twig. |
||||||
25 | */ |
||||||
26 | class TwigTemplate extends BaseTwigTemplate |
||||||
27 | { |
||||||
28 | /** |
||||||
29 | * The constructor will store the instance in the reference, preset some settings and map the custom modifiers. |
||||||
30 | * |
||||||
31 | * @param bool $addToReference Should the instance be added into the reference. |
||||||
32 | */ |
||||||
33 | 131 | public function __construct(bool $addToReference = true) |
|||||
34 | { |
||||||
35 | 131 | $container = Model::getContainer(); |
|||||
36 | 131 | $this->debugMode = $container->getParameter('kernel.debug'); |
|||||
37 | |||||||
38 | 131 | parent::__construct( |
|||||
39 | 131 | $this->buildTwigEnvironmentForTheBackend(), |
|||||
40 | 131 | $container->get('templating.name_parser.public'), |
|||||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||||
41 | 131 | new TemplateLocator($container->get('file_locator.public'), $container->getParameter('kernel.cache_dir')) |
|||||
0 ignored issues
–
show
It seems like
$container->get('file_locator.public') can also be of type null ; however, parameter $locator of Symfony\Bundle\Framework...eLocator::__construct() does only seem to accept Symfony\Component\Config\FileLocatorInterface , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
The class
Symfony\Bundle\Framework...\Loader\TemplateLocator has been deprecated: since version 4.3, to be removed in 5.0; use Twig instead.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
42 | ); |
||||||
43 | |||||||
44 | 131 | if ($addToReference) { |
|||||
45 | 131 | $container->set('template', $this); |
|||||
46 | } |
||||||
47 | |||||||
48 | 131 | $this->forkSettings = $container->get('fork.settings'); |
|||||
49 | 131 | if ($this->debugMode) { |
|||||
50 | 131 | $this->environment->enableAutoReload(); |
|||||
51 | 131 | $this->environment->setCache(false); |
|||||
52 | 131 | $this->environment->addExtension(new DebugExtension()); |
|||||
53 | } |
||||||
54 | 131 | $this->language = BL::getWorkingLanguage(); |
|||||
55 | 131 | $this->connectSymfonyForms(); |
|||||
56 | 131 | $this->connectSymfonyTranslator(); |
|||||
57 | 131 | $this->connectSpoonForm(); |
|||||
58 | 131 | TwigFilters::addFilters($this->environment, 'Backend'); |
|||||
59 | 131 | $this->autoloadMissingTaggedExtensions($container); |
|||||
60 | 131 | } |
|||||
61 | |||||||
62 | /** |
||||||
63 | * Fetch the parsed content from this template. |
||||||
64 | * |
||||||
65 | * @param string $template The location of the template file, used to display this template. |
||||||
66 | * |
||||||
67 | * @return string The actual parsed content after executing this template. |
||||||
68 | */ |
||||||
69 | 71 | public function getContent(string $template): string |
|||||
70 | { |
||||||
71 | 71 | $this->parseUserDefinedConstants(); |
|||||
72 | 71 | $this->parseAuthenticationSettingsForTheAuthenticatedUser(); |
|||||
0 ignored issues
–
show
The function
Backend\Core\Engine\Twig...rTheAuthenticatedUser() has been deprecated: This is a very inaccurate way since it doesn't include the goduser permissions and the always allowed settings into account
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||||
73 | 71 | $this->parseAuthenticatedUser(); |
|||||
74 | 71 | $this->parseDebug(); |
|||||
75 | 71 | $this->parseTranslations(); |
|||||
76 | 71 | $this->parseVars(); |
|||||
77 | 71 | $this->startGlobals($this->environment); |
|||||
78 | |||||||
79 | 71 | return $this->render(str_replace(BACKEND_MODULES_PATH, '', $template), $this->variables); |
|||||
80 | } |
||||||
81 | |||||||
82 | /** |
||||||
83 | * @return Environment |
||||||
84 | */ |
||||||
85 | 131 | private function buildTwigEnvironmentForTheBackend(): Environment |
|||||
86 | { |
||||||
87 | // path to TwigBridge library so we can locate the form theme files. |
||||||
88 | 131 | $appVariableReflection = new ReflectionClass(AppVariable::class); |
|||||
89 | 131 | $vendorTwigBridgeDir = dirname($appVariableReflection->getFileName()); |
|||||
90 | |||||||
91 | // render the compiled File |
||||||
92 | 131 | $loader = new FilesystemLoader( |
|||||
93 | [ |
||||||
94 | 131 | BACKEND_MODULES_PATH, |
|||||
95 | 131 | BACKEND_CORE_PATH, |
|||||
96 | 131 | $vendorTwigBridgeDir . '/Resources/views/Form', |
|||||
97 | ] |
||||||
98 | ); |
||||||
99 | |||||||
100 | 131 | return new Environment( |
|||||
101 | 131 | $loader, |
|||||
102 | [ |
||||||
103 | 131 | 'cache' => Model::getContainer()->getParameter('kernel.cache_dir') . '/twig', |
|||||
104 | 131 | 'debug' => $this->debugMode, |
|||||
105 | ] |
||||||
106 | ); |
||||||
107 | } |
||||||
108 | |||||||
109 | 131 | private function connectSymfonyForms(): void |
|||||
110 | { |
||||||
111 | 131 | $rendererEngine = new TwigRendererEngine( |
|||||
112 | [ |
||||||
113 | 131 | 'Layout/Templates/FormLayout.html.twig', |
|||||
114 | 'MediaLibrary/Resources/views/FormLayout.html.twig', |
||||||
115 | ], |
||||||
116 | 131 | $this->environment |
|||||
117 | ); |
||||||
118 | 131 | $csrfTokenManager = Model::get('security.csrf.token_manager'); |
|||||
119 | 131 | $this->environment->addRuntimeLoader( |
|||||
120 | 131 | new FactoryRuntimeLoader( |
|||||
121 | [ |
||||||
122 | FormRenderer::class => function () use ($rendererEngine, $csrfTokenManager): FormRenderer { |
||||||
123 | 6 | return new FormRenderer($rendererEngine, $csrfTokenManager); |
|||||
124 | 131 | }, |
|||||
125 | ] |
||||||
126 | ) |
||||||
127 | ); |
||||||
128 | |||||||
129 | 131 | if (!$this->environment->hasExtension(SymfonyFormExtension::class)) { |
|||||
130 | 131 | $this->environment->addExtension(new SymfonyFormExtension()); |
|||||
131 | } |
||||||
132 | 131 | } |
|||||
133 | |||||||
134 | 131 | private function connectSymfonyTranslator(): void |
|||||
135 | { |
||||||
136 | 131 | $this->environment->addExtension(new TranslationExtension(Model::get('translator'))); |
|||||
137 | 131 | } |
|||||
138 | |||||||
139 | 131 | private function connectSpoonForm(): void |
|||||
140 | { |
||||||
141 | 131 | new FormExtension($this->environment); |
|||||
142 | 131 | } |
|||||
143 | |||||||
144 | 71 | private function parseUserDefinedConstants(): void |
|||||
145 | { |
||||||
146 | // get all defined constants |
||||||
147 | 71 | $constants = get_defined_constants(true); |
|||||
148 | |||||||
149 | // we should only assign constants if there are constants to assign |
||||||
150 | 71 | if (!empty($constants['user'])) { |
|||||
151 | 71 | $this->assignArray($constants['user']); |
|||||
152 | } |
||||||
153 | |||||||
154 | // we use some abbreviations and common terms, these should also be assigned |
||||||
155 | 71 | $this->assign('LANGUAGE', BL::getWorkingLanguage()); |
|||||
156 | |||||||
157 | // check on url object |
||||||
158 | 71 | if (Model::getContainer()->has('url')) { |
|||||
159 | 71 | $url = Model::get('url'); |
|||||
160 | |||||||
161 | 71 | if ($url instanceof Url) { |
|||||
162 | // assign the current module |
||||||
163 | 71 | $this->assign('MODULE', $url->getModule()); |
|||||
164 | |||||||
165 | // assign the current action |
||||||
166 | 71 | if ($url->getAction() !== '') { |
|||||
167 | 71 | $this->assign('ACTION', $url->getAction()); |
|||||
168 | } |
||||||
169 | |||||||
170 | 71 | if ($url->getModule() === 'Core') { |
|||||
171 | $this->assign( |
||||||
172 | 'BACKEND_MODULE_PATH', |
||||||
173 | BACKEND_PATH . '/' . $url->getModule() |
||||||
174 | ); |
||||||
175 | } else { |
||||||
176 | 71 | $this->assign( |
|||||
177 | 71 | 'BACKEND_MODULE_PATH', |
|||||
178 | 71 | BACKEND_MODULES_PATH . '/' . $url->getModule() |
|||||
179 | ); |
||||||
180 | } |
||||||
181 | } |
||||||
182 | } |
||||||
183 | |||||||
184 | // is the user object filled? |
||||||
185 | 71 | if (Authentication::getUser()->isAuthenticated()) { |
|||||
186 | // assign the authenticated users secret key |
||||||
187 | 38 | $this->assign('SECRET_KEY', Authentication::getUser()->getSecretKey()); |
|||||
188 | |||||||
189 | // assign the authenticated users preferred interface language |
||||||
190 | 38 | $this->assign('INTERFACE_LANGUAGE', (string) Authentication::getUser()->getSetting('interface_language')); |
|||||
191 | } |
||||||
192 | |||||||
193 | // assign some variable constants (such as site-title) |
||||||
194 | 71 | $this->assign( |
|||||
195 | 71 | 'SITE_TITLE', |
|||||
196 | 71 | Model::get('fork.settings')->get('Core', 'site_title_' . BL::getWorkingLanguage(), SITE_DEFAULT_TITLE) |
|||||
197 | ); |
||||||
198 | 71 | } |
|||||
199 | |||||||
200 | 71 | private function parseAuthenticatedUser(): void |
|||||
201 | { |
||||||
202 | // check if the current user is authenticated |
||||||
203 | 71 | if (Authentication::getUser()->isAuthenticated()) { |
|||||
204 | // show stuff that only should be visible if authenticated |
||||||
205 | 38 | $this->assign('isAuthenticated', true); |
|||||
206 | |||||||
207 | // get authenticated user-settings |
||||||
208 | 38 | $settings = (array) Authentication::getUser()->getSettings(); |
|||||
209 | |||||||
210 | 38 | foreach ($settings as $key => $setting) { |
|||||
211 | 38 | $this->assign('authenticatedUser' . \SpoonFilter::toCamelCase($key), $setting ?? ''); |
|||||
212 | } |
||||||
213 | |||||||
214 | // check if this action is allowed |
||||||
215 | 38 | if (Authentication::isAllowedAction('Edit', 'Users')) { |
|||||
216 | // assign special vars |
||||||
217 | 37 | $this->assign( |
|||||
218 | 37 | 'authenticatedUserEditUrl', |
|||||
219 | 37 | Model::createUrlForAction( |
|||||
220 | 37 | 'Edit', |
|||||
221 | 37 | 'Users', |
|||||
222 | 37 | null, |
|||||
223 | 37 | ['id' => Authentication::getUser()->getUserId()] |
|||||
224 | ) |
||||||
225 | ); |
||||||
226 | } |
||||||
227 | } |
||||||
228 | 71 | } |
|||||
229 | |||||||
230 | /** |
||||||
231 | * @deprecated This is a very inaccurate way since it doesn't include the goduser permissions and the always allowed settings into account |
||||||
232 | */ |
||||||
233 | 71 | private function parseAuthenticationSettingsForTheAuthenticatedUser(): void |
|||||
234 | { |
||||||
235 | // loop actions and assign to template |
||||||
236 | 71 | foreach (Authentication::getAllowedActions() as $module => $allowedActions) { |
|||||
0 ignored issues
–
show
The function
Backend\Core\Engine\Auth...on::getAllowedActions() has been deprecated: this will become a private method in Fork 6
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||||
237 | 38 | foreach ($allowedActions as $action => $level) { |
|||||
238 | 38 | if ($level !== 7) { |
|||||
239 | continue; |
||||||
240 | } |
||||||
241 | |||||||
242 | 38 | $this->assign( |
|||||
243 | 38 | 'show' . \SpoonFilter::toCamelCase($module, '_') . \SpoonFilter::toCamelCase( |
|||||
244 | 38 | $action, |
|||||
245 | 38 | '_' |
|||||
246 | ), |
||||||
247 | 38 | true |
|||||
248 | ); |
||||||
249 | } |
||||||
250 | } |
||||||
251 | 71 | } |
|||||
252 | |||||||
253 | 71 | private function parseDebug(): void |
|||||
254 | { |
||||||
255 | 71 | $this->assign('debug', Model::getContainer()->getParameter('kernel.debug')); |
|||||
256 | |||||||
257 | 71 | if ($this->debugMode === true && !$this->environment->hasExtension(DebugExtension::class)) { |
|||||
258 | $this->environment->addExtension(new DebugExtension()); |
||||||
259 | } |
||||||
260 | 71 | } |
|||||
261 | |||||||
262 | 71 | private function parseLabels(array $labels, string $module, string $key): void |
|||||
263 | { |
||||||
264 | 71 | $realLabels = $this->prefixArrayKeys('Core', $labels['Core']); |
|||||
265 | |||||||
266 | 71 | if (array_key_exists($module, $labels)) { |
|||||
267 | 38 | $realLabels = array_merge($realLabels, $labels[$module]); |
|||||
268 | } |
||||||
269 | |||||||
270 | 71 | if ($this->addSlashes) { |
|||||
271 | $realLabels = array_map('addslashes', $realLabels); |
||||||
272 | } |
||||||
273 | |||||||
274 | // just so the dump is nicely sorted |
||||||
275 | 71 | ksort($realLabels); |
|||||
276 | |||||||
277 | 71 | $this->assignArray($realLabels, $key); |
|||||
278 | 71 | } |
|||||
279 | |||||||
280 | 71 | private function prefixArrayKeys(string $prefix, array $array): array |
|||||
281 | { |
||||||
282 | 71 | return array_combine( |
|||||
283 | 71 | array_map( |
|||||
284 | function ($key) use ($prefix) { |
||||||
285 | 71 | return $prefix . \SpoonFilter::ucfirst($key); |
|||||
286 | 71 | }, |
|||||
287 | 71 | array_keys($array) |
|||||
288 | ), |
||||||
289 | 71 | $array |
|||||
290 | ); |
||||||
291 | } |
||||||
292 | |||||||
293 | 71 | private function parseTranslations(): void |
|||||
294 | { |
||||||
295 | 71 | $currentModule = BL::getCurrentModule(); |
|||||
296 | 71 | $this->parseLabels(BL::getErrors(), $currentModule, 'err'); |
|||||
297 | 71 | $this->parseLabels(BL::getLabels(), $currentModule, 'lbl'); |
|||||
298 | 71 | $this->parseLabels(BL::getMessages(), $currentModule, 'msg'); |
|||||
299 | |||||||
300 | 71 | $interfaceLanguage = BL::getInterfaceLanguage(); |
|||||
301 | 71 | $this->assignArray($this->prefixArrayKeys('locMonthLong', \SpoonLocale::getMonths($interfaceLanguage, false))); |
|||||
302 | 71 | $this->assignArray($this->prefixArrayKeys('locMonthShort', \SpoonLocale::getMonths($interfaceLanguage, true))); |
|||||
303 | 71 | $this->assignArray($this->prefixArrayKeys('locDayLong', \SpoonLocale::getWeekDays($interfaceLanguage, false))); |
|||||
304 | 71 | $this->assignArray($this->prefixArrayKeys('locDayShort', \SpoonLocale::getWeekDays($interfaceLanguage, true))); |
|||||
305 | 71 | } |
|||||
306 | |||||||
307 | 71 | private function parseVars(): void |
|||||
308 | { |
||||||
309 | 71 | $this->assign('var', ''); |
|||||
310 | 71 | $this->assign('timestamp', time()); |
|||||
311 | 71 | $this->assign('fork_csrf_token', Model::getToken()); |
|||||
312 | 71 | $this->addBodyClassAndId(); |
|||||
313 | 71 | $this->parseNavigation(); |
|||||
314 | |||||||
315 | 71 | foreach ($this->forms as $form) { |
|||||
316 | 67 | if ($form->isSubmitted() && !$form->isCorrect()) { |
|||||
317 | 4 | $this->assign('form_error', true); |
|||||
318 | 67 | break; |
|||||
319 | } |
||||||
320 | } |
||||||
321 | |||||||
322 | 71 | $this->assign('cookies', Model::getRequest()->cookies->all()); |
|||||
323 | 71 | } |
|||||
324 | |||||||
325 | 71 | private function parseNavigation(): void |
|||||
326 | { |
||||||
327 | 71 | if (!Model::has('navigation')) { |
|||||
328 | return; |
||||||
329 | } |
||||||
330 | |||||||
331 | 71 | $navigation = Model::get('navigation'); |
|||||
332 | 71 | if ($navigation instanceof Navigation) { |
|||||
333 | 71 | $navigation->parse($this); |
|||||
334 | } |
||||||
335 | 71 | } |
|||||
336 | |||||||
337 | 71 | private function addBodyClassAndId(): void |
|||||
338 | { |
||||||
339 | 71 | if (!Model::getContainer()->has('url')) { |
|||||
340 | return; |
||||||
341 | } |
||||||
342 | |||||||
343 | 71 | $url = Model::get('url'); |
|||||
344 | |||||||
345 | 71 | if (!$url instanceof Url) { |
|||||
346 | return; |
||||||
347 | } |
||||||
348 | |||||||
349 | 71 | $this->assign('bodyID', \SpoonFilter::toCamelCase($url->getModule(), '_', true)); |
|||||
350 | 71 | $bodyClass = \SpoonFilter::toCamelCase($url->getModule() . '_' . $url->getAction(), '_', true); |
|||||
351 | 71 | if (in_array(mb_strtolower($url->getAction()), ['add', 'edit'], true)) { |
|||||
352 | 10 | $bodyClass = $url->getModule() . 'AddEdit'; |
|||||
353 | } |
||||||
354 | 71 | $this->assign('bodyClass', $bodyClass); |
|||||
355 | 71 | } |
|||||
356 | |||||||
357 | 131 | private function autoloadMissingTaggedExtensions(ContainerInterface $container): void |
|||||
358 | { |
||||||
359 | 131 | foreach ($container->get('twig')->getExtensions() as $id => $extension) { |
|||||
360 | 131 | if (!$this->environment->hasExtension($id)) { |
|||||
361 | 131 | $this->environment->addExtension($extension); |
|||||
362 | } |
||||||
363 | } |
||||||
364 | 131 | } |
|||||
365 | } |
||||||
366 |