Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 203 |
|
0.00% |
0 / 15 |
CRAP | |
0.00% |
0 / 1 |
GenerisServiceTrait | |
0.00% |
0 / 203 |
|
0.00% |
0 / 15 |
6162 | |
0.00% |
0 / 1 |
searchInstances | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
createInstance | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
createUniqueLabel | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
12 | |||
createSubClass | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
bindProperties | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
cloneInstance | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
30 | |||
cloneInstanceProperty | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
30 | |||
cloneClazz | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
72 | |||
changeClass | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
72 | |||
getClazzProperties | |
0.00% |
0 / 32 |
|
0.00% |
0 / 1 |
132 | |||
getPropertyDiff | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
getTranslatedProperties | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
90 | |||
toArray | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
30 | |||
toTree | |
0.00% |
0 / 33 |
|
0.00% |
0 / 1 |
182 | |||
getDefaultFilters | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getServiceLocator | n/a |
0 / 0 |
n/a |
0 / 0 |
0 |
1 | <?php |
2 | |
3 | /** |
4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License |
6 | * as published by the Free Software Foundation; under version 2 |
7 | * of the License (non-upgradable). |
8 | * |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write to the Free Software |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | * |
18 | * Copyright (c) 2018-2021 (original work) Open Assessment Technologies SA; |
19 | * |
20 | */ |
21 | |
22 | namespace oat\tao\model; |
23 | |
24 | use core_kernel_classes_Class; |
25 | use core_kernel_classes_Property; |
26 | use core_kernel_classes_Resource; |
27 | use oat\generis\model\fileReference\FileReferenceSerializer; |
28 | use oat\generis\model\fileReference\ResourceFileSerializer; |
29 | use oat\generis\model\GenerisRdf; |
30 | use oat\generis\model\OntologyAwareTrait; |
31 | use oat\generis\model\OntologyRdf; |
32 | use oat\generis\model\OntologyRdfs; |
33 | use oat\oatbox\event\EventManagerAwareTrait; |
34 | use oat\oatbox\filesystem\File; |
35 | use oat\oatbox\filesystem\FileSystemService; |
36 | use oat\oatbox\session\SessionService; |
37 | use oat\tao\helpers\TreeHelper; |
38 | use oat\tao\model\event\ClassMovedEvent; |
39 | |
40 | /** |
41 | * Trait GenerisServiceTrait |
42 | * @package oat\tao\model |
43 | * @author Aleh Hutnikau, <hutnikau@1pt.com> |
44 | */ |
45 | trait GenerisServiceTrait |
46 | { |
47 | use EventManagerAwareTrait; |
48 | use OntologyAwareTrait; |
49 | |
50 | /** |
51 | * search the instances matching the filters in parameters |
52 | * |
53 | * @access public |
54 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
55 | * @param array propertyFilters |
56 | * @param core_kernel_classes_Class $topClazz |
57 | * @param array options |
58 | * @return \core_kernel_classes_Resource[] |
59 | */ |
60 | public function searchInstances($propertyFilters = [], core_kernel_classes_Class $topClazz = null, $options = []) |
61 | { |
62 | $returnValue = []; |
63 | |
64 | if (!is_null($topClazz)) { |
65 | $returnValue = $topClazz->searchInstances($propertyFilters, $options); |
66 | } |
67 | return (array) $returnValue; |
68 | } |
69 | |
70 | /** |
71 | * Instantiate an RDFs Class |
72 | * |
73 | * @access public |
74 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
75 | * @param core_kernel_classes_Class $clazz |
76 | * @param string label |
77 | * @return core_kernel_classes_Resource |
78 | * @throws \common_exception_Error |
79 | */ |
80 | public function createInstance(core_kernel_classes_Class $clazz, $label = '') |
81 | { |
82 | if (empty($label)) { |
83 | $label = $this->createUniqueLabel($clazz); |
84 | } |
85 | return $clazz->createInstance($label); |
86 | } |
87 | |
88 | /** |
89 | * Short description of method createUniqueLabel |
90 | * |
91 | * @access public |
92 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
93 | * @param core_kernel_classes_Class $clazz |
94 | * @param boolean $subClassing |
95 | * @throws \common_exception_Error |
96 | * @return string |
97 | */ |
98 | public function createUniqueLabel(core_kernel_classes_Class $clazz, $subClassing = false) |
99 | { |
100 | if ($subClassing) { |
101 | $labelBase = $clazz->getLabel() . '_' ; |
102 | $count = count($clazz->getSubClasses()) + 1; |
103 | } else { |
104 | $labelBase = $clazz->getLabel() . ' ' ; |
105 | $count = count($clazz->getInstances()) + 1; |
106 | } |
107 | |
108 | $options = [ |
109 | 'lang' => $this |
110 | ->getServiceLocator() |
111 | ->get(SessionService::SERVICE_ID) |
112 | ->getCurrentSession() |
113 | ->getDataLanguage(), |
114 | 'like' => false, |
115 | 'recursive' => false |
116 | ]; |
117 | |
118 | do { |
119 | $exist = false; |
120 | $label = $labelBase . $count; |
121 | $result = $clazz->searchInstances([OntologyRdfs::RDFS_LABEL => $label], $options); |
122 | if (count($result) > 0) { |
123 | $exist = true; |
124 | $count++; |
125 | } |
126 | } while ($exist); |
127 | |
128 | return (string) $label; |
129 | } |
130 | |
131 | /** |
132 | * Subclass an RDFS Class |
133 | * |
134 | * @access public |
135 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
136 | * @param core_kernel_classes_Class $parentClazz |
137 | * @param string $label |
138 | * @return core_kernel_classes_Class |
139 | * @throws \common_exception_Error |
140 | */ |
141 | public function createSubClass(core_kernel_classes_Class $parentClazz, $label = '') |
142 | { |
143 | if (empty($label)) { |
144 | $label = $this->createUniqueLabel($parentClazz, true); |
145 | } |
146 | return $parentClazz->createSubClass($label, ''); |
147 | } |
148 | |
149 | /** |
150 | * bind the given RDFS properties to the RDFS resource in parameter |
151 | * |
152 | * @access public |
153 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
154 | * @param core_kernel_classes_Resource $instance |
155 | * @param array properties |
156 | * @return core_kernel_classes_Resource |
157 | * @throws \tao_models_classes_dataBinding_GenerisInstanceDataBindingException |
158 | */ |
159 | public function bindProperties(core_kernel_classes_Resource $instance, $properties = []) |
160 | { |
161 | $binder = new \tao_models_classes_dataBinding_GenerisInstanceDataBinder($instance); |
162 | $binder->bind($properties); |
163 | |
164 | return $instance; |
165 | } |
166 | |
167 | /** |
168 | * @deprecated Use `oat\tao\model\resources\Service\InstanceCopier::transfer()` instead for Items/Tests/Assets |
169 | * |
170 | * duplicate a resource |
171 | * |
172 | * @access public |
173 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
174 | * @param core_kernel_classes_Resource $instance |
175 | * @param core_kernel_classes_Class $clazz |
176 | * @return core_kernel_classes_Resource |
177 | * @throws \common_Exception |
178 | * @throws \common_exception_Error |
179 | */ |
180 | public function cloneInstance(core_kernel_classes_Resource $instance, core_kernel_classes_Class $clazz = null) |
181 | { |
182 | if (is_null($clazz)) { |
183 | $types = $instance->getTypes(); |
184 | $clazz = current($types); |
185 | } |
186 | |
187 | $returnValue = $this->createInstance($clazz); |
188 | if (!is_null($returnValue)) { |
189 | $properties = $clazz->getProperties(true); |
190 | foreach ($properties as $property) { |
191 | $this->cloneInstanceProperty($instance, $returnValue, $property); |
192 | } |
193 | $label = $instance->getLabel(); |
194 | $cloneLabel = "$label bis"; |
195 | if (preg_match("/bis(\s[0-9]+)?$/", $label)) { |
196 | $cloneNumber = (int)preg_replace("/^(.?)*bis/", "", $label); |
197 | $cloneNumber++; |
198 | $cloneLabel = preg_replace("/bis(\s[0-9]+)?$/", "", $label) . "bis $cloneNumber" ; |
199 | } |
200 | |
201 | $returnValue->setLabel($cloneLabel); |
202 | } |
203 | |
204 | return $returnValue; |
205 | } |
206 | |
207 | /** |
208 | * |
209 | * @author Lionel Lecaque, lionel@taotesting.com |
210 | * @param core_kernel_classes_Resource $source |
211 | * @param core_kernel_classes_Resource $destination |
212 | * @param core_kernel_classes_Property $property |
213 | * @throws \common_Exception |
214 | * @throws \common_exception_Error |
215 | */ |
216 | protected function cloneInstanceProperty( |
217 | core_kernel_classes_Resource $source, |
218 | core_kernel_classes_Resource $destination, |
219 | core_kernel_classes_Property $property |
220 | ) { |
221 | $range = $property->getRange(); |
222 | // Avoid doublons, the RDF TYPE property will be set by the implementation layer |
223 | if ($property->getUri() != OntologyRdf::RDF_TYPE) { |
224 | foreach ($source->getPropertyValuesCollection($property)->getIterator() as $propertyValue) { |
225 | if (!is_null($range) && $range->getUri() == GenerisRdf::CLASS_GENERIS_FILE) { |
226 | /** @var FileReferenceSerializer $fileRefSerializer */ |
227 | $fileRefSerializer = $this->getServiceLocator() |
228 | ->get(ResourceFileSerializer::SERVICE_ID); |
229 | |
230 | /** @var File $oldFile */ |
231 | $oldFile = $fileRefSerializer->unserializeFile($propertyValue->getUri()); |
232 | |
233 | $newFileName = \helpers_File::createFileName($oldFile->getBasename()); |
234 | |
235 | /** @var File $newFile */ |
236 | $newFile = $this->getServiceLocator() |
237 | ->get(FileSystemService::SERVICE_ID) |
238 | ->getDirectory($oldFile->getFileSystemId()) |
239 | ->getFile($newFileName); |
240 | |
241 | $newFile->write($oldFile->readStream()); |
242 | |
243 | $newFileUri = $fileRefSerializer->serialize($newFile); |
244 | |
245 | $destination->setPropertyValue($property, new core_kernel_classes_Resource($newFileUri)); |
246 | } else { |
247 | $destination->setPropertyValue($property, $propertyValue); |
248 | } |
249 | } |
250 | } |
251 | } |
252 | |
253 | |
254 | /** |
255 | * Clone a Class and move it under the newParentClazz |
256 | * |
257 | * @access public |
258 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
259 | * @param core_kernel_classes_Class $sourceClazz |
260 | * @param core_kernel_classes_Class $newParentClazz |
261 | * @param core_kernel_classes_Class $topLevelClazz |
262 | * @return core_kernel_classes_Class|null |
263 | * @throws \common_exception_Error |
264 | */ |
265 | public function cloneClazz( |
266 | core_kernel_classes_Class $sourceClazz, |
267 | core_kernel_classes_Class $newParentClazz = null, |
268 | core_kernel_classes_Class $topLevelClazz = null |
269 | ) { |
270 | $returnValue = null; |
271 | |
272 | if (!is_null($sourceClazz) && !is_null($newParentClazz)) { |
273 | if ((is_null($topLevelClazz))) { |
274 | $properties = $sourceClazz->getProperties(false); |
275 | } else { |
276 | $properties = $this->getClazzProperties($sourceClazz, $topLevelClazz); |
277 | } |
278 | |
279 | //check for duplicated properties |
280 | $newParentProperties = $newParentClazz->getProperties(true); |
281 | foreach ($properties as $index => $property) { |
282 | foreach ($newParentProperties as $newParentProperty) { |
283 | if ($property->getUri() == $newParentProperty->getUri()) { |
284 | unset($properties[$index]); |
285 | break; |
286 | } |
287 | } |
288 | } |
289 | |
290 | //create a new class |
291 | $returnValue = $this->createSubClass($newParentClazz, $sourceClazz->getLabel()); |
292 | |
293 | //assign the properties of the source class |
294 | foreach ($properties as $property) { |
295 | $property->setDomain($returnValue); |
296 | } |
297 | } |
298 | return $returnValue; |
299 | } |
300 | |
301 | /** |
302 | * Change the Class (RDF_TYPE) of a resource |
303 | * |
304 | * @access public |
305 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
306 | * @param core_kernel_classes_Resource $instance |
307 | * @param core_kernel_classes_Class $destinationClass |
308 | * @return boolean |
309 | */ |
310 | public function changeClass(core_kernel_classes_Resource $instance, core_kernel_classes_Class $destinationClass) |
311 | { |
312 | if ($instance->isClass()) { |
313 | try { |
314 | /** @var core_kernel_classes_Class $instance */ |
315 | $status = $instance->editPropertyValues( |
316 | $this->getProperty(OntologyRdfs::RDFS_SUBCLASSOF), |
317 | $destinationClass |
318 | ); |
319 | if ($status) { |
320 | $this->getEventManager()->trigger(new ClassMovedEvent($instance)); |
321 | } |
322 | return $status; |
323 | } catch (\Exception $e) { |
324 | return false; |
325 | } |
326 | } else { |
327 | try { |
328 | foreach ($instance->getTypes() as $type) { |
329 | $instance->removeType($type); |
330 | } |
331 | $instance->setType($destinationClass); |
332 | foreach ($instance->getTypes() as $type) { |
333 | if ($type->getUri() == $destinationClass->getUri()) { |
334 | return true; |
335 | } |
336 | } |
337 | } catch (\common_Exception $ce) { |
338 | print $ce; |
339 | return false; |
340 | } |
341 | } |
342 | } |
343 | |
344 | /** |
345 | * Get all the properties of the class in parameter. |
346 | * The properties are taken recursively into the class parents up to the top |
347 | * class. |
348 | * If the top level class is not defined, we used the TAOObject class. |
349 | * |
350 | * @access public |
351 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
352 | * @param core_kernel_classes_Class $clazz |
353 | * @param core_kernel_classes_Class $topLevelClazz |
354 | * @return array |
355 | */ |
356 | public function getClazzProperties( |
357 | core_kernel_classes_Class $clazz, |
358 | core_kernel_classes_Class $topLevelClazz = null |
359 | ) { |
360 | $returnValue = []; |
361 | if (is_null($topLevelClazz)) { |
362 | $topLevelClazz = new core_kernel_classes_Class(TaoOntology::CLASS_URI_OBJECT); |
363 | } |
364 | |
365 | if ($clazz->getUri() == $topLevelClazz->getUri()) { |
366 | $returnValue = $clazz->getProperties(false); |
367 | return (array) $returnValue; |
368 | } |
369 | |
370 | //determine the parent path |
371 | $parents = []; |
372 | $top = false; |
373 | do { |
374 | if (!isset($lastLevelParents)) { |
375 | $parentClasses = $clazz->getParentClasses(false); |
376 | } else { |
377 | $parentClasses = []; |
378 | foreach ($lastLevelParents as $parent) { |
379 | $parentClasses = array_merge($parentClasses, $parent->getParentClasses(false)); |
380 | } |
381 | } |
382 | if (count($parentClasses) == 0) { |
383 | break; |
384 | } |
385 | $lastLevelParents = []; |
386 | foreach ($parentClasses as $parentClass) { |
387 | if ($parentClass->getUri() == $topLevelClazz->getUri()) { |
388 | $parents[$parentClass->getUri()] = $parentClass; |
389 | $top = true; |
390 | break; |
391 | } |
392 | if ($parentClass->getUri() == OntologyRdfs::RDFS_CLASS) { |
393 | continue; |
394 | } |
395 | |
396 | $allParentClasses = $parentClass->getParentClasses(true); |
397 | if (array_key_exists($topLevelClazz->getUri(), $allParentClasses)) { |
398 | $parents[$parentClass->getUri()] = $parentClass; |
399 | } |
400 | $lastLevelParents[$parentClass->getUri()] = $parentClass; |
401 | } |
402 | } while (!$top); |
403 | |
404 | foreach ($parents as $parent) { |
405 | $returnValue = array_merge($returnValue, $parent->getProperties(false)); |
406 | } |
407 | |
408 | $returnValue = array_merge($returnValue, $clazz->getProperties(false)); |
409 | |
410 | return (array) $returnValue; |
411 | } |
412 | |
413 | /** |
414 | * get the properties of the source class that are not in the destination |
415 | * |
416 | * @access public |
417 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
418 | * @param core_kernel_classes_Class $sourceClass |
419 | * @param core_kernel_classes_Class $destinationClass |
420 | * @return array |
421 | */ |
422 | public function getPropertyDiff(core_kernel_classes_Class $sourceClass, core_kernel_classes_Class $destinationClass) |
423 | { |
424 | $returnValue = []; |
425 | $sourceProperties = $sourceClass->getProperties(true); |
426 | $destinationProperties = $destinationClass->getProperties(true); |
427 | foreach ($sourceProperties as $sourcePropertyUri => $sourceProperty) { |
428 | if (!array_key_exists($sourcePropertyUri, $destinationProperties)) { |
429 | $sourceProperty->getLabel(); |
430 | array_push($returnValue, $sourceProperty); |
431 | } |
432 | } |
433 | return (array) $returnValue; |
434 | } |
435 | |
436 | /** |
437 | * get the properties of an instance for a specific language |
438 | * |
439 | * @access public |
440 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
441 | * @param core_kernel_classes_Resource $instance |
442 | * @param string $lang |
443 | * @return array |
444 | */ |
445 | public function getTranslatedProperties(core_kernel_classes_Resource $instance, $lang) |
446 | { |
447 | $returnValue = []; |
448 | |
449 | try { |
450 | foreach ($instance->getTypes() as $clazz) { |
451 | foreach ($clazz->getProperties(true) as $property) { |
452 | if ($property->isLgDependent() || $property->getUri() == OntologyRdfs::RDFS_LABEL) { |
453 | $collection = $instance->getPropertyValuesByLg($property, $lang); |
454 | if ($collection->count() > 0) { |
455 | if ($collection->count() == 1) { |
456 | $returnValue[$property->getUri()] = (string)$collection->get(0); |
457 | } else { |
458 | $propData = []; |
459 | foreach ($collection->getIterator() as $collectionItem) { |
460 | $propData[] = (string)$collectionItem; |
461 | } |
462 | $returnValue[$property->getUri()] = $propData; |
463 | } |
464 | } |
465 | } |
466 | } |
467 | } |
468 | } catch (\Exception $e) { |
469 | print $e; |
470 | } |
471 | |
472 | return (array) $returnValue; |
473 | } |
474 | |
475 | /** |
476 | * Format an RDFS Class to an array |
477 | * |
478 | * @access public |
479 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
480 | * @param core_kernel_classes_Class $clazz |
481 | * @return array |
482 | */ |
483 | public function toArray(core_kernel_classes_Class $clazz) |
484 | { |
485 | $returnValue = []; |
486 | $properties = $clazz->getProperties(false); |
487 | foreach ($clazz->getInstances(false) as $instance) { |
488 | $data = []; |
489 | foreach ($properties as $property) { |
490 | $data[$property->getLabel()] = null; |
491 | $values = $instance->getPropertyValues($property); |
492 | if (count($values) > 1) { |
493 | $data[$property->getLabel()] = $values; |
494 | } elseif (count($values) == 1) { |
495 | $data[$property->getLabel()] = $values[0]; |
496 | } |
497 | } |
498 | array_push($returnValue, $data); |
499 | } |
500 | return (array) $returnValue; |
501 | } |
502 | |
503 | /** |
504 | * Format an RDFS Class to an array to be interpreted by the client tree |
505 | * This is a closed array format. |
506 | * |
507 | * @access public |
508 | * @author Jerome Bogaerts, <jerome.bogaerts@tudor.lu> |
509 | * @param core_kernel_classes_Class $clazz |
510 | * @param array $options |
511 | * @return array |
512 | * @throws \common_exception_Error |
513 | */ |
514 | public function toTree(core_kernel_classes_Class $clazz, array $options = []) |
515 | { |
516 | $searchOptions = []; |
517 | // show instances yes/no |
518 | $instances = (isset($options['instances'])) ? $options['instances'] : true; |
519 | // cut of the class and only display the children? |
520 | $chunk = (isset($options['chunk'])) ? $options['chunk'] : false; |
521 | // probably which subtrees should be opened |
522 | $browse = (isset($options['browse'])) ? $options['browse'] : []; |
523 | // limit of instances shown by subclass if no search label is given |
524 | // if a search string is given, this is the total limit of results, independent of classes |
525 | $limit = (isset($options['limit'])) ? $options['limit'] : 0; |
526 | // offset for limit |
527 | $offset = (isset($options['offset'])) ? $options['offset'] : 0; |
528 | // A unique node URI to be returned from as a tree leaf. |
529 | $uniqueNode = (isset($options['uniqueNode'])) ? $options['uniqueNode'] : null; |
530 | |
531 | if (isset($options['order']) && isset($options['orderdir'])) { |
532 | $searchOptions['order'] = [$options['order'] => $options['orderdir']]; |
533 | } |
534 | |
535 | if ($uniqueNode !== null) { |
536 | $instance = new \core_kernel_classes_Resource($uniqueNode); |
537 | $results[] = TreeHelper::buildResourceNode($instance, $clazz); |
538 | $returnValue = $results; |
539 | } else { |
540 | // Let's walk the tree with super walker! ~~~ p==[w]รต__ |
541 | array_walk($browse, function (&$item) { |
542 | $item = \tao_helpers_Uri::decode($item); |
543 | }); |
544 | $openNodes = TreeHelper::getNodesToOpen($browse, $clazz); |
545 | |
546 | if (!in_array($clazz->getUri(), $openNodes)) { |
547 | $openNodes[] = $clazz->getUri(); |
548 | } |
549 | |
550 | $factory = new GenerisTreeFactory( |
551 | $instances, |
552 | $openNodes, |
553 | $limit, |
554 | $offset, |
555 | $browse, |
556 | $this->getDefaultFilters(), |
557 | $searchOptions |
558 | ); |
559 | $tree = $factory->buildTree($clazz); |
560 | $returnValue = $chunk |
561 | ? (isset($tree['children']) ? $tree['children'] : []) |
562 | : $tree; |
563 | } |
564 | return $returnValue; |
565 | } |
566 | |
567 | /** |
568 | * @return array |
569 | */ |
570 | protected function getDefaultFilters() |
571 | { |
572 | return []; |
573 | } |
574 | |
575 | /** |
576 | * make sure that trait will be mixed to ServiceLocatorAware class |
577 | * @return mixed |
578 | */ |
579 | abstract public function getServiceLocator(); |
580 | } |