1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* @copyright Copyright (C) eZ Systems AS. All rights reserved. |
5
|
|
|
* @license For full copyright and license information view LICENSE file distributed with this source code. |
6
|
|
|
*/ |
7
|
|
|
declare(strict_types=1); |
8
|
|
|
|
9
|
|
|
namespace eZ\Publish\API\Repository\Tests\SearchService; |
10
|
|
|
|
11
|
|
|
use eZ\Publish\API\Repository\SearchService; |
12
|
|
|
use eZ\Publish\API\Repository\Tests\BaseTest; |
13
|
|
|
use eZ\Publish\API\Repository\Values\Content\Content; |
14
|
|
|
use eZ\Publish\API\Repository\Values\Content\ContentCreateStruct; |
15
|
|
|
use eZ\Publish\API\Repository\Values\Content\LocationQuery; |
16
|
|
|
use eZ\Publish\API\Repository\Values\Content\Query; |
17
|
|
|
use eZ\Publish\API\Repository\Values\Content\Query\Criterion; |
18
|
|
|
use eZ\Publish\Core\FieldType\RichText\Value as RichTextValue; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* Test case for full text search in the SearchService (for embed). |
22
|
|
|
* |
23
|
|
|
* @see \eZ\Publish\API\Repository\SearchService |
24
|
|
|
* @group integration |
25
|
|
|
* @group search |
26
|
|
|
* @group fulltext |
27
|
|
|
*/ |
28
|
|
|
class SearchServiceFullTextEmbedTest extends BaseTest |
29
|
|
|
{ |
30
|
|
|
private const EMBEDDED_ARTICLE_NAME = 'test1'; |
31
|
|
|
|
32
|
|
|
private static $createdIds = []; |
33
|
|
|
|
34
|
|
|
protected function setUp(): void |
35
|
|
|
{ |
36
|
|
|
parent::setUp(); |
37
|
|
|
|
38
|
|
|
$repository = $this->getRepository(false); |
39
|
|
|
|
40
|
|
|
if ( |
41
|
|
|
false === $repository->getSearchService()->supports( |
42
|
|
|
SearchService::CAPABILITY_ADVANCED_FULLTEXT |
43
|
|
|
) |
44
|
|
|
) { |
45
|
|
|
$this->markTestSkipped( |
46
|
|
|
'Advanced FullText search is not supported by the current search engine' |
47
|
|
|
); |
48
|
|
|
} |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
public function testFullTextContentSearch(): void |
52
|
|
|
{ |
53
|
|
|
$this->prepareTestContent(); |
54
|
|
|
|
55
|
|
|
$searchService = $this->getRepository()->getSearchService(); |
56
|
|
|
|
57
|
|
|
$query = new Query([ |
58
|
|
|
'query' => new Criterion\FullText(self::EMBEDDED_ARTICLE_NAME), |
59
|
|
|
]); |
60
|
|
|
|
61
|
|
|
$searchResult = $searchService->findContent($query); |
62
|
|
|
|
63
|
|
|
$this->assertGreaterThanOrEqual(2, $searchResult->totalCount); |
64
|
|
|
$this->assertResults($searchResult->searchHits); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
public function testFullTextLocationSearch(): void |
68
|
|
|
{ |
69
|
|
|
$this->prepareTestContent(); |
70
|
|
|
|
71
|
|
|
$searchService = $this->getRepository()->getSearchService(); |
72
|
|
|
|
73
|
|
|
$query = new LocationQuery([ |
74
|
|
|
'query' => new Criterion\FullText(self::EMBEDDED_ARTICLE_NAME), |
75
|
|
|
]); |
76
|
|
|
|
77
|
|
|
$searchResult = $searchService->findLocations($query); |
78
|
|
|
|
79
|
|
|
$this->assertGreaterThanOrEqual(2, $searchResult->totalCount); |
80
|
|
|
$this->assertResults($searchResult->searchHits); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
private function hasTestPreparedContent(): bool |
84
|
|
|
{ |
85
|
|
|
return !empty(self::$createdIds); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
private function prepareTestContent(): void |
89
|
|
|
{ |
90
|
|
|
if ($this->hasTestPreparedContent()) { |
91
|
|
|
return; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
$contentService = $this->getRepository()->getContentService(); |
95
|
|
|
$baseArticleStruct = $this->prepareBaseArticleStruct(); |
96
|
|
|
|
97
|
|
|
$embeddedArticleStruct = $this->fillEmbeddedArticleStruct(clone $baseArticleStruct); |
98
|
|
|
$embeddedArticleContent = $contentService->publishVersion( |
99
|
|
|
$this->createContent($embeddedArticleStruct)->versionInfo |
100
|
|
|
); |
101
|
|
|
|
102
|
|
|
$mainArticleStruct = $this->fillMainArticleStruct(clone $baseArticleStruct, $embeddedArticleContent->id); |
103
|
|
|
$mainArticleContent = $contentService->publishVersion( |
104
|
|
|
$this->createContent($mainArticleStruct)->versionInfo |
105
|
|
|
); |
106
|
|
|
|
107
|
|
|
$this->refreshSearch($this->getRepository()); |
108
|
|
|
|
109
|
|
|
self::$createdIds = [ |
110
|
|
|
$embeddedArticleContent->id, |
111
|
|
|
$mainArticleContent->id, |
112
|
|
|
]; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
private function prepareBaseArticleStruct(): ContentCreateStruct |
116
|
|
|
{ |
117
|
|
|
$introDocument = new \DOMDocument(); |
118
|
|
|
$introDocument->loadXML( |
119
|
|
|
<<<EOT |
120
|
|
|
<?xml version="1.0" encoding="UTF-8"?> |
121
|
|
|
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml" xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" version="5.0-variant ezpublish-1.0"> |
122
|
|
|
<para>some paragraph</para> |
123
|
|
|
</section> |
124
|
|
|
EOT |
125
|
|
|
); |
126
|
|
|
|
127
|
|
|
$repository = $this->getRepository(); |
128
|
|
|
$contentType = $repository->getContentTypeService()->loadContentTypeByIdentifier('article'); |
129
|
|
|
|
130
|
|
|
$articleStruct = $repository->getContentService()->newContentCreateStruct($contentType, 'eng-GB'); |
131
|
|
|
$articleStruct->setField('intro', new RichTextValue($introDocument), 'eng-GB'); |
|
|
|
|
132
|
|
|
|
133
|
|
|
return $articleStruct; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
private function fillEmbeddedArticleStruct( |
137
|
|
|
ContentCreateStruct $articleStruct |
138
|
|
|
): ContentCreateStruct { |
139
|
|
|
$articleBodyDoc = new \DOMDocument(); |
140
|
|
|
$articleBodyDoc->loadXML( |
141
|
|
|
<<<EOT |
142
|
|
|
<?xml version="1.0" encoding="UTF-8"?> |
143
|
|
|
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml" xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" version="5.0-variant ezpublish-1.0"> |
144
|
|
|
<para>body-content</para> |
145
|
|
|
</section> |
146
|
|
|
EOT |
147
|
|
|
); |
148
|
|
|
|
149
|
|
|
$articleStruct->setField('title', self::EMBEDDED_ARTICLE_NAME); |
150
|
|
|
$articleStruct->setField('body', new RichTextValue($articleBodyDoc), 'eng-GB'); |
|
|
|
|
151
|
|
|
|
152
|
|
|
return $articleStruct; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
private function fillMainArticleStruct( |
156
|
|
|
ContentCreateStruct $articleStruct, |
157
|
|
|
int $embedContentId |
158
|
|
|
): ContentCreateStruct { |
159
|
|
|
$mainArticleBodyDoc = new \DOMDocument(); |
160
|
|
|
$mainArticleBodyDoc->loadXML( |
161
|
|
|
<<<EOT |
162
|
|
|
<?xml version="1.0" encoding="UTF-8"?> |
163
|
|
|
<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml" xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" version="5.0-variant ezpublish-1.0"> |
164
|
|
|
<para><ezembedinline xlink:href="ezcontent://{$embedContentId}" view="embed-inline"/></para> |
165
|
|
|
</section> |
166
|
|
|
EOT |
167
|
|
|
); |
168
|
|
|
|
169
|
|
|
$articleStruct->setField('title', 'test'); |
170
|
|
|
$articleStruct->setField('body', new RichTextValue($mainArticleBodyDoc), 'eng-GB'); |
|
|
|
|
171
|
|
|
|
172
|
|
|
return $articleStruct; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
private function createContent(ContentCreateStruct $contentCreateStruct): Content |
176
|
|
|
{ |
177
|
|
|
$repository = $this->getRepository(); |
178
|
|
|
|
179
|
|
|
return $repository->getContentService()->createContent( |
180
|
|
|
$contentCreateStruct, |
181
|
|
|
[$repository->getLocationService()->newLocationCreateStruct(2)] |
182
|
|
|
); |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
private function assertResults(array $searchHits): void |
186
|
|
|
{ |
187
|
|
|
$resultIds = []; |
188
|
|
|
|
189
|
|
|
/** @var \eZ\Publish\API\Repository\Values\Content\Search\SearchHit $contentItem */ |
190
|
|
|
foreach ($searchHits as $contentItem) { |
191
|
|
|
$resultIds[] = $contentItem->valueObject->contentInfo->id; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
self::assertCount(2, array_intersect($resultIds, self::$createdIds)); |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
|
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.