1 | <?php |
||
13 | class Tree implements Buildable, Extension |
||
14 | { |
||
15 | const MACRO_METHOD = 'tree'; |
||
16 | |||
17 | /** |
||
18 | * List of tree strategies available |
||
19 | * |
||
20 | * @var array |
||
21 | */ |
||
22 | private $strategies = [ |
||
23 | 'nested', |
||
24 | 'closure', |
||
25 | 'materializedPath', |
||
26 | ]; |
||
27 | |||
28 | /** |
||
29 | * @var Fluent |
||
30 | */ |
||
31 | private $builder; |
||
32 | |||
33 | /** |
||
34 | * @var ExtensibleClassMetadata |
||
35 | */ |
||
36 | protected $classMetadata; |
||
37 | |||
38 | /** |
||
39 | * @var string |
||
40 | */ |
||
41 | protected $strategy; |
||
42 | |||
43 | /** |
||
44 | * @var string |
||
45 | */ |
||
46 | protected $left; |
||
47 | |||
48 | /** |
||
49 | * @var string |
||
50 | */ |
||
51 | protected $right; |
||
52 | |||
53 | /** |
||
54 | * @var string |
||
55 | */ |
||
56 | protected $level; |
||
57 | |||
58 | /** |
||
59 | * @var string |
||
60 | */ |
||
61 | protected $root; |
||
62 | |||
63 | /** |
||
64 | * @var bool |
||
65 | */ |
||
66 | protected $activateLocking = false; |
||
67 | |||
68 | /** |
||
69 | * @var int |
||
70 | */ |
||
71 | protected $lockingTimeout = 3; |
||
72 | |||
73 | /** |
||
74 | * @var string |
||
75 | */ |
||
76 | protected $closure; |
||
77 | |||
78 | /** |
||
79 | * @var bool |
||
80 | */ |
||
81 | private $autoComplete = false; |
||
82 | |||
83 | /** |
||
84 | * @param Fluent $builder |
||
85 | * @param string $strategy |
||
86 | * @param bool $autoComplete |
||
87 | */ |
||
88 | 10 | public function __construct(Fluent $builder, $strategy = 'nested', $autoComplete = false) |
|
89 | { |
||
90 | 10 | $this->builder = $builder; |
|
91 | 10 | $this->classMetadata = $builder->getBuilder()->getClassMetadata(); |
|
92 | 10 | $this->strategy = $strategy; |
|
93 | 10 | $this->autoComplete = $autoComplete; |
|
94 | 10 | } |
|
95 | |||
96 | /** |
||
97 | * Enable extension |
||
98 | */ |
||
99 | 83 | public static function enable() |
|
100 | { |
||
101 | $macro = function (Fluent $fluent, $strategy = 'nested', $callback = null, $autoComplete = false) { |
||
102 | 3 | $tree = new static($fluent, $strategy, $autoComplete); |
|
103 | |||
104 | 3 | if (is_callable($callback)) { |
|
105 | 1 | call_user_func($callback, $tree); |
|
106 | 1 | } |
|
107 | |||
108 | 3 | return $tree; |
|
109 | 83 | }; |
|
110 | |||
111 | 83 | Builder::macro(self::MACRO_METHOD, $macro); |
|
112 | 83 | Builder::macro('nestedSet', function (Fluent $fluent, $callback = null) use ($macro) { |
|
113 | 2 | return $macro($fluent, 'nested', $callback, true); |
|
114 | 83 | }); |
|
115 | |||
116 | 83 | TreeLeft::enable(); |
|
117 | 83 | TreeRight::enable(); |
|
118 | 83 | TreeLevel::enable(); |
|
119 | 83 | TreeRoot::enable(); |
|
120 | 83 | TreeParent::enable(); |
|
121 | 83 | TreePath::enable(); |
|
122 | 83 | TreePathSource::enable(); |
|
123 | 83 | TreePathHash::enable(); |
|
124 | 83 | TreeLockTime::enable(); |
|
125 | 83 | } |
|
126 | |||
127 | /** |
||
128 | * @param string $field |
||
129 | * @param string $type |
||
130 | * @param string|null $column |
||
131 | * |
||
132 | * @return $this |
||
133 | */ |
||
134 | 4 | public function root($field = 'root', $type = 'integer', $column = null) |
|
135 | { |
||
136 | 4 | $this->mapField($type, $field, $column, true); |
|
137 | |||
138 | 4 | $this->root = $field; |
|
139 | |||
140 | 4 | return $this; |
|
141 | } |
||
142 | |||
143 | /** |
||
144 | * @param string $field |
||
145 | * @param string $type |
||
146 | * @param string|null $column |
||
147 | * |
||
148 | * @return $this |
||
149 | */ |
||
150 | 4 | public function left($field = 'left', $type = 'integer', $column = null) |
|
151 | { |
||
152 | 4 | $this->mapField($type, $field, $column); |
|
153 | |||
154 | 4 | $this->left = $field; |
|
155 | |||
156 | 4 | return $this; |
|
157 | } |
||
158 | |||
159 | /** |
||
160 | * @param string $field |
||
161 | * @param string $type |
||
162 | * @param string|null $column |
||
163 | * |
||
164 | * @return $this |
||
165 | */ |
||
166 | 4 | public function right($field = 'right', $type = 'integer', $column = null) |
|
167 | { |
||
168 | 4 | $this->mapField($type, $field, $column); |
|
169 | |||
170 | 4 | $this->right = $field; |
|
171 | |||
172 | 4 | return $this; |
|
173 | } |
||
174 | |||
175 | /** |
||
176 | * @param string $field |
||
177 | * @param string $type |
||
178 | * @param string|null $column |
||
179 | * |
||
180 | * @return $this |
||
181 | */ |
||
182 | 4 | public function level($field = 'level', $type = 'integer', $column = null) |
|
183 | { |
||
184 | 4 | $this->mapField($type, $field, $column); |
|
185 | |||
186 | 4 | $this->level = $field; |
|
187 | |||
188 | 4 | return $this; |
|
189 | } |
||
190 | |||
191 | /** |
||
192 | * Execute the build process |
||
193 | */ |
||
194 | 7 | public function build() |
|
195 | { |
||
196 | 7 | if (!in_array($this->strategy, $this->strategies)) { |
|
197 | 1 | throw new InvalidMappingException("Tree type: $this->strategy is not available."); |
|
198 | } |
||
199 | |||
200 | 6 | if ($this->autoComplete) { |
|
201 | 3 | $this->addDefaults(); |
|
202 | 3 | } |
|
203 | |||
204 | 6 | $this->classMetadata->appendExtension($this->getExtensionName(), [ |
|
205 | 6 | 'root' => $this->root, |
|
206 | 6 | 'level' => $this->level, |
|
207 | 6 | 'right' => $this->right, |
|
208 | 6 | 'left' => $this->left, |
|
209 | 6 | 'strategy' => $this->strategy, |
|
210 | 6 | 'activate_locking' => $this->activateLocking, |
|
211 | 6 | 'locking_timeout' => $this->lockingTimeout, |
|
212 | 6 | 'closure' => $this->closure, |
|
213 | 6 | ]); |
|
214 | 6 | } |
|
215 | |||
216 | /** |
||
217 | * Return the name of the actual extension. |
||
218 | * |
||
219 | * @return string |
||
220 | */ |
||
221 | 6 | public function getExtensionName() |
|
222 | { |
||
223 | 6 | return FluentDriver::EXTENSION_NAME; |
|
224 | } |
||
225 | |||
226 | /** |
||
227 | * @param bool $activateLocking |
||
228 | * |
||
229 | * @return Tree |
||
230 | */ |
||
231 | 1 | public function activateLocking($activateLocking = true) |
|
232 | { |
||
233 | 1 | $this->activateLocking = $activateLocking; |
|
234 | |||
235 | 1 | return $this; |
|
236 | } |
||
237 | |||
238 | /** |
||
239 | * @param string $strategy |
||
240 | * |
||
241 | * @return Tree |
||
242 | */ |
||
243 | 2 | public function strategy($strategy) |
|
244 | { |
||
245 | 2 | $this->strategy = $strategy; |
|
246 | |||
247 | 2 | return $this; |
|
248 | } |
||
249 | |||
250 | /** |
||
251 | * @param int $lockingTimeout |
||
252 | * |
||
253 | * @return Tree |
||
254 | */ |
||
255 | 2 | public function lockingTimeout($lockingTimeout) |
|
265 | |||
266 | /** |
||
267 | * @param string $closure |
||
268 | * |
||
269 | * @return Tree |
||
270 | */ |
||
271 | 1 | public function closure($closure) |
|
272 | { |
||
273 | 1 | $this->closure = $closure; |
|
274 | |||
275 | 1 | return $this; |
|
277 | |||
278 | /** |
||
279 | * @param string $type |
||
280 | * @param string $field |
||
281 | * @param string $column |
||
282 | * @param bool $nullable |
||
283 | */ |
||
284 | 4 | private function mapField($type, $field, $column = null, $nullable = false) |
|
292 | |||
293 | /** |
||
294 | * Add default values to all required fields. |
||
295 | * |
||
296 | * @return void |
||
297 | */ |
||
298 | 3 | private function addDefaults() |
|
316 | } |
||
317 |
In PHP, under loose comparison (like
==
, or!=
, orswitch
conditions), values of different types might be equal.For
string
values, the empty string''
is a special case, in particular the following results might be unexpected: