Completed
Pull Request — develop (#323)
by Mathias
15:36
created

SelectFactory::createService()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
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)
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...
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
}