Completed
Push — missing_siteaccess_aware_tests ( c030ea...f3bf75 )
by
unknown
29:08 queued 08:31
created

SearchServiceTest   F

Complexity

Total Complexity 159

Size/Duplication

Total Lines 4550
Duplicated Lines 21.41 %

Coupling/Cohesion

Components 1
Dependencies 65

Importance

Changes 0
Metric Value
wmc 159
lcom 1
cbo 65
dl 974
loc 4550
rs 0.8
c 0
b 0
f 0

90 Methods

Rating   Name   Duplication   Size   Complexity  
B getFilterContentSearches() 0 530 5
B getContentQuerySearches() 0 74 1
B getLocationQuerySearches() 0 69 1
A testFindContentFiltered() 0 5 1
A testFindContentInfoFiltered() 0 5 1
A testFindLocationsContentFiltered() 0 5 1
A testDeprecatedCriteriaProperty() 0 14 1
A testQueryContent() 0 5 1
A testQueryContentInfo() 0 5 1
A testQueryContentLocations() 0 5 1
A testQueryLocations() 0 5 1
A getCaseInsensitiveSearches() 0 35 1
A testFindContentFieldFiltersCaseSensitivity() 0 8 1
A testFindLocationsFieldFiltersCaseSensitivity() 0 8 1
B getRelationFieldFilterSearches() 0 73 1
A testRelationContentCreation() 0 23 1
A testFindRelationFieldContentInfoFiltered() 0 6 1
A testFindRelationFieldLocationsFiltered() 0 6 1
A testFindSingle() 16 16 1
A testFindNoPerformCount() 24 24 2
A testFindNoPerformCountException() 18 18 2
A testFindLocationsNoPerformCount() 24 24 2
A testFindLocationsNoPerformCountException() 18 18 2
A createMultipleCountriesContent() 0 43 1
A testFieldCollectionContains() 24 24 1
A testFieldCollectionContainsNoMatch() 19 19 1
A testInvalidFieldIdentifierRange() 18 18 1
A testInvalidFieldIdentifierIn() 18 18 1
A testFindContentWithNonSearchableField() 18 18 1
A testSortFieldWithNonSearchableField() 13 13 1
A testSortMapLocationDistanceWithNonSearchableField() 20 20 1
A testFindSingleFailMultiple() 11 11 1
A testFindSingleWithNonSearchableField() 0 13 1
B getSortedContentSearches() 0 147 2
B getSortedLocationSearches() 0 72 2
A createTestContentType() 36 36 1
A createMultilingualContent() 0 30 3
A checkPrioritizedLanguagesSupport() 0 7 2
B providerForTestMultilingualFieldSort() 0 305 1
A testMultilingualFieldSortContent() 0 13 1
A testMultilingualFieldSortLocation() 0 14 1
B assertMultilingualFieldSort() 19 71 4
B providerForTestMultilingualFieldFilter() 0 158 1
A testMultilingualFieldFilterContent() 0 13 1
A testMultilingualFieldFilterLocation() 0 14 1
B assertMultilingualFieldFilter() 19 76 4
A mapResultContentIds() 0 13 2
A testFindAndSortContent() 0 5 1
A testFindAndSortContentInfo() 0 5 1
A testFindAndSortContentLocations() 0 5 1
A testFindAndSortLocations() 0 5 1
A testFindFacetedContent() 0 4 1
A testFindFacetedContentInfo() 0 4 1
A testQueryCustomField() 19 19 1
A testQueryModifiedField() 29 29 2
A testSortModifiedField() 0 30 2
A createTestPlaceContentType() 27 27 1
B testMapLocationDistanceLessThanOrEqual() 73 73 1
B testMapLocationDistanceGreaterThanOrEqual() 73 73 1
B testMapLocationDistanceBetween() 0 89 1
B testMapLocationDistanceBetweenPolar() 0 57 1
B testMapLocationDistanceSortAscending() 110 110 1
B testMapLocationDistanceSortDescending() 110 110 1
B testMapLocationDistanceWithCustomField() 0 81 2
B testMapLocationDistanceWithCustomFieldSort() 0 118 2
A testFindMainLocation() 39 39 1
A testFindNonMainLocation() 38 38 1
A testSortMainLocationAscending() 37 37 1
A testSortMainLocationDescending() 37 37 1
A testContentWithMultipleLocations() 0 45 1
A createContentForTestUserMetadataGroupHorizontal() 0 52 1
B testUserMetadataGroupHorizontalFilterContent() 0 73 6
A testUserMetadataGroupHorizontalQueryContent() 0 4 1
B testUserMetadataGroupHorizontalFilterLocation() 0 83 6
A testUserMetadataGroupHorizontalQueryLocation() 0 4 1
A testFullTextOnNewContent() 0 35 1
B testLanguageAnalysisSeparateContent() 0 61 2
A testLanguageAnalysisSameContent() 0 47 2
A testLanguageAnalysisSameContentNotFound() 0 48 2
A testFindContentWithLanguageFilter() 0 32 2
A testFulltextComplex() 0 51 1
A testFulltextContentSearchComplex() 14 41 3
B testFulltextLocationSearchComplex() 14 52 6
F assertQueryFixture() 24 90 16
A printResult() 9 9 2
A simplifySearchResult() 6 26 5
A getFixtureDir() 0 4 1
A getContentInfoFixtureClosure() 0 15 4
A testFieldCriterionForContentsWithIdenticalFieldIdentifiers() 0 28 2
A createContentWithFieldType() 0 43 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like SearchServiceTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SearchServiceTest, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * File containing the SearchServiceTest 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\API\Repository\Tests;
10
11
use eZ\Publish\API\Repository\Tests\SetupFactory\LegacyElasticsearch;
12
use EzSystems\EzPlatformSolrSearchEngine\Tests\SetupFactory\LegacySetupFactory as LegacySolrSetupFactory;
13
use eZ\Publish\API\Repository\Values\Content\Content;
14
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
15
use eZ\Publish\API\Repository\Values\Content\Query;
16
use eZ\Publish\API\Repository\Values\Content\Location;
17
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
18
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
19
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
20
use eZ\Publish\API\Repository\Values\Content\Search\SearchResult;
21
use eZ\Publish\API\Repository\Values\Content\Search\SearchHit;
22
use eZ\Publish\API\Repository\Exceptions\NotImplementedException;
23
24
/**
25
 * Test case for operations in the SearchService.
26
 *
27
 * @see eZ\Publish\API\Repository\SearchService
28
 * @group integration
29
 * @group search
30
 */
31
class SearchServiceTest extends BaseTest
32
{
33
    const QUERY_CLASS = Query::class;
34
35
    use Common\FacetedSearchProvider;
36
37
    public function getFilterContentSearches()
38
    {
39
        $fixtureDir = $this->getFixtureDir();
40
41
        return [
42
            0 => [
43
                [
44
                    'filter' => new Criterion\ContentId(
45
                        [1, 4, 10]
46
                    ),
47
                    'sortClauses' => [new SortClause\ContentId()],
48
                ],
49
                $fixtureDir . 'ContentId.php',
50
            ],
51
            1 => [
52
                [
53
                    'filter' => new Criterion\LogicalAnd(
54
                        [
55
                            new Criterion\ContentId(
56
                                [1, 4, 10]
57
                            ),
58
                            new Criterion\ContentId(
59
                                [4, 12]
60
                            ),
61
                        ]
62
                    ),
63
                    'sortClauses' => [new SortClause\ContentId()],
64
                ],
65
                $fixtureDir . 'LogicalAnd.php',
66
            ],
67
            2 => [
68
                [
69
                    'filter' => new Criterion\LogicalOr(
70
                        [
71
                            new Criterion\ContentId(
72
                                [1, 4, 10]
73
                            ),
74
                            new Criterion\ContentId(
75
                                [4, 12]
76
                            ),
77
                        ]
78
                    ),
79
                    'sortClauses' => [new SortClause\ContentId()],
80
                ],
81
                $fixtureDir . 'LogicalOr.php',
82
            ],
83
            3 => [
84
                [
85
                    'filter' => new Criterion\LogicalAnd(
86
                        [
87
                            new Criterion\ContentId(
88
                                [1, 4, 10]
89
                            ),
90
                            new Criterion\LogicalNot(
91
                                new Criterion\ContentId(
92
                                    [10, 12]
93
                                )
94
                            ),
95
                        ]
96
                    ),
97
                    'sortClauses' => [new SortClause\ContentId()],
98
                ],
99
                $fixtureDir . 'LogicalNot.php',
100
            ],
101
            4 => [
102
                [
103
                    'filter' => new Criterion\LogicalAnd(
104
                        [
105
                            new Criterion\ContentId(
106
                                [1, 4, 10]
107
                            ),
108
                            new Criterion\LogicalAnd(
109
                                [
110
                                    new Criterion\LogicalNot(
111
                                        new Criterion\ContentId(
112
                                            [10, 12]
113
                                        )
114
                                    ),
115
                                ]
116
                            ),
117
                        ]
118
                    ),
119
                    'sortClauses' => [new SortClause\ContentId()],
120
                ],
121
                $fixtureDir . 'LogicalNot.php',
122
            ],
123
            5 => [
124
                [
125
                    'filter' => new Criterion\ContentTypeId(
126
                        4
127
                    ),
128
                    'sortClauses' => [new SortClause\ContentId()],
129
                ],
130
                $fixtureDir . 'ContentTypeId.php',
131
            ],
132
            6 => [
133
                [
134
                    'filter' => new Criterion\ContentTypeIdentifier(
135
                        'user'
136
                    ),
137
                    'sortClauses' => [new SortClause\ContentId()],
138
                ],
139
                $fixtureDir . 'ContentTypeId.php',
140
            ],
141
            7 => [
142
                [
143
                    'filter' => new Criterion\MatchNone(),
144
                    'sortClauses' => [new SortClause\ContentId()],
145
                ],
146
                $fixtureDir . 'MatchNone.php',
147
            ],
148
            8 => [
149
                [
150
                    'filter' => new Criterion\ContentTypeGroupId(
151
                        2
152
                    ),
153
                    'sortClauses' => [new SortClause\ContentId()],
154
                ],
155
                $fixtureDir . 'ContentTypeGroupId.php',
156
            ],
157
            9 => [
158
                [
159
                    'filter' => new Criterion\DateMetadata(
160
                        Criterion\DateMetadata::MODIFIED,
161
                        Criterion\Operator::GT,
162
                        1343140540
163
                    ),
164
                    'sortClauses' => [new SortClause\ContentId()],
165
                ],
166
                $fixtureDir . 'DateMetadataGt.php',
167
            ],
168
            10 => [
169
                [
170
                    'filter' => new Criterion\DateMetadata(
171
                        Criterion\DateMetadata::MODIFIED,
172
                        Criterion\Operator::GTE,
173
                        1311154215
174
                    ),
175
                    'sortClauses' => [new SortClause\ContentId()],
176
                ],
177
                $fixtureDir . 'DateMetadataGte.php',
178
            ],
179
            11 => [
180
                [
181
                    'filter' => new Criterion\DateMetadata(
182
                        Criterion\DateMetadata::MODIFIED,
183
                        Criterion\Operator::LTE,
184
                        1311154215
185
                    ),
186
                    'limit' => 10,
187
                    'sortClauses' => [new SortClause\ContentId()],
188
                ],
189
                $fixtureDir . 'DateMetadataLte.php',
190
            ],
191
            12 => [
192
                [
193
                    'filter' => new Criterion\DateMetadata(
194
                        Criterion\DateMetadata::MODIFIED,
195
                        Criterion\Operator::IN,
196
                        [1033920794, 1060695457, 1343140540]
197
                    ),
198
                    'sortClauses' => [new SortClause\ContentId()],
199
                ],
200
                $fixtureDir . 'DateMetadataIn.php',
201
            ],
202
            13 => [
203
                [
204
                    'filter' => new Criterion\DateMetadata(
205
                        Criterion\DateMetadata::MODIFIED,
206
                        Criterion\Operator::BETWEEN,
207
                        [1033920776, 1072180276]
208
                    ),
209
                    'sortClauses' => [new SortClause\ContentId()],
210
                ],
211
                $fixtureDir . 'DateMetadataBetween.php',
212
            ],
213
            14 => [
214
                [
215
                    'filter' => new Criterion\DateMetadata(
216
                        Criterion\DateMetadata::CREATED,
217
                        Criterion\Operator::BETWEEN,
218
                        [1033920776, 1072180278]
219
                    ),
220
                    'sortClauses' => [new SortClause\ContentId()],
221
                ],
222
                $fixtureDir . 'DateMetadataCreated.php',
223
            ],
224
            15 => [
225
                [
226
                    'filter' => new Criterion\CustomField(
227
                        'user_group_name_value_s',
228
                        Criterion\Operator::EQ,
229
                        'Members'
230
                    ),
231
                    'sortClauses' => [new SortClause\ContentId()],
232
                ],
233
                $fixtureDir . 'Field.php',
234
            ],
235
            16 => [
236
                [
237
                    'filter' => new Criterion\CustomField(
238
                        'user_group_name_value_s',
239
                        Criterion\Operator::CONTAINS,
240
                        'Members'
241
                    ),
242
                    'sortClauses' => [new SortClause\ContentId()],
243
                ],
244
                $fixtureDir . 'Field.php',
245
            ],
246
            17 => [
247
                [
248
                    'filter' => new Criterion\CustomField(
249
                        'user_group_name_value_s',
250
                        Criterion\Operator::LT,
251
                        'Members'
252
                    ),
253
                    'sortClauses' => [new SortClause\ContentId()],
254
                ],
255
                $fixtureDir . 'CustomFieldLt.php',
256
            ],
257
            18 => [
258
                [
259
                    'filter' => new Criterion\CustomField(
260
                        'user_group_name_value_s',
261
                        Criterion\Operator::LTE,
262
                        'Members'
263
                    ),
264
                    'sortClauses' => [new SortClause\ContentId()],
265
                ],
266
                $fixtureDir . 'CustomFieldLte.php',
267
            ],
268
            19 => [
269
                [
270
                    'filter' => new Criterion\CustomField(
271
                        'user_group_name_value_s',
272
                        Criterion\Operator::GT,
273
                        'Members'
274
                    ),
275
                    'sortClauses' => [new SortClause\ContentId()],
276
                ],
277
                $fixtureDir . 'CustomFieldGt.php',
278
            ],
279
            20 => [
280
                [
281
                    'filter' => new Criterion\CustomField(
282
                        'user_group_name_value_s',
283
                        Criterion\Operator::GTE,
284
                        'Members'
285
                    ),
286
                    'sortClauses' => [new SortClause\ContentId()],
287
                ],
288
                $fixtureDir . 'CustomFieldGte.php',
289
            ],
290
            21 => [
291
                [
292
                    'filter' => new Criterion\CustomField(
293
                        'user_group_name_value_s',
294
                        Criterion\Operator::BETWEEN,
295
                        ['Administrator users', 'Members']
296
                    ),
297
                    'sortClauses' => [new SortClause\ContentId()],
298
                ],
299
                $fixtureDir . 'CustomFieldBetween.php',
300
            ],
301
            22 => [
302
                [
303
                    'filter' => new Criterion\RemoteId(
304
                        ['f5c88a2209584891056f987fd965b0ba', 'faaeb9be3bd98ed09f606fc16d144eca']
305
                    ),
306
                    'sortClauses' => [new SortClause\ContentId()],
307
                ],
308
                $fixtureDir . 'RemoteId.php',
309
            ],
310
            23 => [
311
                [
312
                    'filter' => new Criterion\SectionId(
313
                        [2]
314
                    ),
315
                    'sortClauses' => [new SortClause\ContentId()],
316
                ],
317
                $fixtureDir . 'SectionId.php',
318
            ],
319
            24 => [
320
                [
321
                    'filter' => new Criterion\Field(
322
                        'name',
323
                        Criterion\Operator::EQ,
324
                        'Members'
325
                    ),
326
                    'sortClauses' => [new SortClause\ContentId()],
327
                ],
328
                $fixtureDir . 'Field.php',
329
            ],
330
            25 => [
331
                [
332
                    'filter' => new Criterion\Field(
333
                        'name',
334
                        Criterion\Operator::IN,
335
                        ['Members', 'Anonymous Users']
336
                    ),
337
                    'sortClauses' => [new SortClause\ContentId()],
338
                ],
339
                $fixtureDir . 'FieldIn.php',
340
            ],
341
            26 => [
342
                [
343
                    'filter' => new Criterion\DateMetadata(
344
                        Criterion\DateMetadata::MODIFIED,
345
                        Criterion\Operator::BETWEEN,
346
                        [1033920275, 1033920794]
347
                    ),
348
                    'sortClauses' => [new SortClause\ContentId()],
349
                ],
350
                $fixtureDir . 'FieldBetween.php',
351
            ],
352
            27 => [
353
                [
354
                    'filter' => new Criterion\LogicalOr(
355
                        [
356
                            new Criterion\Field(
357
                                'name',
358
                                Criterion\Operator::EQ,
359
                                'Members'
360
                            ),
361
                            new Criterion\DateMetadata(
362
                                Criterion\DateMetadata::MODIFIED,
363
                                Criterion\Operator::BETWEEN,
364
                                [1033920275, 1033920794]
365
                            ),
366
                        ]
367
                    ),
368
                    'sortClauses' => [new SortClause\ContentId()],
369
                ],
370
                $fixtureDir . 'FieldOr.php',
371
            ],
372
            28 => [
373
                [
374
                    'filter' => new Criterion\Subtree(
375
                        '/1/5/'
376
                    ),
377
                    'sortClauses' => [new SortClause\ContentId()],
378
                ],
379
                $fixtureDir . 'Subtree.php',
380
            ],
381
            29 => [
382
                [
383
                    'filter' => new Criterion\LocationId(
384
                        [1, 2, 5]
385
                    ),
386
                    'sortClauses' => [new SortClause\ContentId()],
387
                ],
388
                $fixtureDir . 'LocationId.php',
389
            ],
390
            30 => [
391
                [
392
                    'filter' => new Criterion\ParentLocationId(
393
                        [1]
394
                    ),
395
                    'sortClauses' => [new SortClause\ContentId()],
396
                ],
397
                $fixtureDir . 'ParentLocationId.php',
398
            ],
399
            31 => [
400
                [
401
                    'filter' => new Criterion\LocationRemoteId(
402
                        ['3f6d92f8044aed134f32153517850f5a', 'f3e90596361e31d496d4026eb624c983']
403
                    ),
404
                    'sortClauses' => [new SortClause\ContentId()],
405
                ],
406
                $fixtureDir . 'LocationRemoteId.php',
407
            ],
408
            32 => [
409
                [
410
                    // There is no Status Criterion anymore, this should match all published as well
411
                    'filter' => new Criterion\Subtree(
412
                        '/1/'
413
                    ),
414
                    'sortClauses' => [new SortClause\ContentId()],
415
                    'limit' => 50,
416
                ],
417
                $fixtureDir . 'Status.php',
418
                // Result having the same sort level should be sorted between them to be system independent
419
                function (&$data) {
420
                    usort(
421
                        $data->searchHits,
422
                        function ($a, $b) {
423
                            if ($a->score == $b->score) {
424
                                if ($a->valueObject['id'] == $b->valueObject['id']) {
425
                                    return 0;
426
                                }
427
428
                                // Order by ascending ID
429
                                return ($a->valueObject['id'] < $b->valueObject['id']) ? -1 : 1;
430
                            }
431
432
                            // Order by descending score
433
                            return ($a->score > $b->score) ? -1 : 1;
434
                        }
435
                    );
436
                },
437
            ],
438
            33 => [
439
                [
440
                    'filter' => new Criterion\UserMetadata(
441
                        Criterion\UserMetadata::MODIFIER,
442
                        Criterion\Operator::EQ,
443
                        14
444
                    ),
445
                    'sortClauses' => [
446
                        new SortClause\ContentId(),
447
                    ],
448
                    'limit' => 50,
449
                ],
450
                $fixtureDir . 'UserMetadata.php',
451
            ],
452
            34 => [
453
                [
454
                    'filter' => new Criterion\UserMetadata(
455
                        Criterion\UserMetadata::MODIFIER,
456
                        Criterion\Operator::IN,
457
                        [14]
458
                    ),
459
                    'sortClauses' => [
460
                        new SortClause\ContentId(),
461
                    ],
462
                    'limit' => 50,
463
                ],
464
                $fixtureDir . 'UserMetadata.php',
465
            ],
466
            35 => [
467
                [
468
                    'filter' => new Criterion\UserMetadata(
469
                        Criterion\UserMetadata::OWNER,
470
                        Criterion\Operator::EQ,
471
                        14
472
                    ),
473
                    'sortClauses' => [
474
                        new SortClause\ContentId(),
475
                    ],
476
                    'limit' => 50,
477
                ],
478
                $fixtureDir . 'UserMetadata.php',
479
            ],
480
            36 => [
481
                [
482
                    'filter' => new Criterion\UserMetadata(
483
                        Criterion\UserMetadata::OWNER,
484
                        Criterion\Operator::IN,
485
                        [14]
486
                    ),
487
                    'sortClauses' => [
488
                        new SortClause\ContentId(),
489
                    ],
490
                    'limit' => 50,
491
                ],
492
                $fixtureDir . 'UserMetadata.php',
493
            ],
494
            37 => [
495
                [
496
                    'filter' => new Criterion\UserMetadata(
497
                        Criterion\UserMetadata::GROUP,
498
                        Criterion\Operator::EQ,
499
                        12
500
                    ),
501
                    'sortClauses' => [
502
                        new SortClause\ContentId(),
503
                    ],
504
                    'limit' => 50,
505
                ],
506
                $fixtureDir . 'UserMetadata.php',
507
            ],
508
            38 => [
509
                [
510
                    'filter' => new Criterion\UserMetadata(
511
                        Criterion\UserMetadata::GROUP,
512
                        Criterion\Operator::IN,
513
                        [12]
514
                    ),
515
                    'sortClauses' => [
516
                        new SortClause\ContentId(),
517
                    ],
518
                    'limit' => 50,
519
                ],
520
                $fixtureDir . 'UserMetadata.php',
521
            ],
522
            39 => [
523
                [
524
                    'filter' => new Criterion\UserMetadata(
525
                        Criterion\UserMetadata::GROUP,
526
                        Criterion\Operator::EQ,
527
                        4
528
                    ),
529
                    'sortClauses' => [
530
                        new SortClause\ContentId(),
531
                    ],
532
                    'limit' => 50,
533
                ],
534
                $fixtureDir . 'UserMetadata.php',
535
            ],
536
            40 => [
537
                [
538
                    'filter' => new Criterion\UserMetadata(
539
                        Criterion\UserMetadata::GROUP,
540
                        Criterion\Operator::IN,
541
                        [4]
542
                    ),
543
                    'sortClauses' => [
544
                        new SortClause\ContentId(),
545
                    ],
546
                    'limit' => 50,
547
                ],
548
                $fixtureDir . 'UserMetadata.php',
549
            ],
550
            41 => [
551
                [
552
                    'filter' => new Criterion\Ancestor(
553
                        [
554
                            '/1/5/44/',
555
                            '/1/5/44/45/',
556
                        ]
557
                    ),
558
                    'sortClauses' => [
559
                        new SortClause\ContentId(),
560
                    ],
561
                    'limit' => 50,
562
                ],
563
                $fixtureDir . 'AncestorContent.php',
564
            ],
565
        ];
566
    }
567
568
    public function getContentQuerySearches()
569
    {
570
        $fixtureDir = $this->getFixtureDir();
571
572
        return [
573
            [
574
                [
575
                    'filter' => new Criterion\ContentId(
576
                        [58, 10]
577
                    ),
578
                    'query' => new Criterion\FullText('contact'),
579
                    'sortClauses' => [new SortClause\ContentId()],
580
                ],
581
                $fixtureDir . 'FullTextFiltered.php',
582
            ],
583
            [
584
                [
585
                    'query' => new Criterion\FullText(
586
                        'contact',
587
                        [
588
                            'boost' => [
589
                                'title' => 2,
590
                            ],
591
                            'fuzziness' => .5,
592
                        ]
593
                    ),
594
                    'sortClauses' => [new SortClause\ContentId()],
595
                ],
596
                $fixtureDir . 'FullText.php',
597
            ],
598
            [
599
                [
600
                    'query' => new Criterion\FullText(
601
                        'Contact*'
602
                    ),
603
                    'sortClauses' => [new SortClause\ContentId()],
604
                ],
605
                $fixtureDir . 'FullTextWildcard.php',
606
            ],
607
            [
608
                [
609
                    'query' => new Criterion\LanguageCode('eng-GB', false),
610
                    'sortClauses' => [new SortClause\ContentId()],
611
                ],
612
                $fixtureDir . 'LanguageCode.php',
613
            ],
614
            [
615
                [
616
                    'query' => new Criterion\LanguageCode(['eng-US', 'eng-GB']),
617
                    'offset' => 10,
618
                    'sortClauses' => [new SortClause\ContentId()],
619
                ],
620
                $fixtureDir . 'LanguageCodeIn.php',
621
            ],
622
            [
623
                [
624
                    'query' => new Criterion\LanguageCode('eng-GB'),
625
                    'offset' => 10,
626
                    'sortClauses' => [new SortClause\ContentId()],
627
                ],
628
                $fixtureDir . 'LanguageCodeAlwaysAvailable.php',
629
            ],
630
            [
631
                [
632
                    'query' => new Criterion\Visibility(
633
                        Criterion\Visibility::VISIBLE
634
                    ),
635
                    'sortClauses' => [new SortClause\ContentId()],
636
                    'limit' => 50,
637
                ],
638
                $fixtureDir . 'Visibility.php',
639
            ],
640
        ];
641
    }
642
643
    public function getLocationQuerySearches()
644
    {
645
        $fixtureDir = $this->getFixtureDir();
646
647
        return [
648
            [
649
                [
650
                    'query' => new Criterion\Location\Depth(Criterion\Operator::EQ, 1),
651
                    'sortClauses' => [new SortClause\ContentId()],
652
                ],
653
                $fixtureDir . 'Depth.php',
654
            ],
655
            [
656
                [
657
                    'query' => new Criterion\Location\Depth(Criterion\Operator::IN, [1, 3]),
658
                    'sortClauses' => [new SortClause\ContentId()],
659
                ],
660
                $fixtureDir . 'DepthIn.php',
661
            ],
662
            [
663
                [
664
                    'query' => new Criterion\Location\Depth(Criterion\Operator::GT, 2),
665
                    'sortClauses' => [new SortClause\ContentId()],
666
                ],
667
                $fixtureDir . 'DepthGt.php',
668
            ],
669
            [
670
                [
671
                    'query' => new Criterion\Location\Depth(Criterion\Operator::GTE, 2),
672
                    'sortClauses' => [new SortClause\ContentId()],
673
                    'limit' => 50,
674
                ],
675
                $fixtureDir . 'DepthGte.php',
676
            ],
677
            [
678
                [
679
                    'query' => new Criterion\Location\Depth(Criterion\Operator::LT, 2),
680
                    'sortClauses' => [new SortClause\ContentId()],
681
                ],
682
                $fixtureDir . 'Depth.php',
683
            ],
684
            [
685
                [
686
                    'query' => new Criterion\Location\Depth(Criterion\Operator::LTE, 2),
687
                    'sortClauses' => [new SortClause\ContentId()],
688
                    'limit' => 50,
689
                ],
690
                $fixtureDir . 'DepthLte.php',
691
            ],
692
            [
693
                [
694
                    'query' => new Criterion\Location\Depth(Criterion\Operator::BETWEEN, [1, 2]),
695
                    'sortClauses' => [new SortClause\ContentId()],
696
                    'limit' => 50,
697
                ],
698
                $fixtureDir . 'DepthLte.php',
699
            ],
700
            [
701
                [
702
                    'filter' => new Criterion\Ancestor('/1/5/44/45/'),
703
                    'sortClauses' => [
704
                        new SortClause\Location\Depth(),
705
                    ],
706
                    'limit' => 50,
707
                ],
708
                $fixtureDir . 'AncestorLocation.php',
709
            ],
710
        ];
711
    }
712
713
    /**
714
     * Test for the findContent() method.
715
     *
716
     * @dataProvider getFilterContentSearches
717
     *
718
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
719
     */
720
    public function testFindContentFiltered($queryData, $fixture, $closure = null)
721
    {
722
        $query = new Query($queryData);
723
        $this->assertQueryFixture($query, $fixture, $closure);
724
    }
725
726
    /**
727
     * Test for the findContentInfo() method.
728
     *
729
     * @dataProvider getFilterContentSearches
730
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
731
     */
732
    public function testFindContentInfoFiltered($queryData, $fixture, $closure = null)
733
    {
734
        $query = new Query($queryData);
735
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure($closure), true);
736
    }
737
738
    /**
739
     * Test for the findLocations() method.
740
     *
741
     * @dataProvider getFilterContentSearches
742
     *
743
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
744
     */
745
    public function testFindLocationsContentFiltered($queryData, $fixture, $closure = null)
746
    {
747
        $query = new LocationQuery($queryData);
748
        $this->assertQueryFixture($query, $fixture, $closure);
749
    }
750
751
    /**
752
     * Test for deprecated $criterion property on query object.
753
     *
754
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
755
     * @deprecated
756
     */
757
    public function testDeprecatedCriteriaProperty()
758
    {
759
        $this->assertQueryFixture(
760
            new Query(
761
                [
762
                    'query' => new Criterion\ContentId(
763
                        [1, 4, 10]
764
                    ),
765
                    'sortClauses' => [new SortClause\ContentId()],
766
                ]
767
            ),
768
            $this->getFixtureDir() . 'DeprecatedContentIdQuery.php'
769
        );
770
    }
771
772
    /**
773
     * Test for the findContent() method.
774
     *
775
     * @dataProvider getContentQuerySearches
776
     *
777
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
778
     */
779
    public function testQueryContent($queryData, $fixture, $closure = null)
780
    {
781
        $query = new Query($queryData);
782
        $this->assertQueryFixture($query, $fixture, $closure);
783
    }
784
785
    /**
786
     * Test for the findContentInfo() method.
787
     *
788
     * @dataProvider getContentQuerySearches
789
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
790
     */
791
    public function testQueryContentInfo($queryData, $fixture, $closure = null)
792
    {
793
        $query = new Query($queryData);
794
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure($closure), true);
795
    }
796
797
    /**
798
     * Test for the findLocations() method.
799
     *
800
     * @dataProvider getContentQuerySearches
801
     *
802
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
803
     */
804
    public function testQueryContentLocations($queryData, $fixture, $closure = null)
805
    {
806
        $query = new LocationQuery($queryData);
807
        $this->assertQueryFixture($query, $fixture, $closure);
808
    }
809
810
    /**
811
     * Test for the findLocations() method.
812
     *
813
     * @dataProvider getLocationQuerySearches
814
     *
815
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
816
     */
817
    public function testQueryLocations($queryData, $fixture, $closure = null)
818
    {
819
        $query = new LocationQuery($queryData);
820
        $this->assertQueryFixture($query, $fixture, $closure);
821
    }
822
823
    public function getCaseInsensitiveSearches()
824
    {
825
        return [
826
            [
827
                [
828
                    'filter' => new Criterion\Field(
829
                        'name',
830
                        Criterion\Operator::EQ,
831
                        'Members'
832
                    ),
833
                    'sortClauses' => [new SortClause\ContentId()],
834
                ],
835
            ],
836
            [
837
                [
838
                    'filter' => new Criterion\Field(
839
                        'name',
840
                        Criterion\Operator::EQ,
841
                        'members'
842
                    ),
843
                    'sortClauses' => [new SortClause\ContentId()],
844
                ],
845
            ],
846
            [
847
                [
848
                    'filter' => new Criterion\Field(
849
                        'name',
850
                        Criterion\Operator::EQ,
851
                        'MEMBERS'
852
                    ),
853
                    'sortClauses' => [new SortClause\ContentId()],
854
                ],
855
            ],
856
        ];
857
    }
858
859
    /**
860
     * Test for the findContent() method.
861
     *
862
     * @dataProvider getCaseInsensitiveSearches
863
     *
864
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
865
     */
866
    public function testFindContentFieldFiltersCaseSensitivity($queryData)
867
    {
868
        $query = new Query($queryData);
869
        $this->assertQueryFixture(
870
            $query,
871
            $this->getFixtureDir() . 'Field.php'
872
        );
873
    }
874
875
    /**
876
     * Test for the findLocations() method.
877
     *
878
     * @dataProvider getCaseInsensitiveSearches
879
     *
880
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
881
     */
882
    public function testFindLocationsFieldFiltersCaseSensitivity($queryData)
883
    {
884
        $query = new LocationQuery($queryData);
885
        $this->assertQueryFixture(
886
            $query,
887
            $this->getFixtureDir() . 'Field.php'
888
        );
889
    }
890
891
    public function getRelationFieldFilterSearches()
892
    {
893
        $fixtureDir = $this->getFixtureDir();
894
895
        return [
896
            0 => [
897
                [
898
                    'filter' => new Criterion\FieldRelation(
899
                        'image',
900
                        Criterion\Operator::IN,
901
                        [1, 4, 10]
902
                    ),
903
                    'sortClauses' => [new SortClause\ContentId()],
904
                ],
905
                $fixtureDir . 'FieldRelation.php',
906
            ],
907
            1 => [
908
                [
909
                    'filter' => new Criterion\FieldRelation(
910
                        'image',
911
                        Criterion\Operator::IN,
912
                        [4, 49]
913
                    ),
914
                    'sortClauses' => [new SortClause\ContentId()],
915
                ],
916
                $fixtureDir . 'FieldRelationAll.php',
917
            ],
918
            2 => [
919
                [
920
                    'filter' => new Criterion\FieldRelation(
921
                        'image',
922
                        Criterion\Operator::IN,
923
                        [4]
924
                    ),
925
                    'sortClauses' => [new SortClause\ContentId()],
926
                ],
927
                $fixtureDir . 'FieldRelation.php',
928
            ],
929
            3 => [
930
                [
931
                    'filter' => new Criterion\FieldRelation(
932
                        'image',
933
                        Criterion\Operator::CONTAINS,
934
                        [1, 4, 10]
935
                    ),
936
                    'sortClauses' => [new SortClause\ContentId()],
937
                ],
938
                $fixtureDir . 'MatchNone.php',
939
            ],
940
            4 => [
941
                [
942
                    'filter' => new Criterion\FieldRelation(
943
                        'image',
944
                        Criterion\Operator::CONTAINS,
945
                        [4, 49]
946
                    ),
947
                    'sortClauses' => [new SortClause\ContentId()],
948
                ],
949
                $fixtureDir . 'MatchNone.php',
950
            ],
951
            5 => [
952
                [
953
                    'filter' => new Criterion\FieldRelation(
954
                        'image',
955
                        Criterion\Operator::CONTAINS,
956
                        [4]
957
                    ),
958
                    'sortClauses' => [new SortClause\ContentId()],
959
                ],
960
                $fixtureDir . 'FieldRelation.php',
961
            ],
962
        ];
963
    }
964
965
    /**
966
     * Purely for creating relation data needed for testFindRelationFieldContentInfoFiltered()
967
     * and testFindRelationFieldLocationsFiltered().
968
     */
969
    public function testRelationContentCreation()
970
    {
971
        $repository = $this->getRepository();
972
        $galleryType = $repository->getContentTypeService()->loadContentTypeByIdentifier('gallery');
973
        $contentService = $repository->getContentService();
974
        $locationService = $repository->getLocationService();
975
976
        $locationCreateStruct = $locationService->newLocationCreateStruct(2); // Home
977
978
        $createStruct = $contentService->newContentCreateStruct($galleryType, 'eng-GB');
979
        $createStruct->setField('name', 'Image gallery');
980
        $createStruct->setField('image', 49); // Images folder
981
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
982
        $contentService->publishVersion($draft->getVersionInfo());
983
984
        $createStruct = $contentService->newContentCreateStruct($galleryType, 'eng-GB');
985
        $createStruct->setField('name', 'User gallery');
986
        $createStruct->setField('image', 4); // User folder
987
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
988
        $contentService->publishVersion($draft->getVersionInfo());
989
990
        $this->refreshSearch($repository);
991
    }
992
993
    /**
994
     * Test for FieldRelation using findContentInfo() method.
995
     *
996
     * @dataProvider getRelationFieldFilterSearches
997
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
998
     * @depends eZ\Publish\API\Repository\Tests\SearchServiceTest::testRelationContentCreation
999
     */
1000
    public function testFindRelationFieldContentInfoFiltered($queryData, $fixture)
1001
    {
1002
        $this->getRepository(false); // To make sure repo is setup w/o removing data from getRelationFieldFilterContentSearches
1003
        $query = new Query($queryData);
1004
        $this->assertQueryFixture($query, $fixture, null, true, true, false);
1005
    }
1006
1007
    /**
1008
     * Test for FieldRelation using findLocations() method.
1009
     *
1010
     * @dataProvider getRelationFieldFilterSearches
1011
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
1012
     * @depends eZ\Publish\API\Repository\Tests\SearchServiceTest::testRelationContentCreation
1013
     */
1014
    public function testFindRelationFieldLocationsFiltered($queryData, $fixture)
1015
    {
1016
        $this->getRepository(false); // To make sure repo is setup w/o removing data from getRelationFieldFilterContentSearches
1017
        $query = new LocationQuery($queryData);
1018
        $this->assertQueryFixture($query, $fixture, null, true, false, false);
1019
    }
1020
1021 View Code Duplication
    public function testFindSingle()
1022
    {
1023
        $repository = $this->getRepository();
1024
        $searchService = $repository->getSearchService();
1025
1026
        $content = $searchService->findSingle(
1027
            new Criterion\ContentId(
1028
                [4]
1029
            )
1030
        );
1031
1032
        $this->assertEquals(
1033
            4,
1034
            $content->id
1035
        );
1036
    }
1037
1038 View Code Duplication
    public function testFindNoPerformCount()
1039
    {
1040
        $repository = $this->getRepository();
1041
        $searchService = $repository->getSearchService();
1042
1043
        $query = new Query();
1044
        $query->performCount = false;
1045
        $query->query = new Criterion\ContentTypeId(
1046
            [4]
1047
        );
1048
1049
        $searchHit = $searchService->findContent($query);
1050
1051
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1052
            $this->assertNull(
1053
                $searchHit->totalCount
1054
            );
1055
        } else {
1056
            $this->assertEquals(
1057
                2,
1058
                $searchHit->totalCount
1059
            );
1060
        }
1061
    }
1062
1063
    /**
1064
     * @expectedException \RuntimeException
1065
     */
1066 View Code Duplication
    public function testFindNoPerformCountException()
1067
    {
1068
        if (ltrim(get_class($this->getSetupFactory()), '\\') !== 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1069
            $this->markTestSkipped('Only applicable to Legacy/DB based search');
1070
        }
1071
1072
        $repository = $this->getRepository();
1073
        $searchService = $repository->getSearchService();
1074
1075
        $query = new Query();
1076
        $query->performCount = false;
1077
        $query->limit = 0;
1078
        $query->query = new Criterion\ContentTypeId(
1079
            [4]
1080
        );
1081
1082
        $searchService->findContent($query);
1083
    }
1084
1085 View Code Duplication
    public function testFindLocationsNoPerformCount()
1086
    {
1087
        $repository = $this->getRepository();
1088
        $searchService = $repository->getSearchService();
1089
1090
        $query = new LocationQuery();
1091
        $query->performCount = false;
1092
        $query->query = new Criterion\ContentTypeId(
1093
            [4]
1094
        );
1095
1096
        $searchHit = $searchService->findLocations($query);
1097
1098
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1099
            $this->assertNull(
1100
                $searchHit->totalCount
1101
            );
1102
        } else {
1103
            $this->assertEquals(
1104
                2,
1105
                $searchHit->totalCount
1106
            );
1107
        }
1108
    }
1109
1110
    /**
1111
     * @expectedException \RuntimeException
1112
     */
1113 View Code Duplication
    public function testFindLocationsNoPerformCountException()
1114
    {
1115
        if (ltrim(get_class($this->getSetupFactory()), '\\') !== 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1116
            $this->markTestSkipped('Only applicable to Legacy/DB based search');
1117
        }
1118
1119
        $repository = $this->getRepository();
1120
        $searchService = $repository->getSearchService();
1121
1122
        $query = new LocationQuery();
1123
        $query->performCount = false;
1124
        $query->limit = 0;
1125
        $query->query = new Criterion\ContentTypeId(
1126
            [4]
1127
        );
1128
1129
        $searchService->findLocations($query);
1130
    }
1131
1132
    /**
1133
     * Create test Content with ezcountry field having multiple countries selected.
1134
     *
1135
     * @return Content
1136
     */
1137
    protected function createMultipleCountriesContent()
1138
    {
1139
        $repository = $this->getRepository();
1140
        $contentTypeService = $repository->getContentTypeService();
1141
        $contentService = $repository->getContentService();
1142
1143
        $createStruct = $contentTypeService->newContentTypeCreateStruct('countries-multiple');
1144
        $createStruct->mainLanguageCode = 'eng-GB';
1145
        $createStruct->remoteId = 'countries-multiple-123';
1146
        $createStruct->names = ['eng-GB' => 'Multiple countries'];
1147
        $createStruct->creatorId = 14;
1148
        $createStruct->creationDate = new \DateTime();
1149
1150
        $fieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('countries', 'ezcountry');
1151
        $fieldCreate->names = ['eng-GB' => 'Countries'];
1152
        $fieldCreate->fieldGroup = 'main';
1153
        $fieldCreate->position = 1;
1154
        $fieldCreate->isTranslatable = false;
1155
        $fieldCreate->isSearchable = true;
1156
        $fieldCreate->fieldSettings = ['isMultiple' => true];
1157
1158
        $createStruct->addFieldDefinition($fieldCreate);
1159
1160
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
1161
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
1162
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
1163
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
1164
1165
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1166
        $createStruct->remoteId = 'countries-multiple-456';
1167
        $createStruct->alwaysAvailable = false;
1168
        $createStruct->setField(
1169
            'countries',
1170
            ['BE', 'DE', 'FR', 'HR', 'NO', 'PT', 'RU']
1171
        );
1172
1173
        $draft = $contentService->createContent($createStruct);
1174
        $content = $contentService->publishVersion($draft->getVersionInfo());
1175
1176
        $this->refreshSearch($repository);
1177
1178
        return $content;
1179
    }
1180
1181
    /**
1182
     * Test for the findContent() method.
1183
     *
1184
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
1185
     */
1186 View Code Duplication
    public function testFieldCollectionContains()
1187
    {
1188
        $testContent = $this->createMultipleCountriesContent();
1189
1190
        $query = new Query(
1191
            [
1192
                'query' => new Criterion\Field(
1193
                    'countries',
1194
                    Criterion\Operator::CONTAINS,
1195
                    'Belgium'
1196
                ),
1197
            ]
1198
        );
1199
1200
        $repository = $this->getRepository();
1201
        $searchService = $repository->getSearchService();
1202
        $result = $searchService->findContent($query);
1203
1204
        $this->assertEquals(1, $result->totalCount);
1205
        $this->assertEquals(
1206
            $testContent->id,
1207
            $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...
1208
        );
1209
    }
1210
1211
    /**
1212
     * Test for the findContent() method.
1213
     *
1214
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
1215
     * @depends eZ\Publish\API\Repository\Tests\SearchServiceTest::testFieldCollectionContains
1216
     */
1217 View Code Duplication
    public function testFieldCollectionContainsNoMatch()
1218
    {
1219
        $this->createMultipleCountriesContent();
1220
        $query = new Query(
1221
            [
1222
                'query' => new Criterion\Field(
1223
                    'countries',
1224
                    Criterion\Operator::CONTAINS,
1225
                    'Netherlands Antilles'
1226
                ),
1227
            ]
1228
        );
1229
1230
        $repository = $this->getRepository();
1231
        $searchService = $repository->getSearchService();
1232
        $result = $searchService->findContent($query);
1233
1234
        $this->assertEquals(0, $result->totalCount);
1235
    }
1236
1237
    /**
1238
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1239
     * @expectedExceptionMessage Argument '$criterion->target' is invalid: No searchable fields found for the given criterion target 'some_hopefully_unknown_field'
1240
     */
1241 View Code Duplication
    public function testInvalidFieldIdentifierRange()
1242
    {
1243
        $repository = $this->getRepository();
1244
        $searchService = $repository->getSearchService();
1245
1246
        $searchService->findContent(
1247
            new Query(
1248
                [
1249
                    'filter' => new Criterion\Field(
1250
                        'some_hopefully_unknown_field',
1251
                        Criterion\Operator::BETWEEN,
1252
                        [10, 1000]
1253
                    ),
1254
                    'sortClauses' => [new SortClause\ContentId()],
1255
                ]
1256
            )
1257
        );
1258
    }
1259
1260
    /**
1261
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1262
     * @expectedExceptionMessage Argument '$criterion->target' is invalid: No searchable fields found for the given criterion target 'some_hopefully_unknown_field'
1263
     */
1264 View Code Duplication
    public function testInvalidFieldIdentifierIn()
1265
    {
1266
        $repository = $this->getRepository();
1267
        $searchService = $repository->getSearchService();
1268
1269
        $searchService->findContent(
1270
            new Query(
1271
                [
1272
                    'filter' => new Criterion\Field(
1273
                        'some_hopefully_unknown_field',
1274
                        Criterion\Operator::EQ,
1275
                        1000
1276
                    ),
1277
                    'sortClauses' => [new SortClause\ContentId()],
1278
                ]
1279
            )
1280
        );
1281
    }
1282
1283
    /**
1284
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1285
     * @expectedExceptionMessage Argument '$criterion->target' is invalid: No searchable fields found for the given criterion target 'tag_cloud_url'
1286
     */
1287 View Code Duplication
    public function testFindContentWithNonSearchableField()
1288
    {
1289
        $repository = $this->getRepository();
1290
        $searchService = $repository->getSearchService();
1291
1292
        $searchService->findContent(
1293
            new Query(
1294
                [
1295
                    'filter' => new Criterion\Field(
1296
                        'tag_cloud_url',
1297
                        Criterion\Operator::EQ,
1298
                        'http://nimbus.com'
1299
                    ),
1300
                    'sortClauses' => [new SortClause\ContentId()],
1301
                ]
1302
            )
1303
        );
1304
    }
1305
1306
    /**
1307
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1308
     * @expectedExceptionMessage Argument '$sortClause->targetData' is invalid: No searchable fields found for the given sort clause target 'title' on 'template_look'
1309
     */
1310 View Code Duplication
    public function testSortFieldWithNonSearchableField()
1311
    {
1312
        $repository = $this->getRepository();
1313
        $searchService = $repository->getSearchService();
1314
1315
        $searchService->findContent(
1316
            new Query(
1317
                [
1318
                    'sortClauses' => [new SortClause\Field('template_look', 'title')],
1319
                ]
1320
            )
1321
        );
1322
    }
1323
1324
    /**
1325
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1326
     * @expectedExceptionMessage Argument '$sortClause->targetData' is invalid: No searchable fields found for the given sort clause target 'title' on 'template_look'
1327
     */
1328 View Code Duplication
    public function testSortMapLocationDistanceWithNonSearchableField()
1329
    {
1330
        $repository = $this->getRepository();
1331
        $searchService = $repository->getSearchService();
1332
1333
        $searchService->findContent(
1334
            new Query(
1335
                [
1336
                    'sortClauses' => [
1337
                        new SortClause\MapLocationDistance(
1338
                            'template_look',
1339
                            'title',
1340
                            1,
1341
                            2
1342
                        ),
1343
                    ],
1344
                ]
1345
            )
1346
        );
1347
    }
1348
1349
    /**
1350
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1351
     */
1352 View Code Duplication
    public function testFindSingleFailMultiple()
1353
    {
1354
        $repository = $this->getRepository();
1355
        $searchService = $repository->getSearchService();
1356
1357
        $searchService->findSingle(
1358
            new Criterion\ContentId(
1359
                [4, 10]
1360
            )
1361
        );
1362
    }
1363
1364
    /**
1365
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1366
     */
1367
    public function testFindSingleWithNonSearchableField()
1368
    {
1369
        $repository = $this->getRepository();
1370
        $searchService = $repository->getSearchService();
1371
1372
        $searchService->findSingle(
1373
            new Criterion\Field(
1374
                'tag_cloud_url',
1375
                Criterion\Operator::EQ,
1376
                'http://nimbus.com'
1377
            )
1378
        );
1379
    }
1380
1381
    public function getSortedContentSearches()
1382
    {
1383
        $fixtureDir = $this->getFixtureDir();
1384
1385
        return [
1386
            0 => [
1387
                [
1388
                    'filter' => new Criterion\SectionId([2]),
1389
                    'offset' => 0,
1390
                    'limit' => 10,
1391
                    'sortClauses' => [],
1392
                ],
1393
                $fixtureDir . 'SortNone.php',
1394
                // Result having the same sort level should be sorted between them to be system independent
1395
                function (&$data) {
1396
                    usort(
1397
                        $data->searchHits,
1398
                        function ($a, $b) {
1399
                            return ($a->valueObject['id'] < $b->valueObject['id']) ? -1 : 1;
1400
                        }
1401
                    );
1402
                },
1403
            ],
1404
            1 => [
1405
                [
1406
                    'filter' => new Criterion\SectionId([2]),
1407
                    'offset' => 0,
1408
                    'limit' => 10,
1409
                    'sortClauses' => [
1410
                        new SortClause\DatePublished(),
1411
                        new SortClause\ContentId(),
1412
                    ],
1413
                ],
1414
                $fixtureDir . 'SortDatePublished.php',
1415
            ],
1416
            2 => [
1417
                [
1418
                    'filter' => new Criterion\SectionId([2]),
1419
                    'offset' => 0,
1420
                    'limit' => 50,
1421
                    'sortClauses' => [
1422
                        new SortClause\DateModified(),
1423
                        new SortClause\ContentId(),
1424
                    ],
1425
                ],
1426
                $fixtureDir . 'SortDateModified.php',
1427
            ],
1428
            3 => [
1429
                [
1430
                    'filter' => new Criterion\SectionId([4, 2, 6, 3]),
1431
                    'offset' => 0,
1432
                    'limit' => 50,
1433
                    'sortClauses' => [
1434
                        new SortClause\SectionIdentifier(),
1435
                        new SortClause\ContentId(),
1436
                    ],
1437
                ],
1438
                $fixtureDir . 'SortSectionIdentifier.php',
1439
            ],
1440
            4 => [
1441
                [
1442
                    'filter' => new Criterion\SectionId([4, 2, 6, 3]),
1443
                    'offset' => 0,
1444
                    'limit' => 50,
1445
                    'sortClauses' => [
1446
                        new SortClause\SectionName(),
1447
                        new SortClause\ContentId(),
1448
                    ],
1449
                ],
1450
                $fixtureDir . 'SortSectionName.php',
1451
            ],
1452
            5 => [
1453
                [
1454
                    'filter' => new Criterion\SectionId([2, 3]),
1455
                    'offset' => 0,
1456
                    'limit' => 50,
1457
                    'sortClauses' => [
1458
                        new SortClause\ContentName(),
1459
                        new SortClause\ContentId(),
1460
                    ],
1461
                ],
1462
                $fixtureDir . 'SortContentName.php',
1463
            ],
1464
            6 => [
1465
                [
1466
                    'filter' => new Criterion\ContentTypeId(1),
1467
                    'offset' => 0,
1468
                    'limit' => 50,
1469
                    'sortClauses' => [
1470
                        new SortClause\Field('folder', 'name', Query::SORT_ASC),
1471
                        new SortClause\ContentId(),
1472
                    ],
1473
                ],
1474
                $fixtureDir . 'SortFolderName.php',
1475
            ],
1476
            7 => [
1477
                [
1478
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1479
                    'offset' => 0,
1480
                    'limit' => 50,
1481
                    'sortClauses' => [
1482
                        new SortClause\Field('folder', 'name', Query::SORT_ASC),
1483
                        new SortClause\ContentId(),
1484
                    ],
1485
                ],
1486
                $fixtureDir . 'SortFieldMultipleTypes.php',
1487
            ],
1488
            8 => [
1489
                [
1490
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1491
                    'offset' => 0,
1492
                    'limit' => 50,
1493
                    'sortClauses' => [
1494
                        new SortClause\Field('folder', 'name', Query::SORT_DESC),
1495
                        new SortClause\ContentId(),
1496
                    ],
1497
                ],
1498
                $fixtureDir . 'SortFieldMultipleTypesReverse.php',
1499
            ],
1500
            9 => [
1501
                [
1502
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1503
                    'offset' => 3,
1504
                    'limit' => 5,
1505
                    'sortClauses' => [
1506
                        new SortClause\Field('folder', 'name', Query::SORT_ASC),
1507
                        new SortClause\Field('user', 'first_name', Query::SORT_ASC),
1508
                        new SortClause\ContentId(),
1509
                    ],
1510
                ],
1511
                $fixtureDir . 'SortFieldMultipleTypesSlice.php',
1512
            ],
1513
            10 => [
1514
                [
1515
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1516
                    'offset' => 3,
1517
                    'limit' => 5,
1518
                    'sortClauses' => [
1519
                        new SortClause\Field('folder', 'name', Query::SORT_DESC),
1520
                        new SortClause\Field('user', 'first_name', Query::SORT_ASC),
1521
                        new SortClause\ContentId(),
1522
                    ],
1523
                ],
1524
                $fixtureDir . 'SortFieldMultipleTypesSliceReverse.php',
1525
            ],
1526
        ];
1527
    }
1528
1529
    public function getSortedLocationSearches()
1530
    {
1531
        $fixtureDir = $this->getFixtureDir();
1532
1533
        return [
1534
            [
1535
                [
1536
                    'filter' => new Criterion\SectionId([2]),
1537
                    'offset' => 0,
1538
                    'limit' => 10,
1539
                    'sortClauses' => [new SortClause\Location\Path(Query::SORT_DESC)],
1540
                ],
1541
                $fixtureDir . 'SortPathString.php',
1542
            ],
1543
            [
1544
                [
1545
                    'filter' => new Criterion\SectionId([2]),
1546
                    'offset' => 0,
1547
                    'limit' => 10,
1548
                    'sortClauses' => [new SortClause\Location\Depth(Query::SORT_ASC)],
1549
                ],
1550
                $fixtureDir . 'SortLocationDepth.php',
1551
                // Result having the same sort level should be sorted between them to be system independent
1552
                function (&$data) {
1553
                    // Result with ids:
1554
                    //     4 has depth = 1
1555
                    //     11, 12, 13, 42, 59 have depth = 2
1556
                    //     10, 14 have depth = 3
1557
                    $map = [
1558
                        4 => 0,
1559
                        11 => 1,
1560
                        12 => 2,
1561
                        13 => 3,
1562
                        42 => 4,
1563
                        59 => 5,
1564
                        10 => 6,
1565
                        14 => 7,
1566
                    ];
1567
                    usort(
1568
                        $data->searchHits,
1569
                        function ($a, $b) use ($map) {
1570
                            return ($map[$a->valueObject['id']] < $map[$b->valueObject['id']]) ? -1 : 1;
1571
                        }
1572
                    );
1573
                },
1574
            ],
1575
            [
1576
                [
1577
                    'filter' => new Criterion\SectionId([3]),
1578
                    'offset' => 0,
1579
                    'limit' => 10,
1580
                    'sortClauses' => [
1581
                        new SortClause\Location\Path(Query::SORT_DESC),
1582
                        new SortClause\ContentName(Query::SORT_ASC),
1583
                    ],
1584
                ],
1585
                $fixtureDir . 'SortMultiple.php',
1586
            ],
1587
            [
1588
                [
1589
                    'filter' => new Criterion\SectionId([2]),
1590
                    'offset' => 0,
1591
                    'limit' => 10,
1592
                    'sortClauses' => [
1593
                        new SortClause\Location\Priority(Query::SORT_DESC),
1594
                        new SortClause\ContentId(),
1595
                    ],
1596
                ],
1597
                $fixtureDir . 'SortDesc.php',
1598
            ],
1599
        ];
1600
    }
1601
1602
    /**
1603
     * @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
1604
     */
1605 View Code Duplication
    protected function createTestContentType()
1606
    {
1607
        $repository = $this->getRepository();
1608
        $contentTypeService = $repository->getContentTypeService();
1609
1610
        $createStruct = $contentTypeService->newContentTypeCreateStruct('test-type');
1611
        $createStruct->mainLanguageCode = 'eng-GB';
1612
        $createStruct->names = ['eng-GB' => 'Test type'];
1613
        $createStruct->creatorId = 14;
1614
        $createStruct->creationDate = new \DateTime();
1615
1616
        $translatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('integer', 'ezinteger');
1617
        $translatableFieldCreate->names = ['eng-GB' => 'Simple translatable integer field'];
1618
        $translatableFieldCreate->fieldGroup = 'main';
1619
        $translatableFieldCreate->position = 1;
1620
        $translatableFieldCreate->isTranslatable = true;
1621
        $translatableFieldCreate->isSearchable = true;
1622
1623
        $createStruct->addFieldDefinition($translatableFieldCreate);
1624
1625
        $nonTranslatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('integer2', 'ezinteger');
1626
        $nonTranslatableFieldCreate->names = ['eng-GB' => 'Simple non-translatable integer field'];
1627
        $nonTranslatableFieldCreate->fieldGroup = 'main';
1628
        $nonTranslatableFieldCreate->position = 2;
1629
        $nonTranslatableFieldCreate->isTranslatable = false;
1630
        $nonTranslatableFieldCreate->isSearchable = true;
1631
1632
        $createStruct->addFieldDefinition($nonTranslatableFieldCreate);
1633
1634
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
1635
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
1636
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
1637
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
1638
1639
        return $contentType;
1640
    }
1641
1642
    /**
1643
     * @param \eZ\Publish\API\Repository\Values\ContentType\ContentType $contentType
1644
     * @param int $fieldValue11 Value for translatable field in first language
1645
     * @param int $fieldValue12 Value for translatable field in second language
1646
     * @param int $fieldValue2 Value for non translatable field
1647
     * @param string $mainLanguageCode
1648
     * @param bool $alwaysAvailable
1649
     *
1650
     * @return Content
1651
     */
1652
    protected function createMultilingualContent(
1653
        $contentType,
1654
        $fieldValue11 = null,
1655
        $fieldValue12 = null,
1656
        $fieldValue2 = null,
1657
        $mainLanguageCode = 'eng-GB',
1658
        $alwaysAvailable = false
1659
    ) {
1660
        $repository = $this->getRepository();
1661
        $contentService = $repository->getContentService();
1662
1663
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1664
        $createStruct->alwaysAvailable = $alwaysAvailable;
1665
        $createStruct->mainLanguageCode = $mainLanguageCode;
1666
        if ($fieldValue11) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $fieldValue11 of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1667
            $createStruct->setField('integer', $fieldValue11, 'eng-GB');
1668
        }
1669
        if ($fieldValue12) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $fieldValue12 of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1670
            $createStruct->setField('integer', $fieldValue12, 'ger-DE');
1671
        }
1672
        $createStruct->setField('integer2', $fieldValue2, $mainLanguageCode);
1673
1674
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
1675
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
1676
        $content = $contentService->publishVersion($draft->getVersionInfo());
1677
1678
        $this->refreshSearch($repository);
1679
1680
        return $content;
1681
    }
1682
1683
    protected function checkPrioritizedLanguagesSupport()
1684
    {
1685
        $setupFactory = $this->getSetupFactory();
1686
        if ($setupFactory instanceof LegacyElasticsearch) {
1687
            $this->markTestIncomplete('Prioritized languages are not supported with Elasticsearch engine');
1688
        }
1689
    }
1690
1691
    public function providerForTestMultilingualFieldSort()
1692
    {
1693
        return [
1694
            0 => [
1695
                [
1696
                    1 => [1, 2, 1],
1697
                    2 => [2, 1, 2],
1698
                    3 => [2, 1, 3],
1699
                    4 => [1, 2, 4],
1700
                ],
1701
                [
1702
                    'languages' => [
1703
                        'eng-GB',
1704
                        'ger-DE',
1705
                    ],
1706
                ],
1707
                [
1708
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
1709
                    new SortClause\Field('test-type', 'integer2', Query::SORT_DESC),
1710
                ],
1711
                /**
1712
                 * Expected order, Value eng-GB, Value ger-DE.
1713
                 *
1714
                 * Content 4, 1, 2, 4
1715
                 * Content 1, 1, 2, 1
1716
                 * Content 3, 2, 1, 3
1717
                 * Content 2, 2, 1, 2
1718
                 */
1719
                [4, 1, 3, 2],
1720
            ],
1721
            1 => [
1722
                [
1723
                    1 => [1, 2, 1],
1724
                    2 => [2, 1, 2],
1725
                    3 => [2, 1, 3],
1726
                    4 => [1, 2, 4],
1727
                ],
1728
                [
1729
                    'languages' => [
1730
                        'ger-DE',
1731
                        'eng-GB',
1732
                    ],
1733
                ],
1734
                [
1735
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
1736
                    new SortClause\Field('test-type', 'integer2', Query::SORT_DESC),
1737
                ],
1738
                /**
1739
                 * Expected order, Value eng-GB, Value ger-DE.
1740
                 *
1741
                 * Content 3, 2, 1, 3
1742
                 * Content 2, 2, 1, 2
1743
                 * Content 4, 1, 2, 4
1744
                 * Content 1, 1, 2, 1
1745
                 */
1746
                [3, 2, 4, 1],
1747
            ],
1748
            2 => [
1749
                [
1750
                    1 => [null, 2, null, 'ger-DE'],
1751
                    2 => [3, null, null, 'eng-GB'],
1752
                    3 => [4, null, null, 'eng-GB'],
1753
                    4 => [null, 1, null, 'ger-DE'],
1754
                ],
1755
                [
1756
                    'languages' => [
1757
                        'eng-GB',
1758
                    ],
1759
                ],
1760
                [
1761
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1762
                ],
1763
                /**
1764
                 * Expected order, Value eng-GB, Value ger-DE.
1765
                 *
1766
                 * Content 3, 4, -
1767
                 * Content 2, 3, -
1768
                 */
1769
                [3, 2],
1770
            ],
1771
            3 => [
1772
                [
1773
                    1 => [null, 2, null, 'ger-DE'],
1774
                    2 => [3, null, null, 'eng-GB'],
1775
                    3 => [4, null, null, 'eng-GB'],
1776
                    4 => [null, 1, null, 'ger-DE'],
1777
                ],
1778
                [
1779
                    'languages' => [
1780
                        'ger-DE',
1781
                    ],
1782
                ],
1783
                [
1784
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1785
                ],
1786
                /**
1787
                 * Expected order, Value eng-GB, Value ger-DE.
1788
                 *
1789
                 * Content 1, -, 2
1790
                 * Content 4, -, 1
1791
                 */
1792
                [1, 4],
1793
            ],
1794
            4 => [
1795
                [
1796
                    1 => [null, 2, null, 'ger-DE'],
1797
                    2 => [3, null, null, 'eng-GB'],
1798
                    3 => [4, null, null, 'eng-GB'],
1799
                    4 => [null, 1, null, 'ger-DE'],
1800
                ],
1801
                [
1802
                    'languages' => [
1803
                        'eng-GB',
1804
                        'ger-DE',
1805
                    ],
1806
                ],
1807
                [
1808
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1809
                ],
1810
                /**
1811
                 * Expected order, Value eng-GB, Value ger-DE.
1812
                 *
1813
                 * Content 3, 4, -
1814
                 * Content 2, 3, -
1815
                 * Content 1, -, 2
1816
                 * Content 4, -, 1
1817
                 */
1818
                [3, 2, 1, 4],
1819
            ],
1820
            5 => [
1821
                [
1822
                    1 => [null, 2, null, 'ger-DE'],
1823
                    2 => [3, null, null, 'eng-GB'],
1824
                    3 => [4, null, null, 'eng-GB'],
1825
                    4 => [null, 1, null, 'ger-DE'],
1826
                ],
1827
                [
1828
                    'languages' => [
1829
                        'ger-DE',
1830
                        'eng-GB',
1831
                    ],
1832
                ],
1833
                [
1834
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1835
                ],
1836
                /**
1837
                 * Expected order, Value eng-GB, Value ger-DE.
1838
                 *
1839
                 * Content 3, 4, -
1840
                 * Content 2, 3, -
1841
                 * Content 1, -, 2
1842
                 * Content 4, -, 1
1843
                 */
1844
                [3, 2, 1, 4],
1845
            ],
1846
            6 => [
1847
                [
1848
                    1 => [null, 2, null, 'ger-DE'],
1849
                    2 => [3, 4, null, 'eng-GB'],
1850
                    3 => [4, 3, null, 'eng-GB'],
1851
                    4 => [null, 1, null, 'ger-DE'],
1852
                ],
1853
                [
1854
                    'languages' => [
1855
                        'eng-GB',
1856
                        'ger-DE',
1857
                    ],
1858
                ],
1859
                [
1860
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1861
                ],
1862
                /**
1863
                 * Expected order, Value eng-GB, Value ger-DE.
1864
                 *
1865
                 * Content 3, 4, 3
1866
                 * Content 2, 3, 4
1867
                 * Content 1, -, 2
1868
                 * Content 4, -, 1
1869
                 */
1870
                [3, 2, 1, 4],
1871
            ],
1872
            7 => [
1873
                [
1874
                    1 => [null, 2, null, 'ger-DE'],
1875
                    2 => [3, 4, null, 'eng-GB'],
1876
                    3 => [4, 3, null, 'eng-GB'],
1877
                    4 => [null, 1, null, 'ger-DE'],
1878
                ],
1879
                [
1880
                    'languages' => [
1881
                        'ger-DE',
1882
                        'eng-GB',
1883
                    ],
1884
                ],
1885
                [
1886
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1887
                ],
1888
                /**
1889
                 * Expected order, Value eng-GB, Value ger-DE.
1890
                 *
1891
                 * Content 2, 3, 4
1892
                 * Content 3, 4, 3
1893
                 * Content 1, -, 2
1894
                 * Content 4, -, 1
1895
                 */
1896
                [2, 3, 1, 4],
1897
            ],
1898
            8 => [
1899
                [
1900
                    1 => [null, 1, null, 'ger-DE', true],
1901
                    2 => [4, null, null, 'eng-GB', true],
1902
                    3 => [3, null, null, 'eng-GB', false],
1903
                    4 => [null, 2, null, 'ger-DE', false],
1904
                ],
1905
                [
1906
                    'languages' => [
1907
                        'eng-GB',
1908
                    ],
1909
                ],
1910
                [
1911
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
1912
                ],
1913
                /**
1914
                 * Expected order, Value eng-GB, Value ger-DE.
1915
                 *
1916
                 * Content 1, -, 1
1917
                 * Content 3, 3, -
1918
                 * Content 2, 4, -
1919
                 */
1920
                [1, 3, 2],
1921
            ],
1922
            9 => [
1923
                [
1924
                    1 => [null, 1, null, 'ger-DE', true],
1925
                    2 => [4, null, null, 'eng-GB', true],
1926
                    3 => [3, null, null, 'eng-GB', false],
1927
                    4 => [null, 2, null, 'ger-DE', false],
1928
                ],
1929
                [
1930
                    'languages' => [
1931
                        'ger-DE',
1932
                    ],
1933
                ],
1934
                [
1935
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1936
                ],
1937
                /**
1938
                 * Expected order, Value eng-GB, Value ger-DE.
1939
                 *
1940
                 * Content 2, 4, -
1941
                 * Content 4, -, 2
1942
                 * Content 1, -, 1
1943
                 */
1944
                [2, 4, 1],
1945
            ],
1946
            10 => [
1947
                [
1948
                    1 => [null, 1, null, 'ger-DE', true],
1949
                    2 => [4, null, null, 'eng-GB', true],
1950
                    3 => [3, null, null, 'eng-GB', false],
1951
                    4 => [null, 2, null, 'ger-DE', false],
1952
                ],
1953
                [
1954
                    'languages' => [
1955
                        'eng-GB',
1956
                    ],
1957
                    'useAlwaysAvailable' => false,
1958
                ],
1959
                [
1960
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
1961
                ],
1962
                /**
1963
                 * Expected order, Value eng-GB, Value ger-DE.
1964
                 *
1965
                 * Content 3, 3, -
1966
                 * Content 2, 4, -
1967
                 */
1968
                [3, 2],
1969
            ],
1970
            11 => [
1971
                [
1972
                    1 => [null, 1, null, 'ger-DE', true],
1973
                    2 => [4, null, null, 'eng-GB', true],
1974
                    3 => [3, null, null, 'eng-GB', false],
1975
                    4 => [null, 2, null, 'ger-DE', false],
1976
                ],
1977
                [
1978
                    'languages' => [
1979
                        'ger-DE',
1980
                    ],
1981
                    'useAlwaysAvailable' => false,
1982
                ],
1983
                [
1984
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1985
                ],
1986
                /**
1987
                 * Expected order, Value eng-GB, Value ger-DE.
1988
                 *
1989
                 * Content 4, -, 2
1990
                 * Content 1, -, 1
1991
                 */
1992
                [4, 1],
1993
            ],
1994
        ];
1995
    }
1996
1997
    /**
1998
     * Test for the findContent() method.
1999
     *
2000
     * @group rrr
2001
     * @dataProvider providerForTestMultilingualFieldSort
2002
     *
2003
     * @param array $contentDataList
2004
     * @param array $languageSettings
2005
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] $sortClauses
2006
     * @param array $expected
2007
     */
2008
    public function testMultilingualFieldSortContent(
2009
        array $contentDataList,
2010
        $languageSettings,
2011
        array $sortClauses,
2012
        $expected
2013
    ) {
2014
        $this->assertMultilingualFieldSort(
2015
            $contentDataList,
2016
            $languageSettings,
2017
            $sortClauses,
2018
            $expected
2019
        );
2020
    }
2021
2022
    /**
2023
     * Test for the findLocations() method.
2024
     *
2025
     * @group rrr
2026
     * @dataProvider providerForTestMultilingualFieldSort
2027
     *
2028
     * @param array $contentDataList
2029
     * @param array $languageSettings
2030
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] $sortClauses
2031
     * @param array $expected
2032
     */
2033
    public function testMultilingualFieldSortLocation(
2034
        array $contentDataList,
2035
        $languageSettings,
2036
        array $sortClauses,
2037
        $expected
2038
    ) {
2039
        $this->assertMultilingualFieldSort(
2040
            $contentDataList,
2041
            $languageSettings,
2042
            $sortClauses,
2043
            $expected,
2044
            false
2045
        );
2046
    }
2047
2048
    /**
2049
     * @param array $contentDataList
2050
     * @param array $languageSettings
2051
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] $sortClauses
2052
     * @param array $expected
2053
     * @param bool $contentSearch
2054
     */
2055
    protected function assertMultilingualFieldSort(
2056
        array $contentDataList,
2057
        $languageSettings,
2058
        array $sortClauses,
2059
        $expected,
2060
        $contentSearch = true
2061
    ) {
2062
        $this->checkPrioritizedLanguagesSupport();
2063
        $contentType = $this->createTestContentType();
2064
2065
        // Create a draft to account for behaviour with ContentType in different states
2066
        $repository = $this->getRepository();
2067
        $contentTypeService = $repository->getContentTypeService();
2068
        $contentTypeService->createContentTypeDraft($contentType);
2069
2070
        $defaults = [null, null, null, 'eng-GB', false];
2071
        $contentIdList = [];
2072 View Code Duplication
        foreach ($contentDataList as $key => $contentData) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2073
            $contentData = $contentData + $defaults;
2074
            list(
2075
                $fieldValue11,
2076
                $fieldValue12,
2077
                $fieldValue2,
2078
                $mainLanguageCode,
2079
                $alwaysAvailable
2080
            ) = $contentData;
2081
2082
            $contentIdList[$key] = $this->createMultilingualContent(
2083
                $contentType,
2084
                $fieldValue11,
2085
                $fieldValue12,
2086
                $fieldValue2,
2087
                $mainLanguageCode,
2088
                $alwaysAvailable
2089
            )->id;
2090
        }
2091
2092
        // "article" type Content is not matched, this ensures that non-matched
2093
        // field does not affect sort
2094
        $dummySortClause = new SortClause\Field('article', 'title', Query::SORT_ASC);
2095
        array_unshift($sortClauses, $dummySortClause);
2096
        $sortClauses[] = $dummySortClause;
2097
2098
        $searchService = $repository->getSearchService();
2099
        if ($contentSearch) {
2100
            $query = new Query(
2101
                [
2102
                    'query' => new Criterion\ContentTypeId($contentType->id),
2103
                    'sortClauses' => $sortClauses,
2104
                ]
2105
            );
2106
            $result = $searchService->findContent($query, $languageSettings);
2107
        } else {
2108
            $query = new LocationQuery(
2109
                [
2110
                    'query' => new Criterion\ContentTypeId($contentType->id),
2111
                    'sortClauses' => $sortClauses,
2112
                ]
2113
            );
2114
            $result = $searchService->findLocations($query, $languageSettings);
2115
        }
2116
2117
        $this->assertEquals(count($expected), $result->totalCount);
2118
2119
        $expectedIdList = [];
2120
        foreach ($expected as $contentNumber) {
2121
            $expectedIdList[] = $contentIdList[$contentNumber];
2122
        }
2123
2124
        $this->assertEquals($expectedIdList, $this->mapResultContentIds($result));
2125
    }
2126
2127
    public function providerForTestMultilingualFieldFilter()
2128
    {
2129
        return [
2130
            0 => [
2131
                $fixture = [
2132
                    1 => [null, 1, null, 'ger-DE', true],
2133
                    2 => [4, null, null, 'eng-GB', true],
2134
                    3 => [3, null, null, 'eng-GB', false],
2135
                    4 => [null, 2, null, 'ger-DE', false],
2136
                    5 => [5, null, null, 'eng-GB', true],
2137
                ],
2138
                $languageSettings = [
2139
                    'languages' => [
2140
                        'ger-DE',
2141
                    ],
2142
                ],
2143
                new Criterion\Field('integer', Criterion\Operator::LT, 5),
2144
                /**
2145
                 * Expected order, Value eng-GB, Value ger-DE.
2146
                 *
2147
                 * Content 2, 4, -
2148
                 * Content 4, -, 2
2149
                 * Content 1, -, 1
2150
                 */
2151
                [2, 4, 1],
2152
            ],
2153
            1 => [
2154
                $fixture,
2155
                [
2156
                    'languages' => [
2157
                        'ger-DE',
2158
                    ],
2159
                    'useAlwaysAvailable' => false,
2160
                ],
2161
                new Criterion\Field('integer', Criterion\Operator::LT, 2),
2162
                /**
2163
                 * Expected order, Value eng-GB, Value ger-DE.
2164
                 *
2165
                 * Content 1, -, 1
2166
                 */
2167
                [1],
2168
            ],
2169
            2 => [
2170
                $fixture,
2171
                [
2172
                    'languages' => [
2173
                        'eng-GB',
2174
                    ],
2175
                ],
2176
                new Criterion\Field('integer', Criterion\Operator::LTE, 4),
2177
                /**
2178
                 * Expected order, Value eng-GB, Value ger-DE.
2179
                 *
2180
                 * Content 5, 5, -
2181
                 * Content 2, 4, -
2182
                 * Content 3, 3, -
2183
                 * Content 1, -, 1
2184
                 */
2185
                [2, 3, 1],
2186
            ],
2187
            3 => [
2188
                $fixture,
2189
                [
2190
                    'languages' => [
2191
                        'eng-GB',
2192
                    ],
2193
                    'useAlwaysAvailable' => false,
2194
                ],
2195
                new Criterion\Field('integer', Criterion\Operator::LTE, 4),
2196
                /**
2197
                 * Expected order, Value eng-GB, Value ger-DE.
2198
                 *
2199
                 * Content 2, 4, -
2200
                 * Content 3, 3, -
2201
                 */
2202
                [2, 3],
2203
            ],
2204
            4 => [
2205
                $fixture,
2206
                $languageSettings,
2207
                new Criterion\Field('integer', Criterion\Operator::LTE, 4),
2208
                /**
2209
                 * Expected order, Value eng-GB, Value ger-DE.
2210
                 *
2211
                 * Content 2, 4, -
2212
                 * Content 4, -, 2
2213
                 * Content 1, -, 1
2214
                 */
2215
                [2, 4, 1],
2216
            ],
2217
            5 => [
2218
                $fixture,
2219
                $languageSettings,
2220
                new Criterion\Field('integer', Criterion\Operator::GT, 1),
2221
                /**
2222
                 * Expected order, Value eng-GB, Value ger-DE.
2223
                 *
2224
                 * Content 5, 5, -
2225
                 * Content 2, 4, -
2226
                 * Content 4, -, 2
2227
                 */
2228
                [5, 2, 4],
2229
            ],
2230
            6 => [
2231
                $fixture,
2232
                $languageSettings,
2233
                new Criterion\Field('integer', Criterion\Operator::GTE, 2),
2234
                /**
2235
                 * Expected order, Value eng-GB, Value ger-DE.
2236
                 *
2237
                 * Content 5, 5, -
2238
                 * Content 2, 4, -
2239
                 * Content 4, -, 2
2240
                 */
2241
                [5, 2, 4],
2242
            ],
2243
            7 => [
2244
                $fixture,
2245
                $languageSettings,
2246
                new Criterion\Field('integer', Criterion\Operator::BETWEEN, [2, 4]),
2247
                /**
2248
                 * Expected order, Value eng-GB, Value ger-DE.
2249
                 *
2250
                 * Content 2, 4, -
2251
                 * Content 4, -, 2
2252
                 */
2253
                [2, 4],
2254
            ],
2255
            8 => [
2256
                $fixture,
2257
                $languageSettings,
2258
                new Criterion\Field('integer', Criterion\Operator::BETWEEN, [4, 2]),
2259
                [],
2260
            ],
2261
            9 => [
2262
                $fixture,
2263
                $languageSettings,
2264
                new Criterion\Field('integer', Criterion\Operator::EQ, 4),
2265
                /**
2266
                 * Expected order, Value eng-GB, Value ger-DE.
2267
                 *
2268
                 * Content 4, -, 2
2269
                 */
2270
                [2],
2271
            ],
2272
            10 => [
2273
                $fixture,
2274
                $languageSettings,
2275
                new Criterion\Field('integer', Criterion\Operator::EQ, 2),
2276
                /**
2277
                 * Expected order, Value eng-GB, Value ger-DE.
2278
                 *
2279
                 * Content 2, 4, -
2280
                 */
2281
                [4],
2282
            ],
2283
        ];
2284
    }
2285
2286
    /**
2287
     * Test for the findContent() method.
2288
     *
2289
     * @group ttt
2290
     * @dataProvider providerForTestMultilingualFieldFilter
2291
     *
2292
     * @param array $contentDataList
2293
     * @param array $languageSettings
2294
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
2295
     * @param array $expected
2296
     */
2297
    public function testMultilingualFieldFilterContent(
2298
        array $contentDataList,
2299
        $languageSettings,
2300
        Criterion $criterion,
2301
        $expected
2302
    ) {
2303
        $this->assertMultilingualFieldFilter(
2304
            $contentDataList,
2305
            $languageSettings,
2306
            $criterion,
2307
            $expected
2308
        );
2309
    }
2310
2311
    /**
2312
     * Test for the findLocations() method.
2313
     *
2314
     * @group ttt
2315
     * @dataProvider providerForTestMultilingualFieldFilter
2316
     *
2317
     * @param array $contentDataList
2318
     * @param array $languageSettings
2319
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
2320
     * @param array $expected
2321
     */
2322
    public function testMultilingualFieldFilterLocation(
2323
        array $contentDataList,
2324
        $languageSettings,
2325
        Criterion $criterion,
2326
        $expected
2327
    ) {
2328
        $this->assertMultilingualFieldFilter(
2329
            $contentDataList,
2330
            $languageSettings,
2331
            $criterion,
2332
            $expected,
2333
            false
2334
        );
2335
    }
2336
2337
    /**
2338
     * @param array $contentDataList
2339
     * @param array $languageSettings
2340
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
2341
     * @param array $expected
2342
     * @param bool $contentSearch
2343
     */
2344
    protected function assertMultilingualFieldFilter(
2345
        array $contentDataList,
2346
        $languageSettings,
2347
        Criterion $criterion,
2348
        $expected,
2349
        $contentSearch = true
2350
    ) {
2351
        $this->checkPrioritizedLanguagesSupport();
2352
        $contentType = $this->createTestContentType();
2353
2354
        // Create a draft to account for behaviour with ContentType in different states
2355
        $repository = $this->getRepository();
2356
        $contentTypeService = $repository->getContentTypeService();
2357
        $contentTypeService->createContentTypeDraft($contentType);
2358
2359
        $defaults = [null, null, null, 'eng-GB', false];
2360
        $contentIdList = [];
2361 View Code Duplication
        foreach ($contentDataList as $key => $contentData) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2362
            $contentData = $contentData + $defaults;
2363
            list(
2364
                $fieldValue11,
2365
                $fieldValue12,
2366
                $fieldValue2,
2367
                $mainLanguageCode,
2368
                $alwaysAvailable
2369
            ) = $contentData;
2370
2371
            $contentIdList[$key] = $this->createMultilingualContent(
2372
                $contentType,
2373
                $fieldValue11,
2374
                $fieldValue12,
2375
                $fieldValue2,
2376
                $mainLanguageCode,
2377
                $alwaysAvailable
2378
            )->id;
2379
        }
2380
2381
        $sortClause = new SortClause\Field('test-type', 'integer', Query::SORT_DESC);
2382
        $searchService = $repository->getSearchService();
2383
        if ($contentSearch) {
2384
            $query = new Query(
2385
                [
2386
                    'query' => new Criterion\LogicalAnd(
2387
                        [
2388
                            new Criterion\ContentTypeId($contentType->id),
2389
                            $criterion,
2390
                        ]
2391
                    ),
2392
                    'sortClauses' => [$sortClause],
2393
                ]
2394
            );
2395
            $result = $searchService->findContent($query, $languageSettings);
2396
        } else {
2397
            $query = new LocationQuery(
2398
                [
2399
                    'query' => new Criterion\LogicalAnd(
2400
                        [
2401
                            new Criterion\ContentTypeId($contentType->id),
2402
                            $criterion,
2403
                        ]
2404
                    ),
2405
                    'sortClauses' => [$sortClause],
2406
                ]
2407
            );
2408
            $result = $searchService->findLocations($query, $languageSettings);
2409
        }
2410
2411
        $this->assertEquals(count($expected), $result->totalCount);
2412
2413
        $expectedIdList = [];
2414
        foreach ($expected as $contentNumber) {
2415
            $expectedIdList[] = $contentIdList[$contentNumber];
2416
        }
2417
2418
        $this->assertEquals($expectedIdList, $this->mapResultContentIds($result));
2419
    }
2420
2421
    /**
2422
     * @param \eZ\Publish\API\Repository\Values\Content\Search\SearchResult $result
2423
     *
2424
     * @return array
2425
     */
2426
    protected function mapResultContentIds(SearchResult $result)
2427
    {
2428
        return array_map(
2429
            function (SearchHit $searchHit) {
2430
                if ($searchHit->valueObject instanceof Location) {
2431
                    return $searchHit->valueObject->contentInfo->id;
2432
                }
2433
2434
                return $searchHit->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...
2435
            },
2436
            $result->searchHits
2437
        );
2438
    }
2439
2440
    /**
2441
     * Test for the findContent() method.
2442
     *
2443
     * @dataProvider getSortedContentSearches
2444
     *
2445
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2446
     */
2447
    public function testFindAndSortContent($queryData, $fixture, $closure = null)
2448
    {
2449
        $query = new Query($queryData);
2450
        $this->assertQueryFixture($query, $fixture, $closure);
2451
    }
2452
2453
    /**
2454
     * Test for the findContentInfo() method.
2455
     *
2456
     * @dataProvider getSortedContentSearches
2457
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
2458
     */
2459
    public function testFindAndSortContentInfo($queryData, $fixture, $closure = null)
2460
    {
2461
        $query = new Query($queryData);
2462
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure($closure), true);
2463
    }
2464
2465
    /**
2466
     * Test for the findLocations() method.
2467
     *
2468
     * @dataProvider getSortedContentSearches
2469
     *
2470
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
2471
     */
2472
    public function testFindAndSortContentLocations($queryData, $fixture, $closure = null)
2473
    {
2474
        $query = new LocationQuery($queryData);
2475
        $this->assertQueryFixture($query, $fixture, $closure);
2476
    }
2477
2478
    /**
2479
     * Test for the findLocations() method.
2480
     *
2481
     * @dataProvider getSortedLocationSearches
2482
     *
2483
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
2484
     */
2485
    public function testFindAndSortLocations($queryData, $fixture, $closure = null)
2486
    {
2487
        $query = new LocationQuery($queryData);
2488
        $this->assertQueryFixture($query, $fixture, $closure);
2489
    }
2490
2491
    /**
2492
     * Test for the findContent() method.
2493
     *
2494
     * @dataProvider getFacetedSearches
2495
     *
2496
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2497
     */
2498
    public function testFindFacetedContent(Query $query, $fixture)
2499
    {
2500
        $this->assertQueryFixture($query, $fixture);
2501
    }
2502
2503
    /**
2504
     * Test for the findContentInfo() method.
2505
     *
2506
     * @dataProvider getFacetedSearches
2507
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
2508
     */
2509
    public function testFindFacetedContentInfo(Query $query, $fixture)
2510
    {
2511
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure(), true);
2512
    }
2513
2514
    /**
2515
     * Test for the findContent() method.
2516
     *
2517
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2518
     */
2519 View Code Duplication
    public function testQueryCustomField()
2520
    {
2521
        $query = new Query(
2522
            [
2523
                'query' => new Criterion\CustomField(
2524
                    'custom_field',
2525
                    Criterion\Operator::EQ,
2526
                    'AdMiNiStRaToR'
2527
                ),
2528
                'offset' => 0,
2529
                'limit' => 10,
2530
                'sortClauses' => [new SortClause\ContentId()],
2531
            ]
2532
        );
2533
        $this->assertQueryFixture(
2534
            $query,
2535
            $this->getFixtureDir() . '/QueryCustomField.php'
2536
        );
2537
    }
2538
2539
    /**
2540
     * Test for the findContent() method.
2541
     *
2542
     * This tests explicitely queries the first_name while user is contained in
2543
     * the last_name of admin and anonymous. This is done to show the custom
2544
     * copy field working.
2545
     *
2546
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2547
     */
2548 View Code Duplication
    public function testQueryModifiedField()
2549
    {
2550
        // Check using get_class since the others extend SetupFactory\Legacy
2551
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
2552
            $this->markTestIncomplete(
2553
                'Custom fields not supported by LegacySE ' .
2554
                '(@todo: Legacy should fallback to just querying normal field so this should be tested here)'
2555
            );
2556
        }
2557
2558
        $query = new Query(
2559
            [
2560
                'query' => new Criterion\Field(
2561
                    'first_name',
2562
                    Criterion\Operator::EQ,
2563
                    'User'
2564
                ),
2565
                'offset' => 0,
2566
                'limit' => 10,
2567
                'sortClauses' => [new SortClause\ContentId()],
2568
            ]
2569
        );
2570
        $query->query->setCustomField('user', 'first_name', 'custom_field');
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class eZ\Publish\API\Repositor...Content\Query\Criterion as the method setCustomField() does only exist in the following sub-classes of eZ\Publish\API\Repositor...Content\Query\Criterion: eZ\Publish\API\Repositor...t\Query\Criterion\Field, eZ\Publish\API\Repositor...uery\Criterion\FullText, eZ\Publish\API\Repositor...ion\MapLocationDistance. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
2571
2572
        $this->assertQueryFixture(
2573
            $query,
2574
            $this->getFixtureDir() . '/QueryModifiedField.php'
2575
        );
2576
    }
2577
2578
    /**
2579
     * Test for the findContent() method.
2580
     *
2581
     * This tests first explicitly creates sort clause on the 'short_name' which is empty
2582
     * for all Content instances of 'folder' ContentType. Custom sort field is then set
2583
     * to the index storage name of folder's 'name' field, in order to show the custom
2584
     * sort field working.
2585
     *
2586
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2587
     */
2588
    public function testSortModifiedField()
2589
    {
2590
        // Check using get_class since the others extend SetupFactory\Legacy
2591
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
2592
            $this->markTestIncomplete(
2593
                'Custom field sort not supported by LegacySE ' .
2594
                '(@todo: Legacy should fallback to just querying normal field so this should be tested here)'
2595
            );
2596
        }
2597
2598
        $sortClause = new SortClause\Field('folder', 'short_name', Query::SORT_ASC);
2599
        $sortClause->setCustomField('folder', 'short_name', 'folder_name_value_s');
2600
2601
        $query = new Query(
2602
            [
2603
                'filter' => new Criterion\ContentTypeId(1),
2604
                'offset' => 0,
2605
                'limit' => 10,
2606
                'sortClauses' => [
2607
                    $sortClause,
2608
                    new SortClause\ContentId(),
2609
                ],
2610
            ]
2611
        );
2612
2613
        $this->assertQueryFixture(
2614
            $query,
2615
            $this->getFixtureDir() . '/SortFolderName.php'
2616
        );
2617
    }
2618
2619
    /**
2620
     * @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
2621
     */
2622 View Code Duplication
    protected function createTestPlaceContentType()
2623
    {
2624
        $repository = $this->getRepository();
2625
        $contentTypeService = $repository->getContentTypeService();
2626
2627
        $createStruct = $contentTypeService->newContentTypeCreateStruct('testtype');
2628
        $createStruct->mainLanguageCode = 'eng-GB';
2629
        $createStruct->names = ['eng-GB' => 'Test type'];
2630
        $createStruct->creatorId = 14;
2631
        $createStruct->creationDate = new \DateTime();
2632
2633
        $translatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('maplocation', 'ezgmaplocation');
2634
        $translatableFieldCreate->names = ['eng-GB' => 'Map location field'];
2635
        $translatableFieldCreate->fieldGroup = 'main';
2636
        $translatableFieldCreate->position = 1;
2637
        $translatableFieldCreate->isTranslatable = false;
2638
        $translatableFieldCreate->isSearchable = true;
2639
2640
        $createStruct->addFieldDefinition($translatableFieldCreate);
2641
2642
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
2643
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
2644
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
2645
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
2646
2647
        return $contentType;
2648
    }
2649
2650
    /**
2651
     * Test for the findContent() method.
2652
     *
2653
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2654
     * @group maplocation
2655
     */
2656 View Code Duplication
    public function testMapLocationDistanceLessThanOrEqual()
2657
    {
2658
        $contentType = $this->createTestPlaceContentType();
2659
2660
        // Create a draft to account for behaviour with ContentType in different states
2661
        $repository = $this->getRepository();
2662
        $contentTypeService = $repository->getContentTypeService();
2663
        $contentService = $repository->getContentService();
2664
        $contentTypeService->createContentTypeDraft($contentType);
2665
2666
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2667
        $createStruct->alwaysAvailable = false;
2668
        $createStruct->mainLanguageCode = 'eng-GB';
2669
        $createStruct->setField(
2670
            'maplocation',
2671
            [
2672
                'latitude' => 45.894877,
2673
                'longitude' => 15.972699,
2674
                'address' => 'Here be wild boars',
2675
            ],
2676
            'eng-GB'
2677
        );
2678
2679
        $draft = $contentService->createContent($createStruct);
2680
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
2681
2682
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2683
        $createStruct->alwaysAvailable = false;
2684
        $createStruct->mainLanguageCode = 'eng-GB';
2685
        $createStruct->setField(
2686
            'maplocation',
2687
            [
2688
                'latitude' => 45.927334,
2689
                'longitude' => 15.934847,
2690
                'address' => 'A lone tree',
2691
            ],
2692
            'eng-GB'
2693
        );
2694
2695
        $draft = $contentService->createContent($createStruct);
2696
        $tree = $contentService->publishVersion($draft->getVersionInfo());
0 ignored issues
show
Unused Code introduced by
$tree is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2697
2698
        $this->refreshSearch($repository);
2699
2700
        $query = new Query(
2701
            [
2702
                'filter' => new Criterion\LogicalAnd(
2703
                    [
2704
                        new Criterion\ContentTypeId($contentType->id),
2705
                        new Criterion\MapLocationDistance(
2706
                            'maplocation',
2707
                            Criterion\Operator::LTE,
2708
                            240,
2709
                            43.756825,
2710
                            15.775074
2711
                        ),
2712
                    ]
2713
                ),
2714
                'offset' => 0,
2715
                'limit' => 10,
2716
                'sortClauses' => [],
2717
            ]
2718
        );
2719
2720
        $searchService = $repository->getSearchService();
2721
        $result = $searchService->findContent($query);
2722
2723
        $this->assertEquals(1, $result->totalCount);
2724
        $this->assertEquals(
2725
            $wildBoars->id,
2726
            $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...
2727
        );
2728
    }
2729
2730
    /**
2731
     * Test for the findContent() method.
2732
     *
2733
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2734
     * @group maplocation
2735
     */
2736 View Code Duplication
    public function testMapLocationDistanceGreaterThanOrEqual()
2737
    {
2738
        $contentType = $this->createTestPlaceContentType();
2739
2740
        // Create a draft to account for behaviour with ContentType in different states
2741
        $repository = $this->getRepository();
2742
        $contentTypeService = $repository->getContentTypeService();
2743
        $contentService = $repository->getContentService();
2744
        $contentTypeService->createContentTypeDraft($contentType);
2745
2746
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2747
        $createStruct->alwaysAvailable = false;
2748
        $createStruct->mainLanguageCode = 'eng-GB';
2749
        $createStruct->setField(
2750
            'maplocation',
2751
            [
2752
                'latitude' => 45.894877,
2753
                'longitude' => 15.972699,
2754
                'address' => 'Here be wild boars',
2755
            ],
2756
            'eng-GB'
2757
        );
2758
2759
        $draft = $contentService->createContent($createStruct);
2760
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
0 ignored issues
show
Unused Code introduced by
$wildBoars is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2761
2762
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2763
        $createStruct->alwaysAvailable = false;
2764
        $createStruct->mainLanguageCode = 'eng-GB';
2765
        $createStruct->setField(
2766
            'maplocation',
2767
            [
2768
                'latitude' => 45.927334,
2769
                'longitude' => 15.934847,
2770
                'address' => 'A lone tree',
2771
            ],
2772
            'eng-GB'
2773
        );
2774
2775
        $draft = $contentService->createContent($createStruct);
2776
        $tree = $contentService->publishVersion($draft->getVersionInfo());
2777
2778
        $this->refreshSearch($repository);
2779
2780
        $query = new Query(
2781
            [
2782
                'filter' => new Criterion\LogicalAnd(
2783
                    [
2784
                        new Criterion\ContentTypeId($contentType->id),
2785
                        new Criterion\MapLocationDistance(
2786
                            'maplocation',
2787
                            Criterion\Operator::GTE,
2788
                            240,
2789
                            43.756825,
2790
                            15.775074
2791
                        ),
2792
                    ]
2793
                ),
2794
                'offset' => 0,
2795
                'limit' => 10,
2796
                'sortClauses' => [],
2797
            ]
2798
        );
2799
2800
        $searchService = $repository->getSearchService();
2801
        $result = $searchService->findContent($query);
2802
2803
        $this->assertEquals(1, $result->totalCount);
2804
        $this->assertEquals(
2805
            $tree->id,
2806
            $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...
2807
        );
2808
    }
2809
2810
    /**
2811
     * Test for the findContent() method.
2812
     *
2813
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2814
     * @group maplocation
2815
     */
2816
    public function testMapLocationDistanceBetween()
2817
    {
2818
        $contentType = $this->createTestPlaceContentType();
2819
2820
        // Create a draft to account for behaviour with ContentType in different states
2821
        $repository = $this->getRepository();
2822
        $contentTypeService = $repository->getContentTypeService();
2823
        $contentService = $repository->getContentService();
2824
        $contentTypeService->createContentTypeDraft($contentType);
2825
2826
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2827
        $createStruct->alwaysAvailable = false;
2828
        $createStruct->mainLanguageCode = 'eng-GB';
2829
        $createStruct->setField(
2830
            'maplocation',
2831
            [
2832
                'latitude' => 45.894877,
2833
                'longitude' => 15.972699,
2834
                'address' => 'Here be wild boars',
2835
            ],
2836
            'eng-GB'
2837
        );
2838
2839
        $draft = $contentService->createContent($createStruct);
2840
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
0 ignored issues
show
Unused Code introduced by
$wildBoars is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2841
2842
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2843
        $createStruct->alwaysAvailable = false;
2844
        $createStruct->mainLanguageCode = 'eng-GB';
2845
        $createStruct->setField(
2846
            'maplocation',
2847
            [
2848
                'latitude' => 45.927334,
2849
                'longitude' => 15.934847,
2850
                'address' => 'A lone tree',
2851
            ],
2852
            'eng-GB'
2853
        );
2854
2855
        $draft = $contentService->createContent($createStruct);
2856
        $tree = $contentService->publishVersion($draft->getVersionInfo());
0 ignored issues
show
Unused Code introduced by
$tree is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2857
2858
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2859
        $createStruct->alwaysAvailable = false;
2860
        $createStruct->mainLanguageCode = 'eng-GB';
2861
        $createStruct->setField(
2862
            'maplocation',
2863
            [
2864
                'latitude' => 45.903777,
2865
                'longitude' => 15.958788,
2866
                'address' => 'Meadow with mushrooms',
2867
            ],
2868
            'eng-GB'
2869
        );
2870
2871
        $draft = $contentService->createContent($createStruct);
2872
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
2873
2874
        $this->refreshSearch($repository);
2875
2876
        $query = new Query(
2877
            [
2878
                'filter' => new Criterion\LogicalAnd(
2879
                    [
2880
                        new Criterion\ContentTypeId($contentType->id),
2881
                        new Criterion\MapLocationDistance(
2882
                            'maplocation',
2883
                            Criterion\Operator::BETWEEN,
2884
                            [239, 241],
2885
                            43.756825,
2886
                            15.775074
2887
                        ),
2888
                    ]
2889
                ),
2890
                'offset' => 0,
2891
                'limit' => 10,
2892
                'sortClauses' => [],
2893
            ]
2894
        );
2895
2896
        $searchService = $repository->getSearchService();
2897
        $result = $searchService->findContent($query);
2898
2899
        $this->assertEquals(1, $result->totalCount);
2900
        $this->assertEquals(
2901
            $mushrooms->id,
2902
            $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...
2903
        );
2904
    }
2905
2906
    /**
2907
     * Test for the findContent() method.
2908
     *
2909
     * This tests the distance over the pole. The tests intentionally uses large range,
2910
     * as the flat Earth model used in Legacy Storage Search is not precise for the use case.
2911
     * What is tested here is that outer bounding box is correctly calculated, so that
2912
     * location is not excluded.
2913
     *
2914
     * Range between 222km and 350km shows the magnitude of error between great-circle
2915
     * (always very precise) and flat Earth (very imprecise for this use case) models.
2916
     *
2917
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2918
     * @group maplocation
2919
     */
2920
    public function testMapLocationDistanceBetweenPolar()
2921
    {
2922
        $contentType = $this->createTestPlaceContentType();
2923
2924
        // Create a draft to account for behaviour with ContentType in different states
2925
        $repository = $this->getRepository();
2926
        $contentTypeService = $repository->getContentTypeService();
2927
        $contentService = $repository->getContentService();
2928
        $contentTypeService->createContentTypeDraft($contentType);
2929
2930
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2931
        $createStruct->alwaysAvailable = false;
2932
        $createStruct->mainLanguageCode = 'eng-GB';
2933
        $createStruct->setField(
2934
            'maplocation',
2935
            [
2936
                'latitude' => 89,
2937
                'longitude' => -164,
2938
                'address' => 'Polar bear media tower',
2939
            ],
2940
            'eng-GB'
2941
        );
2942
2943
        $draft = $contentService->createContent($createStruct);
2944
        $polarBear = $contentService->publishVersion($draft->getVersionInfo());
2945
2946
        $this->refreshSearch($repository);
2947
2948
        $query = new Query(
2949
            [
2950
                'filter' => new Criterion\LogicalAnd(
2951
                    [
2952
                        new Criterion\ContentTypeId($contentType->id),
2953
                        new Criterion\MapLocationDistance(
2954
                            'maplocation',
2955
                            Criterion\Operator::BETWEEN,
2956
                            [221, 350],
2957
                            89,
2958
                            16
2959
                        ),
2960
                    ]
2961
                ),
2962
                'offset' => 0,
2963
                'limit' => 10,
2964
                'sortClauses' => [],
2965
            ]
2966
        );
2967
2968
        $searchService = $repository->getSearchService();
2969
        $result = $searchService->findContent($query);
2970
2971
        $this->assertEquals(1, $result->totalCount);
2972
        $this->assertEquals(
2973
            $polarBear->id,
2974
            $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...
2975
        );
2976
    }
2977
2978
    /**
2979
     * Test for the findContent() method.
2980
     *
2981
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2982
     * @group maplocation
2983
     */
2984 View Code Duplication
    public function testMapLocationDistanceSortAscending()
2985
    {
2986
        $contentType = $this->createTestPlaceContentType();
2987
2988
        // Create a draft to account for behaviour with ContentType in different states
2989
        $repository = $this->getRepository();
2990
        $contentTypeService = $repository->getContentTypeService();
2991
        $contentService = $repository->getContentService();
2992
        $contentTypeService->createContentTypeDraft($contentType);
2993
2994
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2995
        $createStruct->alwaysAvailable = false;
2996
        $createStruct->mainLanguageCode = 'eng-GB';
2997
        $createStruct->setField(
2998
            'maplocation',
2999
            [
3000
                'latitude' => 45.894877,
3001
                'longitude' => 15.972699,
3002
                'address' => 'Here be wild boars',
3003
            ],
3004
            'eng-GB'
3005
        );
3006
3007
        $draft = $contentService->createContent($createStruct);
3008
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3009
3010
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3011
        $createStruct->alwaysAvailable = false;
3012
        $createStruct->mainLanguageCode = 'eng-GB';
3013
        $createStruct->setField(
3014
            'maplocation',
3015
            [
3016
                'latitude' => 45.927334,
3017
                'longitude' => 15.934847,
3018
                'address' => 'A lone tree',
3019
            ],
3020
            'eng-GB'
3021
        );
3022
3023
        $draft = $contentService->createContent($createStruct);
3024
        $tree = $contentService->publishVersion($draft->getVersionInfo());
3025
3026
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3027
        $createStruct->alwaysAvailable = false;
3028
        $createStruct->mainLanguageCode = 'eng-GB';
3029
        $createStruct->setField(
3030
            'maplocation',
3031
            [
3032
                'latitude' => 45.903777,
3033
                'longitude' => 15.958788,
3034
                'address' => 'Meadow with mushrooms',
3035
            ],
3036
            'eng-GB'
3037
        );
3038
3039
        $draft = $contentService->createContent($createStruct);
3040
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
3041
3042
        $this->refreshSearch($repository);
3043
3044
        $wellInVodice = [
3045
            'latitude' => 43.756825,
3046
            'longitude' => 15.775074,
3047
        ];
3048
3049
        $query = new Query(
3050
            [
3051
                'filter' => new Criterion\LogicalAnd(
3052
                    [
3053
                        new Criterion\ContentTypeId($contentType->id),
3054
                        new Criterion\MapLocationDistance(
3055
                            'maplocation',
3056
                            Criterion\Operator::GTE,
3057
                            235,
3058
                            $wellInVodice['latitude'],
3059
                            $wellInVodice['longitude']
3060
                        ),
3061
                    ]
3062
                ),
3063
                'offset' => 0,
3064
                'limit' => 10,
3065
                'sortClauses' => [
3066
                    new SortClause\MapLocationDistance(
3067
                        'testtype',
3068
                        'maplocation',
3069
                        $wellInVodice['latitude'],
3070
                        $wellInVodice['longitude'],
3071
                        Query::SORT_ASC
3072
                    ),
3073
                ],
3074
            ]
3075
        );
3076
3077
        $searchService = $repository->getSearchService();
3078
        $result = $searchService->findContent($query);
3079
3080
        $this->assertEquals(3, $result->totalCount);
3081
        $this->assertEquals(
3082
            $wildBoars->id,
3083
            $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...
3084
        );
3085
        $this->assertEquals(
3086
            $mushrooms->id,
3087
            $result->searchHits[1]->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...
3088
        );
3089
        $this->assertEquals(
3090
            $tree->id,
3091
            $result->searchHits[2]->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...
3092
        );
3093
    }
3094
3095
    /**
3096
     * Test for the findContent() method.
3097
     *
3098
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3099
     * @group maplocation
3100
     */
3101 View Code Duplication
    public function testMapLocationDistanceSortDescending()
3102
    {
3103
        $contentType = $this->createTestPlaceContentType();
3104
3105
        // Create a draft to account for behaviour with ContentType in different states
3106
        $repository = $this->getRepository();
3107
        $contentTypeService = $repository->getContentTypeService();
3108
        $contentService = $repository->getContentService();
3109
        $contentTypeService->createContentTypeDraft($contentType);
3110
3111
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3112
        $createStruct->alwaysAvailable = false;
3113
        $createStruct->mainLanguageCode = 'eng-GB';
3114
        $createStruct->setField(
3115
            'maplocation',
3116
            [
3117
                'latitude' => 45.894877,
3118
                'longitude' => 15.972699,
3119
                'address' => 'Here be wild boars',
3120
            ],
3121
            'eng-GB'
3122
        );
3123
3124
        $draft = $contentService->createContent($createStruct);
3125
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3126
3127
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3128
        $createStruct->alwaysAvailable = false;
3129
        $createStruct->mainLanguageCode = 'eng-GB';
3130
        $createStruct->setField(
3131
            'maplocation',
3132
            [
3133
                'latitude' => 45.927334,
3134
                'longitude' => 15.934847,
3135
                'address' => 'A lone tree',
3136
            ],
3137
            'eng-GB'
3138
        );
3139
3140
        $draft = $contentService->createContent($createStruct);
3141
        $tree = $contentService->publishVersion($draft->getVersionInfo());
3142
3143
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3144
        $createStruct->alwaysAvailable = false;
3145
        $createStruct->mainLanguageCode = 'eng-GB';
3146
        $createStruct->setField(
3147
            'maplocation',
3148
            [
3149
                'latitude' => 45.903777,
3150
                'longitude' => 15.958788,
3151
                'address' => 'Meadow with mushrooms',
3152
            ],
3153
            'eng-GB'
3154
        );
3155
3156
        $draft = $contentService->createContent($createStruct);
3157
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
3158
3159
        $this->refreshSearch($repository);
3160
3161
        $well = [
3162
            'latitude' => 43.756825,
3163
            'longitude' => 15.775074,
3164
        ];
3165
3166
        $query = new Query(
3167
            [
3168
                'filter' => new Criterion\LogicalAnd(
3169
                    [
3170
                        new Criterion\ContentTypeId($contentType->id),
3171
                        new Criterion\MapLocationDistance(
3172
                            'maplocation',
3173
                            Criterion\Operator::GTE,
3174
                            235,
3175
                            $well['latitude'],
3176
                            $well['longitude']
3177
                        ),
3178
                    ]
3179
                ),
3180
                'offset' => 0,
3181
                'limit' => 10,
3182
                'sortClauses' => [
3183
                    new SortClause\MapLocationDistance(
3184
                        'testtype',
3185
                        'maplocation',
3186
                        $well['latitude'],
3187
                        $well['longitude'],
3188
                        Query::SORT_DESC
3189
                    ),
3190
                ],
3191
            ]
3192
        );
3193
3194
        $searchService = $repository->getSearchService();
3195
        $result = $searchService->findContent($query);
3196
3197
        $this->assertEquals(3, $result->totalCount);
3198
        $this->assertEquals(
3199
            $wildBoars->id,
3200
            $result->searchHits[2]->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...
3201
        );
3202
        $this->assertEquals(
3203
            $mushrooms->id,
3204
            $result->searchHits[1]->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...
3205
        );
3206
        $this->assertEquals(
3207
            $tree->id,
3208
            $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...
3209
        );
3210
    }
3211
3212
    /**
3213
     * Test for the findContent() method.
3214
     *
3215
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3216
     * @group maplocation
3217
     */
3218
    public function testMapLocationDistanceWithCustomField()
3219
    {
3220
        $setupFactory = $this->getSetupFactory();
3221
        if ($setupFactory instanceof LegacyElasticsearch) {
3222
            $this->markTestIncomplete("TODO: Some issues with 'copy_to' and 'geo_point'");
3223
        }
3224
3225
        $contentType = $this->createTestPlaceContentType();
3226
3227
        // Create a draft to account for behaviour with ContentType in different states
3228
        $repository = $this->getRepository();
3229
        $contentTypeService = $repository->getContentTypeService();
3230
        $contentService = $repository->getContentService();
3231
        $contentTypeService->createContentTypeDraft($contentType);
3232
3233
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3234
        $createStruct->alwaysAvailable = false;
3235
        $createStruct->mainLanguageCode = 'eng-GB';
3236
        $createStruct->setField(
3237
            'maplocation',
3238
            [
3239
                'latitude' => 45.894877,
3240
                'longitude' => 15.972699,
3241
                'address' => 'Here be wild boars',
3242
            ],
3243
            'eng-GB'
3244
        );
3245
3246
        $draft = $contentService->createContent($createStruct);
3247
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3248
3249
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3250
        $createStruct->alwaysAvailable = false;
3251
        $createStruct->mainLanguageCode = 'eng-GB';
3252
        $createStruct->setField(
3253
            'maplocation',
3254
            [
3255
                'latitude' => 45.927334,
3256
                'longitude' => 15.934847,
3257
                'address' => 'A lone tree',
3258
            ],
3259
            'eng-GB'
3260
        );
3261
3262
        $draft = $contentService->createContent($createStruct);
3263
        $tree = $contentService->publishVersion($draft->getVersionInfo());
0 ignored issues
show
Unused Code introduced by
$tree is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
3264
3265
        $this->refreshSearch($repository);
3266
3267
        $distanceCriterion = new Criterion\MapLocationDistance(
3268
            'maplocation',
3269
            Criterion\Operator::LTE,
3270
            240,
3271
            43.756825,
3272
            15.775074
3273
        );
3274
        $distanceCriterion->setCustomField('testtype', 'maplocation', 'custom_geolocation_field');
3275
3276
        $query = new Query(
3277
            [
3278
                'filter' => new Criterion\LogicalAnd(
3279
                    [
3280
                        new Criterion\ContentTypeId($contentType->id),
3281
                        $distanceCriterion,
3282
                    ]
3283
                ),
3284
                'offset' => 0,
3285
                'limit' => 10,
3286
                'sortClauses' => [],
3287
            ]
3288
        );
3289
3290
        $searchService = $repository->getSearchService();
3291
        $result = $searchService->findContent($query);
3292
3293
        $this->assertEquals(1, $result->totalCount);
3294
        $this->assertEquals(
3295
            $wildBoars->id,
3296
            $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...
3297
        );
3298
    }
3299
3300
    /**
3301
     * Test for the findContent() method.
3302
     *
3303
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3304
     * @group maplocation
3305
     */
3306
    public function testMapLocationDistanceWithCustomFieldSort()
3307
    {
3308
        $setupFactory = $this->getSetupFactory();
3309
        if ($setupFactory instanceof LegacyElasticsearch) {
3310
            $this->markTestIncomplete("TODO: Some issues with 'copy_to' and 'geo_point'");
3311
        }
3312
3313
        $contentType = $this->createTestPlaceContentType();
3314
3315
        // Create a draft to account for behaviour with ContentType in different states
3316
        $repository = $this->getRepository();
3317
        $contentTypeService = $repository->getContentTypeService();
3318
        $contentService = $repository->getContentService();
3319
        $contentTypeService->createContentTypeDraft($contentType);
3320
3321
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3322
        $createStruct->alwaysAvailable = false;
3323
        $createStruct->mainLanguageCode = 'eng-GB';
3324
        $createStruct->setField(
3325
            'maplocation',
3326
            [
3327
                'latitude' => 45.894877,
3328
                'longitude' => 15.972699,
3329
                'address' => 'Here be wild boars',
3330
            ],
3331
            'eng-GB'
3332
        );
3333
3334
        $draft = $contentService->createContent($createStruct);
3335
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3336
3337
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3338
        $createStruct->alwaysAvailable = false;
3339
        $createStruct->mainLanguageCode = 'eng-GB';
3340
        $createStruct->setField(
3341
            'maplocation',
3342
            [
3343
                'latitude' => 45.927334,
3344
                'longitude' => 15.934847,
3345
                'address' => 'A lone tree',
3346
            ],
3347
            'eng-GB'
3348
        );
3349
3350
        $draft = $contentService->createContent($createStruct);
3351
        $tree = $contentService->publishVersion($draft->getVersionInfo());
3352
3353
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3354
        $createStruct->alwaysAvailable = false;
3355
        $createStruct->mainLanguageCode = 'eng-GB';
3356
        $createStruct->setField(
3357
            'maplocation',
3358
            [
3359
                'latitude' => 45.903777,
3360
                'longitude' => 15.958788,
3361
                'address' => 'Meadow with mushrooms',
3362
            ],
3363
            'eng-GB'
3364
        );
3365
3366
        $draft = $contentService->createContent($createStruct);
3367
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
3368
3369
        $this->refreshSearch($repository);
3370
3371
        $well = [
3372
            'latitude' => 43.756825,
3373
            'longitude' => 15.775074,
3374
        ];
3375
3376
        $sortClause = new SortClause\MapLocationDistance(
3377
            'testtype',
3378
            'maplocation',
3379
            $well['latitude'],
3380
            $well['longitude'],
3381
            Query::SORT_DESC
3382
        );
3383
        $sortClause->setCustomField('testtype', 'maplocation', 'custom_geolocation_field');
3384
3385
        $query = new Query(
3386
            [
3387
                'filter' => new Criterion\LogicalAnd(
3388
                    [
3389
                        new Criterion\ContentTypeId($contentType->id),
3390
                        new Criterion\MapLocationDistance(
3391
                            'maplocation',
3392
                            Criterion\Operator::GTE,
3393
                            235,
3394
                            $well['latitude'],
3395
                            $well['longitude']
3396
                        ),
3397
                    ]
3398
                ),
3399
                'offset' => 0,
3400
                'limit' => 10,
3401
                'sortClauses' => [
3402
                    $sortClause,
3403
                ],
3404
            ]
3405
        );
3406
3407
        $searchService = $repository->getSearchService();
3408
        $result = $searchService->findContent($query);
3409
3410
        $this->assertEquals(3, $result->totalCount);
3411
        $this->assertEquals(
3412
            $wildBoars->id,
3413
            $result->searchHits[2]->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...
3414
        );
3415
        $this->assertEquals(
3416
            $mushrooms->id,
3417
            $result->searchHits[1]->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...
3418
        );
3419
        $this->assertEquals(
3420
            $tree->id,
3421
            $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...
3422
        );
3423
    }
3424
3425
    /**
3426
     * Test for the findLocations() method.
3427
     *
3428
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3429
     */
3430 View Code Duplication
    public function testFindMainLocation()
3431
    {
3432
        $plainSiteLocationId = 56;
3433
        $designLocationId = 58;
3434
        $partnersContentId = 59;
3435
        $repository = $this->getRepository();
3436
        $locationService = $repository->getLocationService();
3437
        $contentService = $repository->getContentService();
3438
3439
        // Add secondary Location for "Partners" user group, under "Design" page
3440
        $locationService->createLocation(
3441
            $contentService->loadContentInfo($partnersContentId),
3442
            $locationService->newLocationCreateStruct($designLocationId)
3443
        );
3444
3445
        $this->refreshSearch($repository);
3446
3447
        $query = new LocationQuery(
3448
            [
3449
                'filter' => new Criterion\LogicalAnd(
3450
                    [
3451
                        new Criterion\ParentLocationId($designLocationId),
3452
                        new Criterion\Location\IsMainLocation(
3453
                            Criterion\Location\IsMainLocation::MAIN
3454
                        ),
3455
                    ]
3456
                ),
3457
                'offset' => 0,
3458
                'limit' => 10,
3459
                'sortClauses' => [],
3460
            ]
3461
        );
3462
3463
        $searchService = $repository->getSearchService();
3464
        $result = $searchService->findLocations($query);
3465
3466
        $this->assertEquals(1, $result->totalCount);
3467
        $this->assertEquals($plainSiteLocationId, $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...
3468
    }
3469
3470
    /**
3471
     * Test for the findLocations() method.
3472
     *
3473
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3474
     */
3475 View Code Duplication
    public function testFindNonMainLocation()
3476
    {
3477
        $designLocationId = 58;
3478
        $partnersContentId = 59;
3479
        $repository = $this->getRepository();
3480
        $locationService = $repository->getLocationService();
3481
        $contentService = $repository->getContentService();
3482
3483
        // Add secondary Location for "Partners" user group, under "Design" page
3484
        $newLocation = $locationService->createLocation(
3485
            $contentService->loadContentInfo($partnersContentId),
3486
            $locationService->newLocationCreateStruct($designLocationId)
3487
        );
3488
3489
        $this->refreshSearch($repository);
3490
3491
        $query = new LocationQuery(
3492
            [
3493
                'filter' => new Criterion\LogicalAnd(
3494
                    [
3495
                        new Criterion\ParentLocationId($designLocationId),
3496
                        new Criterion\Location\IsMainLocation(
3497
                            Criterion\Location\IsMainLocation::NOT_MAIN
3498
                        ),
3499
                    ]
3500
                ),
3501
                'offset' => 0,
3502
                'limit' => 10,
3503
                'sortClauses' => [],
3504
            ]
3505
        );
3506
3507
        $searchService = $repository->getSearchService();
3508
        $result = $searchService->findLocations($query);
3509
3510
        $this->assertEquals(1, $result->totalCount);
3511
        $this->assertEquals($newLocation->id, $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...
3512
    }
3513
3514
    /**
3515
     * Test for the findLocations() method.
3516
     *
3517
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3518
     */
3519 View Code Duplication
    public function testSortMainLocationAscending()
3520
    {
3521
        $plainSiteLocationId = 56;
3522
        $designLocationId = 58;
3523
        $partnersContentId = 59;
3524
        $repository = $this->getRepository();
3525
        $locationService = $repository->getLocationService();
3526
        $contentService = $repository->getContentService();
3527
3528
        // Add secondary Location for "Partners" user group, under "Design" page
3529
        $newLocation = $locationService->createLocation(
3530
            $contentService->loadContentInfo($partnersContentId),
3531
            $locationService->newLocationCreateStruct($designLocationId)
3532
        );
3533
3534
        $this->refreshSearch($repository);
3535
3536
        $query = new LocationQuery(
3537
            [
3538
                'filter' => new Criterion\ParentLocationId($designLocationId),
3539
                'offset' => 0,
3540
                'limit' => 10,
3541
                'sortClauses' => [
3542
                    new SortClause\Location\IsMainLocation(
3543
                        LocationQuery::SORT_ASC
3544
                    ),
3545
                ],
3546
            ]
3547
        );
3548
3549
        $searchService = $repository->getSearchService();
3550
        $result = $searchService->findLocations($query);
3551
3552
        $this->assertEquals(2, $result->totalCount);
3553
        $this->assertEquals($newLocation->id, $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...
3554
        $this->assertEquals($plainSiteLocationId, $result->searchHits[1]->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...
3555
    }
3556
3557
    /**
3558
     * Test for the findLocations() method.
3559
     *
3560
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3561
     */
3562 View Code Duplication
    public function testSortMainLocationDescending()
3563
    {
3564
        $plainSiteLocationId = 56;
3565
        $designLocationId = 58;
3566
        $partnersContentId = 59;
3567
        $repository = $this->getRepository();
3568
        $locationService = $repository->getLocationService();
3569
        $contentService = $repository->getContentService();
3570
3571
        // Add secondary Location for "Partners" user group, under "Design" page
3572
        $newLocation = $locationService->createLocation(
3573
            $contentService->loadContentInfo($partnersContentId),
3574
            $locationService->newLocationCreateStruct($designLocationId)
3575
        );
3576
3577
        $this->refreshSearch($repository);
3578
3579
        $query = new LocationQuery(
3580
            [
3581
                'filter' => new Criterion\ParentLocationId($designLocationId),
3582
                'offset' => 0,
3583
                'limit' => 10,
3584
                'sortClauses' => [
3585
                    new SortClause\Location\IsMainLocation(
3586
                        LocationQuery::SORT_DESC
3587
                    ),
3588
                ],
3589
            ]
3590
        );
3591
3592
        $searchService = $repository->getSearchService();
3593
        $result = $searchService->findLocations($query);
3594
3595
        $this->assertEquals(2, $result->totalCount);
3596
        $this->assertEquals($plainSiteLocationId, $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...
3597
        $this->assertEquals($newLocation->id, $result->searchHits[1]->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...
3598
    }
3599
3600
    /**
3601
     * Test for the findLocations() method.
3602
     *
3603
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3604
     */
3605
    public function testContentWithMultipleLocations()
3606
    {
3607
        $repository = $this->getRepository();
3608
        $contentService = $repository->getContentService();
3609
        $contentTypeService = $repository->getContentTypeService();
3610
        $locationService = $repository->getLocationService();
3611
3612
        $forumType = $contentTypeService->loadContentTypeByIdentifier('forum');
3613
3614
        $createStruct = $contentService->newContentCreateStruct($forumType, 'eng-GB');
3615
        $createStruct->alwaysAvailable = false;
3616
        $createStruct->setField('name', 'An awesome duplicate forum');
3617
3618
        $draft = $contentService->createContent($createStruct);
3619
        $content = $contentService->publishVersion($draft->getVersionInfo());
3620
3621
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
3622
        $location1 = $locationService->createLocation($content->contentInfo, $locationCreateStruct);
3623
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(5);
3624
        $location2 = $locationService->createLocation($content->contentInfo, $locationCreateStruct);
3625
3626
        $this->refreshSearch($repository);
3627
3628
        $query = new LocationQuery(
3629
            [
3630
                'filter' => new Criterion\ContentId($content->id),
3631
                'sortClauses' => [
3632
                    new SortClause\Location\Id(LocationQuery::SORT_ASC),
3633
                ],
3634
            ]
3635
        );
3636
3637
        $searchService = $repository->getSearchService();
3638
        $result = $searchService->findLocations($query);
3639
3640
        $this->assertEquals(2, $result->totalCount);
3641
        $this->assertEquals(
3642
            $location1->id,
3643
            $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...
3644
        );
3645
        $this->assertEquals(
3646
            $location2->id,
3647
            $result->searchHits[1]->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...
3648
        );
3649
    }
3650
3651
    protected function createContentForTestUserMetadataGroupHorizontal()
3652
    {
3653
        $repository = $this->getRepository();
3654
        $contentService = $repository->getContentService();
3655
        $contentTypeService = $repository->getContentTypeService();
3656
        $locationService = $repository->getLocationService();
3657
        $userService = $repository->getUserService();
3658
        $administratorUser = $repository->getCurrentUser();
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
3659
        // ID of the "Administrators" user group in an eZ Publish demo installation
3660
        $administratorsUserGroupId = 12;
3661
        // ID of the "Editors" user group in an eZ Publish demo installation
3662
        $editorsUserGroupId = 13;
3663
3664
        $administratorsUserGroup = $userService->loadUserGroup($administratorsUserGroupId);
3665
        $editorsUserGroup = $userService->loadUserGroup($editorsUserGroupId);
3666
3667
        // Add additional Location for Administrators UserGroup under Editors UserGroup Location
3668
        $locationCreateStruct = $locationService->newLocationCreateStruct(
3669
            $editorsUserGroup->contentInfo->mainLocationId
3670
        );
3671
        $newAdministratorsUserGroupLocation = $locationService->createLocation(
3672
            $administratorsUserGroup->contentInfo,
3673
            $locationCreateStruct
3674
        );
3675
3676
        // Add additional Location for administrator user under newly created UserGroup Location
3677
        $locationCreateStruct = $locationService->newLocationCreateStruct(
3678
            $newAdministratorsUserGroupLocation->id
3679
        );
3680
        $locationService->createLocation(
3681
            $administratorUser->contentInfo,
3682
            $locationCreateStruct
3683
        );
3684
3685
        // Create a Content to be found through Editors UserGroup id.
3686
        // This ensures data is indexed, it could also be done by updating metadata of
3687
        // an existing Content, but slot would need to reindex Content and that should
3688
        // be tested elsewhere (dedicated indexing integration tests, missing ATM).
3689
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
3690
3691
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3692
        $createStruct->setField('name', 'test');
3693
3694
        $locationCreateStruct = $locationService->newLocationCreateStruct(2);
3695
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
3696
        $content = $contentService->publishVersion($draft->getVersionInfo());
3697
        $contentTypeService->createContentTypeDraft($contentType);
3698
3699
        $this->refreshSearch($repository);
3700
3701
        return $content;
3702
    }
3703
3704
    /**
3705
     * Test for the findContent() method.
3706
     *
3707
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3708
     */
3709
    public function testUserMetadataGroupHorizontalFilterContent($queryType = null)
3710
    {
3711
        if ($queryType === null) {
3712
            $queryType = 'filter';
3713
        }
3714
3715
        $repository = $this->getRepository();
3716
        $searchService = $repository->getSearchService();
3717
        $editorsUserGroupId = 13;
3718
3719
        $content = $this->createContentForTestUserMetadataGroupHorizontal();
3720
3721
        $criteria = [];
3722
        $setupFactory = $this->getSetupFactory();
3723
3724
        // Do not limit for LSE, as it does not not require reindexing.
3725
        // See explanation below.
3726
        if ($setupFactory instanceof LegacySolrSetupFactory || $setupFactory instanceof LegacyElasticsearch) {
0 ignored issues
show
Bug introduced by
The class EzSystems\EzPlatformSolr...tory\LegacySetupFactory does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
3727
            $criteria[] = new Criterion\ContentTypeIdentifier('folder');
3728
        }
3729
3730
        $criteria[] = new Criterion\UserMetadata(
3731
            Criterion\UserMetadata::GROUP,
3732
            Criterion\Operator::EQ,
3733
            $editorsUserGroupId
3734
        );
3735
3736
        $query = new Query(
3737
            [
3738
                $queryType => new Criterion\LogicalAnd($criteria),
3739
                'sortClauses' => [
3740
                    new SortClause\ContentId(),
3741
                ],
3742
                'limit' => 50,
3743
            ]
3744
        );
3745
3746
        if ($setupFactory instanceof LegacySolrSetupFactory || $setupFactory instanceof LegacyElasticsearch) {
0 ignored issues
show
Bug introduced by
The class EzSystems\EzPlatformSolr...tory\LegacySetupFactory does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
3747
            $result = $searchService->findContent($query);
3748
3749
            // Administrator User is owned by itself, when additional Locations are added
3750
            // it should be reindexed and its UserGroups will updated, which means it should
3751
            // also be found as a Content of Editors UserGroup. However we do not handle this
3752
            // in slots yet, and also miss SPI methods to do it without using Search (also
3753
            // needed to decouple services), because as indexing is asynchronous Search
3754
            // should not eat its own dog food for reindexing.
3755
            $this->assertEquals(1, $result->totalCount);
3756
3757
            $this->assertEquals(
3758
                $content->id,
3759
                $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...
3760
            );
3761
        } else {
3762
            // This is how it should eventually work for all search engines,
3763
            // with required reindexing slots properly implemented.
3764
3765
            $result = $searchService->findContent($query);
3766
3767
            // Assert last hit manually, as id will change because it is created in test
3768
            // and not present it base fixture.
3769
            $foundContent1 = array_pop($result->searchHits);
3770
            $result->totalCount = $result->totalCount - 1;
0 ignored issues
show
Documentation Bug introduced by
It seems like $result->totalCount - 1 can also be of type double. However, the property $totalCount is declared as type integer|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
3771
            $this->assertEquals($content->id, $foundContent1->valueObject->id);
3772
3773
            $this->simplifySearchResult($result);
3774
            $this->assertEquals(
3775
                include $this->getFixtureDir() . '/UserMetadata.php',
3776
                $result,
3777
                'Search results do not match.',
3778
                .1 // Be quite generous regarding delay -- most important for scores
3779
            );
3780
        }
3781
    }
3782
3783
    /**
3784
     * Test for the findContent() method.
3785
     *
3786
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3787
     */
3788
    public function testUserMetadataGroupHorizontalQueryContent()
3789
    {
3790
        $this->testUserMetadataGroupHorizontalFilterContent('query');
3791
    }
3792
3793
    /**
3794
     * Test for the findLocations() method.
3795
     *
3796
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3797
     */
3798
    public function testUserMetadataGroupHorizontalFilterLocation($queryType = null)
3799
    {
3800
        if ($queryType === null) {
3801
            $queryType = 'filter';
3802
        }
3803
3804
        $repository = $this->getRepository();
3805
        $searchService = $repository->getSearchService();
3806
        $editorsUserGroupId = 13;
3807
3808
        $content = $this->createContentForTestUserMetadataGroupHorizontal();
3809
3810
        $criteria = [];
3811
        $setupFactory = $this->getSetupFactory();
3812
3813
        // Do not limit for LSE, as it does not not require reindexing.
3814
        // See explanation below.
3815
        if ($setupFactory instanceof LegacySolrSetupFactory || $setupFactory instanceof LegacyElasticsearch) {
0 ignored issues
show
Bug introduced by
The class EzSystems\EzPlatformSolr...tory\LegacySetupFactory does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
3816
            $criteria[] = new Criterion\ContentTypeIdentifier('folder');
3817
        }
3818
3819
        $criteria[] = new Criterion\UserMetadata(
3820
            Criterion\UserMetadata::GROUP,
3821
            Criterion\Operator::EQ,
3822
            $editorsUserGroupId
3823
        );
3824
3825
        $query = new LocationQuery(
3826
            [
3827
                $queryType => new Criterion\LogicalAnd($criteria),
3828
                'sortClauses' => [
3829
                    new SortClause\Location\Id(),
3830
                ],
3831
                'limit' => 50,
3832
            ]
3833
        );
3834
3835
        if ($setupFactory instanceof LegacySolrSetupFactory || $setupFactory instanceof LegacyElasticsearch) {
0 ignored issues
show
Bug introduced by
The class EzSystems\EzPlatformSolr...tory\LegacySetupFactory does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
3836
            $result = $searchService->findLocations($query);
3837
3838
            // Administrator User is owned by itself, when additional Locations are added
3839
            // it should be reindexed and its UserGroups will updated, which means it should
3840
            // also be found as a Content of Editors UserGroup. However we do not handle this
3841
            // in slots yet, and also miss SPI methods to do it without using Search (also
3842
            // needed to decouple services), because as indexing is asynchronous Search
3843
            // should not eat its own dog food for reindexing.
3844
            $this->assertEquals(1, $result->totalCount);
3845
3846
            $this->assertEquals(
3847
                $content->contentInfo->mainLocationId,
3848
                $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...
3849
            );
3850
        } else {
3851
            // This is how it should eventually work for all search engines,
3852
            // with required reindexing slots properly implemented.
3853
3854
            $result = $searchService->findLocations($query);
3855
3856
            // Assert last two hits manually, as ids will change because they are created
3857
            // in test and not present in base fixture.
3858
            $foundLocation1 = array_pop($result->searchHits);
3859
            $foundLocation2 = array_pop($result->searchHits);
3860
            // Remove additional Administrators UserGroup Location
3861
            array_pop($result->searchHits);
3862
            $result->totalCount = $result->totalCount - 2;
0 ignored issues
show
Documentation Bug introduced by
It seems like $result->totalCount - 2 can also be of type double. However, the property $totalCount is declared as type integer|null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
3863
            $this->assertEquals(
3864
                $content->versionInfo->contentInfo->mainLocationId,
3865
                $foundLocation1->valueObject->id
3866
            );
3867
            $this->assertEquals(
3868
                $repository->getCurrentUser()->id,
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
3869
                $foundLocation2->valueObject->contentId
3870
            );
3871
3872
            $this->simplifySearchResult($result);
3873
            $this->assertEquals(
3874
                include $this->getFixtureDir() . '/UserMetadataLocation.php',
3875
                $result,
3876
                'Search results do not match.',
3877
                .1 // Be quite generous regarding delay -- most important for scores
3878
            );
3879
        }
3880
    }
3881
3882
    /**
3883
     * Test for the findLocations() method.
3884
     *
3885
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3886
     */
3887
    public function testUserMetadataGroupHorizontalQueryLocation()
3888
    {
3889
        $this->testUserMetadataGroupHorizontalFilterLocation('query');
3890
    }
3891
3892
    /**
3893
     * Test for FullText on the findContent() method.
3894
     *
3895
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3896
     */
3897
    public function testFullTextOnNewContent()
3898
    {
3899
        $repository = $this->getRepository();
3900
        $contentService = $repository->getContentService();
3901
        $contentTypeService = $repository->getContentTypeService();
3902
        $locationService = $repository->getLocationService();
3903
        $searchService = $repository->getSearchService();
3904
3905
        $contentCreateStruct = $contentService->newContentCreateStruct(
3906
            $contentTypeService->loadContentTypeByIdentifier('folder'),
3907
            'eng-GB'
3908
        );
3909
3910
        $contentCreateStruct->setField('name', 'foxes');
3911
3912
        $englishContent = $contentService->publishVersion(
3913
            $contentService->createContent(
3914
                $contentCreateStruct,
3915
                [$locationService->newLocationCreateStruct(2)]
3916
            )->versionInfo
3917
        );
3918
3919
        $this->refreshSearch($repository);
3920
3921
        $query = new Query(
3922
            [
3923
                'query' => new Criterion\FullText('foxes'),
3924
            ]
3925
        );
3926
3927
        $searchResult = $searchService->findContentInfo($query);
3928
3929
        $this->assertEquals(1, $searchResult->totalCount);
3930
        $this->assertEquals($englishContent->id, $searchResult->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...
3931
    }
3932
3933
    /**
3934
     * Test for the findContent() method.
3935
     *
3936
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3937
     */
3938
    public function testLanguageAnalysisSeparateContent()
3939
    {
3940
        $setupFactory = $this->getSetupFactory();
3941
        if (!$setupFactory instanceof LegacyElasticsearch) {
3942
            $this->markTestSkipped('Language analysis is implemented only for Elasticsearch storage');
3943
        }
3944
3945
        $repository = $this->getRepository();
3946
        $contentService = $repository->getContentService();
3947
        $contentTypeService = $repository->getContentTypeService();
3948
        $locationService = $repository->getLocationService();
3949
        $searchService = $repository->getSearchService();
3950
        $languageService = $repository->getContentLanguageService();
3951
3952
        $languageCreateStruct = $languageService->newLanguageCreateStruct();
3953
        $languageCreateStruct->languageCode = 'rus-RU';
3954
        $languageCreateStruct->name = 'Russian';
3955
3956
        $languageService->createLanguage($languageCreateStruct);
3957
3958
        $contentCreateStruct = $contentService->newContentCreateStruct(
3959
            $contentTypeService->loadContentTypeByIdentifier('folder'),
3960
            'eng-GB'
3961
        );
3962
3963
        $contentCreateStruct->setField('name', 'foxes');
3964
3965
        $englishContent = $contentService->publishVersion(
3966
            $contentService->createContent(
3967
                $contentCreateStruct,
3968
                [$locationService->newLocationCreateStruct(2)]
3969
            )->versionInfo
3970
        );
3971
3972
        $contentCreateStruct = $contentService->newContentCreateStruct(
3973
            $contentTypeService->loadContentTypeByIdentifier('folder'),
3974
            'rus-RU'
3975
        );
3976
3977
        $contentCreateStruct->setField('name', 'foxes');
3978
3979
        $russianContent = $contentService->publishVersion(
0 ignored issues
show
Unused Code introduced by
$russianContent is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
3980
            $contentService->createContent(
3981
                $contentCreateStruct,
3982
                [$locationService->newLocationCreateStruct(2)]
3983
            )->versionInfo
3984
        );
3985
3986
        // Only Content in English should be found, because Content in Russian
3987
        // will not be correctly stemmed
3988
        $query = new Query(
3989
            [
3990
                'query' => new Criterion\FullText('foxing'),
3991
            ]
3992
        );
3993
3994
        $searchResult = $searchService->findContent($query);
3995
3996
        $this->assertEquals(1, $searchResult->totalCount);
3997
        $this->assertEquals($englishContent->id, $searchResult->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...
3998
    }
3999
4000
    /**
4001
     * Test for the findContent() method.
4002
     *
4003
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4004
     */
4005
    public function testLanguageAnalysisSameContent()
4006
    {
4007
        $setupFactory = $this->getSetupFactory();
4008
        if (!$setupFactory instanceof LegacyElasticsearch) {
4009
            $this->markTestSkipped('Language analysis is implemented only for Elasticsearch storage');
4010
        }
4011
4012
        $repository = $this->getRepository();
4013
        $contentService = $repository->getContentService();
4014
        $contentTypeService = $repository->getContentTypeService();
4015
        $locationService = $repository->getLocationService();
4016
        $searchService = $repository->getSearchService();
4017
        $languageService = $repository->getContentLanguageService();
4018
4019
        $languageCreateStruct = $languageService->newLanguageCreateStruct();
4020
        $languageCreateStruct->languageCode = 'rus-RU';
4021
        $languageCreateStruct->name = 'Russian';
4022
4023
        $languageService->createLanguage($languageCreateStruct);
4024
4025
        $contentCreateStruct = $contentService->newContentCreateStruct(
4026
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4027
            'eng-GB'
4028
        );
4029
4030
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'eng-GB');
4031
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'rus-RU');
4032
4033
        $mixedContent = $contentService->publishVersion(
4034
            $contentService->createContent(
4035
                $contentCreateStruct,
4036
                [$locationService->newLocationCreateStruct(2)]
4037
            )->versionInfo
4038
        );
4039
4040
        // Content will be found because translation in Russian will be correctly stemmed
4041
        $query = new Query(
4042
            [
4043
                'query' => new Criterion\FullText('важнее'),
4044
            ]
4045
        );
4046
4047
        $searchResult = $searchService->findContent($query);
4048
4049
        $this->assertEquals(1, $searchResult->totalCount);
4050
        $this->assertEquals($mixedContent->id, $searchResult->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...
4051
    }
4052
4053
    /**
4054
     * Test for the findContent() method.
4055
     *
4056
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4057
     */
4058
    public function testLanguageAnalysisSameContentNotFound()
4059
    {
4060
        $setupFactory = $this->getSetupFactory();
4061
        if (!$setupFactory instanceof LegacyElasticsearch) {
4062
            $this->markTestSkipped('Language analysis is implemented only for Elasticsearch storage');
4063
        }
4064
4065
        $repository = $this->getRepository();
4066
        $contentService = $repository->getContentService();
4067
        $contentTypeService = $repository->getContentTypeService();
4068
        $locationService = $repository->getLocationService();
4069
        $searchService = $repository->getSearchService();
4070
        $languageService = $repository->getContentLanguageService();
4071
4072
        $languageCreateStruct = $languageService->newLanguageCreateStruct();
4073
        $languageCreateStruct->languageCode = 'rus-RU';
4074
        $languageCreateStruct->name = 'Russian';
4075
4076
        $languageService->createLanguage($languageCreateStruct);
4077
4078
        $contentCreateStruct = $contentService->newContentCreateStruct(
4079
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4080
            'eng-GB'
4081
        );
4082
4083
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'eng-GB');
4084
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'rus-RU');
4085
4086
        $mixedContent = $contentService->publishVersion(
0 ignored issues
show
Unused Code introduced by
$mixedContent is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
4087
            $contentService->createContent(
4088
                $contentCreateStruct,
4089
                [$locationService->newLocationCreateStruct(2)]
4090
            )->versionInfo
4091
        );
4092
4093
        // Content should be found because translation in Russian will be correctly stemmed
4094
        $query = new Query(
4095
            [
4096
                'query' => new Criterion\FullText('важнее'),
4097
            ]
4098
        );
4099
4100
        // Filtering fields for only English will cause no match because the term will
4101
        // not be correctly stemmed
4102
        $searchResult = $searchService->findContent($query, ['languages' => ['eng-GB']]);
4103
4104
        $this->assertEquals(0, $searchResult->totalCount);
4105
    }
4106
4107
    /**
4108
     * Test for the findContent() method searching for content filtered by languages.
4109
     *
4110
     * @covers \eZ\Publish\Core\Repository\SearchService::findContent
4111
     */
4112
    public function testFindContentWithLanguageFilter()
4113
    {
4114
        $repository = $this->getRepository();
4115
        $searchService = $repository->getSearchService();
4116
4117
        $query = new Query(
4118
            [
4119
                'filter' => new Criterion\ContentId([4]),
4120
                'offset' => 0,
4121
            ]
4122
        );
4123
        $searchResult = $searchService->findContent(
4124
            $query,
4125
            ['languages' => ['eng-US']],
4126
            false
4127
        );
4128
        /* END: Use Case */
4129
4130
        $this->assertInstanceOf(
4131
            SearchResult::class,
4132
            $searchResult
4133
        );
4134
4135
        $this->assertEquals(1, $searchResult->totalCount);
4136
        $this->assertCount($searchResult->totalCount, $searchResult->searchHits);
4137
        foreach ($searchResult->searchHits as $searchHit) {
4138
            $this->assertInstanceOf(
4139
                SearchHit::class,
4140
                $searchHit
4141
            );
4142
        }
4143
    }
4144
4145
    /**
4146
     * This test prepares data for other tests.
4147
     *
4148
     * @see testFulltextContentSearchComplex
4149
     * @see testFulltextLocationSearchComplex
4150
     *
4151
     * @return array
4152
     */
4153
    public function testFulltextComplex()
4154
    {
4155
        $repository = $this->getRepository();
4156
        $contentService = $repository->getContentService();
4157
        $contentTypeService = $repository->getContentTypeService();
4158
        $locationService = $repository->getLocationService();
4159
4160
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
4161
        $contentCreateStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
4162
4163
        $contentCreateStruct->setField('name', 'red');
4164
        $contentCreateStruct->setField('short_name', 'red apple');
4165
        $content1 = $contentService->publishVersion(
4166
            $contentService->createContent(
4167
                $contentCreateStruct,
4168
                [$locationService->newLocationCreateStruct(2)]
4169
            )->versionInfo
4170
        );
4171
4172
        $contentCreateStruct->setField('name', 'apple');
4173
        $contentCreateStruct->setField('short_name', 'two');
4174
        $content2 = $contentService->publishVersion(
4175
            $contentService->createContent(
4176
                $contentCreateStruct,
4177
                [$locationService->newLocationCreateStruct(2)]
4178
            )->versionInfo
4179
        );
4180
4181
        $contentCreateStruct->setField('name', 'red apple');
4182
        $contentCreateStruct->setField('short_name', 'three');
4183
        $content3 = $contentService->publishVersion(
4184
            $contentService->createContent(
4185
                $contentCreateStruct,
4186
                [$locationService->newLocationCreateStruct(2)]
4187
            )->versionInfo
4188
        );
4189
4190
        $this->refreshSearch($repository);
4191
4192
        $criterion = new Criterion\FullText(
4193
            'red apple',
4194
            [
4195
                'boost' => [
4196
                    'short_name' => 2,
4197
                ],
4198
                'fuzziness' => .1,
4199
            ]
4200
        );
4201
4202
        return [$criterion, $content1, $content2, $content3];
4203
    }
4204
4205
    /**
4206
     * Test for the findContent() method.
4207
     *
4208
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4209
     * @depends testFulltextComplex
4210
     *
4211
     * @param array $data
4212
     */
4213
    public function testFulltextContentSearchComplex(array $data)
4214
    {
4215
        // Do not initialize from scratch
4216
        $repository = $this->getRepository(false);
4217
        $searchService = $repository->getSearchService();
4218
        list($criterion, $content1, $content2, $content3) = $data;
4219
4220
        $searchResult = $searchService->findContent(
4221
            new Query(['query' => $criterion]),
4222
            ['languages' => ['eng-GB']]
4223
        );
4224
        $searchHits = $searchResult->searchHits;
4225
4226
        $this->assertEquals(3, $searchResult->totalCount);
4227
4228
        // Legacy search engine does have scoring, sorting the results by ID in that case
4229
        $setupFactory = $this->getSetupFactory();
4230 View Code Duplication
        if (get_class($setupFactory) === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4231
            usort(
4232
                $searchHits,
4233
                function ($a, $b) {
4234
                    return ($a->valueObject->id < $b->valueObject->id) ? -1 : 1;
4235
                }
4236
            );
4237
4238
            $this->assertEquals($content1->id, $searchHits[0]->valueObject->id);
4239
            $this->assertEquals($content2->id, $searchHits[1]->valueObject->id);
4240
            $this->assertEquals($content3->id, $searchHits[2]->valueObject->id);
4241
4242
            return;
4243
        }
4244
4245
        // Assert scores are descending
4246
        $this->assertGreaterThan($searchHits[1]->score, $searchHits[0]->score);
4247
        $this->assertGreaterThan($searchHits[2]->score, $searchHits[1]->score);
4248
4249
        // Assert order
4250
        $this->assertEquals($content1->id, $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...
4251
        $this->assertEquals($content3->id, $searchHits[1]->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...
4252
        $this->assertEquals($content2->id, $searchHits[2]->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...
4253
    }
4254
4255
    /**
4256
     * Test for the findLocations() method.
4257
     *
4258
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
4259
     * @depends testFulltextComplex
4260
     *
4261
     * @param array $data
4262
     */
4263
    public function testFulltextLocationSearchComplex(array $data)
4264
    {
4265
        $setupFactory = $this->getSetupFactory();
4266
        if ($setupFactory instanceof LegacyElasticsearch) {
4267
            $this->markTestIncomplete(
4268
                'Fulltext criterion is not supported with Location search in Elasticsearch engine'
4269
            );
4270
        }
4271
4272
        if ($setupFactory instanceof LegacySolrSetupFactory && getenv('SOLR_VERSION') === '4.10.4') {
0 ignored issues
show
Bug introduced by
The class EzSystems\EzPlatformSolr...tory\LegacySetupFactory does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
4273
            $this->markTestSkipped('Skipping location search score test on Solr 4.10, you need Solr 6 for this!');
4274
        }
4275
4276
        // Do not initialize from scratch
4277
        $repository = $this->getRepository(false);
4278
        list($criterion, $content1, $content2, $content3) = $data;
4279
        $searchService = $repository->getSearchService();
4280
4281
        $searchResult = $searchService->findLocations(
4282
            new LocationQuery(['query' => $criterion]),
4283
            ['languages' => ['eng-GB']]
4284
        );
4285
        $searchHits = $searchResult->searchHits;
4286
4287
        $this->assertEquals(3, $searchResult->totalCount);
4288
4289
        // Legacy search engine does have scoring, sorting the results by ID in that case
4290
        $setupFactory = $this->getSetupFactory();
4291 View Code Duplication
        if (get_class($setupFactory) === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4292
            usort(
4293
                $searchHits,
4294
                function ($a, $b) {
4295
                    return ($a->valueObject->id < $b->valueObject->id) ? -1 : 1;
4296
                }
4297
            );
4298
4299
            $this->assertEquals($content1->id, $searchHits[0]->valueObject->contentId);
4300
            $this->assertEquals($content2->id, $searchHits[1]->valueObject->contentId);
4301
            $this->assertEquals($content3->id, $searchHits[2]->valueObject->contentId);
4302
4303
            return;
4304
        }
4305
4306
        // Assert scores are descending
4307
        $this->assertGreaterThan($searchHits[1]->score, $searchHits[0]->score);
4308
        $this->assertGreaterThan($searchHits[2]->score, $searchHits[1]->score);
4309
4310
        // Assert order
4311
        $this->assertEquals($content1->id, $searchHits[0]->valueObject->contentId);
0 ignored issues
show
Documentation introduced by
The property contentId 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...
4312
        $this->assertEquals($content3->id, $searchHits[1]->valueObject->contentId);
0 ignored issues
show
Documentation introduced by
The property contentId 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...
4313
        $this->assertEquals($content2->id, $searchHits[2]->valueObject->contentId);
0 ignored issues
show
Documentation introduced by
The property contentId 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...
4314
    }
4315
4316
    /**
4317
     * Assert that query result matches the given fixture.
4318
     *
4319
     * @param Query $query
4320
     * @param string $fixture
4321
     * @param null|callable $closure
4322
     * @param bool $info
4323
     * @param bool $id
4324
     */
4325
    protected function assertQueryFixture(Query $query, $fixture, $closure = null, $ignoreScore = true, $info = false, $id = true)
4326
    {
4327
        $repository = $this->getRepository();
4328
        $searchService = $repository->getSearchService();
4329
4330
        try {
4331
            if ($query instanceof LocationQuery) {
4332
                $setupFactory = $this->getSetupFactory();
4333
                if ($setupFactory instanceof LegacySolrSetupFactory) {
0 ignored issues
show
Bug introduced by
The class EzSystems\EzPlatformSolr...tory\LegacySetupFactory does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
4334
                    // @todo When we want to test score again by default we will need fixtures for Solr
4335
                }
4336
4337
                if ($setupFactory instanceof LegacyElasticsearch) {
4338
                    $position = strrpos($fixture, '/');
4339
                    $fixture = substr_replace($fixture, '/Location', $position, 0);
4340
                }
4341
4342
                $result = $searchService->findLocations($query);
4343
            } elseif ($query instanceof Query) {
4344
                if ($info) {
4345
                    $result = $searchService->findContentInfo($query);
4346
                } else {
4347
                    $result = $searchService->findContent($query);
4348
                }
4349
            } else {
4350
                $this->fail('Expected instance of LocationQuery or Query, got: ' . gettype($query));
4351
            }
4352
            $this->simplifySearchResult($result);
0 ignored issues
show
Bug introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
4353
        } catch (NotImplementedException $e) {
4354
            $this->markTestSkipped(
4355
                'This feature is not supported by the current search backend: ' . $e->getMessage()
4356
            );
4357
        }
4358
4359 View Code Duplication
        if (!is_file($fixture)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4360
            if (isset($_ENV['ez_tests_record'])) {
4361
                file_put_contents(
4362
                    $record = $fixture . '.recording',
4363
                    "<?php\n\nreturn " . var_export($result, true) . ";\n\n"
4364
                );
4365
                $this->markTestIncomplete("No fixture available. Result recorded at $record. Result: \n" . $this->printResult($result));
4366
            } else {
4367
                $this->markTestIncomplete("No fixture available. Set \$_ENV['ez_tests_record'] to generate:\n " . $fixture);
4368
            }
4369
        }
4370
4371
        $fixture = include $fixture;
4372
4373
        if ($closure !== null) {
4374
            $closure($fixture);
4375
            $closure($result);
4376
        }
4377
4378 View Code Duplication
        if ($ignoreScore) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4379
            foreach ([$fixture, $result] as $set) {
4380
                $property = new \ReflectionProperty(get_class($set), 'maxScore');
4381
                $property->setAccessible(true);
4382
                $property->setValue($set, 0.0);
4383
4384
                foreach ($set->searchHits as $hit) {
4385
                    $property = new \ReflectionProperty(get_class($hit), 'score');
4386
                    $property->setAccessible(true);
4387
                    $property->setValue($hit, 0.0);
4388
                }
4389
            }
4390
        }
4391
4392
        foreach ([$fixture, $result] as $set) {
4393
            foreach ($set->searchHits as $hit) {
4394
                $property = new \ReflectionProperty(get_class($hit), 'index');
4395
                $property->setAccessible(true);
4396
                $property->setValue($hit, null);
4397
4398
                $property = new \ReflectionProperty(get_class($hit), 'matchedTranslation');
4399
                $property->setAccessible(true);
4400
                $property->setValue($hit, null);
4401
4402
                if (!$id) {
4403
                    $hit->valueObject['id'] = null;
4404
                }
4405
            }
4406
        }
4407
4408
        $this->assertEquals(
4409
            $fixture,
4410
            $result,
4411
            'Search results do not match.',
4412
            .99 // Be quite generous regarding delay -- most important for scores
4413
        );
4414
    }
4415
4416
    /**
4417
     * Show a simplified view of the search result for manual introspection.
4418
     *
4419
     * @param SearchResult $result
4420
     *
4421
     * @return string
4422
     */
4423 View Code Duplication
    protected function printResult(SearchResult $result)
4424
    {
4425
        $printed = '';
4426
        foreach ($result->searchHits as $hit) {
4427
            $printed .= sprintf(" - %s (%s)\n", $hit->valueObject['title'], $hit->valueObject['id']);
4428
        }
4429
4430
        return $printed;
4431
    }
4432
4433
    /**
4434
     * Simplify search result.
4435
     *
4436
     * This leads to saner comparisons of results, since we do not get the full
4437
     * content objects every time.
4438
     *
4439
     * @param SearchResult $result
4440
     */
4441
    protected function simplifySearchResult(SearchResult $result)
4442
    {
4443
        $result->time = 1;
4444
4445
        foreach ($result->searchHits as $hit) {
4446
            switch (true) {
4447
                case $hit->valueObject instanceof Content:
4448 View Code Duplication
                case $hit->valueObject instanceof Location:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4449
                    $hit->valueObject = [
0 ignored issues
show
Documentation Bug introduced by
It seems like array('id' => $hit->valu...ect->contentInfo->name) of type array<string,?,{"id":"?","title":"?"}> is incompatible with the declared type object<eZ\Publish\API\Re...ory\Values\ValueObject> of property $valueObject.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
4450
                        'id' => $hit->valueObject->contentInfo->id,
4451
                        'title' => $hit->valueObject->contentInfo->name,
4452
                    ];
4453
                    break;
4454
4455
                case $hit->valueObject instanceof ContentInfo:
4456
                    $hit->valueObject = [
0 ignored issues
show
Documentation Bug introduced by
It seems like array('id' => $hit->valu...hit->valueObject->name) of type array<string,*,{"id":"*","title":"string"}> is incompatible with the declared type object<eZ\Publish\API\Re...ory\Values\ValueObject> of property $valueObject.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
4457
                        'id' => $hit->valueObject->id,
4458
                        'title' => $hit->valueObject->name,
4459
                    ];
4460
                    break;
4461
4462
                default:
4463
                    throw new \RuntimeException('Unknown search result hit type: ' . get_class($hit->valueObject));
4464
            }
4465
        }
4466
    }
4467
4468
    /**
4469
     * Get fixture directory.
4470
     *
4471
     * @return string
4472
     */
4473
    protected function getFixtureDir()
4474
    {
4475
        return __DIR__ . '/_fixtures/' . getenv('fixtureDir') . '/';
4476
    }
4477
4478
    /**
4479
     * For findContentInfo tests, to reuse fixtures for findContent tests.
4480
     *
4481
     * @param null|callable $closure
4482
     *
4483
     * @return callable
4484
     */
4485
    private function getContentInfoFixtureClosure($closure = null)
4486
    {
4487
        /** @var $data \eZ\Publish\API\Repository\Values\Content\Search\SearchResult */
4488
        return function (&$data) use ($closure) {
4489
            foreach ($data->searchHits as $searchHit) {
4490
                if ($searchHit->valueObject instanceof Content) {
4491
                    $searchHit->valueObject = $searchHit->valueObject->getVersionInfo()->getContentInfo();
4492
                }
4493
            }
4494
4495
            if (isset($closure)) {
4496
                $closure($data);
4497
            }
4498
        };
4499
    }
4500
4501
    /**
4502
     * Test searching using Field Criterion where the given Field Identifier exists in
4503
     * both searchable and non-searchable Fields.
4504
     * Number of returned results depends on used storage.
4505
     *
4506
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4507
     */
4508
    public function testFieldCriterionForContentsWithIdenticalFieldIdentifiers()
4509
    {
4510
        $this->createContentWithFieldType(
4511
            'url',
4512
            'title',
4513
            'foo'
4514
        );
4515
        $this->createContentWithFieldType(
4516
            'string',
4517
            'title',
4518
            'foo'
4519
        );
4520
        $query = new Query(
4521
            [
4522
                'query' => new Criterion\Field(
4523
                    'title',
4524
                    Criterion\Operator::EQ,
4525
                    'foo'
4526
                ),
4527
            ]
4528
        );
4529
4530
        $repository = $this->getRepository();
4531
        $searchService = $repository->getSearchService();
4532
        $result = $searchService->findContent($query);
4533
4534
        $this->assertTrue(($result->totalCount === 1 || $result->totalCount === 2));
4535
    }
4536
4537
    private function createContentWithFieldType(
4538
        string $fieldType,
4539
        string $fieldName,
4540
        string $fieldValue
4541
    ) {
4542
        $repository = $this->getRepository();
4543
        $contentTypeService = $repository->getContentTypeService();
4544
        $contentService = $repository->getContentService();
4545
4546
        $createStruct = $contentTypeService->newContentTypeCreateStruct($fieldType . uniqid());
4547
        $createStruct->mainLanguageCode = 'eng-GB';
4548
        $createStruct->remoteId = $fieldType . '-123';
4549
        $createStruct->names = ['eng-GB' => $fieldType];
4550
        $createStruct->creatorId = 14;
4551
        $createStruct->creationDate = new \DateTime();
4552
4553
        $fieldCreate = $contentTypeService->newFieldDefinitionCreateStruct($fieldName, 'ez' . $fieldType);
4554
        $fieldCreate->names = ['eng-GB' => $fieldName];
4555
        $fieldCreate->fieldGroup = 'main';
4556
        $fieldCreate->position = 1;
4557
4558
        $createStruct->addFieldDefinition($fieldCreate);
4559
4560
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
4561
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
4562
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
4563
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
4564
4565
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
4566
        $createStruct->remoteId = $fieldType . '-456';
4567
        $createStruct->alwaysAvailable = false;
4568
        $createStruct->setField(
4569
            $fieldName,
4570
            $fieldValue
4571
        );
4572
4573
        $draft = $contentService->createContent($createStruct);
4574
        $content = $contentService->publishVersion($draft->getVersionInfo());
4575
4576
        $this->refreshSearch($repository);
4577
4578
        return $content;
4579
    }
4580
}
4581