Completed
Push — master ( 5fed62...2a4737 )
by Alexis
17:13
created

MenuBuilder::isValidMachineNamme()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
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 UnexpectedValueException;
11
12
class MenuBuilder
13
{
14
    protected $entityManager;
15
    protected $factory;
16
    protected $knpMenu;
17
    protected $defaultLocale;
18
19
20
    /**
21
     * MenuBuilder constructor.
22
     *
23
     * @param EntityManager $entityManager
24
     * @param FactoryInterface $factory
25
     */
26
    public function __construct(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...
27
    {
28
        $this->entityManager = $entityManager;
29
        $this->factory       = $factory;
30
    }
31
32
    /**
33
     * Check if locale is valid
34
     *
35
     * @param $locale
36
     * @return bool
37
     */
38
    public static function isValidLocale($locale)
39
    {
40
        if (is_string($locale) && !empty($locale)) {
41
            return true;
42
        }
43
44
        return false;
45
    }
46
47
    /**
48
     * The parameter $locale must be defined in your
49
     * symfony configuration file under parameters.
50
     *
51
     * @param $locale String
52
     * @return $this
53
     */
54
    public function setDefaultLocale($locale)
55
    {
56
        if (self::isValidLocale($locale)) {
57
            $this->defaultLocale = $locale;
58
59
            return $this;
60
        }
61
62
        throw new LocaleException('
63
            The $locale parameter must be a non empty string or the locale is not defined
64
            under the Symfony parameters configuration.
65
        ');
66
    }
67
68
    /**
69
     * Return default locale
70
     *
71
     * @return string
72
     */
73
    public function getDefaultLocale()
74
    {
75
        return $this->defaultLocale;
76
    }
77
78
    /**
79
     * Check if the machineName is valid
80
     *
81
     * @param $machineName
82
     * @return bool
83
     */
84
    public static function isValidMachineName($machineName)
85
    {
86
        if (is_string($machineName) && !empty($machineName)) {
87
            return true;
88
        }
89
90
        return false;
91
    }
92
93
    /**
94
     * Retrun null or a KnpMenuItem instance
95
     *
96
     * @return null|KnpMenuItem
97
     */
98
    public function getKnpMenu()
99
    {
100
        return $this->knpMenu;
101
    }
102
103
    /**
104
     * Set the KnpMenuItem instance
105
     *
106
     * @param KnpMenuItem $knpMenu
107
     * @return $this
108
     */
109
    public function setKnpMenu(KnpMenuItem $knpMenu)
110
    {
111
        $this->knpMenu = $knpMenu;
112
113
        return $this;
114
    }
115
116
    /**
117
     * Create KnpMenuItem
118
     *
119
     * @param  string $machineName The name of menu
120
     * @param  string $locale      Language code (Recommanded ISO-639)
121
     *
122
     * @return KnpMenuItem         Get formatted menu
123
     */
124
    public function createKnpMenu($machineName, $locale = null)
125
    {
126
        if (!self::isValidMachineName($machineName)) {
127
            throw new UnexpectedValueException('The parameter $machineName must be a non empty string');
128
        }
129
130
        if ($locale === null) {
131
            $locale = $this->getDefaultLocale();
132
        } else if (!self::isValidLocale($locale)) {
133
            throw new LocaleException();
134
        }
135
136
        $repository = $this->entityManager->getRepository('AlpixelMenuBundle:Menu');
137
        $menu       = $repository->findOneMenuByMachineNameAndLocale($machineName, $locale);
138
        $items      = $menu->getItems()->toArray();
139
140
        $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...
141
        foreach ($items as $item) {
142
            if ($item->getParent() === null) {
143
                $this->getTree($this->knpMenu, $item);
144
            }
145
        }
146
147
        return $this->getKnpMenu();
148
    }
149
150
    /**
151
     * Create tree un KnpMenuItem
152
     *
153
     * @param  KnpMenuItem      $knpMenu
154
     * @param  ItemInterface    $item
155
     * @param  KnpMenuItem|null $parent
156
     *
157
     * @return KnpMenuItem      A formatted KnpMenu
158
     */
159
    protected function getTree(KnpMenuItem $knpMenu, ItemInterface $item, KnpMenuItem $parent = null)
160
    {
161
        $menuItem = ($parent === null) ? $knpMenu->addChild($item) : $parent->addChild($item);
162
163
        if ($uri = $item->getUri() !== null) {
164
            $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...
165
        }
166
167
        foreach ($item->getChildren() as $child) {
168
            $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...
169
        }
170
171
        return $menuItem;
172
    }
173
}
174