Completed
Push — master ( c8d3eb...7bdd8d )
by Oleg
03:59
created

AbstractElementFactory::setDisplayRule()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 9.4285
cc 3
eloc 3
nc 2
nop 1
crap 3
1
<?php
2
namespace Malezha\Menu\Factory;
3
4
use Illuminate\Contracts\Config\Repository;
5
use Illuminate\Contracts\Container\Container;
6
use Malezha\Menu\Contracts\Element;
7
use Malezha\Menu\Contracts\ElementFactory;
8
use Malezha\Menu\Traits\DisplayRule;
9
use Opis\Closure\SerializableClosure;
10
11
/**
12
 * Class AbstractElementFactory
13
 * @package Malezha\Menu\Factory
14
 */
15
abstract class AbstractElementFactory implements ElementFactory
16
{
17
    /**
18
     * @var Container
19
     */
20
    protected $app;
21
22
    /**
23
     * @var array
24
     */
25
    protected $parameters = [];
26
27
    /**
28
     * @inheritdoc
29
     */
30 31
    public function __construct(Container $container)
31
    {
32 31
        $this->app = $container;
33 31
    }
34
35
    /**
36
     * @param string $class
37
     * @return array
38
     */
39 31
    protected function getElementConfig($class)
40
    {
41 31
        return $this->app->make(Repository::class)->get('menu.elements')[$class];
42
    }
43
44
    /**
45
     * @param string $name
46
     * @return mixed
47
     */
48 12
    protected function getParameter($name)
49
    {
50 12
        if (array_key_exists($name, $this->parameters)) {
51 12
            return $this->parameters[$name];
52
        }
53
54
        return null;
55
    }
56
57
    /**
58
     * @param string $name
59
     * @param mixed $value
60
     * @return $this
61
     */
62 28
    protected function setParameter($name, $value)
63
    {
64 28
        $this->parameters[$name] = $value;
65
        
66 28
        return $this;
67
    }
68
69
    /**
70
     * @param string $name
71
     * @return $this
72
     */
73
    protected function unsetParameter($name)
74
    {
75
        unset($this->parameters[$name]);
76
        
77
        return $this;
78
    }
79
80
    /**
81
     * @param string $name
82
     * @return bool
83
     */
84
    protected function existsParameter($name)
85
    {
86
        return array_key_exists($name, $this->parameters);
87
    }
88
89
    /**
90
     * @param array $parameters
91
     * @return array
92
     */
93 20
    protected function mergeParameters($parameters = [])
94
    {
95 20
        return array_merge($this->parameters, $parameters);
96
    }
97
98
    /**
99
     * @inheritDoc
100
     */
101 12
    function __get($name)
102
    {
103 12
        return $this->getParameter($name);
104
    }
105
106
    /**
107
     * @inheritDoc
108
     */
109 28
    function __set($name, $value)
110
    {
111 28
        $this->setParameter($name, $value);
112 28
    }
113
114
    /**
115
     * @inheritDoc
116
     */
117
    function __isset($name)
118
    {
119
        return $this->existsParameter($name);
120
    }
121
122
    /**
123
     * @inheritDoc
124
     */
125
    function __unset($name)
126
    {
127
        $this->unsetParameter($name);
128
    }
129
130
    /**
131
     * @inheritDoc
132
     */
133 1
    public function serialize()
134
    {
135 1
        $params = $this->parameters;
136 1
        if ($params['displayRule'] instanceof \Closure) {
137 1
            $params['displayRule'] = new SerializableClosure($params['displayRule']);
138
        }
139
140 1
        return serialize($params);
141
    }
142
143
    /**
144
     * @inheritDoc
145
     */
146 1
    public function unserialize($serialized)
147
    {
148 1
        $this->app = \Illuminate\Container\Container::getInstance();
149 1
        $this->parameters = unserialize($serialized);
150
151 1
        if ($this->parameters['displayRule'] instanceof SerializableClosure) {
152 1
            $this->parameters['displayRule'] = $this->parameters['displayRule']->getClosure();
153
        }
154 1
    }
155
156
    /**
157
     * @inheritDoc
158
     */
159
    public function toArray()
160
    {
161
        return $this->build()->toArray();
162
    }
163
164
    /**
165
     * @param Element $element
166
     */
167 14
    protected function setDisplayRule(Element $element)
168
    {
169 14
        if (array_key_exists('displayRule', $this->parameters) && method_exists($element, 'setDisplayRule')) {
170 14
            $element->setDisplayRule($this->parameters['displayRule']);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Malezha\Menu\Contracts\Element as the method setDisplayRule() does only exist in the following implementations of said interface: Malezha\Menu\Element\Link, Malezha\Menu\Element\SubMenu, Malezha\Menu\Element\Text.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
171
        }
172
    }
173
}