Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
ElementMapFactory
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 7
702
0.00% covered (danger)
0.00%
0 / 1
 withInstance
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 create
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 1
342
 isBlockedForModification
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 getParentProperty
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getFeatureFlagChecker
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getContainer
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFormDataProvider
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 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) 2020-2022 (original work) Open Assessment Technologies SA;
19 */
20
21declare(strict_types=1);
22
23namespace oat\tao\helpers\form;
24
25use common_Logger;
26use core_kernel_classes_Class;
27use core_kernel_classes_Property;
28use core_kernel_classes_Resource;
29use oat\generis\model\OntologyAwareTrait;
30use oat\generis\model\OntologyRdfs;
31use oat\oatbox\service\ConfigurableService;
32use oat\tao\helpers\form\elements\TreeAware;
33use oat\tao\model\featureFlag\FeatureFlagChecker;
34use oat\tao\model\featureFlag\FeatureFlagCheckerInterface;
35use oat\tao\model\form\DataProvider\FormDataProviderInterface;
36use oat\tao\model\form\DataProvider\ProxyFormDataProvider;
37use Psr\Container\ContainerInterface;
38use tao_helpers_Context;
39use tao_helpers_form_elements_AsyncFile as AsyncFile;
40use tao_helpers_form_elements_Authoring as Authoring;
41use tao_helpers_form_elements_GenerisAsyncFile as GenerisAsyncFile;
42use tao_helpers_form_FormElement;
43use tao_helpers_form_FormFactory;
44use tao_helpers_Uri;
45
46class ElementMapFactory extends ConfigurableService
47{
48    use OntologyAwareTrait;
49
50    public const SERVICE_ID = 'tao/ElementMapFactory';
51
52    /** @var core_kernel_classes_Resource */
53    private $instance;
54
55    public function withInstance(core_kernel_classes_Resource $instance): self
56    {
57        $this->instance = $instance;
58
59        return $this;
60    }
61
62    public function create(
63        core_kernel_classes_Property $property,
64        string $language = DEFAULT_LANG
65    ): ?tao_helpers_form_FormElement {
66
67        // Create the element from the right widget
68        $property->feed();
69
70        $widgetResource = $property->getWidget();
71        if (null === $widgetResource) {
72            return null;
73        }
74
75        $widgetUri   = $widgetResource->getUri();
76        $propertyUri = $property->getUri();
77        // Authoring widget is not used in standalone mode
78        if (
79            $widgetUri === Authoring::WIDGET_ID
80            && tao_helpers_Context::check('STANDALONE_MODE')
81        ) {
82            return null;
83        }
84
85        // Horrible hack to fix file widget
86        if ($widgetUri === AsyncFile::WIDGET_ID) {
87            $widgetResource = new core_kernel_classes_Resource(GenerisAsyncFile::WIDGET_ID);
88        }
89
90        $element = tao_helpers_form_FormFactory::getElementByWidget(
91            tao_helpers_Uri::encode($propertyUri),
92            $widgetResource
93        );
94
95        if (null === $element) {
96            return null;
97        }
98
99        $isListsDependencyEnabled = $this->getFeatureFlagChecker()->isEnabled(
100            FeatureFlagCheckerInterface::FEATURE_FLAG_LISTS_DEPENDENCY_ENABLED
101        );
102
103        $parentProperty = null;
104
105        if ($isListsDependencyEnabled) {
106            $parentProperty = $this->getParentProperty($property);
107
108            if ($parentProperty) {
109                $element->addAttribute('data-depends-on-property', tao_helpers_Uri::encode($parentProperty->getUri()));
110            }
111        }
112
113        if ($element->getWidget() !== $widgetUri) {
114            common_Logger::w(sprintf(
115                'Widget definition differs from implementation: %s != %s',
116                $element->getWidget(),
117                $widgetUri
118            ));
119
120            return null;
121        }
122
123        $description = $this->getFormDataProvider()->getDescriptionFromTranslatedPropertyLabel($property, $language);
124
125        $element->setDescription($description);
126
127        if (method_exists($element, 'setOptions')) {
128            // Multi elements use the property range as options
129            $range = $property->getRange();
130
131            if ($range !== null) {
132                if ($element instanceof TreeAware) {
133                    $options = $element->rangeToTree(
134                        $propertyUri === OntologyRdfs::RDFS_RANGE
135                            ? new core_kernel_classes_Class(OntologyRdfs::RDFS_RESOURCE)
136                            : $range
137                    );
138                } else {
139                    if ($this->getFormDataProvider()->isPropertyList($property)) {
140                        $options = $this
141                            ->getFormDataProvider()
142                            ->getPropertyListElementOptions($property, $parentProperty, $this->instance);
143                    } else {
144                        $options = $this->getFormDataProvider()->getPropertyNotListElementOptions($property);
145                    }
146
147                    foreach ($options as [$uri, $label]) {
148                        $options[$uri] = $label;
149                    }
150
151                    // Set the default value to an empty space
152                    if (method_exists($element, 'setEmptyOption')) {
153                        $element->setEmptyOption(' ');
154                    }
155                }
156
157                // Complete the options listing
158                $element->setOptions($options);
159            }
160        }
161
162        if ($this->isBlockedForModification($property)) {
163            $element->disable();
164        }
165
166        foreach ($this->getFormDataProvider()->getPropertyValidators($property) as $validator) {
167            $element->addValidator($validator);
168        }
169
170        return $element;
171    }
172
173    private function isBlockedForModification(core_kernel_classes_Property $property): bool
174    {
175        if ($this->getFeatureFlagChecker()->isEnabled('FEATURE_FLAG_STATISTIC_METADATA_IMPORT')) {
176            return $property->isStatistical();
177        }
178
179        return false;
180    }
181
182    private function getParentProperty(core_kernel_classes_Property $property): ?core_kernel_classes_Property
183    {
184        $collection = $property->getDependsOnPropertyCollection();
185
186        return $collection->offsetExists(0)
187            ? $collection->offsetGet(0)
188            : null;
189    }
190
191    private function getFeatureFlagChecker(): FeatureFlagCheckerInterface
192    {
193        return $this->getContainer()->get(FeatureFlagChecker::class);
194    }
195
196    private function getContainer(): ContainerInterface
197    {
198        return $this->getServiceManager()->getContainer();
199    }
200
201    public function getFormDataProvider(): FormDataProviderInterface
202    {
203        return $this->getContainer()->get(ProxyFormDataProvider::class)->getProvider();
204    }
205}