]> Raphaël G. Git Repositories - userbundle/blob - Controller/AbstractController.php
19e4782884271e4e084b38070d34cba0ebf543bf
[userbundle] / Controller / AbstractController.php
1 <?php declare(strict_types=1);
2
3 /*
4 * This file is part of the Rapsys UserBundle package.
5 *
6 * (c) Raphaël Gertz <symfony@rapsys.eu>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Rapsys\UserBundle\Controller;
13
14 use Doctrine\ORM\EntityManagerInterface;
15 use Doctrine\Persistence\ManagerRegistry;
16 use Psr\Log\LoggerInterface;
17 use Symfony\Bundle\FrameworkBundle\Controller\AbstractController as BaseAbstractController;
18 use Symfony\Bundle\FrameworkBundle\Controller\ControllerTrait;
19 use Symfony\Component\DependencyInjection\ContainerInterface;
20 use Symfony\Component\HttpFoundation\RequestStack;
21 use Symfony\Component\HttpFoundation\Response;
22 use Symfony\Component\Mailer\MailerInterface;
23 use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
24 use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
25 use Symfony\Component\Routing\RouterInterface;
26 use Symfony\Contracts\Service\ServiceSubscriberInterface;
27 use Symfony\Contracts\Translation\TranslatorInterface;
28 use Twig\Environment;
29
30 use Rapsys\PackBundle\Util\SluggerUtil;
31
32 use Rapsys\UserBundle\RapsysUserBundle;
33
34 /**
35 * Provides common features needed in controllers.
36 *
37 * {@inheritdoc}
38 */
39 abstract class AbstractController extends BaseAbstractController implements ServiceSubscriberInterface {
40 ///Config array
41 protected array $config;
42
43 ///Context array
44 protected array $context;
45
46 ///ManagerRegistry
47 protected ManagerRegistry $doctrine;
48
49 ///UserPasswordHasherInterface
50 protected UserPasswordHasherInterface $hasher;
51
52 ///LoggerInterface
53 protected LoggerInterface $logger;
54
55 ///MailerInterface
56 protected MailerInterface $mailer;
57
58 ///EntityManagerInterface
59 protected EntityManagerInterface $manager;
60
61 ///Router instance
62 protected RouterInterface $router;
63
64 ///Slugger util
65 protected SluggerUtil $slugger;
66
67 ///Translator instance
68 protected TranslatorInterface $translator;
69
70 ///Twig\Environment instance
71 protected Environment $twig;
72
73 ///Locale
74 protected string $locale;
75
76 /**
77 * Abstract constructor
78 *
79 * @param ContainerInterface $container The container instance
80 * @param ManagerRegistry $doctrine The doctrine instance
81 * @param UserPasswordHasherInterface $hasher The password hasher instance
82 * @param LoggerInterface $logger The logger instance
83 * @param MailerInterface $mailer The mailer instance
84 * @param EntityManagerInterface $manager The manager instance
85 * @param RouterInterface $router The router instance
86 * @param SluggerUtil $slugger The slugger instance
87 * @param RequestStack $stack The stack instance
88 * @param TranslatorInterface $translator The translator instance
89 * @param Environment $twig The twig environment instance
90 */
91 public function __construct(ContainerInterface $container, ManagerRegistry $doctrine, UserPasswordHasherInterface $hasher, LoggerInterface $logger, MailerInterface $mailer, EntityManagerInterface $manager, RouterInterface $router, SluggerUtil $slugger, RequestStack $stack, TranslatorInterface $translator, Environment $twig) {
92 //Retrieve config
93 $this->config = $container->getParameter(RapsysUserBundle::getAlias());
94
95 //Set container
96 $this->container = $container;
97
98 //Set doctrine
99 $this->doctrine = $doctrine;
100
101 //Set hasher
102 $this->hasher = $hasher;
103
104 //Set logger
105 $this->logger = $logger;
106
107 //Set mailer
108 $this->mailer = $mailer;
109
110 //Set manager
111 $this->manager = $manager;
112
113 //Set router
114 $this->router = $router;
115
116 //Set slugger
117 $this->slugger = $slugger;
118
119 //Set translator
120 $this->translator = $translator;
121
122 //Set twig
123 $this->twig = $twig;
124
125 //Get current request
126 $request = $stack->getCurrentRequest();
127
128 //Get current locale
129 $this->locale = $request->getLocale();
130
131 //Set translate array
132 $translates = [];
133
134 //Look for keys to translate
135 if (!empty($this->config['translate'])) {
136 //Iterate on keys to translate
137 foreach($this->config['translate'] as $translate) {
138 //Set tmp
139 $tmp = null;
140
141 //Iterate on keys
142 foreach(array_reverse(explode('.', $translate)) as $curkey) {
143 $tmp = array_combine([$curkey], [$tmp]);
144 }
145
146 //Append tree
147 $translates = array_replace_recursive($translates, $tmp);
148 }
149 }
150
151 //Inject every requested route in view and mail context
152 foreach($this->config as $tag => $current) {
153 //Look for entry with route subkey
154 if (!empty($current['route'])) {
155 //Generate url for both view and mail
156 foreach(['view', 'mail'] as $view) {
157 //Check that context key is usable
158 if (isset($current[$view]['context']) && is_array($current[$view]['context'])) {
159 //Merge with global context
160 $this->config[$tag][$view]['context'] = array_replace_recursive($this->config['context'], $this->config[$tag][$view]['context']);
161
162 //Process every routes
163 foreach($current['route'] as $route => $key) {
164 //With confirm route
165 if ($route == 'confirm') {
166 //Skip route as it requires some parameters
167 continue;
168 }
169
170 //Set value
171 $value = $this->router->generate(
172 $this->config['route'][$route]['name'],
173 $this->config['route'][$route]['context'],
174 //Generate absolute url for mails
175 $view=='mail'?UrlGeneratorInterface::ABSOLUTE_URL:UrlGeneratorInterface::ABSOLUTE_PATH
176 );
177
178 //Multi level key
179 if (strpos($key, '.') !== false) {
180 //Set tmp
181 $tmp = $value;
182
183 //Iterate on key
184 foreach(array_reverse(explode('.', $key)) as $curkey) {
185 $tmp = array_combine([$curkey], [$tmp]);
186 }
187
188 //Set value
189 $this->config[$tag][$view]['context'] = array_replace_recursive($this->config[$tag][$view]['context'], $tmp);
190 //Single level key
191 } else {
192 //Set value
193 $this->config[$tag][$view]['context'][$key] = $value;
194 }
195 }
196
197 //Look for successful intersections
198 if (!empty(array_intersect_key($translates, $this->config[$tag][$view]['context']))) {
199 //Iterate on keys to translate
200 foreach($this->config['translate'] as $translate) {
201 //Set keys
202 $keys = explode('.', $translate);
203
204 //Set tmp
205 $tmp = $this->config[$tag][$view]['context'];
206
207 //Iterate on keys
208 foreach($keys as $curkey) {
209 //Without child key
210 if (!isset($tmp[$curkey])) {
211 //Skip to next key
212 continue(2);
213 }
214
215 //Get child key
216 $tmp = $tmp[$curkey];
217 }
218
219 //Translate tmp value
220 $tmp = $this->translator->trans($tmp);
221
222 //Iterate on keys
223 foreach(array_reverse($keys) as $curkey) {
224 //Set parent key
225 $tmp = array_combine([$curkey], [$tmp]);
226 }
227
228 //Set value
229 $this->config[$tag][$view]['context'] = array_replace_recursive($this->config[$tag][$view]['context'], $tmp);
230 }
231 }
232
233 //With view context
234 if ($view == 'view') {
235 //Get context path
236 $pathInfo = $this->router->getContext()->getPathInfo();
237
238 //Iterate on locales excluding current one
239 foreach(($locales = array_keys($this->config['languages'])) as $locale) {
240 //Set titles
241 $titles = [];
242
243 //Iterate on other locales
244 foreach(array_diff($locales, [$locale]) as $other) {
245 $titles[$other] = $this->translator->trans($this->config['languages'][$locale], [], null, $other);
246 }
247
248 //Retrieve route matching path
249 $route = $this->router->match($pathInfo);
250
251 //Get route name
252 $name = $route['_route'];
253
254 //Unset route name
255 unset($route['_route']);
256
257 //With current locale
258 if ($locale == $this->locale) {
259 //Set locale locales context
260 $this->config[$tag][$view]['context']['canonical'] = $this->router->generate($name, ['_locale' => $locale]+$route, UrlGeneratorInterface::ABSOLUTE_URL);
261 } else {
262 //Set locale locales context
263 $this->config[$tag][$view]['context']['head']['alternates'][$locale] = [
264 'absolute' => $this->router->generate($name, ['_locale' => $locale]+$route, UrlGeneratorInterface::ABSOLUTE_URL),
265 'relative' => $this->router->generate($name, ['_locale' => $locale]+$route),
266 'title' => implode('/', $titles),
267 'translated' => $this->translator->trans($this->config['languages'][$locale], [], null, $locale)
268 ];
269 }
270
271 //Add shorter locale
272 if (empty($this->config[$tag][$view]['context']['head']['alternates'][$slocale = substr($locale, 0, 2)])) {
273 //Add shorter locale
274 $this->config[$tag][$view]['context']['head']['alternates'][$slocale] = [
275 'absolute' => $this->router->generate($name, ['_locale' => $locale]+$route, UrlGeneratorInterface::ABSOLUTE_URL),
276 'relative' => $this->router->generate($name, ['_locale' => $locale]+$route),
277 'title' => implode('/', $titles),
278 'translated' => $this->translator->trans($this->config['languages'][$locale], [], null, $locale)
279 ];
280 }
281 }
282 }
283 }
284 }
285 }
286 }
287 }
288
289 /**
290 * Renders a view
291 *
292 * {@inheritdoc}
293 */
294 protected function render(string $view, array $parameters = [], Response $response = null): Response {
295 //Create response when null
296 $response ??= new Response();
297
298 //With empty head locale
299 if (empty($parameters['head']['locale'])) {
300 //Set head locale
301 $parameters['head']['locale'] = $this->locale;
302 }
303
304 //With empty head title and section
305 if (empty($parameters['head']['title']) && !empty($parameters['section'])) {
306 //Set head title
307 $parameters['head']['title'] = implode(' - ', [$parameters['title'], $parameters['section'], $parameters['head']['site']]);
308 //With empty head title
309 } elseif (empty($parameters['head']['title'])) {
310 //Set head title
311 $parameters['head']['title'] = implode(' - ', [$parameters['title'], $parameters['head']['site']]);
312 }
313
314 //Call twig render method
315 $content = $this->twig->render($view, $parameters);
316
317 //Invalidate OK response on invalid form
318 if (200 === $response->getStatusCode()) {
319 foreach ($parameters as $v) {
320 if ($v instanceof FormInterface && $v->isSubmitted() && !$v->isValid()) {
321 $response->setStatusCode(422);
322 break;
323 }
324 }
325 }
326
327 //Store content in response
328 $response->setContent($content);
329
330 //Return response
331 return $response;
332 }
333
334 /**
335 * {@inheritdoc}
336 *
337 * @see vendor/symfony/framework-bundle/Controller/AbstractController.php
338 */
339 public static function getSubscribedServices(): array {
340 //Return subscribed services
341 return [
342 'service_container' => ContainerInterface::class,
343 'doctrine' => ManagerRegistry::class,
344 'doctrine.orm.default_entity_manager' => EntityManagerInterface::class,
345 'logger' => LoggerInterface::class,
346 'mailer.mailer' => MailerInterface::class,
347 'rapsys_pack.slugger_util' => SluggerUtil::class,
348 'request_stack' => RequestStack::class,
349 'router' => RouterInterface::class,
350 'security.user_password_hasher' => UserPasswordHasherInterface::class,
351 'translator' => TranslatorInterface::class
352 ];
353 }
354 }