1 | <?php |
||||||
2 | |||||||
3 | namespace SleepingOwl\Admin\Display; |
||||||
4 | |||||||
5 | use Exception; |
||||||
6 | use Illuminate\Database\Eloquent\Builder; |
||||||
7 | use Illuminate\Database\Eloquent\Collection; |
||||||
8 | use Illuminate\Routing\Router; |
||||||
9 | use Illuminate\Support\Facades\Request; |
||||||
10 | use SleepingOwl\Admin\Contracts\Display\ColumnInterface; |
||||||
11 | use SleepingOwl\Admin\Contracts\Repositories\TreeRepositoryInterface; |
||||||
12 | use SleepingOwl\Admin\Contracts\WithRoutesInterface; |
||||||
13 | use SleepingOwl\Admin\Display\Extension\Columns; |
||||||
14 | use SleepingOwl\Admin\Display\Tree\OrderTreeType; |
||||||
15 | use SleepingOwl\Admin\Repositories\TreeRepository; |
||||||
16 | use SleepingOwl\Admin\Traits\PanelControl; |
||||||
17 | |||||||
18 | /** |
||||||
19 | * @method TreeRepositoryInterface getRepository() |
||||||
20 | * @property TreeRepositoryInterface $repository |
||||||
21 | * @method Columns getColumns() |
||||||
22 | * @method $this setColumns(ColumnInterface|ColumnInterface[] $column) |
||||||
23 | 285 | */ |
|||||
24 | class DisplayTree extends Display implements WithRoutesInterface |
||||||
25 | 285 | { |
|||||
26 | 285 | use PanelControl; |
|||||
27 | 285 | ||||||
28 | 285 | /** |
|||||
29 | 285 | * @param Router $router |
|||||
30 | 285 | */ |
|||||
31 | public static function registerRoutes(Router $router) |
||||||
32 | { |
||||||
33 | $routeName = 'admin.display.tree.reorder'; |
||||||
34 | if (! $router->has($routeName)) { |
||||||
35 | $router->post('{adminModel}/reorder', |
||||||
36 | ['as' => $routeName, 'uses' => 'SleepingOwl\Admin\Http\Controllers\DisplayController@treeReorder']); |
||||||
0 ignored issues
–
show
|
|||||||
37 | } |
||||||
38 | } |
||||||
39 | |||||||
40 | /** |
||||||
41 | * @var int |
||||||
42 | */ |
||||||
43 | protected $max_depth = 20; |
||||||
44 | /** |
||||||
45 | * @var string |
||||||
46 | */ |
||||||
47 | protected $view = 'display.tree'; |
||||||
48 | |||||||
49 | /** |
||||||
50 | * @var array |
||||||
51 | */ |
||||||
52 | protected $parameters = []; |
||||||
53 | |||||||
54 | /** |
||||||
55 | * @var bool |
||||||
56 | */ |
||||||
57 | protected $reorderable = true; |
||||||
58 | |||||||
59 | /** |
||||||
60 | * @var string|callable |
||||||
61 | */ |
||||||
62 | protected $value = 'title'; |
||||||
63 | |||||||
64 | /** |
||||||
65 | * @var string |
||||||
66 | */ |
||||||
67 | protected $parentField = 'parent_id'; |
||||||
68 | |||||||
69 | /** |
||||||
70 | * @var string |
||||||
71 | */ |
||||||
72 | protected $orderField = 'order'; |
||||||
73 | |||||||
74 | /** |
||||||
75 | * @var string|null |
||||||
76 | */ |
||||||
77 | protected $rootParentId = null; |
||||||
78 | |||||||
79 | /** |
||||||
80 | * @var string |
||||||
81 | */ |
||||||
82 | protected $repositoryClass = TreeRepository::class; |
||||||
83 | |||||||
84 | /** |
||||||
85 | * @var Column\TreeControl |
||||||
86 | */ |
||||||
87 | protected $controlColumn; |
||||||
88 | |||||||
89 | /** |
||||||
90 | * @var Collection |
||||||
91 | */ |
||||||
92 | protected $collection; |
||||||
93 | |||||||
94 | /** |
||||||
95 | * @var string|null |
||||||
96 | */ |
||||||
97 | protected $newEntryButtonText; |
||||||
98 | |||||||
99 | /** |
||||||
100 | * @var string |
||||||
101 | */ |
||||||
102 | protected $treeType; |
||||||
103 | |||||||
104 | /** |
||||||
105 | * DisplayTree constructor. |
||||||
106 | * |
||||||
107 | * @param string|null $treeType |
||||||
108 | */ |
||||||
109 | public function __construct($treeType = null) |
||||||
110 | { |
||||||
111 | parent::__construct(); |
||||||
112 | |||||||
113 | $this->treeType = $treeType; |
||||||
114 | |||||||
115 | $this->setPanelClass('panel-tree'); |
||||||
116 | |||||||
117 | $this->extend('columns', new Columns()); |
||||||
118 | } |
||||||
119 | |||||||
120 | public function initialize() |
||||||
121 | { |
||||||
122 | parent::initialize(); |
||||||
123 | |||||||
124 | $repository = $this->getRepository() |
||||||
125 | ->setOrderField($this->getOrderField()) |
||||||
126 | ->setRootParentId($this->getRootParentId()); |
||||||
127 | |||||||
128 | if ($this->getParentField()) { |
||||||
129 | $repository = $repository->setParentField($this->getParentField()); |
||||||
130 | } |
||||||
131 | if (! is_null($this->treeType)) { |
||||||
0 ignored issues
–
show
|
|||||||
132 | $repository->setTreeType($this->treeType); |
||||||
0 ignored issues
–
show
The method
setTreeType() does not exist on SleepingOwl\Admin\Contra...TreeRepositoryInterface . Since it exists in all sub-types, consider adding an abstract or default implementation to SleepingOwl\Admin\Contra...TreeRepositoryInterface .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
133 | } |
||||||
134 | |||||||
135 | if ($this->treeType == OrderTreeType::class) { |
||||||
136 | $this->setMaxDepth(1); |
||||||
137 | } |
||||||
138 | |||||||
139 | $this->setHtmlAttribute('data-max-depth', $this->getMaxDepth()); |
||||||
140 | } |
||||||
141 | |||||||
142 | /** |
||||||
143 | * @return string |
||||||
144 | */ |
||||||
145 | public function getMaxDepth() |
||||||
146 | { |
||||||
147 | return $this->max_depth; |
||||||
148 | } |
||||||
149 | |||||||
150 | /** |
||||||
151 | * @param string|callable $value |
||||||
152 | * |
||||||
153 | * @return $this |
||||||
154 | */ |
||||||
155 | public function setMaxDepth($value) |
||||||
156 | { |
||||||
157 | $this->max_depth = $value; |
||||||
0 ignored issues
–
show
It seems like
$value of type callable or string is incompatible with the declared type integer of property $max_depth .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||||||
158 | |||||||
159 | return $this; |
||||||
160 | } |
||||||
161 | |||||||
162 | /** |
||||||
163 | * @return callable|string |
||||||
164 | */ |
||||||
165 | public function getValue() |
||||||
166 | { |
||||||
167 | return $this->value; |
||||||
168 | } |
||||||
169 | |||||||
170 | /** |
||||||
171 | * @param string|callable $value |
||||||
172 | * |
||||||
173 | * @return $this |
||||||
174 | */ |
||||||
175 | public function setValue($value) |
||||||
176 | { |
||||||
177 | $this->value = $value; |
||||||
178 | |||||||
179 | return $this; |
||||||
180 | } |
||||||
181 | |||||||
182 | /** |
||||||
183 | * @return string |
||||||
184 | */ |
||||||
185 | public function getParentField() |
||||||
186 | { |
||||||
187 | return $this->parentField; |
||||||
188 | } |
||||||
189 | |||||||
190 | /** |
||||||
191 | * @param string $parentField |
||||||
192 | * |
||||||
193 | * @return $this |
||||||
194 | */ |
||||||
195 | public function setParentField($parentField) |
||||||
196 | { |
||||||
197 | $this->parentField = $parentField; |
||||||
198 | |||||||
199 | return $this; |
||||||
200 | } |
||||||
201 | |||||||
202 | /** |
||||||
203 | * @return array|\Illuminate\Contracts\Translation\Translator|null|string |
||||||
204 | */ |
||||||
205 | public function getNewEntryButtonText() |
||||||
206 | { |
||||||
207 | if (is_null($this->newEntryButtonText)) { |
||||||
208 | $this->newEntryButtonText = trans('sleeping_owl::lang.table.new-entry'); |
||||||
0 ignored issues
–
show
It seems like
trans('sleeping_owl::lang.table.new-entry') can also be of type array or array . However, the property $newEntryButtonText is declared as type null|string . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||||||
209 | } |
||||||
210 | |||||||
211 | return $this->newEntryButtonText; |
||||||
212 | } |
||||||
213 | |||||||
214 | /** |
||||||
215 | * @param string $newEntryButtonText |
||||||
216 | * |
||||||
217 | * @return $this |
||||||
218 | */ |
||||||
219 | public function setNewEntryButtonText($newEntryButtonText) |
||||||
220 | { |
||||||
221 | $this->newEntryButtonText = $newEntryButtonText; |
||||||
222 | |||||||
223 | return $this; |
||||||
224 | } |
||||||
225 | |||||||
226 | /** |
||||||
227 | * @return string |
||||||
228 | */ |
||||||
229 | public function getOrderField() |
||||||
230 | { |
||||||
231 | return $this->orderField; |
||||||
232 | } |
||||||
233 | |||||||
234 | /** |
||||||
235 | * @param string $orderField |
||||||
236 | * |
||||||
237 | * @return $this |
||||||
238 | */ |
||||||
239 | public function setOrderField($orderField) |
||||||
240 | { |
||||||
241 | $this->orderField = $orderField; |
||||||
242 | |||||||
243 | return $this; |
||||||
244 | } |
||||||
245 | |||||||
246 | /** |
||||||
247 | * @return null|string |
||||||
248 | */ |
||||||
249 | public function getRootParentId() |
||||||
250 | { |
||||||
251 | return $this->rootParentId; |
||||||
252 | } |
||||||
253 | |||||||
254 | /** |
||||||
255 | * @param null|string $rootParentId |
||||||
256 | * |
||||||
257 | * @return $this |
||||||
258 | */ |
||||||
259 | public function setRootParentId($rootParentId) |
||||||
260 | { |
||||||
261 | $this->rootParentId = $rootParentId; |
||||||
262 | |||||||
263 | return $this; |
||||||
264 | } |
||||||
265 | |||||||
266 | /** |
||||||
267 | * @return array |
||||||
268 | */ |
||||||
269 | public function getParameters() |
||||||
270 | { |
||||||
271 | return $this->parameters; |
||||||
272 | } |
||||||
273 | |||||||
274 | /** |
||||||
275 | * @param array $parameters |
||||||
276 | * |
||||||
277 | * @return $this |
||||||
278 | */ |
||||||
279 | public function setParameters($parameters) |
||||||
280 | { |
||||||
281 | $this->parameters = $parameters; |
||||||
282 | |||||||
283 | return $this; |
||||||
284 | } |
||||||
285 | |||||||
286 | /** |
||||||
287 | * @param string $key |
||||||
288 | * @param mixed $value |
||||||
289 | * |
||||||
290 | * @return $this |
||||||
291 | */ |
||||||
292 | public function setParameter($key, $value) |
||||||
293 | { |
||||||
294 | $this->parameters[$key] = $value; |
||||||
295 | |||||||
296 | return $this; |
||||||
297 | } |
||||||
298 | |||||||
299 | /** |
||||||
300 | * @return bool |
||||||
301 | */ |
||||||
302 | public function isReorderable() |
||||||
303 | { |
||||||
304 | return $this->reorderable; |
||||||
305 | } |
||||||
306 | |||||||
307 | /** |
||||||
308 | * @param bool $reorderable |
||||||
309 | * |
||||||
310 | * @return $this |
||||||
311 | */ |
||||||
312 | public function setReorderable($reorderable) |
||||||
313 | { |
||||||
314 | $this->reorderable = (bool) $reorderable; |
||||||
315 | |||||||
316 | return $this; |
||||||
317 | } |
||||||
318 | |||||||
319 | /** |
||||||
320 | * @return array |
||||||
321 | * @throws \Exception |
||||||
322 | */ |
||||||
323 | public function toArray() |
||||||
324 | { |
||||||
325 | $model = $this->getModelConfiguration(); |
||||||
326 | $this->setHtmlAttribute('class', 'dd nestable'); |
||||||
327 | |||||||
328 | return parent::toArray() + [ |
||||||
329 | 'items' => $this->getRepository()->getTree($this->getCollection()), |
||||||
330 | 'reorderable' => $this->isReorderable(), |
||||||
331 | 'url' => $model->getDisplayUrl(), |
||||||
332 | 'value' => $this->getValue(), |
||||||
333 | 'creatable' => $model->isCreatable(), |
||||||
334 | 'createUrl' => $model->getCreateUrl($this->getParameters() + Request::all()), |
||||||
335 | 'controls' => [$this->getColumns()->getControlColumn()], |
||||||
336 | 'newEntryButtonText' => $this->getNewEntryButtonText(), |
||||||
337 | 'max_depth' => $this->getMaxDepth(), |
||||||
338 | 'panel_class' => $this->getPanelClass(), |
||||||
339 | ]; |
||||||
340 | } |
||||||
341 | |||||||
342 | /** |
||||||
343 | * @return Collection |
||||||
344 | * @throws \Exception |
||||||
345 | */ |
||||||
346 | public function getCollection() |
||||||
347 | { |
||||||
348 | if (! $this->isInitialized()) { |
||||||
349 | throw new Exception('Display is not initialized'); |
||||||
350 | } |
||||||
351 | |||||||
352 | if (! is_null($this->collection)) { |
||||||
353 | return $this->collection; |
||||||
354 | } |
||||||
355 | |||||||
356 | $query = $this->getRepository()->getQuery(); |
||||||
357 | |||||||
358 | $this->modifyQuery($query); |
||||||
359 | |||||||
360 | if (method_exists($query, 'defaultOrder')) { |
||||||
361 | return $query->defaultOrder()->get(); |
||||||
362 | } |
||||||
363 | |||||||
364 | return $query->get(); |
||||||
365 | } |
||||||
366 | |||||||
367 | /** |
||||||
368 | * @param \Illuminate\Database\Eloquent\Builder $query |
||||||
369 | */ |
||||||
370 | protected function modifyQuery(Builder $query) |
||||||
371 | { |
||||||
372 | $this->extensions->modifyQuery($query); |
||||||
373 | } |
||||||
374 | |||||||
375 | /** |
||||||
376 | * @return \Illuminate\Foundation\Application|mixed |
||||||
377 | * @throws \Exception |
||||||
378 | */ |
||||||
379 | protected function makeRepository() |
||||||
380 | { |
||||||
381 | $repository = parent::makeRepository(); |
||||||
382 | |||||||
383 | if (! ($repository instanceof TreeRepositoryInterface)) { |
||||||
384 | throw new Exception('Repository class must be instanced of [TreeRepositoryInterface]'); |
||||||
385 | } |
||||||
386 | |||||||
387 | return $repository; |
||||||
388 | } |
||||||
389 | } |
||||||
390 |
If there is a route defined but the controller class cannot be found there are two options: 1. the controller class needs to be implemented or 2. the route is outdated and can be removed.
If ?FooController? was found and ?BarController? is missing for the following example, either the controller should be implemented or the route should be removed: