Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.49% covered (danger)
0.49%
1 / 206
3.23% covered (danger)
3.23%
1 / 31
CRAP
0.00% covered (danger)
0.00%
0 / 1
taoItems_models_classes_ItemsService
0.49% covered (danger)
0.49%
1 / 206
3.23% covered (danger)
3.23%
1 / 31
7546.31
0.00% covered (danger)
0.00%
0 / 1
 getRootClass
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getItemModelProperty
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getItemContentProperty
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getItemClass
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 isItemClass
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 delete
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
20
 deleteItem
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 deleteResource
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 deleteItemClass
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasItemContent
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
 hasItemModel
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 isItemModelDefined
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
 getModelRuntime
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 hasModelStatus
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
56
 render
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 composeItemDirectoryPath
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 cloneInstanceProperty
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 cloneItemContent
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
30
 cloneInstance
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 getPreviewUrl
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getItemModel
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 setItemModel
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSessionLg
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 deleteItemContent
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
 getItemModelImplementation
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
30
 getCompilerClass
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 setDefaultFilesourceId
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getItemDirectory
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
72
 getDefaultItemDirectory
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getAllByModel
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 getFileReferenceSerializer
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) 2008-2010 (original work) Deutsche Institut für Internationale Pädagogische Forschung
19 *                         (under the project TAO-TRANSFER);
20 *               2009-2012 (update and modification) Public Research Centre Henri Tudor
21 *                         (under the project TAO-SUSTAIN & TAO-DEV);
22 *               2012-2023 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT)
23 */
24
25use oat\taoItems\model\Command\DeleteItemCommand;
26use oat\taoItems\model\TaoItemOntology;
27use oat\generis\model\fileReference\FileReferenceSerializer;
28use oat\oatbox\filesystem\Directory;
29use oat\oatbox\filesystem\FileSystemService;
30use oat\oatbox\service\ServiceNotFoundException;
31use oat\tao\model\lock\LockManager;
32use oat\tao\model\OntologyClassService;
33use oat\tao\model\TaoOntology;
34use oat\taoItems\model\event\ItemContentClonedEvent;
35use oat\taoItems\model\event\ItemDuplicatedEvent;
36use oat\taoItems\model\event\ItemRemovedEvent;
37use oat\taoItems\model\ItemModelStatus;
38use oat\taoQtiItem\helpers\QtiFile;
39
40/**
41 * Service methods to manage the Items business models using the RDF API.
42 *
43 * @access public
44 * @author Joel Bout, <joel@taotesting.com>
45 * @package taoItems
46 */
47class taoItems_models_classes_ItemsService extends OntologyClassService
48{
49    /**
50     * Key to use to store the default filesource to be used in for new items
51     */
52    public const CONFIG_DEFAULT_FILESOURCE = 'defaultItemFileSource';
53
54    /** @deprecated Use oat\taoItems\model\TaoItemOntology::PROPERTY_ITEM_MODEL instead */
55    public const PROPERTY_ITEM_MODEL = TaoItemOntology::PROPERTY_ITEM_MODEL;
56
57    /** @deprecated Use oat\taoItems\model\TaoItemOntology::PROPERTY_ITEM_CONTENT instead */
58    public const PROPERTY_ITEM_CONTENT = TaoItemOntology::PROPERTY_ITEM_CONTENT;
59
60    /** @deprecated Use oat\taoItems\model\TaoItemOntology::PROPERTY_MODEL_SERVICE instead */
61    public const PROPERTY_ITEM_MODEL_SERVICE = TaoItemOntology::PROPERTY_MODEL_SERVICE;
62
63    /** @deprecated Use oat\taoItems\model\TaoItemOntology::PROPERTY_ITEM_CONTENT_SOURCE_NAME instead */
64    public const PROPERTY_ITEM_CONTENT_SRC = TaoItemOntology::PROPERTY_ITEM_CONTENT_SOURCE_NAME;
65
66    /** @deprecated Use oat\taoItems\model\TaoItemOntology::PROPERTY_DATA_FILE_NAME instead */
67    public const TAO_ITEM_MODEL_DATAFILE_PROPERTY = TaoItemOntology::PROPERTY_DATA_FILE_NAME;
68
69    public const INSTANCE_SERVICE_ITEM_RUNNER = 'http://www.tao.lu/Ontologies/TAODelivery.rdf#ServiceItemRunner';
70
71    public const INSTANCE_FORMAL_PARAM_ITEM_PATH = 'http://www.tao.lu/Ontologies/TAODelivery.rdf#FormalParamItemPath';
72
73    // phpcs:disable Generic.Files.LineLength
74    public const INSTANCE_FORMAL_PARAM_ITEM_DATA_PATH = 'http://www.tao.lu/Ontologies/TAODelivery.rdf#FormalParamItemDataPath';
75    // phpcs:enable Generic.Files.LineLength
76
77    public const INSTANCE_FORMAL_PARAM_ITEM_URI = 'http://www.tao.lu/Ontologies/TAODelivery.rdf#FormalParamItemUri';
78
79    private const DIV_CLASS_EMPTY = '<div class="empty"';
80
81    public function getRootClass()
82    {
83        return $this->getClass(TaoOntology::CLASS_URI_ITEM);
84    }
85
86    public function getItemModelProperty()
87    {
88        return $this->getProperty(self::PROPERTY_ITEM_MODEL);
89    }
90
91    public function getItemContentProperty()
92    {
93        return $this->getProperty(self::PROPERTY_ITEM_CONTENT);
94    }
95
96    /**
97     * get an item subclass by uri.
98     * If the uri is not set, it returns the  item class (the top level class.
99     * If the uri don't reference an item subclass, it returns null
100     *
101     * @access public
102     * @author Joel Bout, <joel@taotesting.com>
103     * @param  string uri
104     * @return core_kernel_classes_Class
105     * @deprecated
106     */
107    public function getItemClass($uri = '')
108    {
109        $returnValue = null;
110
111        if (empty($uri)) {
112            $returnValue = $this->getRootClass();
113        } else {
114            $clazz = $this->getClass($uri);
115            if ($this->isItemClass($clazz)) {
116                $returnValue = $clazz;
117            }
118        }
119
120        return $returnValue;
121    }
122
123    /**
124     * check if the class is a or a subclass of an Item
125     *
126     * @access public
127     * @author Joel Bout, <joel@taotesting.com>
128     * @param  core_kernel_classes_Class clazz
129     * @return boolean
130     */
131    public function isItemClass(core_kernel_classes_Class $clazz)
132    {
133        return $clazz->equals($this->getRootClass()) || $clazz->isSubClassOf($this->getRootClass());
134    }
135
136    public function delete(DeleteItemCommand $command): void
137    {
138        $resource = $command->getResource();
139
140        if (LockManager::getImplementation()->isLocked($resource)) {
141            $userId = common_session_SessionManager::getSession()->getUser()->getIdentifier();
142            LockManager::getImplementation()->releaseLock($resource, $userId);
143        }
144
145        $result = $this->deleteItemContent($resource) && parent::deleteResource($resource);
146
147        if (!$result) {
148            throw new Exception(
149                sprintf(
150                    'Error deleting item content for resource "%s" [%s]',
151                    $resource->getLabel(),
152                    $resource->getUri()
153                )
154            );
155        }
156
157        $this->getEventManager()->trigger(
158            new ItemRemovedEvent(
159                $resource->getUri(),
160                [
161                    ItemRemovedEvent::PAYLOAD_KEY_DELETE_RELATED_ASSETS => $command->mustDeleteRelatedAssets(),
162                ]
163            )
164        );
165    }
166
167    /**
168     * please call deleteResource() instead
169     * @deprecated
170     */
171    public function deleteItem(core_kernel_classes_Resource $item)
172    {
173        return $this->deleteResource($item);
174    }
175
176    /**
177     * delete an item
178     * @param core_kernel_classes_Resource $resource
179     * @throws common_exception_Unauthorized
180     * @return boolean
181     * @deprecated use self::delete()
182     */
183    public function deleteResource(core_kernel_classes_Resource $resource)
184    {
185        try {
186            $this->delete(new DeleteItemCommand($resource));
187
188            return true;
189        } catch (Throwable $exception) {
190            return false;
191        }
192    }
193
194    /**
195     * delete an item class or subclass
196     * @deprecated
197     */
198    public function deleteItemClass(core_kernel_classes_Class $clazz)
199    {
200        return $this->deleteClass($clazz);
201    }
202
203    /**
204     * Check if the item has an itemContent Property
205     *
206     * @param core_kernel_classes_Resource $item
207     * @param string $lang
208     * @return bool
209     * @throws Exception
210     */
211    public function hasItemContent(core_kernel_classes_Resource $item, $lang = '')
212    {
213        if (is_null($item)) {
214            return false;
215        }
216
217        if (empty($lang)) {
218            $lang = $this->getSessionLg();
219        }
220
221        $itemContents = $item->getPropertyValuesByLg($this->getItemContentProperty(), $lang);
222
223        if ($itemContents->isEmpty()) {
224            return false;
225        }
226
227        $file = $this->getItemDirectory($item, $lang)->getFile(QtiFile::FILE);
228
229        return $file->exists() ? !(strpos($file->read(), self::DIV_CLASS_EMPTY) !== false) : false;
230    }
231
232    /**
233     * Check if the Item has on of the itemModel property in the models array
234     *
235     * @access public
236     * @author Joel Bout, <joel@taotesting.com>
237     * @param  Resource item
238     * @param  array models the list of URI of the itemModel to check
239     * @return boolean
240     */
241    public function hasItemModel(core_kernel_classes_Resource $item, $models)
242    {
243        $returnValue = false;
244
245        $itemModel = $item->getOnePropertyValue($this->getItemModelProperty());
246        if ($itemModel instanceof core_kernel_classes_Resource) {
247            if (in_array($itemModel->getUri(), $models)) {
248                $returnValue = true;
249            }
250        }
251
252        return $returnValue;
253    }
254
255    /**
256     * Check if the itemModel has been defined for that item
257     *
258     * @access public
259     * @author Joel Bout, <joel@taotesting.com>
260     * @param  Resource item
261     * @return boolean
262     */
263    public function isItemModelDefined(core_kernel_classes_Resource $item)
264    {
265        $returnValue = false;
266
267        if (!is_null($item)) {
268            $model = $item->getOnePropertyValue($this->getItemModelProperty());
269            if ($model instanceof core_kernel_classes_Literal) {
270                if (strlen((string)$model) > 0) {
271                    $returnValue = true;
272                }
273            } elseif (!is_null($model)) {
274                $returnValue = true;
275            }
276        }
277
278        return $returnValue;
279    }
280
281    /**
282     * Get the runtime associated to the item model.
283     *
284     * @access public
285     * @author Joel Bout, <joel@taotesting.com>
286     * @param  Resource item
287     * @return core_kernel_classes_Resource
288     */
289    public function getModelRuntime(core_kernel_classes_Resource $item)
290    {
291        $returnValue = null;
292
293        if (!is_null($item)) {
294            $itemModel = $item->getOnePropertyValue($this->getItemModelProperty());
295            if (!is_null($itemModel)) {
296                $returnValue = $itemModel->getOnePropertyValue(
297                    $this->getProperty(taoItems_models_classes_itemModel::CLASS_URI_RUNTIME)
298                );
299            }
300        }
301
302        return $returnValue;
303    }
304
305    /**
306     * Short description of method hasModelStatus
307     *
308     * @access public
309     * @author Joel Bout, <joel@taotesting.com>
310     * @param  Resource item
311     * @param  array status
312     * @return boolean
313     */
314    public function hasModelStatus(core_kernel_classes_Resource $item, $status)
315    {
316        $returnValue = false;
317
318        if (!is_null($item)) {
319            if (!is_array($status) && is_string($status)) {
320                $status = [$status];
321            }
322            try {
323                $itemModel = $item->getOnePropertyValue($this->getItemModelProperty());
324                if ($itemModel instanceof core_kernel_classes_Resource) {
325                    $itemModelStatus = $itemModel->getUniquePropertyValue(
326                        $this->getProperty(ItemModelStatus::CLASS_URI)
327                    );
328
329                    if (in_array($itemModelStatus->getUri(), $status)) {
330                        $returnValue = true;
331                    }
332                }
333            } catch (common_exception_EmptyProperty $ce) {
334                $returnValue = false;
335            }
336        }
337
338        return $returnValue;
339    }
340
341    /**
342     * render used for deploy and preview
343     *
344     * @access public
345     * @author Joel Bout, <joel@taotesting.com>
346     * @param  Resource item
347     * @return string
348     * @throws taoItems_models_classes_ItemModelException
349     */
350    public function render(core_kernel_classes_Resource $item, $language)
351    {
352        $itemModel = $this->getItemModel($item);
353        if (is_null($itemModel)) {
354            throw new common_exception_NoImplementation('No item model for item ' . $item->getUri());
355        }
356        $impl = $this->getItemModelImplementation($itemModel);
357        if (is_null($impl)) {
358            throw new common_exception_NoImplementation('No implementation for model ' . $itemModel->getUri());
359        }
360        return $impl->render($item, $language);
361    }
362
363    /**
364     * @param string $itemContentDirectoryName
365     * @param string $actualLang
366     * @return string
367     */
368    public function composeItemDirectoryPath(string $itemContentDirectoryName, string $actualLang): string
369    {
370        return  $itemContentDirectoryName . DIRECTORY_SEPARATOR . 'itemContent' . DIRECTORY_SEPARATOR . $actualLang;
371    }
372
373    /**
374     * Woraround for item content
375     * (non-PHPdoc)
376     * @see tao_models_classes_GenerisService::cloneInstanceProperty()
377     */
378    protected function cloneInstanceProperty(
379        core_kernel_classes_Resource $source,
380        core_kernel_classes_Resource $destination,
381        core_kernel_classes_Property $property
382    ) {
383        if ($property->getUri() == self::PROPERTY_ITEM_CONTENT) {
384            return $this->cloneItemContent($source, $destination, $property);
385        } else {
386            return parent::cloneInstanceProperty($source, $destination, $property);
387        }
388    }
389
390    /**
391     * Clone item content
392     *
393     * @param core_kernel_classes_Resource $source
394     * @param core_kernel_classes_Resource $destination
395     * @param core_kernel_classes_Property $property
396     * @throws FileNotFoundException
397     * @throws \oat\generis\model\fileReference\FileSerializerException
398     * @throws common_Exception
399     */
400    protected function cloneItemContent(
401        core_kernel_classes_Resource $source,
402        core_kernel_classes_Resource $destination,
403        core_kernel_classes_Property $property
404    ) {
405
406        $serializer = $this->getFileReferenceSerializer();
407        $this->setItemModel($destination, $this->getItemModel($source));
408
409        foreach ($source->getUsedLanguages($this->getItemContentProperty()) as $lang) {
410            $sourceItemDirectory = $this->getItemDirectory($source, $lang);
411            $destinationItemDirectory = $this->getItemDirectory($destination, $lang);
412            $propertyValuesCollection = $source->getPropertyValuesCollection($property, ['lg' => $lang]);
413
414            foreach ($propertyValuesCollection->getIterator() as $propertyValue) {
415                $id = $propertyValue instanceof core_kernel_classes_Resource
416                    ? $propertyValue->getUri()
417                    : (string)$propertyValue;
418                $sourceDirectory = $serializer->unserializeDirectory($id);
419                $iterator = $sourceDirectory->getFlyIterator(Directory::ITERATOR_FILE | Directory::ITERATOR_RECURSIVE);
420
421                foreach ($iterator as $iteratorFile) {
422                    $newFile = $destinationItemDirectory->getFile($sourceItemDirectory->getRelPath($iteratorFile));
423                    $newFile->write($iteratorFile->readStream());
424                }
425
426                $destinationDirectory = $destinationItemDirectory->getDirectory(
427                    $sourceItemDirectory->getRelPath($sourceDirectory)
428                );
429                $serializer->serialize($destinationDirectory);
430            }
431        }
432        $this->getEventManager()->trigger(
433            new ItemContentClonedEvent($source->getUri(), $destination->getUri())
434        );
435    }
436
437    public function cloneInstance(core_kernel_classes_Resource $instance, core_kernel_classes_Class $clazz = null)
438    {
439        $result = parent::cloneInstance($instance, $clazz);
440        if ($result) {
441            // Fixes duplicate item models after cloning.
442            $itemModels = $result->getPropertyValues($this->getItemModelProperty());
443            if (count($itemModels) > 1) {
444                $result->editPropertyValues($this->getItemModelProperty(), current($itemModels));
445            }
446            $this->getEventManager()->trigger(new ItemDuplicatedEvent($instance->getUri(), $result->getUri()));
447        }
448        return $result;
449    }
450
451
452    public function getPreviewUrl(core_kernel_classes_Resource $item, $lang = '')
453    {
454        $itemModel = $this->getItemModel($item);
455        if (is_null($itemModel)) {
456            return null;
457        }
458        return $this->getItemModelImplementation($itemModel)->getPreviewUrl($item, $lang);
459    }
460
461    /**
462     * Short description of method getItemModel
463     *
464     * @access public
465     * @author Joel Bout, <joel@taotesting.com>
466     * @param  Resource item
467     * @return core_kernel_classes_Resource
468     */
469    public function getItemModel(core_kernel_classes_Resource $item)
470    {
471        $returnValue = null;
472
473        $itemModel = $item->getOnePropertyValue($this->getItemModelProperty());
474        if ($itemModel instanceof core_kernel_classes_Resource) {
475            $returnValue = $itemModel;
476        }
477
478        return $returnValue;
479    }
480
481    /**
482     * Set the model of an item
483     *
484     * @param core_kernel_classes_Resource $item
485     * @param core_kernel_classes_Resource $model
486     * @return boolean
487     */
488    public function setItemModel(core_kernel_classes_Resource $item, core_kernel_classes_Resource $model)
489    {
490        return $item->editPropertyValues($this->getProperty(self::PROPERTY_ITEM_MODEL), $model);
491    }
492
493    /**
494     * Rertrieve current user's language from the session object to know where
495     * item content should be located
496     *
497     * @access public
498     * @author Joel Bout, <joel@taotesting.com>
499     * @return string
500     */
501    public function getSessionLg()
502    {
503        $sessionLang = \common_session_SessionManager::getSession()->getDataLanguage();
504        if (empty($sessionLang)) {
505            throw new Exception('the data language of the user cannot be found in session');
506        }
507
508        return (string)$sessionLang;
509    }
510
511    /**
512     * Deletes the content but does not unreference it
513     *
514     * @access public
515     * @author Joel Bout, <joel@taotesting.com>
516     * @param  core_kernel_classes_Resource item
517     * @return boolean
518     */
519    public function deleteItemContent(core_kernel_classes_Resource $item)
520    {
521        // Delete item directory from filesystem
522        $definitonFileValues = $item->getPropertyValues($this->getItemContentProperty());
523        if (!empty($definitonFileValues)) {
524            /** @var Directory $directory */
525            $directory = $this->getFileReferenceSerializer()->unserializeDirectory(reset($definitonFileValues));
526            if ($directory->exists()) {
527                $directory->deleteSelf();
528            }
529        }
530
531        //delete the folder for all languages!
532        foreach ($item->getUsedLanguages($this->getItemContentProperty()) as $lang) {
533            $files = $item->getPropertyValuesByLg($this->getItemContentProperty(), $lang);
534            foreach ($files->getIterator() as $file) {
535                if ($file instanceof core_kernel_classes_Resource) {
536                    $this->getFileReferenceSerializer()->cleanUp($file->getUri());
537                }
538            }
539        }
540
541        return true;
542    }
543
544    /**
545     * Get the correct implementation for a specific item model
546     * @author Joel Bout, <joel@taotesting.com>
547     * @access public
548     *
549     * @param  core_kernel_classes_Resource $itemModel
550     *
551     * @return taoItems_models_classes_itemModel
552     * @throws common_exception_NoImplementation
553     * @throws common_exception_Error
554     */
555    public function getItemModelImplementation(core_kernel_classes_Resource $itemModel)
556    {
557        $serviceId = (string)$itemModel->getOnePropertyValue($this->getProperty(self::PROPERTY_ITEM_MODEL_SERVICE));
558        if (empty($serviceId)) {
559            throw new common_exception_NoImplementation(
560                'No implementation found for item model ' . $itemModel->getUri()
561            );
562        }
563        try {
564            $itemModelService = $this->getServiceManager()->get($serviceId);
565        } catch (ServiceNotFoundException $e) {
566            if (!class_exists($serviceId)) {
567                throw new common_exception_Error('Item model service ' . $serviceId . ' not found');
568            }
569            // for backward compatibility support classname instead of a serviceid
570            common_Logger::w('Outdated model definition "' . $serviceId . '", please use test model service');
571            $itemModelService = new $serviceId();
572        }
573        if (!$itemModelService instanceof taoItems_models_classes_itemModel) {
574            throw new common_exception_Error(
575                'Item model service ' . get_class($itemModelService) . ' not compatible for item model ' . $serviceId
576            );
577        }
578
579        return $itemModelService;
580    }
581
582    public function getCompilerClass(core_kernel_classes_Resource $item)
583    {
584        $itemModel = $this->getItemModel($item);
585        if (is_null($itemModel)) {
586            throw new common_exception_Error('undefined itemmodel for test ' . $item->getUri());
587        }
588        return $this->getItemModelImplementation($itemModel)->getCompilerClass();
589    }
590
591    /**
592     * sets the filesource to use for new items
593     *
594     * @author Joel Bout, <joel@taotesting.com>
595     * @param string $filesourceId
596     */
597    public function setDefaultFilesourceId($filesourceId)
598    {
599        $ext = common_ext_ExtensionsManager::singleton()->getExtensionById('taoItems');
600        $ext->setConfig(self::CONFIG_DEFAULT_FILESOURCE, $filesourceId);
601    }
602
603    /**
604     * Returns the items flysystem directory
605     *
606     * @param core_kernel_classes_Resource $item
607     * @param string $language
608     * @return \oat\oatbox\filesystem\Directory
609     * @throws Exception
610     * @throws common_Exception
611     * @throws core_kernel_persistence_Exception
612     */
613    public function getItemDirectory(core_kernel_classes_Resource $item, $language = '')
614    {
615        // Get file by language
616        if ($language === '') {
617            $files = $item->getPropertyValues($this->getItemContentProperty());
618        } else {
619            $files = $item->getPropertyValuesByLg($this->getItemContentProperty(), $language)->toArray();
620        }
621
622        // If multiple files then throw exception
623        if (count($files) > 1) {
624            common_Logger::i(print_r($files, true));
625            throw new common_Exception(__METHOD__ . ': Item ' . $item->getUri() . ' has multiple.');
626        }
627
628        // If there is one file then return directory
629        if (count($files) == 1) {
630            $file = reset($files);
631            $file = is_object($file) && $file instanceof core_kernel_classes_Resource ? $file->getUri() : (string)$file;
632            return $this->getFileReferenceSerializer()->unserializeDirectory($file);
633        }
634
635        // Otherwise there is no file, create one and return directory
636        $model = $this->getItemModel($item);
637        if (is_null($model)) {
638            throw new common_Exception('Call to ' . __FUNCTION__ . ' for item without model');
639        }
640
641        $itemContentDirectoryName = tao_helpers_Uri::getUniqueId($item->getUri());
642        // File does not exist, let's create it
643        $actualLang = empty($language) ? $this->getSessionLg() : $language;
644
645        $directoryPath = $this->composeItemDirectoryPath($itemContentDirectoryName, $actualLang);
646
647        // Create item directory
648        $itemDirectory = $this->getDefaultItemDirectory()->getDirectory($directoryPath);
649
650        // Set uri file value as serial to item persistence
651        $serial = $this->getFileReferenceSerializer()->serialize($itemDirectory);
652
653        $item->setPropertyValueByLg($this->getItemContentProperty(), $serial, $actualLang);
654
655        return $itemDirectory;
656    }
657
658    /**
659     * Returns the defaul item directory
660     * @return Directory
661     * @throws common_ext_ExtensionException
662     */
663    public function getDefaultItemDirectory()
664    {
665        $filesystemId = common_ext_ExtensionsManager::singleton()
666            ->getExtensionById('taoItems')
667            ->getConfig(self::CONFIG_DEFAULT_FILESOURCE);
668
669        return $this->getServiceManager()
670            ->get(FileSystemService::SERVICE_ID)
671            ->getDirectory($filesystemId);
672    }
673
674    /**
675     * Get items of a specific model
676     * @param string|core_kernel_classes_Resource $itemModel - the item model URI
677     * @return core_kernel_classes_Resource[] the found items
678     */
679    public function getAllByModel($itemModel)
680    {
681        if (!empty($itemModel)) {
682            $uri = ($itemModel instanceof core_kernel_classes_Resource) ? $itemModel->getUri() : $itemModel;
683            return $this->getRootClass()->searchInstances([
684                $this->getItemModelProperty()->getUri() => $uri
685            ], [
686                'recursive' => true
687            ]);
688        }
689        return [];
690    }
691
692    /**
693     * Get serializer to persist filesystem object
694     *
695     * @return FileReferenceSerializer
696     */
697    protected function getFileReferenceSerializer()
698    {
699        return $this->getServiceLocator()->get(FileReferenceSerializer::SERVICE_ID);
700    }
701}