Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
25.33% covered (danger)
25.33%
19 / 75
33.33% covered (danger)
33.33%
3 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
ResourceService
25.33% covered (danger)
25.33%
19 / 75
33.33% covered (danger)
33.33%
3 / 9
575.49
0.00% covered (danger)
0.00%
0 / 1
 getAllClasses
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getSubClasses
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
4
 getNestingLevelLimit
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getResources
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getClasses
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getResourcesPermissions
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 getPropertyFilters
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
110
 getResourceLookup
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 getUris
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
90
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) 2017 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
19 *
20 */
21
22namespace oat\tao\model\resources;
23
24use common_Logger;
25use core_kernel_classes_Class;
26use core_kernel_classes_Resource;
27use Exception;
28use oat\generis\model\data\permission\PermissionInterface;
29use oat\oatbox\service\ConfigurableService;
30use oat\oatbox\service\exception\InvalidServiceManagerException;
31use oat\oatbox\user\User;
32
33/**
34 * This service let's you access resources
35 *
36 * @author Bertrand Chevrier <bertrand@taotesting.com>
37 */
38class ResourceService extends ConfigurableService
39{
40    public const SERVICE_ID = 'tao/ResourceService';
41
42    public const LABEL_URI  = 'http://www.w3.org/2000/01/rdf-schema#label';
43
44    public const OPTION_CLASS_NESTING_LEVEL = 'class-nesting-level';
45
46    private const DEFAULT_CLASS_NESTING_LEVEL = 999;
47
48    /**
49     * The different lookup formats
50     */
51    private static $formats = ['list', 'tree'];
52
53    /**
54     * The lookup instances by format
55     */
56    private $lookups;
57
58    /**
59     * Get the list of  classes from the given root class
60     *
61     * @param core_kernel_classes_Class $rootClass the root class
62     * @return array the classes hierarchy
63     */
64    public function getAllClasses(core_kernel_classes_Class $rootClass): array
65    {
66        return [
67            'uri'      => $rootClass->getUri(),
68            'label'    => $rootClass->getLabel(),
69            'children' => $this->getSubClasses($rootClass->getSubClasses(false))
70        ];
71    }
72
73    /**
74     * Get the class subclasses
75     *
76     * @param core_kernel_classes_Class[] $subClasses
77     * @param int                         $nestingLevel
78     *
79     * @return array the classes hierarchy
80     */
81    private function getSubClasses(array $subClasses, int $nestingLevel = 0): array
82    {
83        if ($nestingLevel >= $this->getNestingLevelLimit()) {
84            return [];
85        }
86
87        $result = [];
88
89        foreach ($subClasses as $subClass) {
90            $children = $subClass->getSubClasses(false);
91            $entry = [
92                'uri' => $subClass->getUri(),
93                'label' => $subClass->getLabel()
94            ];
95
96            if (count($children) > 0) {
97                $entry['children'] = $this->getSubClasses($children, $nestingLevel + 1);
98            }
99
100            $result[] = $entry;
101        }
102
103        return $result;
104    }
105
106    private function getNestingLevelLimit(): int
107    {
108        return $this->getOption(self::OPTION_CLASS_NESTING_LEVEL) ?? self::DEFAULT_CLASS_NESTING_LEVEL;
109    }
110
111    /**
112     * Retrieve the resources for the given parameters
113     *
114     * @param core_kernel_classes_Class $rootClass
115     * @param string                    $format the lookup format
116     * @param array                     $selectedUris
117     * @param string|array              $search to filter by label if a string or provides the search filters
118     * @param int                       $offset for paging
119     * @param int                       $limit  for paging
120     *
121     * @return core_kernel_classes_Class[] the resources
122     * @throws InvalidServiceManagerException
123     */
124    public function getResources(
125        core_kernel_classes_Class $rootClass,
126        $format = 'list',
127        $selectedUris = [],
128        $search = '',
129        $offset = 0,
130        $limit = 30
131    ): array {
132        $propertyFilters = $this->getPropertyFilters($search);
133
134        $result = [];
135
136        $resourceLookup = $this->getResourceLookup($format);
137        if (!is_null($resourceLookup)) {
138            $result = $resourceLookup->getResources($rootClass, $selectedUris, $propertyFilters, $offset, $limit);
139        }
140
141        return $result;
142    }
143
144    /**
145     * Retrieve the classes for the given parameters
146     *
147     * @param core_kernel_classes_Class $rootClass
148     * @param string                    $format the lookup format
149     * @param array                     $selectedUris
150     * @param string|array              $search to filter by label if a string or provides the search filters
151     * @param int                       $offset for paging
152     * @param int                       $limit  for paging
153     *
154     * @return core_kernel_classes_Class[] the classes
155     * @throws InvalidServiceManagerException
156     */
157    public function getClasses(
158        core_kernel_classes_Class $rootClass,
159        $format = 'list',
160        $selectedUris = [],
161        $search = '',
162        $offset = 0,
163        $limit = 30
164    ): array {
165        $propertyFilters = $this->getPropertyFilters($search);
166
167        $result = [];
168
169        $resourceLookup = $this->getResourceLookup($format);
170        if (!is_null($resourceLookup)) {
171            $result = $resourceLookup->getClasses($rootClass, $selectedUris, $propertyFilters, $offset, $limit);
172        }
173        return $result;
174    }
175
176    /**
177     * Get the permissions for a list of resources.
178     *
179     * @param User $user the user to check the permissions
180     * @param array $resources the resources to get the permissions
181     *
182     * @return array the available rights and the permissions per resource
183     */
184    public function getResourcesPermissions(User $user, $resources): array
185    {
186        $permissions = [];
187        if (!is_null($user)) {
188            try {
189                $permissionManager = $this->getServiceManager()->get(PermissionInterface::SERVICE_ID);
190                $supportedRights   = $permissionManager->getSupportedRights();
191                $permissions['supportedRights'] = $supportedRights;
192
193                if (count($supportedRights) > 0) {
194                    $uris = $this->getUris($resources);
195
196                    $permissions['data'] = $permissionManager->getPermissions($user, $uris);
197                }
198            } catch (Exception $e) {
199                common_Logger::w('Unable to retrieve permssions ' . $e->getMessage());
200            }
201        }
202        return $permissions;
203    }
204
205    /**
206     * Get the filters based on the search param
207     *
208     * @param string|array  $search to filter by label if a string or provides the search filters
209     * @return array the list of property filters
210     */
211    private function getPropertyFilters($search = ''): array
212    {
213        $propertyFilters = [];
214
215        if (is_string($search) && strlen(trim($search)) > 0) {
216            $propertyFilters[self::LABEL_URI] = $search;
217        }
218        if (is_array($search)) {
219            foreach ($search as $uri => $value) {
220                if (
221                    is_string($uri) &&
222                    (is_string($value) && strlen(trim($value)) > 0) ||
223                    (is_array($value) && count($value) > 0)
224                ) {
225                    $propertyFilters[$uri] = $value;
226                }
227            }
228        }
229        return $propertyFilters;
230    }
231
232    /**
233     * Get the resource lookup for the given format
234     *
235     * @param $format
236     *
237     * @return ResourceLookup|null
238     *
239     * @throws InvalidServiceManagerException
240     */
241    private function getResourceLookup($format): ?ResourceLookup
242    {
243        if (in_array($format, self::$formats, true)) {
244            if (!isset($this->lookups)) {
245                $this->lookups = [
246                    'list' => $this->getServiceManager()->get(ListResourceLookup::SERVICE_ID),
247                    'tree' => $this->getServiceManager()->get(TreeResourceLookup::SERVICE_ID)
248                ];
249            }
250            return $this->lookups[$format];
251        }
252
253        return null;
254    }
255
256    /**
257     * Walk through the resources (recursively) to get theirs URIs
258     *
259     * @param array|core_kernel_classes_Resource $nodes the tree or a sub tree, a resource or a resource list
260     * @return string[] the list of URIs
261     */
262    private function getUris($nodes): array
263    {
264        $uris = [];
265
266        if ($nodes instanceof core_kernel_classes_Resource) {
267            $uris[] = $nodes->getUri();
268        }
269        if (is_array($nodes)) {
270            //legacy format
271            if (isset($nodes['attributes']['data-uri'])) {
272                $uris[] = $nodes['attributes']['data-uri'];
273            }
274            if (isset($nodes['uri'])) {
275                $uris[] = $nodes['uri'];
276            }
277
278            $treeKeys = array_keys($nodes);
279            if (isset($treeKeys[0]) && is_int($treeKeys[0])) {
280                foreach ($nodes as $node) {
281                    $uris = array_merge($uris, $this->getUris($node));
282                }
283            }
284
285            if (isset($nodes['children'])) {
286                $uris = array_merge($uris, $this->getUris($nodes['children']));
287            }
288        }
289
290        return $uris;
291    }
292}