Completed
Pull Request — master (#433)
by Paul
06:40
created

Bundle/PageBundle/Helper/PageHelper.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Victoire\Bundle\PageBundle\Helper;
4
5
use Doctrine\Common\Util\ClassUtils;
6
use Doctrine\Orm\EntityManager;
7
use Doctrine\ORM\ORMInvalidArgumentException;
8
use Symfony\Component\DependencyInjection\Container;
9
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
10
use Symfony\Component\HttpFoundation\Response;
11
use Symfony\Component\HttpFoundation\Session\Session;
12
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
13
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
14
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
15
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
16
use Victoire\Bundle\BusinessEntityBundle\Helper\BusinessEntityHelper;
17
use Victoire\Bundle\BusinessPageBundle\Builder\BusinessPageBuilder;
18
use Victoire\Bundle\BusinessPageBundle\Entity\BusinessPage;
19
use Victoire\Bundle\BusinessPageBundle\Entity\BusinessTemplate;
20
use Victoire\Bundle\BusinessPageBundle\Helper\BusinessPageHelper;
21
use Victoire\Bundle\CoreBundle\Entity\EntityProxy;
22
use Victoire\Bundle\CoreBundle\Entity\View;
23
use Victoire\Bundle\CoreBundle\Event\PageRenderEvent;
24
use Victoire\Bundle\CoreBundle\Helper\CurrentViewHelper;
25
use Victoire\Bundle\PageBundle\Entity\BasePage;
26
use Victoire\Bundle\PageBundle\Entity\Page;
27
use Victoire\Bundle\SeoBundle\Helper\PageSeoHelper;
28
use Victoire\Bundle\ViewReferenceBundle\Connector\ViewReferenceRepository;
29
use Victoire\Bundle\ViewReferenceBundle\Helper\ViewReferenceHelper;
30
use Victoire\Bundle\ViewReferenceBundle\ViewReference\BusinessPageReference;
31
use Victoire\Bundle\ViewReferenceBundle\ViewReference\ViewReference;
32
use Victoire\Bundle\WidgetMapBundle\Builder\WidgetMapBuilder;
33
use Victoire\Bundle\WidgetMapBundle\Warmer\WidgetDataWarmer;
34
35
/**
36
 * Page helper
37
 * ref: victoire_page.page_helper.
38
 */
39
class PageHelper
40
{
41
    protected $businessEntityHelper;
42
    protected $entityManager;
43
    protected $viewReferenceHelper;
44
    protected $currentViewHelper;
45
    protected $eventDispatcher;
46
    protected $container;
47
    protected $pageSeoHelper;
48
    protected $session;
49
    protected $tokenStorage;
50
    protected $widgetMapBuilder;
51
    protected $businessPageBuilder;
52
    protected $businessPageHelper;
53
    protected $viewReferenceRepository;
54
    protected $widgetDataWarmer;
55
56
    /**
57
     * @param BusinessEntityHelper     $businessEntityHelper
58
     * @param EntityManager            $entityManager
59
     * @param ViewReferenceHelper      $viewReferenceHelper
60
     * @param CurrentViewHelper        $currentViewHelper
61
     * @param EventDispatcherInterface $eventDispatcher
62
     * @param Container                $container
63
     * @param PageSeoHelper            $pageSeoHelper
64
     * @param Session                  $session
65
     * @param TokenStorage             $tokenStorage
66
     * @param AuthorizationChecker     $authorizationChecker
67
     * @param WidgetMapBuilder         $widgetMapBuilder
68
     * @param BusinessPageBuilder      $businessPageBuilder
69
     * @param BusinessPageHelper       $businessPageHelper
70
     * @param WidgetDataWarmer         $widgetDataWarmer
71
     * @param ViewReferenceRepository  $viewReferenceRepository
72
     */
73
    public function __construct(
74
        BusinessEntityHelper $businessEntityHelper,
75
        EntityManager $entityManager,
76
        ViewReferenceHelper $viewReferenceHelper,
77
        CurrentViewHelper $currentViewHelper,
78
        EventDispatcherInterface $eventDispatcher,
79
        Container $container,
80
        PageSeoHelper $pageSeoHelper,
81
        Session $session,
82
        TokenStorage $tokenStorage,
83
        AuthorizationChecker $authorizationChecker,
84
        WidgetMapBuilder $widgetMapBuilder,
85
        BusinessPageBuilder $businessPageBuilder,
86
        BusinessPageHelper $businessPageHelper,
87
        WidgetDataWarmer $widgetDataWarmer,
88
        ViewReferenceRepository $viewReferenceRepository
89
    ) {
90
        $this->businessEntityHelper = $businessEntityHelper;
91
        $this->entityManager = $entityManager;
92
        $this->viewReferenceHelper = $viewReferenceHelper;
93
        $this->currentViewHelper = $currentViewHelper;
94
        $this->eventDispatcher = $eventDispatcher;
95
        $this->container = $container;
96
        $this->pageSeoHelper = $pageSeoHelper;
97
        $this->session = $session;
98
        $this->tokenStorage = $tokenStorage;
99
        $this->authorizationChecker = $authorizationChecker;
100
        $this->widgetMapBuilder = $widgetMapBuilder;
101
        $this->businessPageBuilder = $businessPageBuilder;
102
        $this->businessPageHelper = $businessPageHelper;
103
        $this->widgetDataWarmer = $widgetDataWarmer;
104
        $this->viewReferenceRepository = $viewReferenceRepository;
105
    }
106
107
    /**
108
     * generates a response from parameters.
109
     *
110
     * @return View
111
     */
112
    public function findPageByParameters($parameters)
113
    {
114
        if (!empty($parameters['id']) && !preg_match('/^ref_/', $parameters['id'])) {
115
            $page = $this->entityManager->getRepository('VictoireCoreBundle:View')->findOneBy([
116
                'id' => $parameters['id'],
117
            ]);
118
119
            $entity = null;
120
            if (method_exists($page, 'getBusinessEntity')) {
121
                $entity = $page->getBusinessEntity();
122
            }
123
            $this->checkPageValidity($page, $entity, $parameters);
124
        } else {
125
            $viewReference = $this->viewReferenceRepository->getOneReferenceByParameters($parameters);
126
            if ($viewReference === null && !empty($parameters['viewId'])) {
127
                $parameters['templateId'] = $parameters['viewId'];
128
                unset($parameters['viewId']);
129
                $viewReference = $this->viewReferenceRepository->getOneReferenceByParameters($parameters);
130
            }
131
132
            if ($viewReference instanceof ViewReference) {
133
                $page = $this->findPageByReference($viewReference, $this->findEntityByReference($viewReference));
134
            } else {
135
                $parametersAsString = [];
136
                foreach ($parameters as $key => $value) {
137
                    $parametersAsString[] = $key.': '.$value;
138
                }
139
140
                throw new \Exception(sprintf('Oh no! Cannot find a viewReference for the given parameters %s', implode(',', $parametersAsString)));
141
            }
142
            $page->setReference($viewReference, $viewReference->getLocale());
143
        }
144
145
        return $page;
146
    }
147
148
    /**
149
     * generates a response from a page url.
150
     * if seo redirect, return target.
151
     *
152
     * @param string $url
153
     *
154
     * @return Response
155
     */
156
    public function renderPageByUrl($url, $locale, $isAjax = false)
157
    {
158
        $page = null;
159
        if ($viewReference = $this->viewReferenceRepository->getReferenceByUrl($url, $locale)) {
160
            $page = $this->findPageByReference($viewReference, $entity = $this->findEntityByReference($viewReference));
161
162
            if ($page instanceof BasePage
163
                && $page->getSeo()
164
                && $page->getSeo()->getRedirectTo()
165
                && !$this->session->get('victoire.edit_mode', false)) {
166
                $page = $page->getSeo()->getRedirectTo();
167
            }
168
169
            $this->checkPageValidity($page, $entity, ['url' => $url, 'locale' => $locale]);
170
            $page->setReference($viewReference);
171
172
            return $this->renderPage($page, $isAjax);
173
        } else {
174
            throw new NotFoundHttpException(sprintf('Page not found (url: "%s", locale: "%s")', $url, $locale));
175
        }
176
    }
177
178
    /**
179
     * generates a response from a page.
180
     *
181
     * @param View $view
182
     *
183
     * @return Response
184
     */
185
    public function renderPage($view, $isAjax = false)
186
    {
187
        $event = new \Victoire\Bundle\PageBundle\Event\Menu\PageMenuContextualEvent($view);
188
189
        //Set currentView and dispatch victoire.on_render_page event with this currentView
190
        $this->currentViewHelper->setCurrentView($view);
191
        $pageRenderEvent = new PageRenderEvent($view);
192
        $this->eventDispatcher->dispatch('victoire.on_render_page', $pageRenderEvent);
193
194
        //Build WidgetMap
195
        $this->widgetMapBuilder->build($view, $this->entityManager, true);
196
197
        //Populate widgets with their data
198
        $this->widgetDataWarmer->warm($this->entityManager, $view);
199
200
        //Dispatch contextual event regarding page type
201
        if ($view->getType() == 'business_page') {
202
            //Dispatch also an event with the Business entity name
203
            $eventName = 'victoire_core.page_menu.contextual';
204
            if (!$view->getId()) {
205
                $eventName = 'victoire_core.business_template_menu.contextual';
206
                $event = new \Victoire\Bundle\PageBundle\Event\Menu\PageMenuContextualEvent($view->getTemplate());
207
            }
208
            $this->eventDispatcher->dispatch($eventName, $event);
209
            $type = $view->getBusinessEntityId();
210
        } else {
211
            $type = $view->getType();
212
        }
213
214
        $eventName = 'victoire_core.'.$type.'_menu.contextual';
215
        $this->eventDispatcher->dispatch($eventName, $event);
216
217
        //Determine which layout to use
218
        $layout = $this->guessBestLayoutForView($view, $isAjax);
219
220
        //Create the response
221
        $response = $this->container->get('templating')->renderResponse('VictoireCoreBundle:Layout:'.$layout, [
222
            'view' => $view,
223
        ]);
224
225
        return $response;
226
    }
227
228
    /**
229
     * populate the page with given entity.
230
     *
231
     * @param View           $page
232
     * @param BusinessEntity $entity
233
     */
234
    public function updatePageWithEntity(BusinessTemplate $page, $entity)
235
    {
236
        $page = $this->businessPageBuilder->generateEntityPageFromTemplate($page, $entity, $this->entityManager);
237
        $this->pageSeoHelper->updateSeoByEntity($page, $entity);
238
239
        //update the parameters of the page
240
        $this->businessPageBuilder->updatePageParametersByEntity($page, $entity);
241
242
        return $page;
243
    }
244
245
    /**
246
     * @param BusinessPageReference $viewReference
247
     *
248
     * @return BusinessPage
249
     *                      read the cache to find entity according tu given url.
250
     * @return object|null
251
     */
252
    protected function findEntityByReference(ViewReference $viewReference)
253
    {
254
        if ($viewReference instanceof BusinessPageReference && !empty($viewReference->getEntityId())) {
255
            return $this->entityManager->getRepository($viewReference->getEntityNamespace())
256
                ->findOneById($viewReference->getEntityId());
257
        }
258
    }
259
260
    /**
261
     * find the page according to given url.
262
     *
263
     * @return View
264
     */
265
    public function findPageByReference($viewReference, $entity = null)
266
    {
267
        $page = null;
268
        if ($viewReference instanceof BusinessPageReference) {
269
            if ($viewReference->getViewId()) { //BusinessPage
270
                $page = $this->entityManager->getRepository('VictoireCoreBundle:View')
271
                    ->findOneBy([
272
                        'id'     => $viewReference->getViewId(),
273
                    ]);
274
                $page->setCurrentLocale($viewReference->getLocale());
275
            } else { //VirtualBusinessPage
276
                $page = $this->entityManager->getRepository('VictoireCoreBundle:View')
277
                    ->findOneBy([
278
                        'id'     => $viewReference->getTemplateId(),
279
                    ]);
280
                $page->setCurrentLocale($viewReference->getLocale());
281
                if ($entity) {
282
                    if ($page instanceof BusinessTemplate) {
283
                        $page = $this->updatePageWithEntity($page, $entity);
284
                    } elseif ($page instanceof BusinessPage) {
285
                        $this->pageSeoHelper->updateSeoByEntity($page, $entity);
286
                    }
287
                }
288
            }
289
        } elseif ($viewReference instanceof ViewReference) {
290
            $page = $this->entityManager->getRepository('VictoireCoreBundle:View')
291
                ->findOneBy([
292
                    'id'     => $viewReference->getViewId(),
293
                ]);
294
            $page->setCurrentLocale($viewReference->getLocale());
295
        } else {
296
            throw new \Exception(sprintf('Oh no! Cannot find a page for this ViewReference (%s)', ClassUtils::getClass($viewReference)));
297
        }
298
299
        return $page;
300
    }
301
302
    /**
303
     * @param View $page
304
     * @param $locale
305
     */
306
    private function refreshPage($page, $locale)
0 ignored issues
show
This method is not used, and could be removed.
Loading history...
307
    {
308
        if ($page && $page instanceof View) {
309
            try {
310
                $this->entityManager->refresh($page->setTranslatableLocale($locale));
0 ignored issues
show
The method setTranslatableLocale() does not seem to exist on object<Victoire\Bundle\CoreBundle\Entity\View>.

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...
311
            } catch (ORMInvalidArgumentException $e) {
312
            }
313
        }
314
    }
315
316
    /**
317
     * If the page is not valid, an exception is thrown.
318
     *
319
     * @param mixed $page
320
     * @param mixed $entity
321
     * @param mixed $parameters
322
     *
323
     * @throws \Exception
324
     */
325
    protected function checkPageValidity($page, $entity = null, $parameters = null)
326
    {
327
        $errorMessage = 'The page was not found';
328
        if ($parameters) {
329
            $errorMessage .= ' for parameters "'.implode('", "', $parameters).'"';
330
        }
331
        $isPageOwner = false;
332
333
        //there is no page
334
        if ($page === null) {
335
            throw new NotFoundHttpException($errorMessage);
336
        }
337
338
        if ($this->tokenStorage->getToken()) {
339
            $isPageOwner = $this->authorizationChecker->isGranted('PAGE_OWNER', $page);
340
        }
341
342
        //a page not published, not owned, nor granted throw an exception
343
        if (($page instanceof BasePage && !$page->isPublished()) && !$isPageOwner) {
344
            throw new NotFoundHttpException($errorMessage);
345
        }
346
347
        //if the page is a BusinessTemplate and the entity is not allowed for this page pattern
348
        if ($page instanceof BusinessTemplate) {
349
            //only victoire users are able to access a business page
350
            if (!$this->authorizationChecker->isGranted('ROLE_VICTOIRE')) {
351
                throw new AccessDeniedException('You are not allowed to see this page');
352
            }
353
        } elseif ($page instanceof BusinessPage) {
354
            if ($page->getTemplate()->isAuthorRestricted() && !$this->authorizationChecker->isGranted('BUSINESS_ENTITY_OWNER', $page->getBusinessEntity())) {
355
                throw new AccessDeniedException('You are not allowed to see this page');
356
            }
357
358
            if (!$entity->isVisibleOnFront() && !$this->authorizationChecker->isGranted('ROLE_VICTOIRE')) {
359
                throw new NotFoundHttpException('The BusinessPage for '.get_class($entity).'#'.$entity->getId().' is not visible on front.');
360
            }
361
            if (!$page->getId()) {
362
                $entityAllowed = $this->businessPageHelper->isEntityAllowed($page->getTemplate(), $entity, $this->entityManager);
363
364
                if ($entityAllowed === false) {
365
                    throw new NotFoundHttpException('The entity ['.$entity->getId().'] is not allowed for the page pattern ['.$page->getTemplate()->getId().']');
366
                }
367
            }
368
        }
369
    }
370
371
    /**
372
     * Create an instance of the business entity page.
373
     *
374
     * @param BusinessTemplate $BusinessTemplate The business entity page
375
     * @param entity           $entity           The entity
376
     * @param string           $url              The new url
377
     *
378
     * @return \Victoire\Bundle\PageBundle\Entity\Page
379
     */
380
    public function createPageInstanceFromBusinessTemplate(BusinessTemplate $BusinessTemplate, $entity, $url)
381
    {
382
        //create a new page
383
        $newPage = new Page();
384
385
        $parentPage = $BusinessTemplate->getParent();
386
387
        //set the page parameter by the business entity page
388
        $newPage->setParent($parentPage);
389
        $newPage->setTemplate($BusinessTemplate);
390
        $newPage->setUrl($url);
391
392
        $newPage->setTitle($BusinessTemplate->getTitle());
393
394
        //update the parameters of the page
395
        $this->businessPageBuilder->updatePageParametersByEntity($newPage, $entity);
396
397
        $businessEntity = $this->businessEntityHelper->findByEntityInstance($entity);
398
        $entityProxy = new EntityProxy();
399
        $entityProxy->setEntity($entity, $businessEntity->getName());
400
401
        $newPage->setEntityProxy($entityProxy);
402
403
        return $newPage;
404
    }
405
406
    /**
407
     * Guess which layout to use for a given View.
408
     *
409
     * @param View $view
410
     * @param bool $isAjax
411
     *
412
     * @return string
413
     */
414
    private function guessBestLayoutForView(View $view, $isAjax)
415
    {
416
        if ($isAjax) {
417
            $viewLayout = 'modal';
418
        } elseif (method_exists($view, 'getLayout') && $view->getLayout()) {
419
            $viewLayout = $view->getLayout();
420
        } else {
421
            $viewLayout = $view->getTemplate()->getLayout();
422
        }
423
424
        return $viewLayout.'.html.twig';
425
    }
426
}
427