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

AbstractHelper   F

Complexity

Total Complexity 60

Size/Duplication

Total Lines 365
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 106
c 0
b 0
f 0
dl 0
loc 365
rs 3.6
wmc 60

18 Methods

Rating   Name   Duplication   Size   Complexity  
A getTagname() 0 2 1
A render() 0 14 3
A getFooter() 0 2 1
A __call() 0 5 1
A setTagname() 0 5 2
A buildComponent() 0 20 4
A getDOMDoc() 0 5 2
A getHeader() 0 2 1
A normalizeId() 0 6 1
A isAllowed() 0 4 1
A setHeader() 0 5 2
A setFooter() 0 5 2
A setDOMDoc() 0 3 1
A __toString() 0 3 1
A htmlify() 0 19 1
A getContent() 0 2 1
D _createElement() 0 39 34
A setContent() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like AbstractHelper 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 AbstractHelper, 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 RecursiveIteratorIterator;
19
use Zend\EventManager\EventManager;
20
use Zend\EventManager\EventManagerAwareInterface;
21
use Zend\EventManager\EventManagerInterface;
22
use Zend\I18n\Translator\TranslatorAwareInterface;
23
use Zend\Navigation\Page\AbstractPage;
24
use Zend\Navigation\AbstractContainer;
25
use Zend\Permissions\Acl;
26
use Zend\ServiceManager\ServiceLocatorAwareInterface;
27
use Zend\ServiceManager\ServiceLocatorInterface;
28
use Zend\View;
29
use Zend\View\Exception;
30
use \UIComponents\Translator\TranslatorAwareInterfaceTrait;
0 ignored issues
show
Bug introduced by
The type \UIComponents\Translator...atorAwareInterfaceTrait 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...
31
use \UIComponents\View\Helper\Traits\ComponentClassnamesTrait;
0 ignored issues
show
Bug introduced by
The type \UIComponents\View\Helpe...omponentClassnamesTrait 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...
32
use \UIComponents\View\Helper\Traits\ComponentAttributesTrait;
0 ignored issues
show
Bug introduced by
The type \UIComponents\View\Helpe...omponentAttributesTrait 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...
33
use \UIComponents\View\Helper\Traits\ComponentServiceManagersTrait;
0 ignored issues
show
Bug introduced by
The type \UIComponents\View\Helpe...entServiceManagersTrait 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...
34
use \UIComponents\View\Helper\Traits\ComponentAclTrait;
0 ignored issues
show
Bug introduced by
The type \UIComponents\View\Helper\Traits\ComponentAclTrait 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...
35
use \UIComponents\View\Helper\Traits\ComponentNavigationTrait;
0 ignored issues
show
Bug introduced by
The type \UIComponents\View\Helpe...omponentNavigationTrait 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...
36
37
/**
38
 * Base class for navigational helpers
39
 */
40
abstract class AbstractHelper extends \Zend\View\Helper\AbstractHtmlElement implements
41
    EventManagerAwareInterface,
42
    HelperInterface,
43
    ServiceLocatorAwareInterface,
44
    TranslatorAwareInterface
45
{
46
    
47
    use TranslatorAwareInterfaceTrait;
48
    use ComponentClassnamesTrait;
49
    use ComponentAttributesTrait;
50
    use ComponentServiceManagersTrait;
51
    use ComponentAclTrait;
52
    use ComponentNavigationTrait;
53
    
54
    //
55
    // component related vars/properties/providers/services...
56
    //
57
    
58
    /**
59
     * component's tag-name
60
     *
61
     * @var string
62
     */
63
    protected $tagname = 'div';
64
    
65
    
66
    /**
67
     * component's header
68
     *
69
     * @var mixed
70
     */
71
    protected $header = null;
72
    
73
    /**
74
     * component's footer
75
     *
76
     * @var mixed
77
     */
78
    protected $footer = null;
79
    
80
    /**
81
     * component's main content
82
     *
83
     * @var string|array
84
     */
85
    protected $content = '';
86
    
87
    /**
88
     * component's size attributes
89
     *
90
     * @var string|array
91
     */
92
    protected $size = '';
93
    
94
    
95
96
    /**
97
     * DOM object container needed for element creation with php's default DOM method
98
     * 
99
     * @var \DOMDocument
100
     */
101
    protected $_DOMDoc = null;
102
    
103
    
104
105
   /**
106
     * Magic overload: Proxy calls to the navigation container
107
     *
108
     * @param    string $method    method name in container
109
     * @param    array    $arguments rguments to pass
110
     * @return mixed
111
     * @throws Navigation\Exception\ExceptionInterface
112
     */
113
    public function __call($method, array $arguments = [])
114
    {
115
        return call_user_func_array(
116
            [$this->getContainer(), $method],
117
            $arguments
118
        );
119
    }
120
121
    /**
122
     * Magic overload: Proxy to {@link render()}.
123
     *
124
     * This method will trigger an E_USER_ERROR if rendering the helper causes
125
     * an exception to be thrown.
126
     *
127
     * Implements {@link HelperInterface::__toString()}.
128
     *
129
     * @return string
130
     */
131
    public function __toString()
132
    {
133
        return $this->render();
134
    }
135
136
    /**
137
     * render component
138
     * 
139
     * @param boolean $output
140
     * 
141
     * @return string
142
     */
143
    public function render($output = false)
144
    {    
145
        try {
146
            
147
            if ($output) {
148
                echo $this->buildComponent();
149
            }
150
            return $this->buildComponent();
151
            
152
        } catch (\Exception $e) {
153
            
154
            $msg = get_class($e) . ': ' . $e->getMessage() . "\n" . $e->getTraceAsString();
155
            trigger_error($msg, E_USER_ERROR);
156
            return '';
157
            
158
        }
159
    }
160
161
    /**
162
     * Determines whether a page should be allowed given certain parameters
163
     *
164
     * @param    array    $params
165
     * @return    bool
166
     */
167
    protected function isAllowed($params)
168
    {
169
        $results = $this->getEventManager()->trigger(__FUNCTION__, $this, $params);
170
        return $results->last();
171
    }
172
173
    // Util methods:
174
175
    /**
176
     * Returns an HTML string containing an 'a' element for the given page
177
     *
178
     * @param    AbstractPage $page    page to generate HTML for
179
     * @return string                HTML string (<a href="…">Label</a>)
180
     */
181
    public function htmlify(AbstractPage $page)
182
    {
183
        $label = $this->translate($page->getLabel(), $page->getTextDomain());
184
        $title = $this->translate($page->getTitle(), $page->getTextDomain());
185
186
        // get attribs for anchor element
187
        $attribs = [
188
            'id'     => $page->getId(),
189
            'title'    => $title,
190
            'class'    => $page->getClass(),
191
            'href'    => $page->getHref(),
192
            'target' => $page->getTarget()
193
        ];
194
195
        /** @var \Zend\View\Helper\EscapeHtml $escaper */
196
        $escaper = $this->view->plugin('escapeHtml');
0 ignored issues
show
Bug introduced by
The method plugin() does not exist on Zend\View\Renderer\RendererInterface. It seems like you code against a sub-type of Zend\View\Renderer\RendererInterface such as Zend\View\Renderer\PhpRenderer. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

196
        /** @scrutinizer ignore-call */ 
197
        $escaper = $this->view->plugin('escapeHtml');
Loading history...
197
        $label    = $escaper($label);
198
199
        return '<a' . $this->htmlAttribs($attribs) . '>' . $label . '</a>';
200
    }
201
202
    /**
203
     * Normalize an ID
204
     *
205
     * Overrides {@link View\Helper\AbstractHtmlElement::normalizeId()}.
206
     *
207
     * @param    string $value
208
     * @return string
209
     */
210
    protected function normalizeId($value)
211
    {
212
        $prefix = get_class($this);
213
        $prefix = strtolower(trim(substr($prefix, strrpos($prefix, '\\')), '\\'));
214
215
        return $prefix . '-' . $value;
216
    }
217
218
    //
219
    // component related methods
220
    //
221
    
222
    /**
223
     * @return string the assemled component rendered to HTML
224
     */
225
    public function buildComponent() {
226
        $html = ' '.__CLASS__.' ';
0 ignored issues
show
Unused Code introduced by
The assignment to $html is dead and can be removed.
Loading history...
227
        if ( empty($this->getTagname()) ) {
228
            return '';
229
        }
230
        
231
        $header = $this->getHeader();
232
        
233
        $footer = $this->getFooter();
234
        
235
        $body = $this->getContent();
236
        
237
        $content = (array($header, $body, $footer));
238
        if ( is_array($body) && !isset($body["tagname"])) {
0 ignored issues
show
introduced by
The condition is_array($body) is always false.
Loading history...
239
            $content = array_merge(array($header), ($body), array($footer));
240
        }
241
        
242
        $component = $this->_createElement($this->getTagname(), $this->getClassnames(), (array)$this->getAttributes(), $content);
243
244
        return $component;
245
246
    } 
247
    
248
    /**
249
     * create the component markup
250
     * 
251
     * @param string $tagname 
252
     * @param string $classnames 
253
     * @param array $attributes 
254
     * @param string|mixed $content 
255
     * 
256
     * @return string the component markup
257
     */
258
    public function _createElement($tagname = 'div', $classnames = '', $attributes = array(), $content = '') {
259
        $html = '';
260
        $html .= '<'.$tagname.''.((isset($classnames) && !empty($classnames)) ? ' class="'.$classnames.'"' : '').' '.$this->htmlAttribs($attributes).'>';
261
        if (!empty($content)) {
262
            if ( $content instanceof AbstractHelper ) {
263
                $html .= $content->render();
264
            } else if ( is_array($content) && isset($content['tagname']) ) {
265
                $html .= $this->_createElement(
266
                    $content['tagname'],
267
                    (isset($content['classnames']) && !empty($content['classnames']) ? $content['classnames'] : (isset($content['class']) && !empty($content['class']) ? $content['class'] : '')),
268
                    (isset($content['attributes']) && !empty($content['attributes']) ? $content['attributes'] : (isset($content['attr']) && !empty($content['attr']) ? $content['attr'] : '')),
0 ignored issues
show
Bug introduced by
It seems like IssetNode && ! empty($co...? $content['attr'] : '' can also be of type string; however, parameter $attributes of UIComponents\View\Helper...elper::_createElement() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

268
                    /** @scrutinizer ignore-type */ (isset($content['attributes']) && !empty($content['attributes']) ? $content['attributes'] : (isset($content['attr']) && !empty($content['attr']) ? $content['attr'] : '')),
Loading history...
269
                    (isset($content['content']) && !empty($content['content']) ? $content['content'] : '')
270
                );
271
            } else if ( is_array($content) ) {
272
                foreach ($content as $key => $item) {
273
                    if ( $item instanceof AbstractHelper ) {
274
                        $html .= $item->render();
275
                    } else if ( is_array($item) && isset($item['tagname']) ) {
276
                        $html .= $this->_createElement(
277
                            $item['tagname'],
278
                            (isset($item['classnames']) && !empty($item['classnames']) ? $item['classnames'] : (isset($item['class']) && !empty($item['class']) ? $item['class'] : '')),
279
                            (array)(isset($item['attributes']) && !empty($item['attributes']) ? $item['attributes'] : (isset($item['attr']) && !empty($item['attr']) ? $item['attr'] : '')),
280
                            (isset($item['content']) && !empty($item['content']) ? $item['content'] : '')
281
                        );
282
                    } else if ( is_array($item) ) {
283
                        foreach ($content as $key => $value) {
0 ignored issues
show
Comprehensibility Bug introduced by
$key is overwriting a variable from outer foreach loop.
Loading history...
284
                            $html .= (string)$value;
285
                        }
286
                    } else {
287
                        $html .= $item;
288
                    }
289
                }
290
            } else {
291
                $html .= $content;
292
            }
293
        }
294
        $html .= '</'.$tagname.'>';
295
        
296
        return $html;
297
    } 
298
    
299
    
300
    //
301
    // component related getters/setters
302
    //
303
    
304
    /**
305
     * get main tag-name
306
     * 
307
     * @return string the $tagname
308
     */
309
    public function getTagname() {
310
        return $this->tagname;
311
    }
312
313
    /**
314
     * set main tag-name
315
     * 
316
     * @param string $tagname
317
     */
318
    public function setTagname($tagname) {
319
        if ( null !== $tagname ) {
0 ignored issues
show
introduced by
The condition null !== $tagname is always true.
Loading history...
320
            $this->tagname = $tagname;
321
        }
322
        return $this;
323
    }
324
325
    /**
326
     * get the element header
327
     * 
328
     * @return mixed the $header
329
     */
330
    public function getHeader() {
331
        return $this->header;
332
    }
333
334
    /**
335
     * set the element header
336
     * 
337
     * @param mixed $header
338
     */
339
    public function setHeader($header) {
340
        if ( null !== $header ) {
341
            $this->header = $header;
342
        }
343
        return $this;
344
    }
345
346
    /**
347
     * get the element footer
348
     * 
349
     * @return mixed the $footer
350
     */
351
    public function getFooter() {
352
        return $this->footer;
353
    }
354
355
    /**
356
     * set the element footer
357
     * 
358
     * @param mixed $footer
359
     */
360
    public function setFooter($footer = null) {
361
        if ( null !== $footer ) {
362
            $this->footer = $footer;
363
        }
364
        return $this;
365
    }
366
367
    /**
368
     * get the element content
369
     * @return the $content
0 ignored issues
show
Bug introduced by
The type UIComponents\View\Helper\the 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...
370
     */
371
    public function getContent() {
372
        return $this->content;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->content returns the type array|string which is incompatible with the documented return type UIComponents\View\Helper\the.
Loading history...
373
    }
374
375
    /**
376
     * set the element content
377
     * 
378
     * @param string|array $content
379
     */
380
    public function setContent($content = '') {
381
        $this->content = $content;
382
        return $this;
383
    }
384
    
385
    /**
386
     * get DOM object
387
     * 
388
     * @return the $_DOMDoc
389
     */
390
    public function getDOMDoc() {
391
        if ( ! $this->_DOMDoc instanceof \DOMDocument ) {
0 ignored issues
show
introduced by
$this->_DOMDoc is always a sub-type of DOMDocument.
Loading history...
392
            $this->_DOMDoc = new \DOMDocument();
393
        }
394
        return $this->_DOMDoc;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_DOMDoc returns the type DOMDocument which is incompatible with the documented return type UIComponents\View\Helper\the.
Loading history...
395
    }
396
397
    /**
398
     * set DOM object
399
     * 
400
     * @param \DOMDocument $_DOMDoc
401
     */
402
    public function setDOMDoc(\DOMDocument $_DOMDoc) {
403
        $this->_DOMDoc = $_DOMDoc;
404
        return $this;
405
    }
406
    
407
}
408