Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
44.30% covered (danger)
44.30%
140 / 316
48.28% covered (danger)
48.28%
14 / 29
CRAP
0.00% covered (danger)
0.00%
0 / 1
core_kernel_persistence_smoothsql_Resource
44.30% covered (danger)
44.30%
140 / 316
48.28% covered (danger)
48.28%
14 / 29
1457.54
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPersistence
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModelReadSqlCondition
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getModelWriteSqlCondition
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getNewTripleModelId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getTypes
71.43% covered (warning)
71.43%
5 / 7
0.00% covered (danger)
0.00%
0 / 1
2.09
 getParentClassesIds
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
2
 getClassesResourceIds
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
12
 getNestedResources
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
2
 getPropertyValues
83.87% covered (warning)
83.87%
26 / 31
0.00% covered (danger)
0.00%
0 / 1
9.34
 getPropertyValuesByLg
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 setPropertyValue
78.57% covered (warning)
78.57%
11 / 14
0.00% covered (danger)
0.00%
0 / 1
4.16
 setPropertiesValues
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
4
 setPropertyValueByLg
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 removePropertyValues
38.64% covered (danger)
38.64%
17 / 44
0.00% covered (danger)
0.00%
0 / 1
59.29
 removePropertyValueByLg
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 getRdfTriples
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
2
 isWritable
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getUsedLanguages
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 duplicate
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
7
 delete
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
20
 getPropertiesValues
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
42
 setType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 removeType
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
2
 getServiceLocator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 buildTrippleArray
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
4
 normalizePropertyValues
54.55% covered (warning)
54.55%
6 / 11
0.00% covered (danger)
0.00%
0 / 1
11.60
 getDataLanguage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
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) 2002-2008 (original work) Public Research Centre Henri Tudor & University of Luxembourg
19 *                         (under the project TAO & TAO2);
20 *               2008-2010 (update and modification) Deutsche Institut für Internationale Pädagogische Forschung
21 *                         (under the project TAO-TRANSFER);
22 *               2009-2012 (update and modification) Public Research Centre Henri Tudor
23 *                         (under the project TAO-SUSTAIN & TAO-DEV);
24 *               2017 (update and modification) Open Assessment Technologies SA (under the project TAO-PRODUCT);
25 */
26
27use oat\generis\model\OntologyRdf;
28use oat\generis\model\OntologyRdfs;
29use oat\oatbox\session\SessionService;
30use oat\oatbox\user\UserLanguageServiceInterface;
31use oat\generis\model\kernel\uri\UriProvider;
32use Zend\ServiceManager\ServiceLocatorInterface;
33
34/**
35 * Short description of class core_kernel_persistence_smoothsql_Resource
36 *
37 * @access public
38 * @author Joel Bout, <joel.bout@tudor.lu>
39 * @package generis
40
41 */
42class core_kernel_persistence_smoothsql_Resource implements core_kernel_persistence_ResourceInterface
43{
44    /**
45     * @var core_kernel_persistence_smoothsql_SmoothModel
46     */
47    private $model;
48
49    public function __construct(core_kernel_persistence_smoothsql_SmoothModel $model)
50    {
51        $this->model = $model;
52    }
53
54    protected function getModel()
55    {
56        return $this->model;
57    }
58
59    /**
60     * @return common_persistence_SqlPersistence
61     */
62    protected function getPersistence()
63    {
64        return $this->model->getPersistence();
65    }
66
67    protected function getModelReadSqlCondition()
68    {
69        return 'modelid IN (' . implode(',', $this->model->getReadableModels()) . ')';
70    }
71
72    protected function getModelWriteSqlCondition()
73    {
74        return 'modelid IN (' . implode(',', $this->model->getWritableModels()) . ')';
75    }
76
77    protected function getNewTripleModelId()
78    {
79        return $this->model->getNewTripleModelId();
80    }
81
82    /**
83     * returns an array of types the resource has
84     *
85     * @access public
86     * @author Joel Bout, <joel.bout@tudor.lu>
87     * @param  core_kernel_classes_Resource resource
88     * @return array
89     */
90    public function getTypes(core_kernel_classes_Resource $resource)
91    {
92        $returnValue = [];
93
94        // TODO: refactor this to use a triple retrieving method.
95        $sqlQuery = 'SELECT object FROM statements WHERE subject = ? and predicate = ?';
96        $sth = $this->getPersistence()->query($sqlQuery, [$resource->getUri(), OntologyRdf::RDF_TYPE]);
97
98        while ($row = $sth->fetch()) {
99            $uri = $this->getPersistence()->getPlatForm()->getPhpTextValue($row['object']);
100            $returnValue[$uri] = $this->getModel()->getClass($uri);
101        }
102
103        return (array) $returnValue;
104    }
105
106    public function getParentClassesIds(string $resourceUri): array
107    {
108        $query = <<<'SQL'
109WITH RECURSIVE statements_tree AS (
110    SELECT
111        r.object
112    FROM statements r
113    WHERE r.subject = ?
114      AND r.predicate IN (?, ?)
115      AND r.object != ?
116    UNION ALL
117    SELECT
118        s.object
119    FROM statements s
120        JOIN statements_tree st
121            ON s.subject = st.object
122                   AND s.predicate IN (?, ?)
123                   AND s.object NOT IN (?, ?, ?, ?)
124)
125SELECT object FROM statements_tree;
126SQL;
127
128        $statement = $this->getPersistence()->query(
129            $query,
130            [
131                $resourceUri,
132                OntologyRdfs::RDFS_SUBCLASSOF,
133                OntologyRdf::RDF_TYPE,
134                'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject',
135                OntologyRdfs::RDFS_SUBCLASSOF,
136                OntologyRdf::RDF_TYPE,
137                'http://www.tao.lu/Ontologies/TAO.rdf#AssessmentContentObject',
138                'http://www.tao.lu/Ontologies/TAO.rdf#TAOObject',
139                'http://www.tao.lu/Ontologies/generis.rdf#generis_Ressource',
140                'http://www.w3.org/2000/01/rdf-schema#Resource',
141            ]
142        );
143
144        return array_column($statement->fetchAll(), 'object');
145    }
146
147    /**
148     * @param array $classIds
149     * @return array [
150     *     '{classUri}' => [
151     *         '{resourceUri_1}',
152     *         '{resourceUri_N...}',
153     *     ]
154     * ]
155     */
156    public function getClassesResourceIds(array $classIds): array
157    {
158        if (empty($classIds)) {
159            return [];
160        }
161
162        $query = sprintf(
163            'SELECT subject, object FROM statements WHERE predicate IN (?, ?) AND object IN (%s)',
164            implode(',', array_fill(0, count($classIds), '?'))
165        );
166
167        $statement = $this->getPersistence()->query(
168            $query,
169            [
170                OntologyRdfs::RDFS_SUBCLASSOF,
171                OntologyRdf::RDF_TYPE,
172                ...$classIds,
173            ]
174        );
175
176        $results = $statement->fetchAll();
177        $resourceIds = [];
178
179        // Iterate over the provided class IDs to keep the same order
180        foreach ($classIds as $classId) {
181            $resources = array_filter($results, static fn (array $result): bool => $result['object'] === $classId);
182            $resourceIds[$classId] = array_column($resources, 'subject');
183        }
184
185        return $resourceIds;
186    }
187
188    /**
189     * Returns a list of nested resources/classes under a resource
190     *
191     * @param string $classId
192     * @return array [
193     *     [
194     *         'id' => '{resourceId}',
195     *         'isClass' => true|false,
196     *         'level' => 1..N,
197     *     ]
198     * ]
199     */
200    public function getNestedResources(string $classId): array
201    {
202        $query = <<<'SQL'
203WITH RECURSIVE statements_tree AS (
204    SELECT
205        r.subject,
206        r.predicate,
207        1 as level
208    FROM statements r
209    WHERE r.subject = ?
210      AND r.predicate IN (?, ?)
211    UNION ALL
212    SELECT
213        s.subject,
214        s.predicate,
215        level + 1
216    FROM statements s
217        JOIN statements_tree st
218            ON s.object = st.subject
219    WHERE s.predicate IN (?, ?)
220)
221SELECT
222    subject as id,
223    CASE WHEN predicate = ? THEN 1 ELSE 0 END as isClass,
224    level
225FROM statements_tree;
226SQL;
227
228        $statement = $this->getPersistence()->query(
229            $query,
230            [
231                $classId,
232                OntologyRdfs::RDFS_SUBCLASSOF,
233                OntologyRdf::RDF_TYPE,
234                OntologyRdfs::RDFS_SUBCLASSOF,
235                OntologyRdf::RDF_TYPE,
236                OntologyRdfs::RDFS_SUBCLASSOF,
237            ]
238        );
239
240        return $statement->fetchAll();
241    }
242
243    /**
244     * Short description of method getPropertyValues
245     *
246     * @access public
247     * @param core_kernel_classes_Resource $resource
248     * @param core_kernel_classes_Property $property
249     * @param array $options
250     * @return array
251     * @throws core_kernel_persistence_Exception
252     * @author Joel Bout, <joel.bout@tudor.lu>
253     */
254    public function getPropertyValues(
255        core_kernel_classes_Resource $resource,
256        core_kernel_classes_Property $property,
257        $options = []
258    ) {
259        $returnValue = [];
260
261        $one = isset($options['one']) && $options['one'] == true ? true : false;
262        if (isset($options['last'])) {
263            throw new core_kernel_persistence_Exception('Option \'last\' no longer supported');
264        }
265        $platform = $this->getPersistence()->getPlatForm();
266
267        // Define language if required
268        $defaultLg = '';
269        if (isset($options['lg'])) {
270            $lang = $options['lg'];
271        } else {
272            $lang = $this->getDataLanguage();
273            $default = $this->getServiceLocator()->get(UserLanguageServiceInterface::SERVICE_ID)->getDefaultLanguage();
274            $defaultLg = ' OR l_language = ' . $this->getPersistence()->quote($default);
275        }
276
277        // TODO: refactor this to use a triple retrieving method.
278        $query =  'SELECT object, l_language
279                    FROM statements 
280                    WHERE subject = ? 
281                    AND predicate = ?
282                    AND (l_language = ? OR l_language = ' . $this->getPersistence()->quote('') . $defaultLg . ')
283                    AND ' . $this->getModelReadSqlCondition();
284
285        if ($one) {
286            // Select first
287            $query .= ' ORDER BY id DESC';
288            $query = $platform->limitStatement($query, 1, 0);
289            $result = $this->getPersistence()->query($query, [$resource->getUri(), $property->getUri(), $lang]);
290        } else {
291            // Select All
292            $result = $this->getPersistence()->query($query, [$resource->getUri(), $property->getUri(), $lang]);
293        }
294
295        // Treat the query result
296        if ($result == true) {
297            if (isset($options['lg'])) {
298                // If a language has been defined, do not filter result by language
299                while ($row = $result->fetch()) {
300                    $returnValue[] = $this->getPersistence()->getPlatForm()->getPhpTextValue($row['object']);
301                }
302            } else {
303                // Filter result by language and return one set of values (User language in top priority, default
304                // language in second and the fallback language (null) in third)
305                $returnValue = core_kernel_persistence_smoothsql_Utils::filterByLanguage(
306                    $this->getPersistence(),
307                    $result->fetchAll(),
308                    'l_language',
309                    $lang,
310                    $default
311                );
312            }
313        }
314
315        return (array) $returnValue;
316    }
317
318    /**
319     * Short description of method getPropertyValuesByLg
320     *
321     * @access public
322     * @param core_kernel_classes_Resource $resource
323     * @param core_kernel_classes_Property $property
324     * @param string $lg
325     * @return core_kernel_classes_ContainerCollection
326     * @throws core_kernel_persistence_Exception
327     * @author Joel Bout, <joel.bout@tudor.lu>
328     */
329    public function getPropertyValuesByLg(
330        core_kernel_classes_Resource $resource,
331        core_kernel_classes_Property $property,
332        $lg
333    ) {
334        $options =  ['lg' => $lg];
335
336        $returnValue = new core_kernel_classes_ContainerCollection($resource);
337        foreach ($this->getPropertyValues($resource, $property, $options) as $value) {
338            $returnValue->add(common_Utils::toResource($value));
339        }
340
341        return $returnValue;
342    }
343
344    /**
345     * Short description of method setPropertyValue
346     *
347     * @access public
348     * @param core_kernel_classes_Resource $resource
349     * @param core_kernel_classes_Property $property
350     * @param $object
351     * @param null $lg
352     * @return boolean
353     * @author Joel Bout, <joel.bout@tudor.lu>
354     */
355    public function setPropertyValue(
356        core_kernel_classes_Resource $resource,
357        core_kernel_classes_Property $property,
358        $object,
359        $lg = null
360    ) {
361        $object  = $object instanceof core_kernel_classes_Resource ? $object->getUri() : (string) $object;
362        if ($property->isLgDependent()) {
363            $lang = ((null != $lg)
364                ? $lg
365                : $this->getDataLanguage());
366        } else {
367            $lang = '';
368        }
369        $triple = core_kernel_classes_Triple::createTriple(
370            $this->getNewTripleModelId(),
371            $resource->getUri(),
372            $property->getUri(),
373            $object,
374            $lang
375        );
376        return $this->getModel()->getRdfInterface()->add($triple);
377    }
378
379    /**
380     * Short description of method setPropertiesValues
381     *
382     * @access public
383     * @param core_kernel_classes_Resource $resource
384     * @param Resource resource
385     * @return boolean
386     * @author Joel Bout, <joel.bout@tudor.lu>
387     */
388    public function setPropertiesValues(core_kernel_classes_Resource $resource, $properties)
389    {
390        $returnValue = false;
391        $triples = [];
392
393        if (is_array($properties) && count($properties) > 0) {
394
395            /** @var common_session_Session $session */
396            $session = $this->getServiceLocator()->get(SessionService::SERVICE_ID)->getCurrentSession();
397
398            $triples = $this->buildTrippleArray(
399                $resource,
400                $properties,
401                (string)$session->getUser()->getIdentifier(),
402                $session->getDataLanguage()
403            );
404        }
405
406        if (!empty($triples)) {
407            $this->getModel()->getRdfInterface()->addTripleCollection($triples);
408            $returnValue = true;
409        }
410
411        return $returnValue;
412    }
413
414    /**
415     * Short description of method setPropertyValueByLg
416     *
417     * @access public
418     * @param core_kernel_classes_Resource $resource
419     * @param core_kernel_classes_Property $property
420     * @param $value
421     * @param $lg
422     * @return boolean
423     * @author Joel Bout, <joel.bout@tudor.lu>
424     */
425    public function setPropertyValueByLg(
426        core_kernel_classes_Resource $resource,
427        core_kernel_classes_Property $property,
428        $value,
429        $lg
430    ) {
431        $triple = core_kernel_classes_Triple::createTriple(
432            $this->getNewTripleModelId(),
433            $resource->getUri(),
434            $property->getUri(),
435            $value,
436            ($property->isLgDependent() ? $lg : '')
437        );
438        return $this->getModel()->getRdfInterface()->add($triple);
439    }
440
441    /**
442     * Short description of method removePropertyValues
443     *
444     * @access public
445     * @param core_kernel_classes_Resource $resource
446     * @param core_kernel_classes_Property $property
447     * @param array options
448     * @return boolean
449     * @author Joel Bout, <joel.bout@tudor.lu>
450     */
451    public function removePropertyValues(
452        core_kernel_classes_Resource $resource,
453        core_kernel_classes_Property $property,
454        $options = []
455    ) {
456        // Optional params
457        $pattern = isset($options['pattern']) && !is_null($options['pattern']) ? $options['pattern'] : null;
458        $like = isset($options['like']) && $options['like'] == true ? true : false;
459
460        // TODO: refactor this to use a triple store abstraction
461        //build query:
462        $query = 'DELETE FROM statements WHERE subject = ? AND predicate = ?';
463        $objectType = $this->getPersistence()->getPlatForm()->getObjectTypeCondition();
464        $conditions = [];
465        if (is_string($pattern)) {
466            if (!is_null($pattern)) {
467                $searchPattern = core_kernel_persistence_smoothsql_Utils::buildSearchPattern(
468                    $this->getPersistence(),
469                    $pattern,
470                    $like
471                );
472                $conditions[] = '( ' . $objectType . ' ' . $searchPattern . ' )';
473            }
474        } elseif (is_array($pattern)) {
475            if (count($pattern) > 0) {
476                $multiCondition =  "( ";
477                foreach ($pattern as $i => $patternToken) {
478                    $searchPattern = core_kernel_persistence_smoothsql_Utils::buildSearchPattern(
479                        $this->getPersistence(),
480                        $patternToken,
481                        $like
482                    );
483                    if ($i > 0) {
484                        $multiCondition .= " OR ";
485                    }
486                    $multiCondition .= '(' . $objectType . ' ' . $searchPattern . ' )';
487                }
488                $conditions[] = "{$multiCondition} ) ";
489            }
490        }
491
492        foreach ($conditions as $i => $additionalCondition) {
493            $query .= " AND ( {$additionalCondition} ) ";
494        }
495
496        //be sure the property we try to remove is included in an updatable model
497        $query .= ' AND ' . $this->getModelWriteSqlCondition();
498
499        if ($property->isLgDependent()) {
500            $query .=  ' AND (l_language = ? OR l_language = ?) ';
501            $returnValue = $this->getPersistence()->exec($query, [
502                $resource->getUri(),
503                $property->getUri(),
504                '',
505                $this->getDataLanguage()
506            ]);
507        } else {
508            $returnValue = $this->getPersistence()->exec($query, [
509                $resource->getUri(),
510                $property->getUri()
511            ]);
512        }
513
514        if (!$returnValue) {
515            $returnValue = false;
516        }
517
518        return (bool) $returnValue;
519    }
520
521    /**
522     * Short description of method removePropertyValueByLg
523     *
524     * @access public
525     * @param core_kernel_classes_Resource $resource
526     * @param core_kernel_classes_Property $property
527     * @param Resource resource
528     * @param array $options
529     * @return boolean
530     * @author Joel Bout, <joel.bout@tudor.lu>
531     */
532    public function removePropertyValueByLg(
533        core_kernel_classes_Resource $resource,
534        core_kernel_classes_Property $property,
535        $lg,
536        $options = []
537    ) {
538        $sqlQuery = 'DELETE FROM statements WHERE subject = ? and predicate = ? and l_language = ?';
539        //be sure the property we try to remove is included in an updatable model
540        $sqlQuery .= ' AND ' . $this->getModelWriteSqlCondition();
541
542        $returnValue = $this->getPersistence()->exec($sqlQuery, [
543            $resource->getUri(),
544            $property->getUri(),
545            ($property->isLgDependent() ? $lg : ''),
546        ]);
547
548        if (!$returnValue) {
549            $returnValue = false;
550        }
551
552        return (bool) $returnValue;
553    }
554
555    /**
556     * returns the triples having as subject the current resource
557     *
558     * @access public
559     * @author Joel Bout, <joel@taotesting.com>
560     * @param  core_kernel_classes_Resource resource
561     * @return core_kernel_classes_ContainerCollection
562     */
563    public function getRdfTriples(core_kernel_classes_Resource $resource)
564    {
565        // TODO: refactor this to use a triple store abstraction
566        $query = 'SELECT * FROM statements WHERE subject = ? AND ' . $this->getModelReadSqlCondition()
567            . ' ORDER BY predicate';
568        $result = $this->getPersistence()->query($query, [$resource->getUri()]);
569
570        $returnValue = new core_kernel_classes_ContainerCollection(new common_Object(__METHOD__));
571        while ($statement = $result->fetch()) {
572            $triple = new core_kernel_classes_Triple();
573            $triple->modelid = $statement["modelid"];
574            $triple->subject = $statement["subject"];
575            $triple->predicate = $statement["predicate"];
576            $triple->object = $statement["object"];
577            $triple->id = $statement["id"];
578            $triple->epoch = $statement["epoch"];
579            $triple->lg = $statement["l_language"];
580            $triple->author = $statement["author"];
581            $returnValue->add($triple);
582        }
583
584        return $returnValue;
585    }
586
587    public function isWritable(core_kernel_classes_Resource $resource): bool
588    {
589        return $this->model->isWritable($resource);
590    }
591
592    /**
593     * Short description of method getUsedLanguages
594     *
595     * @access public
596     * @param core_kernel_classes_Resource $resource
597     * @param core_kernel_classes_Property $property
598     * @return array
599     * @author Joel Bout, <joel.bout@tudor.lu>
600     */
601    public function getUsedLanguages(core_kernel_classes_Resource $resource, core_kernel_classes_Property $property)
602    {
603        $returnValue = [];
604
605        $sqlQuery = 'SELECT l_language FROM statements WHERE subject = ? AND predicate = ? ';
606        $sqlResult = $this->getPersistence()->query($sqlQuery, [
607            $resource->getUri(),
608            $property->getUri(),
609        ]);
610        while ($row = $sqlResult->fetch()) {
611            if (!empty($row['l_language'])) {
612                $returnValue[] = $row['l_language'];
613            }
614        }
615
616        return $returnValue;
617    }
618
619    /**
620     * Short description of method duplicate
621     *
622     * @access public
623     * @param core_kernel_classes_Resource $resource
624     * @param array excludedProperties
625     * @return core_kernel_classes_Resource
626     * @author Joel Bout, <joel.bout@tudor.lu>
627     */
628    public function duplicate(core_kernel_classes_Resource $resource, $excludedProperties = [])
629    {
630        $returnValue = null;
631        $newUri = $this->getServiceLocator()->get(UriProvider::SERVICE_ID)->provide();
632        $collection = $this->getRdfTriples($resource);
633
634        if ($collection->count() > 0) {
635            $user = $this->getServiceLocator()->get(SessionService::SERVICE_ID)->getCurrentUser()->getIdentifier();
636            $triples = [];
637
638            foreach ($collection->getIterator() as $triple) {
639                if (!in_array($triple->predicate, $excludedProperties)) {
640                    $triples[] = core_kernel_classes_Triple::createTriple(
641                        $this->getNewTripleModelId(),
642                        $newUri,
643                        $triple->predicate,
644                        ($triple->object == null) ? '' : $triple->object,
645                        ($triple->lg == null) ? '' : $triple->lg,
646                        (string)$user
647                    );
648                }
649            }
650
651            if (!empty($triples)) {
652                $this->getModel()->getRdfInterface()->addTripleCollection($triples);
653                $returnValue = $this->getModel()->getResource($newUri);
654            }
655        }
656
657        return $returnValue;
658    }
659
660    /**
661     * Short description of method delete
662     *
663     * @access public
664     * @param core_kernel_classes_Resource $resource
665     * @param boolean deleteReference
666     * @return boolean
667     * @author Joel Bout, <joel.bout@tudor.lu>
668     */
669    public function delete(core_kernel_classes_Resource $resource, $deleteReference = false)
670    {
671        $query = 'DELETE FROM statements WHERE subject = ? AND ' . $this->getModelWriteSqlCondition();
672        $returnValue = $this->getPersistence()->exec($query, [$resource->getUri()]);
673
674        //if no rows affected return false
675        if (!$returnValue) {
676            $returnValue = false;
677        } elseif ($deleteReference) {
678            $sqlQuery = 'DELETE FROM statements WHERE '
679                . $this->getPersistence()->getPlatForm()->getObjectTypeCondition() . ' = ? AND '
680                . $this->getModelWriteSqlCondition();
681            $return = $this->getPersistence()->exec($sqlQuery, [$resource->getUri()]);
682
683            if ($return !== false) {
684                $returnValue = true;
685            }
686        }
687
688        return (bool) $returnValue;
689    }
690
691    /**
692     * Short description of method getPropertiesValues
693     *
694     * @access public
695     * @param core_kernel_classes_Resource $resource
696     * @param Resource resource
697     * @return array
698     * @author Joel Bout, <joel.bout@tudor.lu>
699     */
700    public function getPropertiesValues(core_kernel_classes_Resource $resource, $properties)
701    {
702        $returnValue = [];
703
704        // check whenever or not properties is empty
705        if (count($properties) == 0) {
706            return [];
707        }
708
709        $predicatesQuery = '';
710        //build the predicate query
711        //$predicatesQuery = implode(',', $properties);
712        foreach ($properties as $property) {
713            $uri = (is_string($property) ? $property : $property->getUri());
714            $returnValue[$uri] = [];
715            $predicatesQuery .= ", " . $this->getPersistence()->quote($uri);
716        }
717        $predicatesQuery = substr($predicatesQuery, 1);
718
719        $platform = $this->getPersistence()->getPlatForm();
720        $lang = $this->getDataLanguage();
721        $default = $this->getServiceLocator()->get(UserLanguageServiceInterface::SERVICE_ID)->getDefaultLanguage();
722
723        // TODO: refactor this to use a triple store abstraction
724        //the unique sql query
725        $query =  'SELECT predicate, object, l_language 
726            FROM statements 
727            WHERE 
728                subject = ' . $this->getPersistence()->quote($resource->getUri()) . 
729                AND predicate IN (' . $predicatesQuery . ')
730                AND (l_language = ' . $this->getPersistence()->quote('') .
731                    ' OR l_language = ' . $this->getPersistence()->quote($default) .
732                    ' OR l_language = ' . $this->getPersistence()->quote($lang) . ')
733                AND ' . $this->getModelReadSqlCondition();
734        $result = $this->getPersistence()->query($query);
735
736        $rows = $result->fetchAll();
737        foreach ($rows as $row) {
738            $value = $platform->getPhpTextValue($row['object']);
739            $returnValue[$row['predicate']][] = common_Utils::isUri($value)
740                ? $this->getModel()->getResource($value)
741                : new core_kernel_classes_Literal($value);
742        }
743
744        return (array) $returnValue;
745    }
746
747    /**
748     * Short description of method setType
749     *
750     * @access public
751     * @param core_kernel_classes_Resource $resource
752     * @param core_kernel_classes_Class $class
753     * @return boolean
754     * @author Joel Bout, <joel.bout@tudor.lu>
755     */
756    public function setType(core_kernel_classes_Resource $resource, core_kernel_classes_Class $class)
757    {
758        return $this->setPropertyValue($resource, $this->getModel()->getProperty(OntologyRdf::RDF_TYPE), $class);
759    }
760
761    /**
762     * Short description of method removeType
763     *
764     * @access public
765     * @param core_kernel_classes_Resource $resource
766     * @param core_kernel_classes_Class $class
767     * @return boolean
768     * @author Joel Bout, <joel.bout@tudor.lu>
769     */
770    public function removeType(core_kernel_classes_Resource $resource, core_kernel_classes_Class $class)
771    {
772        $query =  'DELETE FROM statements WHERE subject = ? AND predicate = ? AND '
773            . $this->getPersistence()->getPlatForm()->getObjectTypeCondition() . ' = ?';
774
775        //be sure the property we try to remove is included in an updatable model
776        $query .= ' AND ' . $this->getModelWriteSqlCondition();
777
778        $returnValue = $this->getPersistence()->exec($query, [
779            $resource->getUri(),
780            OntologyRdf::RDF_TYPE,
781            $class->getUri()
782        ]);
783
784        $returnValue = true;
785
786        return $returnValue;
787    }
788
789    /**
790     * @return ServiceLocatorInterface
791     */
792    public function getServiceLocator()
793    {
794        return $this->getModel()->getServiceLocator();
795    }
796
797    /**
798     * @param core_kernel_classes_Resource $resource
799     * @param array $properties
800     * @param string $userIdentifier
801     * @param string $dataLanguage
802     * @return array
803     */
804    private function buildTrippleArray(
805        core_kernel_classes_Resource $resource,
806        array $properties,
807        string $userIdentifier,
808        string $dataLanguage
809    ) {
810        $triples = [];
811        foreach ($properties as $propertyUri => $value) {
812            $property = $this->getModel()->getProperty($propertyUri);
813
814            $lang = ($property->isLgDependent() ? $dataLanguage : '');
815
816            $formattedValues = $this->normalizePropertyValues($value);
817
818            foreach ($formattedValues as $object) {
819                $triples[] = core_kernel_classes_Triple::createTriple(
820                    $this->getNewTripleModelId(),
821                    $resource->getUri(),
822                    $property->getUri(),
823                    $object,
824                    $lang,
825                    $userIdentifier
826                );
827            }
828        }
829
830        return $triples;
831    }
832
833    /**
834     * @param $value
835     * @param array $formattedValues
836     * @return array
837     */
838    private function normalizePropertyValues($value)
839    {
840        $normalizedValues = [];
841        if ($value instanceof core_kernel_classes_Resource) {
842            $normalizedValues[] = $value->getUri();
843        } elseif (is_array($value)) {
844            foreach ($value as $val) {
845                if ($val !== null) {
846                    $normalizedValues[] = $val instanceof core_kernel_classes_Resource
847                        ? $val->getUri()
848                        : $val;
849                }
850            }
851        } else {
852            $normalizedValues[] = ($value == null) ? '' : $value;
853        }
854        return $normalizedValues;
855    }
856
857    /**
858     * @return mixed
859     */
860    private function getDataLanguage()
861    {
862        return $this->getServiceLocator()->get(SessionService::SERVICE_ID)->getCurrentSession()->getDataLanguage();
863    }
864}