Completed
Push — master ( 20cff0...467065 )
by Benjamin
19:18
created

MenuBuilder::isValidMachineName()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 8
rs 9.4285
cc 3
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace Alpixel\Bundle\MenuBundle\Builder;
4
5
use Alpixel\Bundle\MenuBundle\Exception\LocaleException;
6
use Alpixel\Bundle\MenuBundle\Model\ItemInterface;
7
use Doctrine\ORM\EntityManager;
8
use Knp\Menu\FactoryInterface;
9
use Knp\Menu\MenuItem as KnpMenuItem;
10
use Symfony\Component\HttpFoundation\RequestStack;
11
use UnexpectedValueException;
12
13
class MenuBuilder
14
{
15
    protected $currentUri;
16
    protected $entityManager;
17
    protected $factory;
18
    protected $knpMenu;
19
    protected $defaultLocale;
20
21
    /**
22
     * MenuBuilder constructor.
23
     *
24
     * @param EntityManager    $entityManager
25
     * @param FactoryInterface $factory
26
     */
27
    public function __construct(RequestStack $requestStack, EntityManager $entityManager, FactoryInterface $factory)
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...
28
    {
29
        $this->entityManager = $entityManager;
30
        $this->factory = $factory;
31
32
        $request = $requestStack->getCurrentRequest();
33
        $this->currentUri = $request->getRequestUri();
34
    }
35
36
    /**
37
     * Check if locale is valid.
38
     *
39
     * @param $locale
40
     *
41
     * @return bool
42
     */
43
    public static function isValidLocale($locale)
44
    {
45
        if (is_string($locale) && !empty($locale)) {
46
            return true;
47
        }
48
49
        return false;
50
    }
51
52
    /**
53
     * The parameter $locale must be defined in your
54
     * symfony configuration file under parameters.
55
     *
56
     * @param $locale String
57
     *
58
     * @return $this
59
     */
60
    public function setDefaultLocale($locale)
61
    {
62
        if (self::isValidLocale($locale)) {
63
            $this->defaultLocale = $locale;
64
65
            return $this;
66
        }
67
68
        throw new LocaleException('
69
            The $locale parameter must be a non empty string or the locale is not defined
70
            under the Symfony parameters configuration.
71
        ');
72
    }
73
74
    /**
75
     * Return default locale.
76
     *
77
     * @return string
78
     */
79
    public function getDefaultLocale()
80
    {
81
        return $this->defaultLocale;
82
    }
83
84
    /**
85
     * Check if the machineName is valid.
86
     *
87
     * @param $machineName
88
     *
89
     * @return bool
90
     */
91
    public static function isValidMachineName($machineName)
92
    {
93
        if (is_string($machineName) && !empty($machineName)) {
94
            return true;
95
        }
96
97
        return false;
98
    }
99
100
    /**
101
     * Retrun null or a KnpMenuItem instance.
102
     *
103
     * @return null|KnpMenuItem
104
     */
105
    public function getKnpMenu()
106
    {
107
        return $this->knpMenu;
108
    }
109
110
    /**
111
     * Set the KnpMenuItem instance.
112
     *
113
     * @param KnpMenuItem $knpMenu
114
     *
115
     * @return $this
116
     */
117
    public function setKnpMenu(KnpMenuItem $knpMenu)
118
    {
119
        $this->knpMenu = $knpMenu;
120
121
        return $this;
122
    }
123
124
    /**
125
     * Create KnpMenuItem.
126
     *
127
     * @param string $machineName The name of menu
128
     * @param string $locale      Language code (Recommanded ISO-639)
129
     *
130
     * @return KnpMenuItem Get formatted menu
131
     */
132
    public function createKnpMenu($machineName, $locale = null)
133
    {
134
        if (!self::isValidMachineName($machineName)) {
135
            throw new UnexpectedValueException('The parameter $machineName must be a non empty string');
136
        }
137
138
        if ($locale === null) {
139
            $locale = $this->getDefaultLocale();
140
        } elseif (!self::isValidLocale($locale)) {
141
            throw new LocaleException();
142
        }
143
144
        $this->setKnpMenu($this->factory->createItem('root'));
0 ignored issues
show
Compatibility introduced by
$this->factory->createItem('root') of type object<Knp\Menu\ItemInterface> is not a sub-type of object<Knp\Menu\MenuItem>. It seems like you assume a concrete implementation of the interface Knp\Menu\ItemInterface 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...
145
146
        $menu = $this->entityManager
147
                     ->getRepository('AlpixelMenuBundle:Menu')
148
                     ->findOneMenuByMachineNameAndLocale($machineName, $locale);
149
150
        $items = $menu->getItems()->toArray();
151
152
        foreach ($items as $item) {
153
            if ($item->getParent() === null) {
154
                $this->getTree($this->knpMenu, $item);
155
            }
156
        }
157
158
        return $this->getKnpMenu();
159
    }
160
161
    /**
162
     * Create tree un KnpMenuItem.
163
     *
164
     * @param KnpMenuItem      $knpMenu
165
     * @param ItemInterface    $item
166
     * @param KnpMenuItem|null $parent
167
     *
168
     * @return KnpMenuItem A formatted KnpMenu
169
     */
170
    protected function getTree(KnpMenuItem $knpMenu, ItemInterface $item, KnpMenuItem $parent = null)
171
    {
172
        $menuItem = ($parent === null) ? $knpMenu->addChild($item) : $parent->addChild($item);
173
174
        if ($uri = $item->getUri() !== null) {
175
            $menuItem->setUri($uri);
0 ignored issues
show
Documentation introduced by
$uri is of type boolean, but the function expects a string.

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...
176
        }
177
178
        foreach ($item->getChildren() as $child) {
179
            if ($this->currentUri == $child->getUri()) {
180
                $this->setParentActive($child->getParent());
0 ignored issues
show
Bug introduced by
The method setParentActive() does not seem to exist on object<Alpixel\Bundle\Me...le\Builder\MenuBuilder>.

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...
181
            }
182
            $this->getTree($knpMenu, $child, $menuItem);
0 ignored issues
show
Documentation introduced by
$menuItem is of type object<Knp\Menu\ItemInterface>, but the function expects a null|object<Knp\Menu\MenuItem>.

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...
183
        }
184
185
        return $menuItem;
186
    }
187
}
188