1 | <?php |
||
17 | class MenuService |
||
18 | { |
||
19 | private $menuMapper; |
||
20 | private $menuFilter; |
||
21 | private $categoryService; |
||
22 | private $pageService; |
||
23 | |||
24 | public function __construct( |
||
25 | MenuMapper $menuMapper, |
||
26 | MenuFilter $menuFilter, |
||
27 | CategoryService $categoryService, |
||
28 | PageService $pageService |
||
29 | ) { |
||
30 | $this->menuMapper = $menuMapper; |
||
31 | $this->menuFilter = $menuFilter; |
||
32 | $this->categoryService = $categoryService; |
||
33 | $this->pageService = $pageService; |
||
34 | } |
||
35 | |||
36 | /** |
||
37 | * We store menu items in DB as flat structure, |
||
38 | * but we need nested(tree) structure to show in the menu. |
||
39 | * |
||
40 | * @param array $flatArray Array from DB |
||
41 | * @param int|bool $parent |
||
42 | * |
||
43 | * @return array Return same array with tree structure |
||
44 | */ |
||
45 | private function buildTree(array $flatArray, $parent = null) |
||
46 | { |
||
47 | $result = []; |
||
48 | |||
49 | foreach ($flatArray as $element) { |
||
50 | if ($element['parent_id'] == $parent) { |
||
51 | $children = $this->buildTree($flatArray, $element['menu_id']); |
||
52 | $element['children'] = ($children) ? $children : []; |
||
53 | $result[] = $element; |
||
54 | } |
||
55 | } |
||
56 | |||
57 | return $result; |
||
58 | } |
||
59 | |||
60 | public function getNestedAll($isActive = null, $filter = []) |
||
61 | { |
||
62 | $items = $this->menuMapper->selectAll($isActive, $filter)->toArray(); |
||
63 | |||
64 | return $this->buildTree($items); |
||
65 | } |
||
66 | |||
67 | public function get($id) |
||
68 | { |
||
69 | return $this->menuMapper->get($id); |
||
70 | } |
||
71 | |||
72 | public function addMenuItem($data) |
||
73 | { |
||
74 | $data = $this->filterMenuItem($data); |
||
75 | $order = $this->getMaxParentsOrderNumber(); |
||
76 | |||
77 | $data['menu_id'] = Uuid::uuid1()->toString(); |
||
78 | $data['menu_uuid'] = (new MysqlUuid($data['menu_id']))->toFormat(new Binary()); |
||
79 | $data['order_no'] = (!empty($order)) ? ($order + 1) : 1; |
||
80 | |||
81 | return $this->menuMapper->insertMenuItem($data); |
||
82 | } |
||
83 | |||
84 | public function updateMenuItem($data, $id) |
||
85 | { |
||
86 | $data = $this->filterMenuItem($data); |
||
87 | |||
88 | return $this->menuMapper->updateMenuItem($data, $id); |
||
89 | } |
||
90 | |||
91 | public function delete($id) |
||
92 | { |
||
93 | $menu = $this->menuMapper->select(['menu_id' => $id]); |
||
94 | $children = $this->menuMapper->select(['parent_id' => $id]); |
||
95 | |||
96 | if ($children->count()) { |
||
97 | $menu = $menu->current(); |
||
98 | $this->menuMapper->update([ |
||
99 | 'order_no' => new Expression('order_no + ' . ($children->count() - 1))], [ |
||
100 | 'parent_id' => $menu->parent_id, |
||
101 | 'order_no' => new Expression('order_no > ' . ($menu->order_no)) |
||
102 | ]); |
||
103 | |||
104 | foreach ($children->toArray() as $child) { |
||
105 | $child['parent_id'] = $menu->parent_id; |
||
106 | $child['order_no'] += ($menu->order_no - 1); |
||
107 | $this->menuMapper->update($child, [ |
||
108 | 'menu_id' => $child['menu_id'] |
||
109 | ]); |
||
110 | } |
||
111 | } |
||
112 | |||
113 | return $this->menuMapper->delete(['menu_id' => $id]); |
||
114 | } |
||
115 | |||
116 | public function getForSelect() |
||
117 | { |
||
118 | return $this->menuMapper->forSelect(); |
||
119 | } |
||
120 | |||
121 | public function updateMenuOrder($menuOrder) |
||
122 | { |
||
123 | if (!$menuOrder) { |
||
124 | return true; |
||
125 | } |
||
126 | |||
127 | try { |
||
128 | $this->menuMapper->getAdapter()->getDriver()->getConnection()->beginTransaction(); |
||
129 | $this->updateLevel($menuOrder, null); |
||
130 | $this->menuMapper->getAdapter()->getDriver()->getConnection()->commit(); |
||
131 | } catch (\Exception $e) { |
||
132 | $this->menuMapper->getAdapter()->getDriver()->getConnection()->rollback(); |
||
133 | |||
134 | throw $e; |
||
135 | } |
||
136 | |||
137 | return true; |
||
138 | } |
||
139 | |||
140 | private function updateLevel($children, $parentId = null) |
||
141 | { |
||
142 | $i=0; foreach ($children as $v) { $i++; |
||
143 | if (isset($v->children)) { |
||
144 | $this->menuMapper->update(['order_no' => $i, 'parent_id' => $parentId], ['menu_id' => $v->id]); |
||
145 | $this->updateLevel($v->children, $v->id); |
||
146 | } else { |
||
147 | $this->menuMapper->update(['order_no' => $i, 'parent_id' => $parentId], ['menu_id' => $v->id]); |
||
148 | } |
||
149 | } |
||
150 | } |
||
151 | |||
152 | private function filterMenuItem($data) |
||
184 | |||
185 | /** |
||
186 | * Returns max order number if found. |
||
187 | * |
||
188 | * @return integer|null |
||
189 | */ |
||
190 | private function getMaxParentsOrderNumber() |
||
191 | { |
||
192 | $select = $this->menuMapper |
||
193 | ->getSql() |
||
194 | ->setTable('menu') |
||
203 | } |
||
204 |