Completed
Push — master ( 0b2e6b...2c86a7 )
by Paul
49:42 queued 39:17
created

PageHelper::renderPageByUrl()   C

Complexity

Conditions 7
Paths 3

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 24
rs 6.7272
cc 7
eloc 16
nc 3
nop 3
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\RedirectResponse;
11
use Symfony\Component\HttpFoundation\Response;
12
use Symfony\Component\HttpFoundation\Session\Session;
13
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
14
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
15
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
16
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
17
use Victoire\Bundle\BusinessEntityBundle\Helper\BusinessEntityHelper;
18
use Victoire\Bundle\BusinessPageBundle\Builder\BusinessPageBuilder;
19
use Victoire\Bundle\BusinessPageBundle\Entity\BusinessPage;
20
use Victoire\Bundle\BusinessPageBundle\Entity\BusinessTemplate;
21
use Victoire\Bundle\BusinessPageBundle\Helper\BusinessPageHelper;
22
use Victoire\Bundle\CoreBundle\Entity\EntityProxy;
23
use Victoire\Bundle\CoreBundle\Entity\Link;
24
use Victoire\Bundle\CoreBundle\Entity\View;
25
use Victoire\Bundle\CoreBundle\Event\PageRenderEvent;
26
use Victoire\Bundle\CoreBundle\Helper\CurrentViewHelper;
27
use Victoire\Bundle\PageBundle\Entity\BasePage;
28
use Victoire\Bundle\PageBundle\Entity\Page;
29
use Victoire\Bundle\SeoBundle\Helper\PageSeoHelper;
30
use Victoire\Bundle\ViewReferenceBundle\Connector\ViewReferenceRepository;
31
use Victoire\Bundle\ViewReferenceBundle\Exception\ViewReferenceNotFoundException;
32
use Victoire\Bundle\ViewReferenceBundle\Helper\ViewReferenceHelper;
33
use Victoire\Bundle\ViewReferenceBundle\ViewReference\BusinessPageReference;
34
use Victoire\Bundle\ViewReferenceBundle\ViewReference\ViewReference;
35
use Victoire\Bundle\WidgetMapBundle\Builder\WidgetMapBuilder;
36
use Victoire\Bundle\WidgetMapBundle\Warmer\WidgetDataWarmer;
37
38
/**
39
 * Page helper
40
 * ref: victoire_page.page_helper.
41
 */
42
class PageHelper
43
{
44
    protected $businessEntityHelper;
45
    protected $entityManager;
46
    protected $viewReferenceHelper;
47
    protected $currentViewHelper;
48
    protected $eventDispatcher;
49
    protected $container;
50
    protected $pageSeoHelper;
51
    protected $session;
52
    protected $tokenStorage;
53
    protected $widgetMapBuilder;
54
    protected $businessPageBuilder;
55
    protected $businessPageHelper;
56
    protected $viewReferenceRepository;
57
    protected $widgetDataWarmer;
58
59
    /**
60
     * @param BusinessEntityHelper     $businessEntityHelper
61
     * @param EntityManager            $entityManager
62
     * @param ViewReferenceHelper      $viewReferenceHelper
63
     * @param CurrentViewHelper        $currentViewHelper
64
     * @param EventDispatcherInterface $eventDispatcher
65
     * @param Container                $container
66
     * @param PageSeoHelper            $pageSeoHelper
67
     * @param Session                  $session
68
     * @param TokenStorage             $tokenStorage
69
     * @param AuthorizationChecker     $authorizationChecker
70
     * @param WidgetMapBuilder         $widgetMapBuilder
71
     * @param BusinessPageBuilder      $businessPageBuilder
72
     * @param BusinessPageHelper       $businessPageHelper
73
     * @param WidgetDataWarmer         $widgetDataWarmer
74
     * @param ViewReferenceRepository  $viewReferenceRepository
75
     */
76
    public function __construct(
77
        BusinessEntityHelper $businessEntityHelper,
78
        EntityManager $entityManager,
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $entityManager. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
79
        ViewReferenceHelper $viewReferenceHelper,
80
        CurrentViewHelper $currentViewHelper,
81
        EventDispatcherInterface $eventDispatcher,
82
        Container $container,
83
        PageSeoHelper $pageSeoHelper,
84
        Session $session,
85
        TokenStorage $tokenStorage,
86
        AuthorizationChecker $authorizationChecker,
87
        WidgetMapBuilder $widgetMapBuilder,
88
        BusinessPageBuilder $businessPageBuilder,
89
        BusinessPageHelper $businessPageHelper,
90
        WidgetDataWarmer $widgetDataWarmer,
91
        ViewReferenceRepository $viewReferenceRepository
92
    ) {
93
        $this->businessEntityHelper = $businessEntityHelper;
94
        $this->entityManager = $entityManager;
95
        $this->viewReferenceHelper = $viewReferenceHelper;
96
        $this->currentViewHelper = $currentViewHelper;
97
        $this->eventDispatcher = $eventDispatcher;
98
        $this->container = $container;
99
        $this->pageSeoHelper = $pageSeoHelper;
100
        $this->session = $session;
101
        $this->tokenStorage = $tokenStorage;
102
        $this->authorizationChecker = $authorizationChecker;
0 ignored issues
show
Bug introduced by
The property authorizationChecker does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
103
        $this->widgetMapBuilder = $widgetMapBuilder;
104
        $this->businessPageBuilder = $businessPageBuilder;
105
        $this->businessPageHelper = $businessPageHelper;
106
        $this->widgetDataWarmer = $widgetDataWarmer;
107
        $this->viewReferenceRepository = $viewReferenceRepository;
108
    }
109
110
    /**
111
     * generates a response from parameters.
112
     *
113
     * @return View
114
     */
115
    public function findPageByParameters($parameters)
116
    {
117
        if (!empty($parameters['id']) && !preg_match('/^ref_/', $parameters['id'])) {
118
            $page = $this->entityManager->getRepository('VictoireCoreBundle:View')->findOneBy([
119
                'id' => $parameters['id'],
120
            ]);
121
122
            $this->checkPageValidity($page, $parameters);
123
        } else {
124
            if (isset($parameters['id']) && isset($parameters['locale'])) {
125
                //if locale is missing, we add append locale
126
                if (preg_match('/^ref_[0-9]*$/', $parameters['id'])) {
127
                    $parameters['id'] .= '_'.$parameters['locale'];
128
                }
129
            }
130
            $viewReference = $this->viewReferenceRepository->getOneReferenceByParameters($parameters);
131
            if ($viewReference === null && !empty($parameters['viewId'])) {
132
                $parameters['templateId'] = $parameters['viewId'];
133
                unset($parameters['viewId']);
134
                $viewReference = $this->viewReferenceRepository->getOneReferenceByParameters($parameters);
135
            }
136
137
            if ($viewReference instanceof ViewReference) {
138
                $page = $this->findPageByReference($viewReference);
139
            } else {
140
                throw new ViewReferenceNotFoundException($parameters);
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;
0 ignored issues
show
Unused Code introduced by
$page is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
159
        if ($viewReference = $this->viewReferenceRepository->getReferenceByUrl($url, $locale)) {
160
            $page = $this->findPageByReference($viewReference);
161
            $this->checkPageValidity($page, ['url' => $url, 'locale' => $locale]);
162
            $page->setReference($viewReference);
163
164
            if ($page instanceof BasePage
165
                && $page->getSeo()
166
                && $page->getSeo()->getRedirectTo()
167
                && $page->getSeo()->getRedirectTo()->getLinkType() != Link::TYPE_NONE
0 ignored issues
show
Bug introduced by
The method getLinkType cannot be called on $page->getSeo()->getRedirectTo() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
168
                && !$this->session->get('victoire.edit_mode', false)) {
169
                $link = $page->getSeo()->getRedirectTo();
170
171
                return new RedirectResponse($this->container->get('victoire_widget.twig.link_extension')->victoireLinkUrl($link->getParameters()));
0 ignored issues
show
Bug introduced by
The method getParameters cannot be called on $link (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
172
            }
173
174
175
            return $this->renderPage($page, $isAjax);
0 ignored issues
show
Bug introduced by
It seems like $page defined by $this->findPageByReference($viewReference) on line 160 can be null; however, Victoire\Bundle\PageBund...ageHelper::renderPage() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
176
        } else {
177
            throw new NotFoundHttpException(sprintf('Page not found (url: "%s", locale: "%s")', $url, $locale));
178
        }
179
    }
180
181
    /**
182
     * generates a response from a page.
183
     *
184
     * @param View $view
185
     *
186
     * @return Response
187
     */
188
    public function renderPage($view, $isAjax = false)
189
    {
190
        $event = new \Victoire\Bundle\PageBundle\Event\Menu\PageMenuContextualEvent($view);
191
192
        //Set currentView and dispatch victoire.on_render_page event with this currentView
193
        $this->currentViewHelper->setCurrentView($view);
194
        $pageRenderEvent = new PageRenderEvent($view);
195
        $this->eventDispatcher->dispatch('victoire.on_render_page', $pageRenderEvent);
196
197
        //Build WidgetMap
198
        $this->widgetMapBuilder->build($view, $this->entityManager, true);
199
200
        //Populate widgets with their data
201
        $this->widgetDataWarmer->warm($this->entityManager, $view);
202
203
        //Dispatch contextual event regarding page type
204
        if (in_array($view->getType(), ['business_page', 'virtual_business_page'])) {
205
            //Dispatch also an event with the Business entity name
206
            $eventName = 'victoire_core.page_menu.contextual';
207
            if (!$view->getId()) {
208
                $eventName = 'victoire_core.business_template_menu.contextual';
209
                $event = new \Victoire\Bundle\PageBundle\Event\Menu\PageMenuContextualEvent($view->getTemplate());
0 ignored issues
show
Documentation introduced by
$view->getTemplate() is of type string, but the function expects a object<Victoire\Bundle\CoreBundle\Entity\View>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
210
            }
211
            $this->eventDispatcher->dispatch($eventName, $event);
212
            $type = $view->getBusinessEntityId();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Victoire\Bundle\CoreBundle\Entity\View as the method getBusinessEntityId() does only exist in the following sub-classes of Victoire\Bundle\CoreBundle\Entity\View: Victoire\Bundle\BlogBundle\Entity\ArticleTemplate, Victoire\Bundle\Business...dle\Entity\BusinessPage, Victoire\Bundle\Business...Entity\BusinessTemplate, Victoire\Bundle\Business...ity\VirtualBusinessPage. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
213
        } else {
214
            $type = $view->getType();
215
        }
216
217
        $eventName = 'victoire_core.'.$type.'_menu.contextual';
218
        $this->eventDispatcher->dispatch($eventName, $event);
219
220
        //Determine which layout to use
221
        $layout = $this->guessBestLayoutForView($view, $isAjax);
222
223
        //Create the response
224
        $response = $this->container->get('templating')->renderResponse('VictoireCoreBundle:Layout:'.$layout, [
225
            'view' => $view,
226
        ]);
227
228
        return $response;
229
    }
230
231
    /**
232
     * populate the page with given entity.
233
     *
234
     * @param View           $page
235
     * @param BusinessEntity $entity
236
     */
237
    public function updatePageWithEntity(BusinessTemplate $page, $entity)
238
    {
239
        $page = $this->businessPageBuilder->generateEntityPageFromTemplate($page, $entity, $this->entityManager);
240
        $this->pageSeoHelper->updateSeoByEntity($page, $entity);
241
242
        //update the parameters of the page
243
        $this->businessPageBuilder->updatePageParametersByEntity($page, $entity);
244
245
        return $page;
246
    }
247
248
    /**
249
     * @param BusinessPageReference $viewReference
250
     *
251
     * @return BusinessPage
252
     *                      read the cache to find entity according tu given url.
253
     * @return object|null
254
     */
255
    protected function findEntityByReference(ViewReference $viewReference)
256
    {
257
        if ($viewReference instanceof BusinessPageReference && !empty($viewReference->getEntityId())) {
258
            return $this->entityManager->getRepository($viewReference->getEntityNamespace())
259
                ->findOneById($viewReference->getEntityId());
260
        }
261
    }
262
263
    /**
264
     * find the page according to given url.
265
     *
266
     * @return View
267
     */
268
    public function findPageByReference($viewReference)
269
    {
270
        $page = null;
0 ignored issues
show
Unused Code introduced by
$page is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
271
        if ($viewReference instanceof BusinessPageReference) {
272
            if ($viewReference->getViewId()) { //BusinessPage
273
                $page = $this->entityManager->getRepository('VictoireCoreBundle:View')
274
                    ->findOneBy([
275
                        'id'     => $viewReference->getViewId(),
276
                    ]);
277
                $page->setCurrentLocale($viewReference->getLocale());
278
            } else { //VirtualBusinessPage
279
                $page = $this->entityManager->getRepository('VictoireCoreBundle:View')
280
                    ->findOneBy([
281
                        'id'     => $viewReference->getTemplateId(),
282
                    ]);
283
                if ($entity = $this->findEntityByReference($viewReference)) {
284
                    if ($page instanceof BusinessTemplate) {
285
                        $page = $this->updatePageWithEntity($page, $entity);
0 ignored issues
show
Documentation introduced by
$entity is of type object<Victoire\Bundle\B...le\Entity\BusinessPage>, but the function expects a object<Victoire\Bundle\P...\Helper\BusinessEntity>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
286
                    }
287
                    if ($page instanceof BusinessPage) {
288
                        if ($page->getSeo()) {
289
                            $page->getSeo()->setCurrentLocale($viewReference->getLocale());
290
                        }
291
                        $this->pageSeoHelper->updateSeoByEntity($page, $entity);
0 ignored issues
show
Documentation introduced by
$entity is of type object<Victoire\Bundle\B...le\Entity\BusinessPage>, but the function expects a object<Victoire\Bundle\SeoBundle\Helper\Entity>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
292
                    }
293
                }
294
            }
295
        } elseif ($viewReference instanceof ViewReference) {
296
            $page = $this->entityManager->getRepository('VictoireCoreBundle:View')
297
                ->findOneBy([
298
                    'id'     => $viewReference->getViewId(),
299
                ]);
300
            $page->setCurrentLocale($viewReference->getLocale());
301
        } else {
302
            throw new \Exception(sprintf('Oh no! Cannot find a page for this ViewReference (%s)', ClassUtils::getClass($viewReference)));
303
        }
304
305
        return $page;
306
    }
307
308
    /**
309
     * @param View $page
310
     * @param $locale
311
     */
312
    private function refreshPage($page, $locale)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
313
    {
314
        if ($page && $page instanceof View) {
315
            try {
316
                $this->entityManager->refresh($page->setTranslatableLocale($locale));
0 ignored issues
show
Bug introduced by
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...
317
            } catch (ORMInvalidArgumentException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
318
            }
319
        }
320
    }
321
322
    /**
323
     * If the page is not valid, an exception is thrown.
324
     *
325
     * @param mixed $page
326
     * @param mixed $parameters
327
     *
328
     * @throws \Exception
329
     */
330
    public function checkPageValidity($page, $parameters = null)
331
    {
332
        $entity = null;
333
        $errorMessage = 'The page was not found';
334
        if ($parameters) {
335
            $errorMessage .= ' for parameters "'.implode('", "', $parameters).'"';
336
        }
337
        $isPageOwner = false;
338
339
        //there is no page
340
        if ($page === null) {
341
            throw new NotFoundHttpException($errorMessage);
342
        }
343
344
        if ($this->tokenStorage->getToken()) {
345
            $isPageOwner = $this->authorizationChecker->isGranted('PAGE_OWNER', $page);
346
        }
347
348
        //a page not published, not owned, nor granted throw an exception
349
        if (($page instanceof BasePage && !$page->isPublished()) && !$isPageOwner) {
350
            throw new NotFoundHttpException($errorMessage);
351
        }
352
353
        //if the page is a BusinessTemplate and the entity is not allowed for this page pattern
354
        if ($page instanceof BusinessTemplate) {
355
            //only victoire users are able to access a business page
356
            if (!$this->authorizationChecker->isGranted('ROLE_VICTOIRE')) {
357
                throw new AccessDeniedException('You are not allowed to see this page');
358
            }
359
        } elseif ($page instanceof BusinessPage) {
360
            $entity = $page->getBusinessEntity();
361
            if (!$entity->isVisibleOnFront() && !$this->authorizationChecker->isGranted('ROLE_VICTOIRE')) {
362
                throw new NotFoundHttpException('The BusinessPage for '.get_class($entity).'#'.$entity->getId().' is not visible on front.');
363
            }
364
            if (!$page->getId()) {
365
                $entityAllowed = $this->businessPageHelper->isEntityAllowed($page->getTemplate(), $entity, $this->entityManager);
0 ignored issues
show
Documentation introduced by
$page->getTemplate() is of type string, but the function expects a object<Victoire\Bundle\B...ntity\BusinessTemplate>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
366
367
                if ($entityAllowed === false) {
368
                    throw new NotFoundHttpException('The entity ['.$entity->getId().'] is not allowed for the page pattern ['.$page->getTemplate()->getId().']');
0 ignored issues
show
Bug introduced by
The method getId cannot be called on $page->getTemplate() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
369
                }
370
            }
371
        }
372
373
        if (!$this->authorizationChecker->isGranted('ROLE_VICTOIRE')) {
374
            $roles = $this->getPageRoles($page);
375
            if ($roles && !$this->authorizationChecker->isGranted($roles, $entity)) {
376
                throw new AccessDeniedException('You are not allowed to see this page, see the access roles defined in the view or it\'s parents and templates');
377
            }
378
        }
379
    }
380
381
    /**
382
     * Create an instance of the business entity page.
383
     *
384
     * @param BusinessTemplate $BusinessTemplate The business entity page
385
     * @param entity           $entity           The entity
386
     * @param string           $url              The new url
387
     *
388
     * @return \Victoire\Bundle\PageBundle\Entity\Page
389
     */
390
    public function createPageInstanceFromBusinessTemplate(BusinessTemplate $BusinessTemplate, $entity, $url)
391
    {
392
        //create a new page
393
        $newPage = new Page();
394
395
        $parentPage = $BusinessTemplate->getParent();
396
397
        //set the page parameter by the business entity page
398
        $newPage->setParent($parentPage);
399
        $newPage->setTemplate($BusinessTemplate);
400
        $newPage->setUrl($url);
401
402
        $newPage->setTitle($BusinessTemplate->getTitle());
0 ignored issues
show
Bug introduced by
The method getTitle() does not seem to exist on object<Victoire\Bundle\B...ntity\BusinessTemplate>.

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...
Bug introduced by
The method setTitle() does not seem to exist on object<Victoire\Bundle\PageBundle\Entity\Page>.

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...
403
404
        //update the parameters of the page
405
        $this->businessPageBuilder->updatePageParametersByEntity($newPage, $entity);
0 ignored issues
show
Compatibility introduced by
$newPage of type object<Victoire\Bundle\PageBundle\Entity\Page> is not a sub-type of object<Victoire\Bundle\B...le\Entity\BusinessPage>. It seems like you assume a child class of the class Victoire\Bundle\PageBundle\Entity\Page to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
406
407
        $businessEntity = $this->businessEntityHelper->findByEntityInstance($entity);
408
        $entityProxy = new EntityProxy();
409
        $entityProxy->setEntity($entity, $businessEntity->getName());
410
411
        $newPage->setEntityProxy($entityProxy);
412
413
        return $newPage;
414
    }
415
416
    /**
417
     * Guess which layout to use for a given View.
418
     *
419
     * @param View $view
420
     * @param bool $isAjax
421
     *
422
     * @return string
423
     */
424
    private function guessBestLayoutForView(View $view, $isAjax)
425
    {
426
        if ($isAjax) {
427
            $viewLayout = 'modal';
428
        } elseif (method_exists($view, 'getLayout') && $view->getLayout()) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Victoire\Bundle\CoreBundle\Entity\View as the method getLayout() does only exist in the following sub-classes of Victoire\Bundle\CoreBundle\Entity\View: Victoire\Bundle\BlogBundle\Entity\ArticleTemplate, Victoire\Bundle\Business...Entity\BusinessTemplate, Victoire\Bundle\TemplateBundle\Entity\Template. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
429
            $viewLayout = $view->getLayout();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Victoire\Bundle\CoreBundle\Entity\View as the method getLayout() does only exist in the following sub-classes of Victoire\Bundle\CoreBundle\Entity\View: Victoire\Bundle\BlogBundle\Entity\ArticleTemplate, Victoire\Bundle\Business...Entity\BusinessTemplate, Victoire\Bundle\TemplateBundle\Entity\Template. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
430
        } else {
431
            $viewLayout = $view->getTemplate()->getLayout();
0 ignored issues
show
Bug introduced by
The method getLayout cannot be called on $view->getTemplate() (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
432
        }
433
434
        return $viewLayout.'.html.twig';
435
    }
436
437
    /**
438
     * Find page's ancestors (templates and parents) and flatted all their roles.
439
     *
440
     * @param View $view
441
     *
442
     * @return array
443
     */
444
    private function getPageRoles(View $view)
445
    {
446
        $insertAncestorRole = function (View $view = null) use (&$insertAncestorRole) {
447
            if ($view === null) {
448
                return;
449
            }
450
            $roles = $view->getRoles();
451
452
            if ($templateRoles = $insertAncestorRole($view->getTemplate(), $roles)) {
453
                $roles .= ($roles ? ',' : '').$templateRoles;
454
            }
455
            if ($parentRoles = $insertAncestorRole($view->getParent(), $roles)) {
456
                $roles .= ($roles ? ',' : '').$parentRoles;
457
            }
458
459
            return $roles;
460
        };
461
462
        $roles = $insertAncestorRole($view);
463
464
        if ($roles) {
465
            return array_unique(explode(',', $roles));
466
        }
467
    }
468
}
469