Passed
Branch ops-updates (277b44)
by Björn
05:09
created

AbstractProxyHelper   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 373
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 84
c 2
b 0
f 1
dl 0
loc 373
rs 8.8
wmc 45

18 Methods

Rating   Name   Duplication   Size   Complexity  
A getDefaultProxy() 0 3 1
A setContainer() 0 6 1
A getInjectContainer() 0 3 1
A setInjectContainer() 0 4 1
A setDefaultProxy() 0 4 1
A render() 0 3 1
A setInjectTranslator() 0 4 1
A setView() 0 7 3
A setPluginManager() 0 9 2
A getContainer() 0 7 2
A __invoke() 0 7 3
A getPluginManager() 0 7 2
B inject() 0 22 10
A getInjectTranslator() 0 3 1
A getInjectAcl() 0 3 1
A __call() 0 19 6
A setInjectAcl() 0 4 1
B findHelper() 0 32 7

How to fix   Complexity   

Complex Class

Complex classes like AbstractProxyHelper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractProxyHelper, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * BB's Zend Framework 2 Components
4
 *
5
 * UI Components
6
 *
7
 * @package     [MyApplication]
8
 * @subpackage  BB's Zend Framework 2 Components
9
 * @subpackage  UI Components
10
 * @author      Björn Bartels <[email protected]>
11
 * @link        https://gitlab.bjoernbartels.earth/groups/zf2
12
 * @license     http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
13
 * @copyright   copyright (c) 2016 Björn Bartels <[email protected]>
14
 */
15
16
namespace UIComponents\View\Helper;
17
18
use Zend\ServiceManager\ServiceLocatorAwareInterface;
19
use Zend\View\Exception;
20
use Zend\View\Renderer\RendererInterface as Renderer;
21
22
/**
23
 * Proxy helper for retrieving navigational helpers and forwarding calls
24
 */
25
class AbstractProxyHelper extends AbstractHelper
26
{
27
    /**
28
     * View helper namespace
29
     *
30
     * @var string
31
     */
32
    const NS = 'UIComponents\View\Helper\Components';
33
34
    /**
35
     * Default proxy to use in {@link render()}
36
     *
37
     * @var string
38
     */
39
    protected $defaultProxy = 'element';
40
41
    /**
42
     * Indicates whether or not a given helper has been injected
43
     *
44
     * @var array
45
     */
46
    protected $injected = [];
47
48
    /**
49
     * Whether ACL should be injected when proxying
50
     *
51
     * @var bool
52
     */
53
    protected $injectAcl = true;
54
55
    /**
56
     * Whether container should be injected when proxying
57
     *
58
     * @var bool
59
     */
60
    protected $injectContainer = true;
61
62
    /**
63
     * Whether translator should be injected when proxying
64
     *
65
     * @var bool
66
     */
67
    protected $injectTranslator = true;
68
69
    /**
70
     * @var Navigation\PluginManager
0 ignored issues
show
Bug introduced by
The type UIComponents\View\Helper\Navigation\PluginManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
71
     */
72
    protected $plugins;
73
74
    /**
75
     * AbstractContainer to operate on by default
76
     *
77
     * @var Navigation\AbstractContainer|Navigation\Navigation|\Zend\Navigation\AbstractContainer
0 ignored issues
show
Bug introduced by
The type UIComponents\View\Helper...ation\AbstractContainer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
Bug introduced by
The type UIComponents\View\Helper\Navigation\Navigation was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
78
     */
79
    protected $container;
80
81
    /**
82
     * Helper entry point
83
     *
84
     * @param  array $options option to operate on
85
     * @return Components
86
     */
87
    public function __invoke($options = array())
88
    {
89
        if (isset($options['container']) && null !== $options['container']) {
90
            $this->setContainer($options['container']);
91
        }
92
93
        return ($this);
94
    }
95
96
    /**
97
     * Magic overload: Proxy to other navigation helpers or the container
98
     *
99
     * Examples of usage from a view script or layout:
100
     * <code>
101
     *   echo $this->Components()->Widget(...);
102
     * </code>
103
     *
104
     * @param  string $method             helper name or method name in container
105
     * @param  array  $arguments          [optional] arguments to pass
106
     * @throws \Zend\View\Exception\ExceptionInterface        if proxying to a helper, and the
107
     *                                    helper is not an instance of the
108
     *                                    interface specified in
109
     *                                    {@link findHelper()}
110
     * @throws \Zend\View\Exception\ExceptionInterface  if method does not exist in container
111
     * @return mixed                      returns what the proxied call returns
112
     */
113
    public function __call($method, array $arguments = [])
114
    {
115
        // check if call should proxy to another helper
116
        $helper = $this->findHelper($method, false);
117
        if ($helper) {
118
            //if ($helper instanceof ServiceLocatorAwareInterface && $this->getServiceLocator()) {
119
            if (method_exists($helper, "setServiceLocator") && $this->getServiceLocator()) {
120
                $helper->setServiceLocator($this->getServiceLocator());
121
            }
122
123
            if (method_exists($helper, "setTranslator") && $this->getTranslator()) {
124
                $helper->setTranslator($this->getTranslator());
125
            }
126
127
            return call_user_func_array($helper, $arguments);
128
        }
129
130
        // default behaviour: proxy call to container
131
        return parent::__call($method, $arguments);
132
    }
133
134
    /**
135
     * Sets navigation container the helper operates on by default
136
     *
137
     * Implements {@link HelperInterface::setContainer()}.
138
     *
139
     * @param  string|Navigation\AbstractContainer $container Default is null, meaning container will be reset.
140
     * @return AbstractHelper
141
     */
142
    public function setContainer($container = null)
143
    {
144
        $this->parseContainer($container);
145
        $this->container = $container;
0 ignored issues
show
Documentation Bug introduced by
It seems like $container can also be of type string. However, the property $container is declared as type UIComponents\View\Helper...ation\AbstractContainer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
146
147
        return $this;
148
    }
149
150
    /**
151
     * Returns the navigation container helper operates on by default
152
     *
153
     * Implements {@link HelperInterface::getContainer()}.
154
     *
155
     * If no container is set, a new container will be instantiated and
156
     * stored in the helper.
157
     *
158
     * @return Navigation\AbstractContainer|\Zend\Navigation\AbstractContainer    navigation container
159
     */
160
    public function getContainer()
161
    {
162
        if (null === $this->container) {
163
            $this->container = new \UIComponents\Navigation\Navigation();
164
        }
165
166
        return $this->container;
167
    }
168
169
    /**
170
     * Renders helper
171
     *
172
     * @param  AbstractContainer $container
0 ignored issues
show
Bug introduced by
The type UIComponents\View\Helper\AbstractContainer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
173
     * @return string
174
     * @throws Exception\RuntimeException
175
     */
176
    public function render($container = null)
177
    {
178
        return '';
179
        //return $this->findHelper($this->getDefaultProxy())->render($container);
180
    }
181
182
    /**
183
     * Returns the helper matching $proxy
184
     *
185
     * The helper must implement the interface
186
     * {@link UIComponents\View\Helper\Components\HelperInterface}.
187
     *
188
     * @param string $proxy  helper name
189
     * @param bool   $strict [optional] whether exceptions should be
190
     *                                  thrown if something goes
191
     *                                  wrong. Default is true.
192
     * @throws Exception\RuntimeException if $strict is true and helper cannot be found
193
     * @return boolean|\UIComponents\View\Helper\Components\HelperInterface  helper instance
0 ignored issues
show
Bug introduced by
The type UIComponents\View\Helper...ponents\HelperInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
194
     */
195
    public function findHelper($proxy, $strict = true)
196
    {
197
        $plugins = $this->getPluginManager();
198
        if (!$plugins->has($proxy)) {
199
            if ($strict) {
200
                throw new Exception\RuntimeException(sprintf(
201
                    'Failed to find plugin for %s',
202
                    $proxy
203
                ));
204
            }
205
            return false;
206
        }
207
208
        $helper    = $plugins->get($proxy);
209
210
        if ($helper && ($helper instanceof \Zend\View\Helper\Navigation\Menu)) {
211
212
            $container = $this->getContainer();
213
            $hash      = spl_object_hash($container) . spl_object_hash($helper);
214
            if (!isset($this->injected[$hash])) {
215
                $helper->setContainer();
216
                $this->inject($helper);
217
                $this->injected[$hash] = true;
218
            } else {
219
                if ($this->getInjectContainer()) {
220
                    $helper->setContainer($container);
221
                }
222
            }
223
224
        }
225
226
        return $helper;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $helper also could return the type Zend\View\Helper\Navigation\Menu which is incompatible with the documented return type UIComponents\View\Helper...HelperInterface|boolean.
Loading history...
227
    }
228
229
    /**
230
     * Injects container, ACL, and translator to the given $helper if this
231
     * helper is configured to do so
232
     *
233
     * @param  \Zend\View\Helper\AbstractHelper $helper helper instance
234
     * @return void
235
     */
236
    protected function inject(\Zend\View\Helper\AbstractHelper $helper)
237
    {
238
		if (
239
			($helper instanceof \UIComponents\View\Helper\AbstractHelper) ||
240
			($helper instanceof \UIComponents\View\Helper\Navigation\Menu)
241
		) {
242
	        if ($this->getInjectContainer() && !$helper->hasContainer()) {
243
	            $helper->setContainer($this->getContainer());
244
	        }
245
246
	        if ($this->getInjectAcl()) {
247
	            if (!$helper->hasAcl()) {
248
	                $helper->setAcl($this->getAcl());
249
	            }
250
	            if (!$helper->hasRole()) {
251
	                $helper->setRole($this->getRole());
252
	            }
253
	        }
254
	        if ($this->getInjectTranslator() && !$helper->hasTranslator()) {
255
	            $helper->setTranslator(
256
	                $this->getTranslator(),
257
	                $this->getTranslatorTextDomain()
258
	            );
259
	        }
260
		}
261
    }
262
263
    /**
264
     * Sets the default proxy to use in {@link render()}
265
     *
266
     * @param  string $proxy default proxy
267
     * @return Bootstrap
0 ignored issues
show
Bug introduced by
The type UIComponents\View\Helper\Bootstrap was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
268
     */
269
    public function setDefaultProxy($proxy)
270
    {
271
        $this->defaultProxy = (string) $proxy;
272
        return $this;
273
    }
274
275
    /**
276
     * Returns the default proxy to use in {@link render()}
277
     *
278
     * @return string
279
     */
280
    public function getDefaultProxy()
281
    {
282
        return $this->defaultProxy;
283
    }
284
285
    /**
286
     * Sets whether container should be injected when proxying
287
     *
288
     * @param  bool $injectContainer
289
     * @return Bootstrap
290
     */
291
    public function setInjectContainer($injectContainer = true)
292
    {
293
        $this->injectContainer = (bool) $injectContainer;
294
        return $this;
295
    }
296
297
    /**
298
     * Returns whether container should be injected when proxying
299
     *
300
     * @return bool
301
     */
302
    public function getInjectContainer()
303
    {
304
        return $this->injectContainer;
305
    }
306
307
    /**
308
     * Sets whether ACL should be injected when proxying
309
     *
310
     * @param  bool $injectAcl
311
     * @return NavigBootstrapation
0 ignored issues
show
Bug introduced by
The type UIComponents\View\Helper\NavigBootstrapation was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
312
     */
313
    public function setInjectAcl($injectAcl = true)
314
    {
315
        $this->injectAcl = (bool) $injectAcl;
316
        return $this;
317
    }
318
319
    /**
320
     * Returns whether ACL should be injected when proxying
321
     *
322
     * @return bool
323
     */
324
    public function getInjectAcl()
325
    {
326
        return $this->injectAcl;
327
    }
328
329
    /**
330
     * Sets whether translator should be injected when proxying
331
     *
332
     * @param  bool $injectTranslator
333
     * @return Bootstrap
334
     */
335
    public function setInjectTranslator($injectTranslator = true)
336
    {
337
        $this->injectTranslator = (bool) $injectTranslator;
338
        return $this;
339
    }
340
341
    /**
342
     * Returns whether translator should be injected when proxying
343
     *
344
     * @return bool
345
     */
346
    public function getInjectTranslator()
347
    {
348
        return $this->injectTranslator;
349
    }
350
351
    /**
352
     * Set manager for retrieving navigation helpers
353
     *
354
     * @param  Components\PluginManager $plugins
355
     * @return Components
356
     */
357
    public function setPluginManager(AbstractPluginManager $plugins)
358
    {
359
        $renderer = $this->getView();
360
        if ($renderer) {
0 ignored issues
show
introduced by
$renderer is of type Zend\View\Renderer\RendererInterface, thus it always evaluated to true.
Loading history...
361
            $plugins->setRenderer($renderer);
362
        }
363
        $this->plugins = $plugins;
0 ignored issues
show
Documentation Bug introduced by
It seems like $plugins of type UIComponents\View\Helper\AbstractPluginManager is incompatible with the declared type UIComponents\View\Helper\Navigation\PluginManager of property $plugins.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
364
365
        return $this;
366
    }
367
368
    /**
369
     * Retrieve plugin loader for navigation helpers
370
     *
371
     * Lazy-loads an instance of Navigation\HelperLoader if none currently
372
     * registered.
373
     *
374
     * @return Components\PluginManager
375
     */
376
    public function getPluginManager()
377
    {
378
        if (null === $this->plugins) {
379
            $this->setPluginManager(new Components\PluginManager());
380
        }
381
382
        return $this->plugins;
383
    }
384
385
    /**
386
     * Set the View object
387
     *
388
     * @param  Renderer $view
389
     * @return self
390
     */
391
    public function setView(Renderer $view)
392
    {
393
        parent::setView($view);
394
        if ($view && $this->plugins) {
395
            $this->plugins->setRenderer($view);
396
        }
397
        return $this;
398
    }
399
}
400