Completed
Push — master ( 7401ec...da8bd4 )
by André
58:00 queued 29:35
created

SearchEngineIndexingTest::testDeleteVersion()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 16
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 24
rs 8.9713
1
<?php
2
3
/**
4
 * This file is part of the eZ Publish Kernel package.
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
 * @version //autogentag//
10
 */
11
namespace eZ\Publish\API\Repository\Tests;
12
13
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
14
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
15
use eZ\Publish\API\Repository\Values\Content\Query;
16
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
17
use DateTime;
18
19
/**
20
 * Test case for indexing operations with a search engine.
21
 *
22
 * @group integration
23
 * @group search
24
 * @group indexing
25
 */
26
class SearchEngineIndexingTest extends BaseTest
27
{
28
    /**
29
     * EZP-26186: Make sure index is NOT deleted on removal of version draft (affected Solr & content index on Elastic).
30
     */
31
    public function testDeleteVersion()
32
    {
33
        $repository = $this->getRepository();
34
        $contentService = $repository->getContentService();
35
        $searchService = $repository->getSearchService();
36
37
        $membersContentId = $this->generateId('content', 11);
38
        $contentInfo = $contentService->loadContentInfo($membersContentId);
39
40
        $draft = $contentService->createContentDraft($contentInfo);
41
        $contentService->deleteVersion($draft->getVersionInfo());
42
43
        $this->refreshSearch($repository);
44
45
        // Found
46
        $criterion = new Criterion\LocationId($contentInfo->mainLocationId);
47
        $query = new Query(array('filter' => $criterion));
48
        $result = $searchService->findContentInfo($query);
49
        $this->assertEquals(1, $result->totalCount);
50
        $this->assertEquals(
51
            $contentInfo->id,
52
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
53
        );
54
    }
55
56
    /**
57
     * EZP-26186: Make sure affected child locations are deleted on content deletion (affected Solr & Elastic).
58
     */
59
    public function testDeleteContent()
60
    {
61
        $repository = $this->getRepository();
62
        $contentService = $repository->getContentService();
63
        $searchService = $repository->getSearchService();
64
65
        $anonymousUsersContentId = $this->generateId('content', 42);
66
        $contentInfo = $contentService->loadContentInfo($anonymousUsersContentId);
67
68
        $contentService->deleteContent($contentInfo);
69
70
        $this->refreshSearch($repository);
71
72
        // Should not be found
73
        $criterion = new Criterion\ParentLocationId($contentInfo->mainLocationId);
74
        $query = new LocationQuery(array('filter' => $criterion));
75
        $result = $searchService->findLocations($query);
76
        $this->assertEquals(0, $result->totalCount);
77
    }
78
79
    public function testCreateLocation()
80
    {
81
        $repository = $this->getRepository();
82
        $locationService = $repository->getLocationService();
83
        $contentService = $repository->getContentService();
84
        $searchService = $repository->getSearchService();
85
86
        $rootLocationId = 2;
87
        $membersContentId = 11;
88
        $membersContentInfo = $contentService->loadContentInfo($membersContentId);
89
90
        $locationCreateStruct = $locationService->newLocationCreateStruct($rootLocationId);
91
        $membersLocation = $locationService->createLocation($membersContentInfo, $locationCreateStruct);
92
93
        $this->refreshSearch($repository);
94
95
        // Found
96
        $criterion = new Criterion\LocationId($membersLocation->id);
97
        $query = new LocationQuery(array('filter' => $criterion));
98
        $result = $searchService->findLocations($query);
99
        $this->assertEquals(1, $result->totalCount);
100
        $this->assertEquals(
101
            $membersLocation->id,
102
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
103
        );
104
    }
105
106
    public function testMoveSubtree()
107
    {
108
        $repository = $this->getRepository();
109
        $locationService = $repository->getLocationService();
110
        $contentService = $repository->getContentService();
111
        $searchService = $repository->getSearchService();
112
113
        $rootLocationId = 2;
114
        $membersContentId = 11;
115
        $adminsContentId = 12;
116
        $editorsContentId = 13;
117
        $membersContentInfo = $contentService->loadContentInfo($membersContentId);
118
        $adminsContentInfo = $contentService->loadContentInfo($adminsContentId);
119
        $editorsContentInfo = $contentService->loadContentInfo($editorsContentId);
120
121
        $locationCreateStruct = $locationService->newLocationCreateStruct($rootLocationId);
122
        $membersLocation = $locationService->createLocation($membersContentInfo, $locationCreateStruct);
123
        $editorsLocation = $locationService->createLocation($editorsContentInfo, $locationCreateStruct);
124
        $adminsLocation = $locationService->createLocation(
125
            $adminsContentInfo,
126
            $locationService->newLocationCreateStruct($membersLocation->id)
127
        );
128
129
        $this->refreshSearch($repository);
130
131
        // Not found under Editors
132
        $criterion = new Criterion\ParentLocationId($editorsLocation->id);
133
        $query = new LocationQuery(array('filter' => $criterion));
134
        $result = $searchService->findLocations($query);
135
        $this->assertEquals(0, $result->totalCount);
136
137
        // Found under Members
138
        $criterion = new Criterion\ParentLocationId($membersLocation->id);
139
        $query = new LocationQuery(array('filter' => $criterion));
140
        $result = $searchService->findLocations($query);
141
        $this->assertEquals(1, $result->totalCount);
142
        $this->assertEquals(
143
            $adminsLocation->id,
144
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
145
        );
146
147
        $locationService->moveSubtree($adminsLocation, $editorsLocation);
148
        $this->refreshSearch($repository);
149
150
        // Found under Editors
151
        $criterion = new Criterion\ParentLocationId($editorsLocation->id);
152
        $query = new LocationQuery(array('filter' => $criterion));
153
        $result = $searchService->findLocations($query);
154
        $this->assertEquals(1, $result->totalCount);
155
        $this->assertEquals(
156
            $adminsLocation->id,
157
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
158
        );
159
160
        // Not found under Members
161
        $criterion = new Criterion\ParentLocationId($membersLocation->id);
162
        $query = new LocationQuery(array('filter' => $criterion));
163
        $result = $searchService->findLocations($query);
164
        $this->assertEquals(0, $result->totalCount);
165
    }
166
167
    /**
168
     * Testing that content is indexed even when containing only fields with values
169
     * considered to be empty by the search engine.
170
     */
171
    public function testIndexContentWithNullField()
172
    {
173
        $repository = $this->getRepository();
174
        $contentService = $repository->getContentService();
175
        $contentTypeService = $repository->getContentTypeService();
176
        $searchService = $repository->getSearchService();
177
178
        $createStruct = $contentTypeService->newContentTypeCreateStruct('test-type');
179
        $createStruct->mainLanguageCode = 'eng-GB';
180
        $createStruct->names = array('eng-GB' => 'Test type');
181
        $createStruct->creatorId = 14;
182
        $createStruct->creationDate = new DateTime();
183
184
        $translatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct(
185
            'integer',
186
            'ezinteger'
187
        );
188
        $translatableFieldCreate->names = array('eng-GB' => 'Simple translatable integer field');
189
        $translatableFieldCreate->fieldGroup = 'main';
190
        $translatableFieldCreate->position = 1;
191
        $translatableFieldCreate->isTranslatable = true;
192
        $translatableFieldCreate->isSearchable = true;
193
194
        $createStruct->addFieldDefinition($translatableFieldCreate);
195
196
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
197
        $contentTypeDraft = $contentTypeService->createContentType(
198
            $createStruct,
199
            array($contentGroup)
200
        );
201
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
202
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
0 ignored issues
show
Documentation introduced by
The property $id is declared protected in eZ\Publish\API\Repositor...ContentType\ContentType. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
203
204
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
205
        $createStruct->alwaysAvailable = false;
206
        $createStruct->mainLanguageCode = 'eng-GB';
207
208
        $draft = $contentService->createContent($createStruct);
209
        $content = $contentService->publishVersion($draft->getVersionInfo());
210
211
        $this->refreshSearch($repository);
212
213
        // Found
214
        $criterion = new Criterion\ContentId($content->id);
215
        $query = new Query(array('filter' => $criterion));
216
        $result = $searchService->findContent($query);
217
        $this->assertEquals(1, $result->totalCount);
218
        $this->assertEquals(
219
            $content->id,
220
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
221
        );
222
    }
223
224
    public function testUpdateLocation()
225
    {
226
        $repository = $this->getRepository();
227
        $locationService = $repository->getLocationService();
228
        $searchService = $repository->getSearchService();
229
230
        $rootLocationId = 2;
231
        $locationToUpdate = $locationService->loadLocation($rootLocationId);
232
233
        $criterion = new Criterion\LogicalAnd([
234
            new Criterion\LocationId($rootLocationId),
235
            new Criterion\Location\Priority(Criterion\Operator::GT, 0),
236
        ]);
237
238
        $query = new LocationQuery(array('filter' => $criterion));
239
        $result = $searchService->findLocations($query);
240
241
        $this->assertEquals(0, $result->totalCount);
242
243
        $locationUpdateStruct = $locationService->newLocationUpdateStruct();
244
        $locationUpdateStruct->priority = 4;
245
        $locationService->updateLocation($locationToUpdate, $locationUpdateStruct);
246
247
        $this->refreshSearch($repository);
248
249
        $result = $searchService->findLocations($query);
250
251
        $this->assertEquals(1, $result->totalCount);
252
        $this->assertEquals(
253
            $locationToUpdate->id,
254
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
255
        );
256
    }
257
258
    /**
259
     * Testing that content will be deleted with all of its subitems but subitems with additional location will stay as
260
     * they are.
261
     */
262
    public function testDeleteLocation()
263
    {
264
        $repository = $this->getRepository();
265
        $locationService = $repository->getLocationService();
266
267
        $treeContainerContent = $this->createContentWithName('Tree Container', [2]);
268
        $supposeBeDeletedSubItem = $this->createContentWithName(
269
            'Suppose to be deleted sub-item',
270
            [$treeContainerContent->contentInfo->mainLocationId]
271
        );
272
        $supposeSurviveSubItem = $this->createContentWithName(
273
            'Suppose to Survive Item',
274
            [2, $treeContainerContent->contentInfo->mainLocationId]
275
        );
276
277
        $treeContainerLocation = $locationService->loadLocation($treeContainerContent->contentInfo->mainLocationId);
278
279
        $this->refreshSearch($repository);
280
281
        $this->assertContentIdSearch($treeContainerContent->id, 1);
282
        $this->assertContentIdSearch($supposeSurviveSubItem->id, 1);
283
        $this->assertContentIdSearch($supposeBeDeletedSubItem->id, 1);
284
285
        $locationService->deleteLocation($treeContainerLocation);
286
287
        $this->refreshSearch($repository);
288
289
        $this->assertContentIdSearch($supposeSurviveSubItem->id, 1);
290
        $this->assertContentIdSearch($treeContainerContent->id, 0);
291
        $this->assertContentIdSearch($supposeBeDeletedSubItem->id, 0);
292
    }
293
294
    /**
295
     * Will create if not exists an simple content type for deletion test purpose with just and required field name.
296
     *
297
     * @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
298
     */
299
    protected function createDeletionTestContentType()
300
    {
301
        $repository = $this->getRepository();
302
        $contentTypeService = $repository->getContentTypeService();
303
        try {
304
            return $contentTypeService->loadContentTypeByIdentifier('deletion-test');
305
        } catch (NotFoundException $e) {
306
            // continue creation process
307
        }
308
309
        $nameField = $contentTypeService->newFieldDefinitionCreateStruct('name', 'ezstring');
310
        $nameField->fieldGroup = 'main';
311
        $nameField->position = 1;
312
        $nameField->isTranslatable = true;
313
        $nameField->isSearchable = true;
314
        $nameField->isRequired = true;
315
316
        $contentTypeStruct = $contentTypeService->newContentTypeCreateStruct('deletion-test');
317
        $contentTypeStruct->mainLanguageCode = 'eng-GB';
318
        $contentTypeStruct->creatorId = 14;
319
        $contentTypeStruct->creationDate = new DateTime();
320
        $contentTypeStruct->names = ['eng-GB' => 'Deletion test'];
321
        $contentTypeStruct->addFieldDefinition($nameField);
322
323
        $contentTypeGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
324
325
        $contentTypeDraft = $contentTypeService->createContentType($contentTypeStruct, [$contentTypeGroup]);
326
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
327
328
        return $contentTypeService->loadContentTypeByIdentifier('deletion-test');
329
    }
330
331
    /**
332
     * Will create and publish an content with a filed with a given content name in location provided into
333
     * $parentLocationIdList.
334
     *
335
     * @param string $contentName
336
     * @param array $parentLocationIdList
337
     *
338
     * @return \eZ\Publish\API\Repository\Values\Content\Content
339
     */
340
    protected function createContentWithName($contentName, array $parentLocationIdList = array())
341
    {
342
        $contentService = $this->getRepository()->getContentService();
343
        $locationService = $this->getRepository()->getLocationService();
344
345
        $testableContentType = $this->createDeletionTestContentType();
346
347
        $rootContentStruct = $contentService->newContentCreateStruct($testableContentType, 'eng-GB');
348
        $rootContentStruct->setField('name', $contentName);
349
350
        $parentLocationList = [];
351
        foreach ($parentLocationIdList as $locationID) {
352
            $parentLocationList[] = $locationService->newLocationCreateStruct($locationID);
353
        }
354
355
        $contentDraft = $contentService->createContent($rootContentStruct, $parentLocationList);
356
        $publishedContent = $contentService->publishVersion($contentDraft->getVersionInfo());
357
358
        return $publishedContent;
359
    }
360
361
    /**
362
     * Asserts an content id if it exists still in the solr core.
363
     *
364
     * @param int $contentId
365
     * @param int $expectedCount
366
     */
367
    protected function assertContentIdSearch($contentId, $expectedCount)
368
    {
369
        $searchService = $this->getRepository()->getSearchService();
370
371
        $criterion = new Criterion\ContentId($contentId);
372
        $query = new Query(array('filter' => $criterion));
373
        $result = $searchService->findContent($query);
374
375
        $this->assertEquals($expectedCount, $result->totalCount);
376
        if ($expectedCount == 0) {
377
            return;
378
        }
379
380
        $this->assertEquals(
381
            $contentId,
382
            $result->searchHits[0]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
383
        );
384
    }
385
}
386