Completed
Push — master ( 9745cb...81e988 )
by Paul
06:43
created

PageHelper::refreshPage()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
rs 9.2
cc 4
eloc 5
nc 3
nop 2
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,
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...
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;
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...
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;
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, $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);
0 ignored issues
show
Bug introduced by
It seems like $page can also be of type null or string; however, Victoire\Bundle\PageBund...ageHelper::renderPage() does only seem to accept object<Victoire\Bundle\CoreBundle\Entity\View>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
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());
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...
207
            }
208
            $this->eventDispatcher->dispatch($eventName, $event);
209
            $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...
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;
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...
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
                $this->refreshPage($page, $viewReference->getLocale());
0 ignored issues
show
Documentation introduced by
$page is of type object|null, 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...
275
            } else { //VirtualBusinessPage
276
                $page = $this->entityManager->getRepository('VictoireCoreBundle:View')
277
                    ->findOneBy([
278
                        'id'     => $viewReference->getTemplateId(),
279
                    ]);
280
                $this->refreshPage($page, $viewReference->getLocale());
0 ignored issues
show
Documentation introduced by
$page is of type object|null, 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...
281
282
                if ($entity) {
283
                    if ($page instanceof BusinessTemplate) {
284
                        $page = $this->updatePageWithEntity($page, $entity);
285
                    } elseif ($page instanceof BusinessPage) {
286
                        $this->pageSeoHelper->updateSeoByEntity($page, $entity);
287
                    }
288
                }
289
            }
290
        } elseif ($viewReference instanceof ViewReference) {
291
            $page = $this->entityManager->getRepository('VictoireCoreBundle:View')
292
                ->findOneBy([
293
                    'id'     => $viewReference->getViewId(),
294
                ]);
295
            $this->refreshPage($page, $viewReference->getLocale());
0 ignored issues
show
Documentation introduced by
$page is of type object|null, 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...
296
        } else {
297
            throw new \Exception(sprintf('Oh no! Cannot find a page for this ViewReference (%s)', ClassUtils::getClass($viewReference)));
298
        }
299
300
        return $page;
301
    }
302
303
    /**
304
     * @param View $page
305
     * @param $locale
306
     */
307
    private function refreshPage($page, $locale)
308
    {
309
        if ($page && $page instanceof View) {
310
            try {
311
                $this->entityManager->refresh($page->setTranslatableLocale($locale));
312
            } catch (ORMInvalidArgumentException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
313
            }
314
        }
315
    }
316
317
    /**
318
     * If the page is not valid, an exception is thrown.
319
     *
320
     * @param mixed $page
321
     * @param mixed $entity
322
     * @param mixed $parameters
323
     *
324
     * @throws \Exception
325
     */
326
    protected function checkPageValidity($page, $entity = null, $parameters = null)
327
    {
328
        $errorMessage = 'The page was not found';
329
        if ($parameters) {
330
            $errorMessage .= ' for parameters "'.implode('", "', $parameters).'"';
331
        }
332
        $isPageOwner = false;
333
334
        //there is no page
335
        if ($page === null) {
336
            throw new NotFoundHttpException($errorMessage);
337
        }
338
339
        if ($this->tokenStorage->getToken()) {
340
            $isPageOwner = $this->authorizationChecker->isGranted('PAGE_OWNER', $page);
341
        }
342
343
        //a page not published, not owned, nor granted throw an exception
344
        if (($page instanceof BasePage && !$page->isPublished()) && !$isPageOwner) {
345
            throw new NotFoundHttpException($errorMessage);
346
        }
347
348
        //if the page is a BusinessTemplate and the entity is not allowed for this page pattern
349
        if ($page instanceof BusinessTemplate) {
350
            //only victoire users are able to access a business page
351
            if (!$this->authorizationChecker->isGranted('ROLE_VICTOIRE')) {
352
                throw new AccessDeniedException('You are not allowed to see this page');
353
            }
354
        } elseif ($page instanceof BusinessPage) {
355
            if ($page->getTemplate()->isAuthorRestricted() && !$this->authorizationChecker->isGranted('BUSINESS_ENTITY_OWNER', $page->getBusinessEntity())) {
0 ignored issues
show
Bug introduced by
The method isAuthorRestricted 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...
356
                throw new AccessDeniedException('You are not allowed to see this page');
357
            }
358
359
            if (!$entity->isVisibleOnFront() && !$this->authorizationChecker->isGranted('ROLE_VICTOIRE')) {
360
                throw new NotFoundHttpException('The BusinessPage for '.get_class($entity).'#'.$entity->getId().' is not visible on front.');
361
            }
362
            if (!$page->getId()) {
363
                $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...
364
365
                if ($entityAllowed === false) {
366
                    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...
367
                }
368
            }
369
        }
370
    }
371
372
    /**
373
     * Create an instance of the business entity page.
374
     *
375
     * @param BusinessTemplate $BusinessTemplate The business entity page
376
     * @param entity           $entity           The entity
377
     * @param string           $url              The new url
378
     *
379
     * @return \Victoire\Bundle\PageBundle\Entity\Page
380
     */
381
    public function createPageInstanceFromBusinessTemplate(BusinessTemplate $BusinessTemplate, $entity, $url)
382
    {
383
        //create a new page
384
        $newPage = new Page();
385
386
        $parentPage = $BusinessTemplate->getParent();
387
388
        //set the page parameter by the business entity page
389
        $newPage->setParent($parentPage);
390
        $newPage->setTemplate($BusinessTemplate);
391
        $newPage->setUrl($url);
392
393
        $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...
394
395
        //update the parameters of the page
396
        $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...
397
398
        $businessEntity = $this->businessEntityHelper->findByEntityInstance($entity);
399
        $entityProxy = new EntityProxy();
400
        $entityProxy->setEntity($entity, $businessEntity->getName());
401
402
        $newPage->setEntityProxy($entityProxy);
403
404
        return $newPage;
405
    }
406
407
    /**
408
     * Guess which layout to use for a given View.
409
     *
410
     * @param View $view
411
     * @param bool $isAjax
412
     *
413
     * @return string
414
     */
415
    private function guessBestLayoutForView(View $view, $isAjax)
416
    {
417
        if ($isAjax) {
418
            $viewLayout = 'modal';
419
        } 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...
420
            $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...
421
        } else {
422
            $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...
423
        }
424
425
        return $viewLayout.'.html.twig';
426
    }
427
}
428