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'), |
|
41 | 131 | new TemplateLocator($container->get('file_locator.public'), $container->getParameter('kernel.cache_dir')) |
|
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(); |
|
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
|
|||
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 |
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.