1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* File containing the eZ\Publish\Core\Repository\SearchService class. |
5
|
|
|
* |
6
|
|
|
* @copyright Copyright (C) eZ Systems AS. All rights reserved. |
7
|
|
|
* @license For full copyright and license information view LICENSE file distributed with this source code. |
8
|
|
|
*/ |
9
|
|
|
namespace eZ\Publish\Core\Repository; |
10
|
|
|
|
11
|
|
|
use eZ\Publish\API\Repository\SearchService as SearchServiceInterface; |
12
|
|
|
use eZ\Publish\API\Repository\SearchServiceSortClause as SearchServiceSortClauseInterface; |
13
|
|
|
use eZ\Publish\API\Repository\Values\Content\Location; |
14
|
|
|
use eZ\Publish\API\Repository\Values\Content\Query\Criterion; |
15
|
|
|
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalOperator; |
16
|
|
|
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\Location as LocationCriterion; |
17
|
|
|
use eZ\Publish\API\Repository\Values\Content\Query\SortClause\Location as LocationSortClause; |
18
|
|
|
use eZ\Publish\API\Repository\Values\Content\Query; |
19
|
|
|
use eZ\Publish\API\Repository\Values\Content\LocationQuery; |
20
|
|
|
use eZ\Publish\API\Repository\Repository as RepositoryInterface; |
21
|
|
|
use eZ\Publish\API\Repository\Values\Content\Search\SearchResult; |
22
|
|
|
use eZ\Publish\Core\Base\Exceptions\NotFoundException; |
23
|
|
|
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException; |
24
|
|
|
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentType; |
25
|
|
|
use eZ\Publish\Core\Repository\Mapper\SortClauseMapper; |
26
|
|
|
use eZ\Publish\SPI\Search\Handler; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Search service. |
30
|
|
|
*/ |
31
|
|
|
class SearchService implements SearchServiceInterface, SearchServiceSortClauseInterface |
|
|
|
|
32
|
|
|
{ |
33
|
|
|
/** |
34
|
|
|
* @var \eZ\Publish\Core\Repository\Repository |
35
|
|
|
*/ |
36
|
|
|
protected $repository; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var \eZ\Publish\SPI\Search\Handler |
40
|
|
|
*/ |
41
|
|
|
protected $searchHandler; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @var array |
45
|
|
|
*/ |
46
|
|
|
protected $settings; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* @var \eZ\Publish\Core\Repository\Helper\DomainMapper |
50
|
|
|
*/ |
51
|
|
|
protected $domainMapper; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @var \eZ\Publish\Core\Repository\PermissionsCriterionHandler |
55
|
|
|
*/ |
56
|
|
|
protected $permissionsCriterionHandler; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* @var \eZ\Publish\Core\Repository\Mapper\SortClauseMapper |
60
|
|
|
*/ |
61
|
|
|
protected $sortClauseMapper; |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Setups service with reference to repository object that created it & corresponding handler. |
65
|
|
|
* |
66
|
|
|
* @param \eZ\Publish\API\Repository\Repository $repository |
67
|
|
|
* @param \eZ\Publish\SPI\Search\Handler $searchHandler |
68
|
|
|
* @param \eZ\Publish\Core\Repository\Helper\DomainMapper $domainMapper |
69
|
|
|
* @param \eZ\Publish\Core\Repository\PermissionsCriterionHandler $permissionsCriterionHandler |
70
|
|
|
* @param \eZ\Publish\Core\Repository\Mapper\SortClauseMapper $sortClauseMapper |
71
|
|
|
* @param array $settings |
72
|
|
|
*/ |
73
|
|
|
public function __construct( |
74
|
|
|
RepositoryInterface $repository, |
75
|
|
|
Handler $searchHandler, |
76
|
|
|
Helper\DomainMapper $domainMapper, |
77
|
|
|
PermissionsCriterionHandler $permissionsCriterionHandler, |
78
|
|
|
SortClauseMapper $sortClauseMapper, |
79
|
|
|
array $settings = array() |
80
|
|
|
) { |
81
|
|
|
$this->repository = $repository; |
|
|
|
|
82
|
|
|
$this->searchHandler = $searchHandler; |
83
|
|
|
$this->domainMapper = $domainMapper; |
84
|
|
|
// Union makes sure default settings are ignored if provided in argument |
85
|
|
|
$this->settings = $settings + array( |
86
|
|
|
//'defaultSetting' => array(), |
87
|
|
|
); |
88
|
|
|
$this->permissionsCriterionHandler = $permissionsCriterionHandler; |
89
|
|
|
$this->sortClauseMapper = $sortClauseMapper; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Finds content objects for the given query. |
94
|
|
|
* |
95
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if query is not valid |
96
|
|
|
* |
97
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Query $query |
98
|
|
|
* @param array $languageFilter Configuration for specifying prioritized languages query will be performed on. |
99
|
|
|
* Currently supports: <code>array("languages" => array(<language1>,..), "useAlwaysAvailable" => bool)</code> |
100
|
|
|
* useAlwaysAvailable defaults to true to avoid exceptions on missing translations. |
101
|
|
|
* @param bool $filterOnUserPermissions if true only the objects which the user is allowed to read are returned. |
102
|
|
|
* |
103
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Search\SearchResult |
104
|
|
|
*/ |
105
|
|
|
public function findContent(Query $query, array $languageFilter = array(), $filterOnUserPermissions = true) |
106
|
|
|
{ |
107
|
|
|
$contentService = $this->repository->getContentService(); |
108
|
|
|
$result = $this->internalFindContentInfo($query, $languageFilter, $filterOnUserPermissions); |
109
|
|
|
foreach ($result->searchHits as $hit) { |
110
|
|
|
// As we get ContentInfo from SPI, we need to load full content (avoids getting stale content data) |
111
|
|
|
$hit->valueObject = $contentService->internalLoadContent( |
|
|
|
|
112
|
|
|
$hit->valueObject->id, |
113
|
|
|
(!empty($languageFilter['languages']) ? $languageFilter['languages'] : null), |
114
|
|
|
null, |
115
|
|
|
false, |
116
|
|
|
(isset($languageFilter['useAlwaysAvailable']) ? $languageFilter['useAlwaysAvailable'] : true) |
117
|
|
|
); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
return $result; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Finds contentInfo objects for the given query. |
125
|
|
|
* |
126
|
|
|
* @see SearchServiceInterface::findContentInfo() |
127
|
|
|
* |
128
|
|
|
* @since 5.4.5 |
129
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if query is not valid |
130
|
|
|
* |
131
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Query $query |
132
|
|
|
* @param array $languageFilter - a map of filters for the returned fields. |
133
|
|
|
* Currently supports: <code>array("languages" => array(<language1>,..), "useAlwaysAvailable" => bool)</code> |
134
|
|
|
* useAlwaysAvailable defaults to true to avoid exceptions on missing translations. |
135
|
|
|
* @param bool $filterOnUserPermissions if true (default) only the objects which is the user allowed to read are returned. |
136
|
|
|
* |
137
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Search\SearchResult |
138
|
|
|
*/ |
139
|
|
|
public function findContentInfo(Query $query, array $languageFilter = array(), $filterOnUserPermissions = true) |
140
|
|
|
{ |
141
|
|
|
$result = $this->internalFindContentInfo($query, $languageFilter, $filterOnUserPermissions); |
142
|
|
|
foreach ($result->searchHits as $hit) { |
143
|
|
|
$hit->valueObject = $this->domainMapper->buildContentInfoDomainObject( |
144
|
|
|
$hit->valueObject |
145
|
|
|
); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
return $result; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* Finds SPI content info objects for the given query. |
153
|
|
|
* |
154
|
|
|
* Internal for use by {@link findContent} and {@link findContentInfo}. |
155
|
|
|
* |
156
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if query is not valid |
157
|
|
|
* |
158
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Query $query |
159
|
|
|
* @param array $languageFilter - a map of filters for the returned fields. |
160
|
|
|
* Currently supports: <code>array("languages" => array(<language1>,..), "useAlwaysAvailable" => bool)</code> |
161
|
|
|
* useAlwaysAvailable defaults to true to avoid exceptions on missing translations. |
162
|
|
|
* @param bool $filterOnUserPermissions if true only the objects which is the user allowed to read are returned. |
163
|
|
|
* |
164
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Search\SearchResult With "raw" SPI contentInfo objects in result |
165
|
|
|
*/ |
166
|
|
|
protected function internalFindContentInfo(Query $query, array $languageFilter = array(), $filterOnUserPermissions = true) |
167
|
|
|
{ |
168
|
|
|
if (!is_int($query->offset)) { |
169
|
|
|
throw new InvalidArgumentType( |
170
|
|
|
'$query->offset', |
171
|
|
|
'integer', |
172
|
|
|
$query->offset |
173
|
|
|
); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
if (!is_int($query->limit)) { |
177
|
|
|
throw new InvalidArgumentType( |
178
|
|
|
'$query->limit', |
179
|
|
|
'integer', |
180
|
|
|
$query->limit |
181
|
|
|
); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
$query = clone $query; |
185
|
|
|
$query->filter = $query->filter ?: new Criterion\MatchAll(); |
186
|
|
|
|
187
|
|
|
$this->validateContentCriteria(array($query->query), '$query'); |
188
|
|
|
$this->validateContentCriteria(array($query->filter), '$query'); |
189
|
|
|
$this->validateContentSortClauses($query); |
190
|
|
|
|
191
|
|
View Code Duplication |
if ($filterOnUserPermissions && !$this->permissionsCriterionHandler->addPermissionsCriterion($query->filter)) { |
|
|
|
|
192
|
|
|
return new SearchResult(array('time' => 0, 'totalCount' => 0)); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
return $this->searchHandler->findContent($query, $languageFilter); |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Checks that $criteria does not contain Location criterions. |
200
|
|
|
* |
201
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException |
202
|
|
|
* |
203
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion[] $criteria |
204
|
|
|
* @param string $argumentName |
205
|
|
|
*/ |
206
|
|
|
protected function validateContentCriteria(array $criteria, $argumentName) |
207
|
|
|
{ |
208
|
|
|
foreach ($criteria as $criterion) { |
209
|
|
|
if ($criterion instanceof LocationCriterion) { |
210
|
|
|
throw new InvalidArgumentException( |
211
|
|
|
$argumentName, |
212
|
|
|
'Location criterions cannot be used in Content search' |
213
|
|
|
); |
214
|
|
|
} |
215
|
|
|
if ($criterion instanceof LogicalOperator) { |
216
|
|
|
$this->validateContentCriteria($criterion->criteria, $argumentName); |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* Checks that $query does not contain Location sort clauses. |
223
|
|
|
* |
224
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException |
225
|
|
|
* |
226
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Query $query |
227
|
|
|
*/ |
228
|
|
|
protected function validateContentSortClauses(Query $query) |
229
|
|
|
{ |
230
|
|
|
foreach ($query->sortClauses as $sortClause) { |
231
|
|
|
if ($sortClause instanceof LocationSortClause) { |
232
|
|
|
throw new InvalidArgumentException('$query', 'Location sort clauses cannot be used in Content search'); |
233
|
|
|
} |
234
|
|
|
} |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* Performs a query for a single content object. |
239
|
|
|
* |
240
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException if the object was not found by the query or due to permissions |
241
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if criterion is not valid |
242
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if there is more than one result matching the criterions |
243
|
|
|
* |
244
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $filter |
245
|
|
|
* @param array $languageFilter Configuration for specifying prioritized languages query will be performed on. |
246
|
|
|
* Currently supports: <code>array("languages" => array(<language1>,..), "useAlwaysAvailable" => bool)</code> |
247
|
|
|
* useAlwaysAvailable defaults to true to avoid exceptions on missing translations. |
248
|
|
|
* @param bool $filterOnUserPermissions if true only the objects which is the user allowed to read are returned. |
249
|
|
|
* |
250
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Content |
251
|
|
|
*/ |
252
|
|
|
public function findSingle(Criterion $filter, array $languageFilter = array(), $filterOnUserPermissions = true) |
253
|
|
|
{ |
254
|
|
|
$this->validateContentCriteria(array($filter), '$filter'); |
255
|
|
|
|
256
|
|
|
if ($filterOnUserPermissions && !$this->permissionsCriterionHandler->addPermissionsCriterion($filter)) { |
257
|
|
|
throw new NotFoundException('Content', '*'); |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
$contentInfo = $this->searchHandler->findSingle($filter, $languageFilter); |
261
|
|
|
|
262
|
|
|
return $this->repository->getContentService()->internalLoadContent( |
|
|
|
|
263
|
|
|
$contentInfo->id, |
264
|
|
|
(!empty($languageFilter['languages']) ? $languageFilter['languages'] : null), |
265
|
|
|
null, |
266
|
|
|
false, |
267
|
|
|
(isset($languageFilter['useAlwaysAvailable']) ? $languageFilter['useAlwaysAvailable'] : true) |
268
|
|
|
); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* Suggests a list of values for the given prefix. |
273
|
|
|
* |
274
|
|
|
* @param string $prefix |
275
|
|
|
* @param string[] $fieldPaths |
276
|
|
|
* @param int $limit |
277
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $filter |
278
|
|
|
*/ |
279
|
|
|
public function suggest($prefix, $fieldPaths = array(), $limit = 10, Criterion $filter = null) |
280
|
|
|
{ |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
/** |
284
|
|
|
* Finds Locations for the given query. |
285
|
|
|
* |
286
|
|
|
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException if query is not valid |
287
|
|
|
* |
288
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\LocationQuery $query |
289
|
|
|
* @param array $languageFilter Configuration for specifying prioritized languages query will be performed on. |
290
|
|
|
* Currently supports: <code>array("languages" => array(<language1>,..), "useAlwaysAvailable" => bool)</code> |
291
|
|
|
* useAlwaysAvailable defaults to true to avoid exceptions on missing translations |
292
|
|
|
* @param bool $filterOnUserPermissions if true only the objects which is the user allowed to read are returned. |
293
|
|
|
* |
294
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Search\SearchResult |
295
|
|
|
*/ |
296
|
|
|
public function findLocations(LocationQuery $query, array $languageFilter = array(), $filterOnUserPermissions = true) |
297
|
|
|
{ |
298
|
|
|
if (!is_int($query->offset)) { |
299
|
|
|
throw new InvalidArgumentType( |
300
|
|
|
'$query->offset', |
301
|
|
|
'integer', |
302
|
|
|
$query->offset |
303
|
|
|
); |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
if (!is_int($query->limit)) { |
307
|
|
|
throw new InvalidArgumentType( |
308
|
|
|
'$query->limit', |
309
|
|
|
'integer', |
310
|
|
|
$query->limit |
311
|
|
|
); |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
$query = clone $query; |
315
|
|
|
$query->filter = $query->filter ?: new Criterion\MatchAll(); |
316
|
|
|
|
317
|
|
View Code Duplication |
if ($filterOnUserPermissions && !$this->permissionsCriterionHandler->addPermissionsCriterion($query->filter)) { |
|
|
|
|
318
|
|
|
return new SearchResult(array('time' => 0, 'totalCount' => 0)); |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
$result = $this->searchHandler->findLocations($query, $languageFilter); |
322
|
|
|
|
323
|
|
|
foreach ($result->searchHits as $hit) { |
324
|
|
|
$hit->valueObject = $this->domainMapper->buildLocationDomainObject( |
325
|
|
|
$hit->valueObject |
326
|
|
|
); |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
return $result; |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
/** |
333
|
|
|
* Get SortClause objects built from $location's sort options. |
334
|
|
|
* |
335
|
|
|
* @param \eZ\Publish\API\Repository\Values\Content\Location $location |
336
|
|
|
* |
337
|
|
|
* @return \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] |
338
|
|
|
*/ |
339
|
|
|
public function getSortClauseFromLocation(Location $location) |
340
|
|
|
{ |
341
|
|
|
return $this->sortClauseMapper->getSortClauseFromLocation($location); |
342
|
|
|
} |
343
|
|
|
} |
344
|
|
|
|
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.