Completed
Push — master ( 6a996d...b41795 )
by Mathieu
13:00 queued 10:14
created

AbstractMenu   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 138
Duplicated Lines 10.87 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 3
dl 15
loc 138
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A setMenuItemBuilder() 0 5 1
A setItemCallback() 0 5 1
A setItems() 0 8 2
B addItem() 0 26 6
A items() 15 15 4
A hasItems() 0 4 1
A numItems() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace Charcoal\Ui\Menu;
4
5
use \InvalidArgumentException;
6
7
// Intra-module (`charcoal-ui`) dependencies
8
use \Charcoal\Ui\AbstractUiItem;
9
use \Charcoal\Ui\Menu\MenuInterface;
10
use \Charcoal\Ui\MenuItem\MenuItemInterface;
11
use \Charcoal\Ui\MenuItem\MenuItemBuilder;
12
13
/**
14
 * A Basic Menu
15
 *
16
 * Abstract implementation of {@see \Charcoal\Ui\Menu\MenuInterface}.
17
 */
18
abstract class AbstractMenu extends AbstractUiItem implements
19
    MenuInterface
20
{
21
    /**
22
     * A collection menu items.
23
     *
24
     * @var MenuItemInterface[]
25
     */
26
    private $items = [];
27
28
    /**
29
     * A callback applied to each menu item output by {@see self::items()}.
30
     *
31
     * @var callable
32
     */
33
    private $itemCallback;
34
35
    /**
36
     * Store a menu builder instance.
37
     *
38
     * @var MenuItemBuilder $menuItemBuilder
39
     */
40
    private $menuItemBuilder;
41
42
    /**
43
     * Return a new menu.
44
     *
45
     * @param array|\ArrayAccess $data Class dependencies.
46
     */
47
    public function __construct($data)
48
    {
49
        $this->setMenuItemBuilder($data['menu_item_builder']);
50
    }
51
52
    /**
53
     * @param MenuItemBuilder $menuItemBuilder The Menu Item Builder that will be used to create new items.
54
     * @return AsbtractMenu Chainable
55
     */
56
    public function setMenuItemBuilder(MenuItemBuilder $menuItemBuilder)
57
    {
58
        $this->menuItemBuilder = $menuItemBuilder;
59
        return $this;
60
    }
61
62
    /**
63
     * @param callable $cb The item callback.
64
     * @return AbstractMenu Chainable
65
     */
66
    public function setItemCallback(callable $cb)
67
    {
68
        $this->itemCallback = $cb;
69
        return $this;
70
    }
71
72
    /**
73
     * @param array $items The menu items.
74
     * @return AbstractMenu Chainable
75
     */
76
    public function setItems(array $items)
77
    {
78
        $this->items = [];
79
        foreach ($items as $ident => $item) {
80
            $this->addItem($item, $ident);
81
        }
82
        return $this;
83
    }
84
85
    /**
86
     * @param array|MenuItemInterface $item  A menu item structure or object.
87
     * @param string                  $ident The menu item identifier, if any.
88
     * @throws InvalidArgumentException If the item argument is not a structure or object.
89
     * @return MenuItem Chainable
90
     */
91
    public function addItem($item, $ident = null)
92
    {
93
        if (is_array($item)) {
94
            $item['menu'] = $this;
95
            if (!isset($item['ident'])) {
96
                $item['ident'] = $ident;
97
            }
98
            $i = $this->menuItemBuilder->build($item);
99
            $item = $i;
100
        } elseif ($item instanceof MenuItemInterface) {
101
            if ($item->ident() === null) {
102
                $item->setIdent($ident);
103
            }
104
            $item->setMenu($this);
105
        } else {
106
            throw new InvalidArgumentException(
107
                'Item must be an array of menu item options or a MenuItem object'
108
            );
109
        }
110
        if ($ident === null) {
111
            $this->items[] = $item;
112
        } else {
113
            $this->items[$ident] = $item;
114
        }
115
        return $this;
116
    }
117
118
    /**
119
     * Menu Item generator.
120
     *
121
     * @param callable $itemCallback Optional. Item callback.
122
     * @return MenuItemInterface[]
123
     */
124 View Code Duplication
    public function items(callable $itemCallback = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
Coding Style introduced by
items uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
125
    {
126
        $items = $this->items;
127
        uasort($items, [$this, 'sortItemsByPriority']);
128
129
        $itemCallback = isset($itemCallback) ? $itemCallback : $this->itemCallback;
130
        foreach ($items as $item) {
131
            if ($itemCallback) {
132
                $itemCallback($item);
133
            }
134
            $GLOBALS['widget_template'] = $item->template();
135
            yield $item->ident() => $item;
136
            $GLOBALS['widget_template'] = '';
137
        }
138
    }
139
140
    /**
141
     * @return boolean
142
     */
143
    public function hasItems()
144
    {
145
        return (count($this->items) > 0);
146
    }
147
148
    /**
149
     * @return integer
150
     */
151
    public function numItems()
152
    {
153
        return count($this->items);
154
    }
155
}
156