1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* YAWIK |
4
|
|
|
* |
5
|
|
|
* @filesource |
6
|
|
|
* @license MIT |
7
|
|
|
* @copyright 2013 - 2016 Cross Solution <http://cross-solution.de> |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
/** */ |
11
|
|
|
namespace Core\Factory\Form\Tree; |
12
|
|
|
|
13
|
|
|
use Core\Entity\Tree\NodeInterface; |
14
|
|
|
use Core\Form\Hydrator\Strategy\TreeSelectStrategy; |
15
|
|
|
use Core\Form\Tree\Select; |
16
|
|
|
use Interop\Container\ContainerInterface; |
17
|
|
|
use Zend\ServiceManager\FactoryInterface; |
18
|
|
|
use Zend\ServiceManager\MutableCreationOptionsInterface; |
19
|
|
|
use Zend\ServiceManager\ServiceLocatorInterface; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Factory for a tree select form element. |
23
|
|
|
* |
24
|
|
|
* @author Mathias Gelhausen <[email protected]> |
25
|
|
|
* @since 0.29 |
26
|
|
|
*/ |
27
|
|
|
class SelectFactory implements FactoryInterface, MutableCreationOptionsInterface |
28
|
|
|
{ |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Creation options. |
32
|
|
|
* |
33
|
|
|
* @var array |
34
|
|
|
*/ |
35
|
|
|
protected $options = []; |
36
|
|
|
|
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Creates a tree select form element |
40
|
|
|
* |
41
|
|
|
* @param ContainerInterface $container |
42
|
|
|
* @param string $requestedName |
43
|
|
|
* @param array|null $options |
44
|
|
|
* |
45
|
|
|
* @return Select |
46
|
|
|
* @throws \RuntimeException |
47
|
|
|
* @throws \DomainException |
48
|
|
|
*/ |
49
|
|
|
public function __invoke(ContainerInterface $container, $requestedName, array $options = null) |
50
|
|
|
{ |
51
|
|
|
if (!is_array($options) |
52
|
|
|
|| !isset($options['tree']['entity']) |
53
|
|
|
|| (!isset($options['tree']['value']) && !isset($options['tree']['name'])) |
54
|
|
|
) { |
55
|
|
|
throw new \DomainException('You must specify ["tree"]["entity"] and either ["tree"]["value"] or ["tree"]["name"]'); |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
if (isset($options['tree']['value'])) { |
59
|
|
|
$criteria = ['value' => $options['tree']['value']]; |
60
|
|
|
} else { |
61
|
|
|
$criteria = ['name' => $options['tree']['name']]; |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
$root = $container |
65
|
|
|
->get('repositories') |
66
|
|
|
->get($options['tree']['entity']) |
67
|
|
|
->findOneBy($criteria); |
68
|
|
|
|
69
|
|
|
if (!$root) { |
70
|
|
|
throw new \RuntimeException('Tree root not found'); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
$select = new Select(); |
74
|
|
|
|
75
|
|
|
if (isset($options['name'])) { |
76
|
|
|
$select->setName($options['name']); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
if (isset($options['options'])) { |
80
|
|
|
$select->setOptions($options['options']); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
if (isset($options['attributes'])) { |
84
|
|
|
$select->setAttributes($options['attributes']); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
$valueOptions = $this->createValueOptions($root, isset($options['allow_select_nodes']) && $options['allow_select_nodes']); |
88
|
|
|
if (!isset($options['use_root_item']) || !$options['use_root_item']) { |
89
|
|
|
$valueOptions = array_shift($valueOptions); |
90
|
|
|
$valueOptions = is_array($valueOptions) ? $valueOptions['options'] : []; |
91
|
|
|
} |
92
|
|
|
$select->setValueOptions($valueOptions); |
93
|
|
|
|
94
|
|
|
$strategy = new TreeSelectStrategy(); |
95
|
|
|
$strategy->setTreeRoot($root); |
96
|
|
|
$strategy->setAllowSelectMultipleItems(function() use ($select) { |
97
|
|
|
return $select->isMultiple(); |
98
|
|
|
}); |
99
|
|
|
|
100
|
|
|
$select->setHydratorStrategy($strategy); |
101
|
|
|
|
102
|
|
|
return $select; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Set creation options |
107
|
|
|
* |
108
|
|
|
* @param array $options |
109
|
|
|
* |
110
|
|
|
* @return void |
111
|
|
|
*/ |
112
|
|
|
public function setCreationOptions(array $options) |
113
|
|
|
{ |
114
|
|
|
$this->options = $options; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* Create a tree select form element. |
120
|
|
|
* |
121
|
|
|
* @internal |
122
|
|
|
* proxies to {@link __invoke}. |
123
|
|
|
* |
124
|
|
|
* @param ServiceLocatorInterface $serviceLocator |
125
|
|
|
* @return Select |
126
|
|
|
*/ |
127
|
|
|
public function createService(ServiceLocatorInterface $serviceLocator) |
128
|
|
|
{ |
129
|
|
|
/* @var \Zend\ServiceManager\AbstractPluginManager $serviceLocator */ |
130
|
|
|
$select = $this($serviceLocator->getServiceLocator(), self::class, $this->options); |
131
|
|
|
$this->options = []; |
132
|
|
|
|
133
|
|
|
return $select; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* Create value options from a node. |
138
|
|
|
* |
139
|
|
|
* @param NodeInterface $node |
140
|
|
|
* @param bool $allowSelectNodes |
141
|
|
|
* @param bool $isRoot |
142
|
|
|
* |
143
|
|
|
* @return array |
144
|
|
|
*/ |
145
|
|
|
protected function createValueOptions(NodeInterface $node, $allowSelectNodes = false, $isRoot=true) |
146
|
|
|
{ |
147
|
|
|
$key = $isRoot ? $node->getValue() : $this->getItemValue($node); |
148
|
|
|
$name = $node->getName(); |
149
|
|
|
|
150
|
|
|
if ($node->hasChildren()) { |
151
|
|
|
$leafOptions = []; |
152
|
|
|
|
153
|
|
|
if ($allowSelectNodes && !$isRoot) { |
154
|
|
|
$leafOptions[$key] = $name; |
155
|
|
|
$key = "$key-group"; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
foreach ($node->getChildren() as $child) { |
159
|
|
|
$leafOptions += $this->createValueOptions($child, $allowSelectNodes, false); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
$value = [ |
163
|
|
|
'label' => $name, |
164
|
|
|
'options' => $leafOptions |
165
|
|
|
]; |
166
|
|
|
|
167
|
|
|
} else { |
168
|
|
|
$value = $name; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
return [$key => $value]; |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* Get item value for use in the option tag. |
176
|
|
|
* |
177
|
|
|
* @param NodeInterface $item |
178
|
|
|
* |
179
|
|
|
* @return string item value prepended with all parent values except root node. |
180
|
|
|
* @todo This code is currently duplicated in \Core\Form\Tree\Select. |
181
|
|
|
*/ |
182
|
|
View Code Duplication |
private function getItemValue(NodeInterface $item) |
|
|
|
|
183
|
|
|
{ |
184
|
|
|
$parts = [ $item->getValue() ]; |
185
|
|
|
|
186
|
|
|
while ($item = $item->getParent()) { |
187
|
|
|
$parts[] = $item->getValue(); |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
array_pop($parts); // No root node. |
191
|
|
|
|
192
|
|
|
$parts = array_reverse($parts); |
193
|
|
|
$value = join('-', $parts); |
194
|
|
|
|
195
|
|
|
return $value; |
196
|
|
|
} |
197
|
|
|
} |
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.