Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
83.87% |
52 / 62 |
|
54.55% |
6 / 11 |
CRAP | |
0.00% |
0 / 1 |
DependsOnPropertyRepository | |
83.87% |
52 / 62 |
|
54.55% |
6 / 11 |
57.67 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
withProperties | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
findAll | |
91.18% |
31 / 34 |
|
0.00% |
0 / 1 |
24.40 | |||
getListUri | |
60.00% |
3 / 5 |
|
0.00% |
0 / 1 |
8.30 | |||
isSameParentProperty | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
isRemoteListProperty | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
6 | |||
isParentProperty | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
isPropertyNotSupported | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
getProperties | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isPropertyWidgetAllowed | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
4 | |||
isParentPropertyWidgetAllowed | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 |
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) 2021 (original work) Open Assessment Technologies SA; |
19 | */ |
20 | |
21 | declare(strict_types=1); |
22 | |
23 | namespace oat\tao\model\Lists\DataAccess\Repository; |
24 | |
25 | use InvalidArgumentException; |
26 | use core_kernel_classes_Class; |
27 | use core_kernel_classes_Property; |
28 | use tao_helpers_form_elements_Combobox; |
29 | use tao_helpers_form_GenerisFormFactory; |
30 | use oat\tao\model\featureFlag\FeatureFlagChecker; |
31 | use oat\tao\helpers\form\elements\xhtml\SearchTextBox; |
32 | use oat\tao\helpers\form\elements\xhtml\SearchDropdown; |
33 | use oat\tao\model\Lists\Business\Domain\DependsOnProperty; |
34 | use oat\tao\model\featureFlag\FeatureFlagCheckerInterface; |
35 | use oat\tao\model\Specification\PropertySpecificationInterface; |
36 | use oat\tao\model\Lists\Business\Domain\DependsOnPropertyCollection; |
37 | use oat\tao\model\Lists\Business\Contract\DependsOnPropertyRepositoryInterface; |
38 | use oat\tao\model\Lists\Business\Contract\ParentPropertyListRepositoryInterface; |
39 | |
40 | class DependsOnPropertyRepository implements DependsOnPropertyRepositoryInterface |
41 | { |
42 | public const DEPENDENT_RESTRICTED_TYPES = [ |
43 | tao_helpers_form_elements_Combobox::WIDGET_ID, |
44 | SearchDropdown::WIDGET_ID, |
45 | SearchTextBox::WIDGET_ID |
46 | ]; |
47 | |
48 | /** @var FeatureFlagCheckerInterface */ |
49 | private $featureFlagChecker; |
50 | |
51 | /** @var PropertySpecificationInterface */ |
52 | private $primaryPropertySpecification; |
53 | |
54 | /** @var PropertySpecificationInterface */ |
55 | private $remoteListPropertySpecification; |
56 | |
57 | /** @var PropertySpecificationInterface */ |
58 | private $dependentPropertySpecification; |
59 | |
60 | /** @var ParentPropertyListRepositoryInterface */ |
61 | private $parentPropertyListRepository; |
62 | |
63 | /** @var core_kernel_classes_Property[] */ |
64 | private $properties; |
65 | |
66 | public function __construct( |
67 | FeatureFlagCheckerInterface $featureFlagChecker, |
68 | PropertySpecificationInterface $primaryPropertySpecification, |
69 | PropertySpecificationInterface $remoteListPropertySpecification, |
70 | PropertySpecificationInterface $dependentPropertySpecification, |
71 | ParentPropertyListRepositoryInterface $parentPropertyListRepository |
72 | ) { |
73 | $this->featureFlagChecker = $featureFlagChecker; |
74 | $this->primaryPropertySpecification = $primaryPropertySpecification; |
75 | $this->remoteListPropertySpecification = $remoteListPropertySpecification; |
76 | $this->dependentPropertySpecification = $dependentPropertySpecification; |
77 | $this->parentPropertyListRepository = $parentPropertyListRepository; |
78 | } |
79 | |
80 | public function withProperties(array $properties) |
81 | { |
82 | $this->properties = $properties; |
83 | } |
84 | |
85 | public function findAll(array $filter): DependsOnPropertyCollection |
86 | { |
87 | $collection = new DependsOnPropertyCollection(); |
88 | |
89 | if (!$this->featureFlagChecker->isEnabled(FeatureFlagChecker::FEATURE_FLAG_LISTS_DEPENDENCY_ENABLED)) { |
90 | return $collection; |
91 | } |
92 | |
93 | if (empty($filter[self::FILTER_PROPERTY]) && empty($filter[self::FILTER_CLASS])) { |
94 | throw new InvalidArgumentException('class or property filter need to be provided'); |
95 | } |
96 | |
97 | /** @var core_kernel_classes_Property $property */ |
98 | $property = $filter[self::FILTER_PROPERTY] ?? null; |
99 | |
100 | if ( |
101 | ($property && $this->primaryPropertySpecification->isSatisfiedBy($property)) |
102 | || !$this->isPropertyWidgetAllowed($filter) |
103 | ) { |
104 | return $collection; |
105 | } |
106 | |
107 | /** @var core_kernel_classes_Class $class */ |
108 | $class = $property |
109 | ? ($property->getDomain()->count() > 0 ? $property->getDomain()->get(0) : null) |
110 | : $filter[self::FILTER_CLASS] ?? null; |
111 | |
112 | if ($class === null || (empty($filter[self::FILTER_LIST_URI]) && $property && !$property->getRange())) { |
113 | return $collection; |
114 | } |
115 | |
116 | if (isset($filter[self::FILTER_LIST_URI]) && $property && !$property->getRange()) { |
117 | $property = null; |
118 | } |
119 | |
120 | $listUri = $this->getListUri($filter, $property); |
121 | |
122 | if (!$listUri) { |
123 | return $collection; |
124 | } |
125 | |
126 | if ($property && !$this->isRemoteListProperty($property)) { |
127 | return $collection; |
128 | } |
129 | |
130 | $parentPropertiesUris = $this->parentPropertyListRepository->findAllUris( |
131 | [ |
132 | 'listUri' => $listUri |
133 | ] |
134 | ); |
135 | |
136 | if (empty($parentPropertiesUris)) { |
137 | return $collection; |
138 | } |
139 | |
140 | /** @var core_kernel_classes_Property $property */ |
141 | foreach ($this->getProperties($class) as $classProperty) { |
142 | if ( |
143 | ($property && $this->isPropertyNotSupported($property, $classProperty)) |
144 | || !$this->isParentProperty($classProperty, $parentPropertiesUris) |
145 | ) { |
146 | continue; |
147 | } |
148 | |
149 | $collection->append(new DependsOnProperty($classProperty)); |
150 | } |
151 | |
152 | return $collection; |
153 | } |
154 | |
155 | private function getListUri(array $options, core_kernel_classes_Property $property = null): ?string |
156 | { |
157 | if (empty($options['listUri']) && $property && !$property->getRange()) { |
158 | return null; |
159 | } |
160 | |
161 | return empty($options['listUri']) && $property |
162 | ? $property->getRange()->getUri() |
163 | : ($options['listUri'] ?? null); |
164 | } |
165 | |
166 | private function isSameParentProperty( |
167 | core_kernel_classes_Property $property, |
168 | core_kernel_classes_Property $classProperty |
169 | ): bool { |
170 | $parentProperty = $classProperty->getDependsOnPropertyCollection()->current(); |
171 | |
172 | return $parentProperty && $property->getUri() === $parentProperty->getUri(); |
173 | } |
174 | |
175 | private function isRemoteListProperty(core_kernel_classes_Property $property): bool |
176 | { |
177 | return $property->getDomain()->count() && $this->remoteListPropertySpecification->isSatisfiedBy($property); |
178 | } |
179 | |
180 | private function isParentProperty(core_kernel_classes_Property $classProperty, array $parentPropertiesUris): bool |
181 | { |
182 | return !$this->dependentPropertySpecification->isSatisfiedBy($classProperty) |
183 | && in_array($classProperty->getUri(), $parentPropertiesUris, true) |
184 | && $this->isParentPropertyWidgetAllowed($classProperty); |
185 | } |
186 | |
187 | private function isPropertyNotSupported( |
188 | core_kernel_classes_Property $property, |
189 | core_kernel_classes_Property $classProperty |
190 | ): bool { |
191 | return $property->getUri() === $classProperty->getUri() |
192 | || !$this->remoteListPropertySpecification->isSatisfiedBy($classProperty); |
193 | } |
194 | |
195 | private function getProperties(core_kernel_classes_Class $class): array |
196 | { |
197 | return $this->properties ?? tao_helpers_form_GenerisFormFactory::getClassProperties($class); |
198 | } |
199 | |
200 | private function isPropertyWidgetAllowed(array $filter): bool |
201 | { |
202 | /** @var core_kernel_classes_Property $property */ |
203 | $property = $filter[self::FILTER_PROPERTY] ?? null; |
204 | |
205 | $widgetUri = $filter[self::FILTER_PROPERTY_WIDGET_URI] ?? null; |
206 | $widgetUri = $widgetUri ?? ($property && $property->getWidget() ? $property->getWidget()->getUri() : null); |
207 | |
208 | if ($widgetUri === null) { |
209 | return true; |
210 | } |
211 | |
212 | return in_array($widgetUri, self::DEPENDENT_RESTRICTED_TYPES, true); |
213 | } |
214 | |
215 | private function isParentPropertyWidgetAllowed(core_kernel_classes_Property $property): bool |
216 | { |
217 | return $property->getWidget() |
218 | && in_array($property->getWidget()->getUri(), self::DEPENDENT_RESTRICTED_TYPES, true); |
219 | } |
220 | } |