Completed
Push — master ( d1535f...93b502 )
by Leny
06:44
created

PageHelper::checkPageValidity()   C

Complexity

Conditions 16
Paths 38

Size

Total Lines 45
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 45
rs 5.0152
cc 16
eloc 23
nc 38
nop 3

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Victoire\Bundle\PageBundle\Helper;
4
5
use Doctrine\Common\Util\ClassUtils;
6
use Doctrine\Orm\EntityManager;
7
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
8
use Symfony\Component\HttpFoundation\Response;
9
use Symfony\Component\HttpFoundation\Session\Session;
10
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
11
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
12
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
13
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
14
use Victoire\Bundle\BusinessEntityBundle\Helper\BusinessEntityHelper;
15
use Victoire\Bundle\BusinessPageBundle\Builder\BusinessPageBuilder;
16
use Victoire\Bundle\BusinessPageBundle\Entity\BusinessPage;
17
use Victoire\Bundle\BusinessPageBundle\Entity\BusinessTemplate;
18
use Victoire\Bundle\BusinessPageBundle\Helper\BusinessPageHelper;
19
use Victoire\Bundle\CoreBundle\Entity\EntityProxy;
20
use Victoire\Bundle\CoreBundle\Entity\View;
21
use Victoire\Bundle\CoreBundle\Event\PageRenderEvent;
22
use Victoire\Bundle\CoreBundle\Helper\CurrentViewHelper;
23
use Victoire\Bundle\CoreBundle\Template\TemplateMapper;
24
use Victoire\Bundle\PageBundle\Entity\BasePage;
25
use Victoire\Bundle\PageBundle\Entity\Page;
26
use Victoire\Bundle\SeoBundle\Helper\PageSeoHelper;
27
use Victoire\Bundle\ViewReferenceBundle\Cache\Xml\ViewReferenceXmlCacheRepository;
28
use Victoire\Bundle\ViewReferenceBundle\Helper\ViewReferenceHelper;
29
use Victoire\Bundle\ViewReferenceBundle\ViewReference\BusinessPageReference;
30
use Victoire\Bundle\ViewReferenceBundle\ViewReference\ViewReference;
31
use Victoire\Bundle\WidgetMapBundle\Builder\WidgetMapBuilder;
32
use Victoire\Bundle\WidgetMapBundle\Warmer\WidgetDataWarmer;
33
34
/**
35
 * Page helper
36
 * ref: victoire_page.page_helper.
37
 */
38
class PageHelper
39
{
40
    protected $businessEntityHelper;
41
    protected $entityManager;
42
    protected $viewReferenceHelper;
43
    protected $currentViewHelper;
44
    protected $eventDispatcher;
45
    protected $victoireTemplating;
46
    protected $pageSeoHelper;
47
    protected $session;
48
    protected $tokenStorage;
49
    protected $widgetMapBuilder;
50
    protected $businessPageBuilder;
51
    protected $businessPageHelper;
52
    protected $viewCacheRepository;
53
    protected $widgetDataWarmer;
54
55
    /**
56
     * @param BusinessEntityHelper            $businessEntityHelper
57
     * @param EntityManager                   $entityManager
58
     * @param ViewReferenceHelper             $viewReferenceHelper
59
     * @param CurrentViewHelper               $currentViewHelper
60
     * @param EventDispatcherInterface        $eventDispatcher
61
     * @param TemplateMapper                  $victoireTemplating
62
     * @param PageSeoHelper                   $pageSeoHelper
63
     * @param Session                         $session
64
     * @param TokenStorage                    $tokenStorage
65
     * @param AuthorizationChecker            $authorizationChecker
66
     * @param WidgetMapBuilder                $widgetMapBuilder
67
     * @param BusinessPageBuilder             $businessPageBuilder
68
     * @param BusinessPageHelper              $businessPageHelper
69
     * @param WidgetDataWarmer                $widgetDataWarmer
70
     * @param ViewReferenceXmlCacheRepository $viewCacheRepository
71
     */
72
    public function __construct(
73
        BusinessEntityHelper $businessEntityHelper,
74
        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...
75
        ViewReferenceHelper $viewReferenceHelper,
76
        CurrentViewHelper $currentViewHelper,
77
        EventDispatcherInterface $eventDispatcher,
78
        TemplateMapper $victoireTemplating,
79
        PageSeoHelper $pageSeoHelper,
80
        Session $session,
81
        TokenStorage $tokenStorage,
82
        AuthorizationChecker $authorizationChecker,
83
        WidgetMapBuilder $widgetMapBuilder,
84
        BusinessPageBuilder $businessPageBuilder,
85
        BusinessPageHelper $businessPageHelper,
86
        WidgetDataWarmer $widgetDataWarmer,
87
        ViewReferenceXmlCacheRepository $viewCacheRepository
88
    ) {
89
        $this->businessEntityHelper = $businessEntityHelper;
90
        $this->entityManager = $entityManager;
91
        $this->viewReferenceHelper = $viewReferenceHelper;
92
        $this->currentViewHelper = $currentViewHelper;
93
        $this->eventDispatcher = $eventDispatcher;
94
        $this->victoireTemplating = $victoireTemplating;
95
        $this->pageSeoHelper = $pageSeoHelper;
96
        $this->session = $session;
97
        $this->tokenStorage = $tokenStorage;
98
        $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...
99
        $this->widgetMapBuilder = $widgetMapBuilder;
100
        $this->businessPageBuilder = $businessPageBuilder;
101
        $this->businessPageHelper = $businessPageHelper;
102
        $this->widgetDataWarmer = $widgetDataWarmer;
103
        $this->viewCacheRepository = $viewCacheRepository;
104
    }
105
106
    /**
107
     * generates a response from a page url.
108
     *
109
     * @return View
110
     */
111
    public function findPageByParameters($parameters)
112
    {
113
        if (!empty($parameters['id']) && !preg_match('/^ref_/', $parameters['id'])) {
114
            $page = $this->entityManager->getRepository('VictoireCoreBundle:View')->findOneById($parameters['id']);
115
116
            $entity = null;
117
            if (method_exists($page, 'getBusinessEntity')) {
118
                $entity = $page->getBusinessEntity();
119
            }
120
            $this->checkPageValidity($page, $entity, $parameters);
121
        } else {
122
            $viewReference = $this->viewCacheRepository->getOneReferenceByParameters($parameters);
123
            if ($viewReference === null && !empty($parameters['viewId'])) {
124
                $parameters['templateId'] = $parameters['viewId'];
125
                unset($parameters['viewId']);
126
                $viewReference = $this->viewCacheRepository->getOneReferenceByParameters($parameters);
127
            }
128
129
            if ($viewReference instanceof ViewReference) {
130
                $page = $this->findPageByReference($viewReference, $this->findEntityByReference($viewReference));
131
                $page->setReference($viewReference);
132
            } else {
133
                $parametersAsString = [];
134
                foreach ($parameters as $key => $value) {
135
                    $parametersAsString[] = $key.': '.$value;
136
                }
137
138
                throw new \Exception(sprintf('Oh no! Cannot find a viewReference for the given parameters %s', implode(',', $parametersAsString)));
139
            }
140
        }
141
142
        return $page;
143
    }
144
145
    /**
146
     * generates a response from a page url.
147
     * if seo redirect, return target.
148
     *
149
     * @param string $url
150
     *
151
     * @return Response
152
     */
153
    public function renderPageByUrl($url, $locale, $isAjax = false)
0 ignored issues
show
Unused Code introduced by
The parameter $isAjax is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
154
    {
155
        $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...
156
        if ($viewReference = $this->viewCacheRepository->getReferenceByUrl($url, $locale)) {
157
            $page = $this->findPageByReference($viewReference, $entity = $this->findEntityByReference($viewReference));
158
159
            if ($page instanceof BasePage
160
                && $page->getSeo()
161
                && $page->getSeo()->getRedirectTo()
162
                && !$this->session->get('victoire.edit_mode', false)) {
163
                $page = $page->getSeo()->getRedirectTo();
164
            }
165
166
            $page->setReference($viewReference);
167
            $this->widgetMapBuilder->build($page);
0 ignored issues
show
Bug introduced by
It seems like $page defined by $page->getSeo()->getRedirectTo() on line 163 can also be of type string; however, Victoire\Bundle\WidgetMa...dgetMapBuilder::build() 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...
168
            $this->checkPageValidity($page, $entity, ['url' => $url, 'locale' => $locale]);
169
170
            return $this->renderPage($page);
0 ignored issues
show
Bug introduced by
It seems like $page defined by $page->getSeo()->getRedirectTo() on line 163 can also be of type 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...
171
        } else {
172
            throw new NotFoundHttpException(sprintf('Page not found (url: "%s", locale: "%s")', $url, $locale));
173
        }
174
    }
175
176
    /**
177
     * generates a response from a page.
178
     *
179
     * @param View $view
180
     *
181
     * @return Response
182
     */
183
    public function renderPage($view, $isAjax = false)
184
    {
185
        $event = new \Victoire\Bundle\PageBundle\Event\Menu\PageMenuContextualEvent($view);
186
187
        //Build WidgetMap
188
        $this->widgetMapBuilder->build($view, true);
189
190
        //Populate widgets with their data
191
        $this->widgetDataWarmer->warm($this->entityManager, $view);
192
193
        //Dispatch contextual event regarding page type
194
        if ($view->getType() == 'business_page') {
195
            //Dispatch also an event with the Business entity name
196
            $eventName = 'victoire_core.page_menu.contextual';
197
            if (!$view->getId()) {
198
                $eventName = 'victoire_core.business_template_menu.contextual';
199
                $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...
200
            }
201
            $this->eventDispatcher->dispatch($eventName, $event);
202
            $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...
203
        } else {
204
            $type = $view->getType();
205
        }
206
207
        $eventName = 'victoire_core.'.$type.'_menu.contextual';
208
        $this->eventDispatcher->dispatch($eventName, $event);
209
210
        //Determine which layout to use
211
        $layout = $this->guessBestLayoutForView($view, $isAjax);
212
213
        //Set currentView and dispatch victoire.on_render_page event with this currentView
214
        $this->currentViewHelper->setCurrentView($view);
215
        $event = new PageRenderEvent($view);
216
        $this->eventDispatcher->dispatch('victoire.on_render_page', $event);
217
218
        //Create the response
219
        $response = $this->victoireTemplating->renderResponse($layout, [
220
            'view' => $view,
221
        ]);
222
223
        return $response;
224
    }
225
226
    /**
227
     * populate the page with given entity.
228
     *
229
     * @param View           $page
230
     * @param BusinessEntity $entity
231
     *
232
     * @return BusinessPage
233
     */
234
    public function updatePageWithEntity(BusinessTemplate $page, $entity)
235
    {
236
        $page = $this->businessPageBuilder->generateEntityPageFromTemplate($page, $entity, $this->entityManager);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->businessPageBuild... $this->entityManager); of type object|array adds the type array to the return on line 247 which is incompatible with the return type documented by Victoire\Bundle\PageBund...r::updatePageWithEntity of type Victoire\Bundle\Business...dle\Entity\BusinessPage.
Loading history...
237
        $this->pageSeoHelper->updateSeoByEntity($page, $entity);
0 ignored issues
show
Documentation introduced by
$page is of type object|array, but the function expects a object<Victoire\Bundle\P...Bundle\Entity\BasePage>.

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...
238
239
        //update the parameters of the page
240
        $this->businessPageBuilder->updatePageParametersByEntity($page, $entity);
0 ignored issues
show
Documentation introduced by
$page is of type object|array, but the function expects a object<Victoire\Bundle\B...le\Entity\BusinessPage>.

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...
241
242
        $businessEntity = $this->businessEntityHelper->findByEntityInstance($entity);
243
        $entityProxy = new EntityProxy();
244
        $entityProxy->setEntity($entity, $businessEntity->getName());
245
        $page->setEntityProxy($entityProxy);
246
247
        return $page;
248
    }
249
250
    /**
251
     * read the cache to find entity according tu given url.
252
     *
253
     * @param BusinessPageReference $viewReference
254
     *
255
     * @return object|null
256
     */
257
    protected function findEntityByReference(ViewReference $viewReference)
258
    {
259
        if ($viewReference instanceof BusinessPageReference && !empty($viewReference->getEntityId())) {
260
            return $this->entityManager->getRepository($viewReference->getEntityNamespace())
261
                ->findOneById($viewReference->getEntityId());
262
        }
263
    }
264
265
    /**
266
     * find the page according to given url.
267
     *
268
     * @return View
269
     */
270
    public function findPageByReference($viewReference, $entity = null)
271
    {
272
        $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...
273
        if ($viewReference instanceof BusinessPageReference) {
274
            if ($viewReference->getViewId()) { //BusinessPage
275
                $page = $this->entityManager->getRepository('VictoireCoreBundle:View')
276
                    ->findOneById($viewReference->getViewId());
277
            } else { //VirtualBusinessPage
278
                $page = $this->entityManager->getRepository('VictoireCoreBundle:View')
279
                    ->findOneById($viewReference->getTemplateId());
280
                if ($entity) {
281
                    if ($page instanceof BusinessTemplate) {
282
                        $page = $this->updatePageWithEntity($page, $entity);
283
                    } elseif ($page instanceof BusinessPage) {
284
                        $this->pageSeoHelper->updateSeoByEntity($page, $entity);
285
                    }
286
                }
287
            }
288
        } elseif ($viewReference instanceof ViewReference) {
289
            $page = $this->entityManager->getRepository('VictoireCoreBundle:View')
290
                ->findOneById($viewReference->getViewId());
291
        } else {
292
            throw new \Exception(sprintf('Oh no! Cannot find a page for this ViewReference (%s)', ClassUtils::getClass($viewReference)));
293
        }
294
295
        return $page;
296
    }
297
298
    /**
299
     * If the page is not valid, an exception is thrown.
300
     *
301
     * @param mixed $page
302
     * @param mixed $entity
303
     * @param mixed $parameters
304
     *
305
     * @throws \Exception
306
     */
307
    protected function checkPageValidity($page, $entity = null, $parameters = null)
308
    {
309
        $errorMessage = 'The page was not found';
310
        if ($parameters) {
311
            $errorMessage .= ' for parameters "'.implode('", "', $parameters).'"';
312
        }
313
        $isPageOwner = false;
314
315
        //there is no page
316
        if ($page === null) {
317
            throw new NotFoundHttpException($errorMessage);
318
        }
319
320
        if ($this->tokenStorage->getToken()) {
321
            $isPageOwner = $this->authorizationChecker->isGranted('PAGE_OWNER', $page);
322
        }
323
324
        //a page not published, not owned, nor granted throw an exception
325
        if (($page instanceof BasePage && !$page->isPublished()) && !$isPageOwner) {
326
            throw new NotFoundHttpException($errorMessage);
327
        }
328
329
        //if the page is a BusinessTemplate and the entity is not allowed for this page pattern
330
        if ($page instanceof BusinessTemplate) {
331
            //only victoire users are able to access a business page
332
            if (!$this->authorizationChecker->isGranted('ROLE_VICTOIRE')) {
333
                throw new AccessDeniedException('You are not allowed to see this page');
334
            }
335
        } elseif ($page instanceof BusinessPage) {
336
            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...
337
                throw new AccessDeniedException('You are not allowed to see this page');
338
            }
339
340
            if (!$entity->isVisibleOnFront() && !$this->authorizationChecker->isGranted('ROLE_VICTOIRE')) {
341
                throw new NotFoundHttpException('The BusinessPage for '.get_class($entity).'#'.$entity->getId().' is not visible on front.');
342
            }
343
            if (!$page->getId()) {
344
                $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...
345
346
                if ($entityAllowed === false) {
347
                    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...
348
                }
349
            }
350
        }
351
    }
352
353
    /**
354
     * Create an instance of the business entity page.
355
     *
356
     * @param BusinessTemplate $BusinessTemplate The business entity page
357
     * @param entity           $entity           The entity
358
     * @param string           $url              The new url
359
     *
360
     * @return \Victoire\Bundle\PageBundle\Entity\Page
361
     */
362
    public function createPageInstanceFromBusinessTemplate(BusinessTemplate $BusinessTemplate, $entity, $url)
363
    {
364
        //create a new page
365
        $newPage = new Page();
366
367
        $parentPage = $BusinessTemplate->getParent();
368
369
        //set the page parameter by the business entity page
370
        $newPage->setParent($parentPage);
371
        $newPage->setTemplate($BusinessTemplate);
372
        $newPage->setUrl($url);
373
374
        $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...
375
376
        //update the parameters of the page
377
        $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...
378
379
        $businessEntity = $this->businessEntityHelper->findByEntityInstance($entity);
380
        $entityProxy = new EntityProxy();
381
        $entityProxy->setEntity($entity, $businessEntity->getName());
382
383
        $newPage->setEntityProxy($entityProxy);
384
385
        return $newPage;
386
    }
387
388
    /**
389
     * Guess which layout to use for a given View.
390
     *
391
     * @param View $view
392
     * @param bool $isAjax
393
     *
394
     * @return string
395
     */
396
    private function guessBestLayoutForView(View $view, $isAjax)
397
    {
398
        if ($isAjax) {
399
            $viewLayout = 'modal';
400
        } 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...
401
            $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...
402
        } else {
403
            $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...
404
        }
405
406
        return 'AppBundle:Layout:'.$viewLayout.'.html.twig';
407
    }
408
}
409