Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 72
0.00% covered (danger)
0.00%
0 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
AbstractDatatablePayload
0.00% covered (danger)
0.00%
0 / 72
0.00% covered (danger)
0.00%
0 / 16
870
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getPropertiesMap
n/a
0 / 0
n/a
0 / 0
0
 getType
n/a
0 / 0
n/a
0 / 0
0
 getPayload
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getFilters
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doFiltration
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
30
 doPagination
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 doSorting
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 doSearch
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doPostProcessing
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 getPage
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getRows
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSortBy
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSortOrder
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSearchService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 map
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
30
 fetchPropertyValues
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
12
 jsonSerialize
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) 2016 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
19 *
20 */
21
22namespace oat\tao\model\datatable\implementation;
23
24use ArrayIterator;
25use oat\generis\model\kernel\persistence\smoothsql\search\ComplexSearchService;
26use oat\generis\model\kernel\persistence\smoothsql\search\TaoResultSet;
27use oat\oatbox\service\ServiceManager;
28use oat\search\base\QueryBuilderInterface;
29use oat\search\helper\SupportedOperatorHelper;
30use oat\tao\model\datatable\DatatablePayload as DatatablePayloadInterface;
31use oat\tao\model\datatable\DatatableRequest as DatatableRequestInterface;
32use Zend\ServiceManager\ServiceLocatorAwareInterface;
33use Zend\ServiceManager\ServiceLocatorAwareTrait;
34
35/**
36 * class DatatablePayload
37 * @package oat\tao\model\datatable
38 * @author Aleh Hutnikau, <hutnikau@1pt.com>
39 */
40abstract class AbstractDatatablePayload implements DatatablePayloadInterface, ServiceLocatorAwareInterface
41{
42    use ServiceLocatorAwareTrait;
43
44    /**
45     * @var DatatableRequest
46     */
47    protected $request;
48
49    /**
50     * DatatablePayload constructor.
51     * @param DatatableRequestInterface|null $request
52     */
53    public function __construct(DatatableRequestInterface $request = null)
54    {
55        $this->setServiceLocator(ServiceManager::getServiceManager());
56
57        if ($request === null) {
58            $request = DatatableRequest::fromGlobals();
59        }
60
61        $this->request = $request;
62    }
63
64    /**
65     * Get properties map
66     * Example:
67     * ```php
68     * [
69     *    'firstname' => 'http://www.tao.lu/Ontologies/generis.rdf#userFirstName',
70     *    'lastname' => 'http://www.tao.lu/Ontologies/generis.rdf#userLastName',
71     * ]
72     * ```
73     * @return array
74     */
75    abstract protected function getPropertiesMap();
76
77    /**
78     * Get uri of class in which search should be done.
79     * @return string
80     */
81    abstract protected function getType();
82
83    /**
84     * Template method to find data.
85     * Any step (such as filtration, pagination, sorting e.t.c. can be changed in concrete class).
86     */
87    public function getPayload(): array
88    {
89        $queryBuilder = $this->getSearchService()->query();
90
91        $this->doFiltration($queryBuilder);
92        $this->doPagination($queryBuilder);
93        $this->doSorting($queryBuilder);
94        $searchResult = $this->doSearch($queryBuilder);
95
96        return  $this->doPostProcessing($searchResult);
97    }
98
99    /**
100     * @return array
101     */
102    protected function getFilters()
103    {
104        return $this->request->getFilters();
105    }
106
107    /**
108     * Apply filters to search query
109     * @param QueryBuilderInterface $queryBuilder
110     */
111    protected function doFiltration(QueryBuilderInterface $queryBuilder)
112    {
113        $search = $this->getSearchService();
114
115        $filters = $this->map($this->getFilters(), true);
116        $query = $search->searchType($queryBuilder, $this->getType(), true);
117
118        foreach ($filters as $filterProp => $filterVal) {
119            foreach ($filterVal as $values) {
120                if (is_array($values)) {
121                    $query->addCriterion($filterProp, SupportedOperatorHelper::IN, $values);
122                } elseif (is_string($values)) {
123                    $query->addCriterion($filterProp, SupportedOperatorHelper::CONTAIN, $values);
124                }
125            }
126        }
127
128        $queryBuilder->setCriteria($query);
129    }
130
131    /**
132     * @param QueryBuilderInterface $queryBuilder
133     */
134    protected function doPagination(QueryBuilderInterface $queryBuilder)
135    {
136        $rows = $this->getRows();
137        $page = $this->getPage();
138
139        if ($rows > 0) {
140            $queryBuilder->setLimit($rows);
141            $queryBuilder->setOffset(($page - 1) * $rows);
142        }
143    }
144
145    /**
146     * @param QueryBuilderInterface $queryBuilder
147     */
148    protected function doSorting(QueryBuilderInterface $queryBuilder)
149    {
150        $sortBy = $this->getSortBy();
151        $sortOrder = $this->getSortOrder();
152        $queryBuilder->sort($this->map([$sortBy => $sortOrder]));
153    }
154
155    /**
156     * @param QueryBuilderInterface $queryBuilder
157     * @return ArrayIterator search result
158     */
159    protected function doSearch(QueryBuilderInterface $queryBuilder)
160    {
161        return $this->getSearchService()->getGateway()->search($queryBuilder);
162    }
163
164    protected function doPostProcessing(TaoResultSet $result): array
165    {
166        $payload = [
167            'data' => $result->getArrayCopy(),
168            'page' => (int) $this->getPage(),
169            'records' => (int) $result->count(),
170            'total' => $this->getRows() > 0
171                ? ceil($result->total() / $this->getRows())
172                : (int) $result->count()
173        ];
174
175        return $this->fetchPropertyValues($payload);
176    }
177
178    /**
179     * @return int
180     */
181    protected function getPage()
182    {
183        return $this->request->getPage();
184    }
185
186    /**
187     * @return int
188     */
189    protected function getRows()
190    {
191        return $this->request->getRows();
192    }
193
194    /**
195     * @return string
196     */
197    protected function getSortBy()
198    {
199        return $this->request->getSortBy();
200    }
201
202    /**
203     * @return string
204     */
205    protected function getSortOrder()
206    {
207        return $this->request->getSortOrder();
208    }
209
210    /**
211     * @return ComplexSearchService
212     */
213    protected function getSearchService()
214    {
215        return $this->getServiceLocator()->get(ComplexSearchService::SERVICE_ID);
216    }
217
218    /**
219     * Convert array keys specified in the CSV file to keys which are used in the TAO.
220     * If $reverse is `true` reverse conversion will be performed.
221     *
222     * Example:
223     * ```php
224     * $studentCsvMapper->map(['fname' => 'john']);
225     * // ['http://www.tao.lu/Ontologies/generis.rdf#userFirstName' => 'john']
226     * ```
227     * @param array $filter
228     * @param bool|string $multitask will return all filters as [[filter1], [filter2]]
229     * @return array
230     */
231    protected function map($filter, $multitask = false)
232    {
233        $data = [];
234        $map = $this->getPropertiesMap();
235        foreach ($filter as $key => $val) {
236            $key = isset($map[$key]) ? $map[$key] : $key;
237
238            if ($multitask) {
239                if (!is_array($val)) {
240                    $data[$key] = [$val];
241                } else {
242                    $data[$key][] = array_unique($val);
243                }
244            } else {
245                $data[$key] = $val;
246            }
247        }
248
249        return $data;
250    }
251
252
253    /**
254     * Fetch all the values of properties listed in properties map
255     *
256     * @param $payload
257     * @throws \common_exception_InvalidArgumentType
258     */
259    protected function fetchPropertyValues($payload): array
260    {
261        $propertyMap = $this->getPropertiesMap();
262        $data = [];
263        foreach ($payload['data'] as $resource) {
264            $resource = (object)$resource;
265            $resource = new \core_kernel_classes_Resource($resource->subject);
266            $resourceData = $resource->getPropertiesValues($propertyMap);
267            $entityInfo = array_map(function ($row) use ($resourceData) {
268                $stringData = array_map(function ($value) {
269                    return ($value instanceof \core_kernel_classes_Resource) ? $value->getUri() : (string) $value;
270                }, $resourceData[$row]);
271                return join(',', $stringData);
272            }, $propertyMap);
273
274            $entityInfo['uri'] = $resource->getUri();
275            $entityInfo['id'] = \tao_helpers_Uri::encode($resource->getUri());
276            $data[] = $entityInfo;
277        }
278        $payload['data'] = $data;
279
280        return $payload;
281    }
282
283    public function jsonSerialize(): array
284    {
285        return $this->getPayload();
286    }
287}