Completed
Push — apply-code-style ( 1a43bf...37cc85 )
by
unknown
45:48
created

testMapLocationDistanceGreaterThanOrEqual()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 73

Duplication

Lines 73
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 73
loc 73
rs 8.589
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 InvalidArgumentException;
14
use eZ\Publish\API\Repository\Values\Content\Content;
15
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
16
use eZ\Publish\API\Repository\Values\Content\Query;
17
use eZ\Publish\API\Repository\Values\Content\Location;
18
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
19
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
20
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
21
use eZ\Publish\API\Repository\Values\Content\Search\SearchResult;
22
use eZ\Publish\API\Repository\Values\Content\Search\SearchHit;
23
use eZ\Publish\API\Repository\Exceptions\NotImplementedException;
24
25
/**
26
 * Test case for operations in the SearchService.
27
 *
28
 * @see eZ\Publish\API\Repository\SearchService
29
 * @group integration
30
 * @group search
31
 */
32
class SearchServiceTest extends BaseTest
33
{
34
    const QUERY_CLASS = Query::class;
35
36
    const FIND_CONTENT_METHOD = 'findContent';
37
    const FIND_LOCATION_METHOD = 'findLocations';
38
39
    const AVAILABLE_FIND_METHODS = [
40
        self::FIND_CONTENT_METHOD,
41
        self::FIND_LOCATION_METHOD,
42
    ];
43
44
    use Common\FacetedSearchProvider;
45
46
    public function getFilterContentSearches()
47
    {
48
        $fixtureDir = $this->getFixtureDir();
49
50
        return [
51
            0 => [
52
                [
53
                    'filter' => new Criterion\ContentId(
54
                        [1, 4, 10]
55
                    ),
56
                    'sortClauses' => [new SortClause\ContentId()],
57
                ],
58
                $fixtureDir . 'ContentId.php',
59
            ],
60
            1 => [
61
                [
62
                    'filter' => new Criterion\LogicalAnd(
63
                        [
64
                            new Criterion\ContentId(
65
                                [1, 4, 10]
66
                            ),
67
                            new Criterion\ContentId(
68
                                [4, 12]
69
                            ),
70
                        ]
71
                    ),
72
                    'sortClauses' => [new SortClause\ContentId()],
73
                ],
74
                $fixtureDir . 'LogicalAnd.php',
75
            ],
76
            2 => [
77
                [
78
                    'filter' => new Criterion\LogicalOr(
79
                        [
80
                            new Criterion\ContentId(
81
                                [1, 4, 10]
82
                            ),
83
                            new Criterion\ContentId(
84
                                [4, 12]
85
                            ),
86
                        ]
87
                    ),
88
                    'sortClauses' => [new SortClause\ContentId()],
89
                ],
90
                $fixtureDir . 'LogicalOr.php',
91
            ],
92
            3 => [
93
                [
94
                    'filter' => new Criterion\LogicalAnd(
95
                        [
96
                            new Criterion\ContentId(
97
                                [1, 4, 10]
98
                            ),
99
                            new Criterion\LogicalNot(
100
                                new Criterion\ContentId(
101
                                    [10, 12]
102
                                )
103
                            ),
104
                        ]
105
                    ),
106
                    'sortClauses' => [new SortClause\ContentId()],
107
                ],
108
                $fixtureDir . 'LogicalNot.php',
109
            ],
110
            4 => [
111
                [
112
                    'filter' => new Criterion\LogicalAnd(
113
                        [
114
                            new Criterion\ContentId(
115
                                [1, 4, 10]
116
                            ),
117
                            new Criterion\LogicalAnd(
118
                                [
119
                                    new Criterion\LogicalNot(
120
                                        new Criterion\ContentId(
121
                                            [10, 12]
122
                                        )
123
                                    ),
124
                                ]
125
                            ),
126
                        ]
127
                    ),
128
                    'sortClauses' => [new SortClause\ContentId()],
129
                ],
130
                $fixtureDir . 'LogicalNot.php',
131
            ],
132
            5 => [
133
                [
134
                    'filter' => new Criterion\ContentTypeId(
135
                        4
136
                    ),
137
                    'sortClauses' => [new SortClause\ContentId()],
138
                ],
139
                $fixtureDir . 'ContentTypeId.php',
140
            ],
141
            6 => [
142
                [
143
                    'filter' => new Criterion\ContentTypeIdentifier(
144
                        'user'
145
                    ),
146
                    'sortClauses' => [new SortClause\ContentId()],
147
                ],
148
                $fixtureDir . 'ContentTypeId.php',
149
            ],
150
            7 => [
151
                [
152
                    'filter' => new Criterion\ContentTypeIdentifier(
153
                        'user',
154
                        'invalid'
155
                    ),
156
                    'sortClauses' => [new SortClause\ContentId()],
157
                ],
158
                $fixtureDir . 'ContentTypeId.php',
159
            ],
160
            8 => [
161
                [
162
                    'filter' => new Criterion\ContentTypeIdentifier(
163
                        'invalid1',
164
                        'invalid2'
165
                    ),
166
                    'sortClauses' => [new SortClause\ContentId()],
167
                ],
168
                $fixtureDir . 'MatchNone.php',
169
            ],
170
            9 => [
171
                [
172
                    'filter' => new Criterion\MatchNone(),
173
                    'sortClauses' => [new SortClause\ContentId()],
174
                ],
175
                $fixtureDir . 'MatchNone.php',
176
            ],
177
            10 => [
178
                [
179
                    'filter' => new Criterion\ContentTypeGroupId(
180
                        2
181
                    ),
182
                    'sortClauses' => [new SortClause\ContentId()],
183
                ],
184
                $fixtureDir . 'ContentTypeGroupId.php',
185
            ],
186
            11 => [
187
                [
188
                    'filter' => new Criterion\DateMetadata(
189
                        Criterion\DateMetadata::MODIFIED,
190
                        Criterion\Operator::GT,
191
                        1343140540
192
                    ),
193
                    'sortClauses' => [new SortClause\ContentId()],
194
                ],
195
                $fixtureDir . 'DateMetadataGt.php',
196
            ],
197
            12 => [
198
                [
199
                    'filter' => new Criterion\DateMetadata(
200
                        Criterion\DateMetadata::MODIFIED,
201
                        Criterion\Operator::GTE,
202
                        1311154215
203
                    ),
204
                    'sortClauses' => [new SortClause\ContentId()],
205
                ],
206
                $fixtureDir . 'DateMetadataGte.php',
207
            ],
208
            13 => [
209
                [
210
                    'filter' => new Criterion\DateMetadata(
211
                        Criterion\DateMetadata::MODIFIED,
212
                        Criterion\Operator::LTE,
213
                        1311154215
214
                    ),
215
                    'limit' => 10,
216
                    'sortClauses' => [new SortClause\ContentId()],
217
                ],
218
                $fixtureDir . 'DateMetadataLte.php',
219
            ],
220
            14 => [
221
                [
222
                    'filter' => new Criterion\DateMetadata(
223
                        Criterion\DateMetadata::MODIFIED,
224
                        Criterion\Operator::IN,
225
                        [1033920794, 1060695457, 1343140540]
226
                    ),
227
                    'sortClauses' => [new SortClause\ContentId()],
228
                ],
229
                $fixtureDir . 'DateMetadataIn.php',
230
            ],
231
            15 => [
232
                [
233
                    'filter' => new Criterion\DateMetadata(
234
                        Criterion\DateMetadata::MODIFIED,
235
                        Criterion\Operator::BETWEEN,
236
                        [1033920776, 1072180276]
237
                    ),
238
                    'sortClauses' => [new SortClause\ContentId()],
239
                ],
240
                $fixtureDir . 'DateMetadataBetween.php',
241
            ],
242
            16 => [
243
                [
244
                    'filter' => new Criterion\DateMetadata(
245
                        Criterion\DateMetadata::CREATED,
246
                        Criterion\Operator::BETWEEN,
247
                        [1033920776, 1072180278]
248
                    ),
249
                    'sortClauses' => [new SortClause\ContentId()],
250
                ],
251
                $fixtureDir . 'DateMetadataCreated.php',
252
            ],
253
            17 => [
254
                [
255
                    'filter' => new Criterion\CustomField(
256
                        'user_group_name_value_s',
257
                        Criterion\Operator::EQ,
258
                        'Members'
259
                    ),
260
                    'sortClauses' => [new SortClause\ContentId()],
261
                ],
262
                $fixtureDir . 'Field.php',
263
            ],
264
            18 => [
265
                [
266
                    'filter' => new Criterion\CustomField(
267
                        'user_group_name_value_s',
268
                        Criterion\Operator::CONTAINS,
269
                        'Members'
270
                    ),
271
                    'sortClauses' => [new SortClause\ContentId()],
272
                ],
273
                $fixtureDir . 'Field.php',
274
            ],
275
            19 => [
276
                [
277
                    'filter' => new Criterion\CustomField(
278
                        'user_group_name_value_s',
279
                        Criterion\Operator::LT,
280
                        'Members'
281
                    ),
282
                    'sortClauses' => [new SortClause\ContentId()],
283
                ],
284
                $fixtureDir . 'CustomFieldLt.php',
285
            ],
286
            20 => [
287
                [
288
                    'filter' => new Criterion\CustomField(
289
                        'user_group_name_value_s',
290
                        Criterion\Operator::LTE,
291
                        'Members'
292
                    ),
293
                    'sortClauses' => [new SortClause\ContentId()],
294
                ],
295
                $fixtureDir . 'CustomFieldLte.php',
296
            ],
297
            21 => [
298
                [
299
                    'filter' => new Criterion\CustomField(
300
                        'user_group_name_value_s',
301
                        Criterion\Operator::GT,
302
                        'Members'
303
                    ),
304
                    'sortClauses' => [new SortClause\ContentId()],
305
                ],
306
                $fixtureDir . 'CustomFieldGt.php',
307
            ],
308
            22 => [
309
                [
310
                    'filter' => new Criterion\CustomField(
311
                        'user_group_name_value_s',
312
                        Criterion\Operator::GTE,
313
                        'Members'
314
                    ),
315
                    'sortClauses' => [new SortClause\ContentId()],
316
                ],
317
                $fixtureDir . 'CustomFieldGte.php',
318
            ],
319
            23 => [
320
                [
321
                    'filter' => new Criterion\CustomField(
322
                        'user_group_name_value_s',
323
                        Criterion\Operator::BETWEEN,
324
                        ['Administrator users', 'Members']
325
                    ),
326
                    'sortClauses' => [new SortClause\ContentId()],
327
                ],
328
                $fixtureDir . 'CustomFieldBetween.php',
329
            ],
330
            24 => [
331
                [
332
                    'filter' => new Criterion\RemoteId(
333
                        ['f5c88a2209584891056f987fd965b0ba', 'faaeb9be3bd98ed09f606fc16d144eca']
334
                    ),
335
                    'sortClauses' => [new SortClause\ContentId()],
336
                ],
337
                $fixtureDir . 'RemoteId.php',
338
            ],
339
            25 => [
340
                [
341
                    'filter' => new Criterion\SectionId(
342
                        [2]
343
                    ),
344
                    'sortClauses' => [new SortClause\ContentId()],
345
                ],
346
                $fixtureDir . 'SectionId.php',
347
            ],
348
            26 => [
349
                [
350
                    'filter' => new Criterion\Field(
351
                        'name',
352
                        Criterion\Operator::EQ,
353
                        'Members'
354
                    ),
355
                    'sortClauses' => [new SortClause\ContentId()],
356
                ],
357
                $fixtureDir . 'Field.php',
358
            ],
359
            27 => [
360
                [
361
                    'filter' => new Criterion\Field(
362
                        'name',
363
                        Criterion\Operator::IN,
364
                        ['Members', 'Anonymous Users']
365
                    ),
366
                    'sortClauses' => [new SortClause\ContentId()],
367
                ],
368
                $fixtureDir . 'FieldIn.php',
369
            ],
370
            28 => [
371
                [
372
                    'filter' => new Criterion\DateMetadata(
373
                        Criterion\DateMetadata::MODIFIED,
374
                        Criterion\Operator::BETWEEN,
375
                        [1033920275, 1033920794]
376
                    ),
377
                    'sortClauses' => [new SortClause\ContentId()],
378
                ],
379
                $fixtureDir . 'FieldBetween.php',
380
            ],
381
            29 => [
382
                [
383
                    'filter' => new Criterion\LogicalOr(
384
                        [
385
                            new Criterion\Field(
386
                                'name',
387
                                Criterion\Operator::EQ,
388
                                'Members'
389
                            ),
390
                            new Criterion\DateMetadata(
391
                                Criterion\DateMetadata::MODIFIED,
392
                                Criterion\Operator::BETWEEN,
393
                                [1033920275, 1033920794]
394
                            ),
395
                        ]
396
                    ),
397
                    'sortClauses' => [new SortClause\ContentId()],
398
                ],
399
                $fixtureDir . 'FieldOr.php',
400
            ],
401
            30 => [
402
                [
403
                    'filter' => new Criterion\Subtree(
404
                        '/1/5/'
405
                    ),
406
                    'sortClauses' => [new SortClause\ContentId()],
407
                ],
408
                $fixtureDir . 'Subtree.php',
409
            ],
410
            31 => [
411
                [
412
                    'filter' => new Criterion\LocationId(
413
                        [1, 2, 5]
414
                    ),
415
                    'sortClauses' => [new SortClause\ContentId()],
416
                ],
417
                $fixtureDir . 'LocationId.php',
418
            ],
419
            32 => [
420
                [
421
                    'filter' => new Criterion\ParentLocationId(
422
                        [1]
423
                    ),
424
                    'sortClauses' => [new SortClause\ContentId()],
425
                ],
426
                $fixtureDir . 'ParentLocationId.php',
427
            ],
428
            33 => [
429
                [
430
                    'filter' => new Criterion\LocationRemoteId(
431
                        ['3f6d92f8044aed134f32153517850f5a', 'f3e90596361e31d496d4026eb624c983']
432
                    ),
433
                    'sortClauses' => [new SortClause\ContentId()],
434
                ],
435
                $fixtureDir . 'LocationRemoteId.php',
436
            ],
437
            34 => [
438
                [
439
                    // There is no Status Criterion anymore, this should match all published as well
440
                    'filter' => new Criterion\Subtree(
441
                        '/1/'
442
                    ),
443
                    'sortClauses' => [new SortClause\ContentId()],
444
                    'limit' => 50,
445
                ],
446
                $fixtureDir . 'Status.php',
447
                // Result having the same sort level should be sorted between them to be system independent
448
                function (&$data) {
449
                    usort(
450
                        $data->searchHits,
451
                        function ($a, $b) {
452
                            if ($a->score == $b->score) {
453
                                if ($a->valueObject['id'] == $b->valueObject['id']) {
454
                                    return 0;
455
                                }
456
457
                                // Order by ascending ID
458
                                return ($a->valueObject['id'] < $b->valueObject['id']) ? -1 : 1;
459
                            }
460
461
                            // Order by descending score
462
                            return ($a->score > $b->score) ? -1 : 1;
463
                        }
464
                    );
465
                },
466
            ],
467
            35 => [
468
                [
469
                    'filter' => new Criterion\UserMetadata(
470
                        Criterion\UserMetadata::MODIFIER,
471
                        Criterion\Operator::EQ,
472
                        14
473
                    ),
474
                    'sortClauses' => [
475
                        new SortClause\ContentId(),
476
                    ],
477
                    'limit' => 50,
478
                ],
479
                $fixtureDir . 'UserMetadata.php',
480
            ],
481
            36 => [
482
                [
483
                    'filter' => new Criterion\UserMetadata(
484
                        Criterion\UserMetadata::MODIFIER,
485
                        Criterion\Operator::IN,
486
                        [14]
487
                    ),
488
                    'sortClauses' => [
489
                        new SortClause\ContentId(),
490
                    ],
491
                    'limit' => 50,
492
                ],
493
                $fixtureDir . 'UserMetadata.php',
494
            ],
495
            37 => [
496
                [
497
                    'filter' => new Criterion\UserMetadata(
498
                        Criterion\UserMetadata::OWNER,
499
                        Criterion\Operator::EQ,
500
                        14
501
                    ),
502
                    'sortClauses' => [
503
                        new SortClause\ContentId(),
504
                    ],
505
                    'limit' => 50,
506
                ],
507
                $fixtureDir . 'UserMetadata.php',
508
            ],
509
            38 => [
510
                [
511
                    'filter' => new Criterion\UserMetadata(
512
                        Criterion\UserMetadata::OWNER,
513
                        Criterion\Operator::IN,
514
                        [14]
515
                    ),
516
                    'sortClauses' => [
517
                        new SortClause\ContentId(),
518
                    ],
519
                    'limit' => 50,
520
                ],
521
                $fixtureDir . 'UserMetadata.php',
522
            ],
523
            39 => [
524
                [
525
                    'filter' => new Criterion\UserMetadata(
526
                        Criterion\UserMetadata::GROUP,
527
                        Criterion\Operator::EQ,
528
                        12
529
                    ),
530
                    'sortClauses' => [
531
                        new SortClause\ContentId(),
532
                    ],
533
                    'limit' => 50,
534
                ],
535
                $fixtureDir . 'UserMetadata.php',
536
            ],
537
            40 => [
538
                [
539
                    'filter' => new Criterion\UserMetadata(
540
                        Criterion\UserMetadata::GROUP,
541
                        Criterion\Operator::IN,
542
                        [12]
543
                    ),
544
                    'sortClauses' => [
545
                        new SortClause\ContentId(),
546
                    ],
547
                    'limit' => 50,
548
                ],
549
                $fixtureDir . 'UserMetadata.php',
550
            ],
551
            41 => [
552
                [
553
                    'filter' => new Criterion\UserMetadata(
554
                        Criterion\UserMetadata::GROUP,
555
                        Criterion\Operator::EQ,
556
                        4
557
                    ),
558
                    'sortClauses' => [
559
                        new SortClause\ContentId(),
560
                    ],
561
                    'limit' => 50,
562
                ],
563
                $fixtureDir . 'UserMetadata.php',
564
            ],
565
            42 => [
566
                [
567
                    'filter' => new Criterion\UserMetadata(
568
                        Criterion\UserMetadata::GROUP,
569
                        Criterion\Operator::IN,
570
                        [4]
571
                    ),
572
                    'sortClauses' => [
573
                        new SortClause\ContentId(),
574
                    ],
575
                    'limit' => 50,
576
                ],
577
                $fixtureDir . 'UserMetadata.php',
578
            ],
579
            43 => [
580
                [
581
                    'filter' => new Criterion\Ancestor(
582
                        [
583
                            '/1/5/44/',
584
                            '/1/5/44/45/',
585
                        ]
586
                    ),
587
                    'sortClauses' => [
588
                        new SortClause\ContentId(),
589
                    ],
590
                    'limit' => 50,
591
                ],
592
                $fixtureDir . 'AncestorContent.php',
593
            ],
594
        ];
595
    }
596
597
    public function getContentQuerySearches()
598
    {
599
        $fixtureDir = $this->getFixtureDir();
600
601
        return [
602
            [
603
                [
604
                    'filter' => new Criterion\ContentId(
605
                        [58, 10]
606
                    ),
607
                    'query' => new Criterion\FullText('contact'),
608
                    'sortClauses' => [new SortClause\ContentId()],
609
                ],
610
                $fixtureDir . 'FullTextFiltered.php',
611
            ],
612
            [
613
                [
614
                    'query' => new Criterion\FullText(
615
                        'contact',
616
                        [
617
                            'boost' => [
618
                                'title' => 2,
619
                            ],
620
                            'fuzziness' => .5,
621
                        ]
622
                    ),
623
                    'sortClauses' => [new SortClause\ContentId()],
624
                ],
625
                $fixtureDir . 'FullText.php',
626
            ],
627
            [
628
                [
629
                    'query' => new Criterion\FullText(
630
                        'Contact*'
631
                    ),
632
                    'sortClauses' => [new SortClause\ContentId()],
633
                ],
634
                $fixtureDir . 'FullTextWildcard.php',
635
            ],
636
            [
637
                [
638
                    'query' => new Criterion\LanguageCode('eng-GB', false),
639
                    'sortClauses' => [new SortClause\ContentId()],
640
                ],
641
                $fixtureDir . 'LanguageCode.php',
642
            ],
643
            [
644
                [
645
                    'query' => new Criterion\LanguageCode(['eng-US', 'eng-GB']),
646
                    'offset' => 10,
647
                    'sortClauses' => [new SortClause\ContentId()],
648
                ],
649
                $fixtureDir . 'LanguageCodeIn.php',
650
            ],
651
            [
652
                [
653
                    'query' => new Criterion\LanguageCode('eng-GB'),
654
                    'offset' => 10,
655
                    'sortClauses' => [new SortClause\ContentId()],
656
                ],
657
                $fixtureDir . 'LanguageCodeAlwaysAvailable.php',
658
            ],
659
            [
660
                [
661
                    'query' => new Criterion\Visibility(
662
                        Criterion\Visibility::VISIBLE
663
                    ),
664
                    'sortClauses' => [new SortClause\ContentId()],
665
                    'limit' => 50,
666
                ],
667
                $fixtureDir . 'Visibility.php',
668
            ],
669
        ];
670
    }
671
672
    public function getLocationQuerySearches()
673
    {
674
        $fixtureDir = $this->getFixtureDir();
675
676
        return [
677
            [
678
                [
679
                    'query' => new Criterion\Location\Depth(Criterion\Operator::EQ, 1),
680
                    'sortClauses' => [new SortClause\ContentId()],
681
                ],
682
                $fixtureDir . 'Depth.php',
683
            ],
684
            [
685
                [
686
                    'query' => new Criterion\Location\Depth(Criterion\Operator::IN, [1, 3]),
687
                    'sortClauses' => [new SortClause\ContentId()],
688
                ],
689
                $fixtureDir . 'DepthIn.php',
690
            ],
691
            [
692
                [
693
                    'query' => new Criterion\Location\Depth(Criterion\Operator::GT, 2),
694
                    'sortClauses' => [new SortClause\ContentId()],
695
                ],
696
                $fixtureDir . 'DepthGt.php',
697
            ],
698
            [
699
                [
700
                    'query' => new Criterion\Location\Depth(Criterion\Operator::GTE, 2),
701
                    'sortClauses' => [new SortClause\ContentId()],
702
                    'limit' => 50,
703
                ],
704
                $fixtureDir . 'DepthGte.php',
705
            ],
706
            [
707
                [
708
                    'query' => new Criterion\Location\Depth(Criterion\Operator::LT, 2),
709
                    'sortClauses' => [new SortClause\ContentId()],
710
                ],
711
                $fixtureDir . 'Depth.php',
712
            ],
713
            [
714
                [
715
                    'query' => new Criterion\Location\Depth(Criterion\Operator::LTE, 2),
716
                    'sortClauses' => [new SortClause\ContentId()],
717
                    'limit' => 50,
718
                ],
719
                $fixtureDir . 'DepthLte.php',
720
            ],
721
            [
722
                [
723
                    'query' => new Criterion\Location\Depth(Criterion\Operator::BETWEEN, [1, 2]),
724
                    'sortClauses' => [new SortClause\ContentId()],
725
                    'limit' => 50,
726
                ],
727
                $fixtureDir . 'DepthLte.php',
728
            ],
729
            [
730
                [
731
                    'filter' => new Criterion\Ancestor('/1/5/44/45/'),
732
                    'sortClauses' => [
733
                        new SortClause\Location\Depth(),
734
                    ],
735
                    'limit' => 50,
736
                ],
737
                $fixtureDir . 'AncestorLocation.php',
738
            ],
739
        ];
740
    }
741
742
    /**
743
     * Test for the findContent() method.
744
     *
745
     * @dataProvider getFilterContentSearches
746
     *
747
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
748
     */
749
    public function testFindContentFiltered($queryData, $fixture, $closure = null)
750
    {
751
        $query = new Query($queryData);
752
        $this->assertQueryFixture($query, $fixture, $closure);
753
    }
754
755
    /**
756
     * Test for the findContentInfo() method.
757
     *
758
     * @dataProvider getFilterContentSearches
759
     *
760
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
761
     */
762
    public function testFindContentInfoFiltered($queryData, $fixture, $closure = null)
763
    {
764
        $query = new Query($queryData);
765
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure($closure), true);
766
    }
767
768
    /**
769
     * Test for the findLocations() method.
770
     *
771
     * @dataProvider getFilterContentSearches
772
     *
773
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
774
     */
775
    public function testFindLocationsContentFiltered($queryData, $fixture, $closure = null)
776
    {
777
        $query = new LocationQuery($queryData);
778
        $this->assertQueryFixture($query, $fixture, $closure);
779
    }
780
781
    /**
782
     * Test for deprecated $criterion property on query object.
783
     *
784
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
785
     * @deprecated
786
     */
787
    public function testDeprecatedCriteriaProperty()
788
    {
789
        $this->assertQueryFixture(
790
            new Query(
791
                [
792
                    'query' => new Criterion\ContentId(
793
                        [1, 4, 10]
794
                    ),
795
                    'sortClauses' => [new SortClause\ContentId()],
796
                ]
797
            ),
798
            $this->getFixtureDir() . 'DeprecatedContentIdQuery.php'
799
        );
800
    }
801
802
    /**
803
     * Test for the findContent() method.
804
     *
805
     * @dataProvider getContentQuerySearches
806
     *
807
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
808
     */
809
    public function testQueryContent($queryData, $fixture, $closure = null)
810
    {
811
        $query = new Query($queryData);
812
        $this->assertQueryFixture($query, $fixture, $closure);
813
    }
814
815
    /**
816
     * Test for the findContentInfo() method.
817
     *
818
     * @dataProvider getContentQuerySearches
819
     *
820
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
821
     */
822
    public function testQueryContentInfo($queryData, $fixture, $closure = null)
823
    {
824
        $query = new Query($queryData);
825
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure($closure), true);
826
    }
827
828
    /**
829
     * Test for the findLocations() method.
830
     *
831
     * @dataProvider getContentQuerySearches
832
     *
833
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
834
     */
835
    public function testQueryContentLocations($queryData, $fixture, $closure = null)
836
    {
837
        $query = new LocationQuery($queryData);
838
        $this->assertQueryFixture($query, $fixture, $closure);
839
    }
840
841
    /**
842
     * Test for the findLocations() method.
843
     *
844
     * @dataProvider getLocationQuerySearches
845
     *
846
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
847
     */
848
    public function testQueryLocations($queryData, $fixture, $closure = null)
849
    {
850
        $query = new LocationQuery($queryData);
851
        $this->assertQueryFixture($query, $fixture, $closure);
852
    }
853
854
    public function getCaseInsensitiveSearches()
855
    {
856
        return [
857
            [
858
                [
859
                    'filter' => new Criterion\Field(
860
                        'name',
861
                        Criterion\Operator::EQ,
862
                        'Members'
863
                    ),
864
                    'sortClauses' => [new SortClause\ContentId()],
865
                ],
866
            ],
867
            [
868
                [
869
                    'filter' => new Criterion\Field(
870
                        'name',
871
                        Criterion\Operator::EQ,
872
                        'members'
873
                    ),
874
                    'sortClauses' => [new SortClause\ContentId()],
875
                ],
876
            ],
877
            [
878
                [
879
                    'filter' => new Criterion\Field(
880
                        'name',
881
                        Criterion\Operator::EQ,
882
                        'MEMBERS'
883
                    ),
884
                    'sortClauses' => [new SortClause\ContentId()],
885
                ],
886
            ],
887
        ];
888
    }
889
890
    /**
891
     * Test for the findContent() method.
892
     *
893
     * @dataProvider getCaseInsensitiveSearches
894
     *
895
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
896
     */
897
    public function testFindContentFieldFiltersCaseSensitivity($queryData)
898
    {
899
        $query = new Query($queryData);
900
        $this->assertQueryFixture(
901
            $query,
902
            $this->getFixtureDir() . 'Field.php'
903
        );
904
    }
905
906
    /**
907
     * Test for the findLocations() method.
908
     *
909
     * @dataProvider getCaseInsensitiveSearches
910
     *
911
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
912
     */
913
    public function testFindLocationsFieldFiltersCaseSensitivity($queryData)
914
    {
915
        $query = new LocationQuery($queryData);
916
        $this->assertQueryFixture(
917
            $query,
918
            $this->getFixtureDir() . 'Field.php'
919
        );
920
    }
921
922
    public function getRelationFieldFilterSearches()
923
    {
924
        $fixtureDir = $this->getFixtureDir();
925
926
        return [
927
            0 => [
928
                [
929
                    'filter' => new Criterion\FieldRelation(
930
                        'image',
931
                        Criterion\Operator::IN,
932
                        [1, 4, 10]
933
                    ),
934
                    'sortClauses' => [new SortClause\ContentId()],
935
                ],
936
                $fixtureDir . 'FieldRelation.php',
937
            ],
938
            1 => [
939
                [
940
                    'filter' => new Criterion\FieldRelation(
941
                        'image',
942
                        Criterion\Operator::IN,
943
                        [4, 49]
944
                    ),
945
                    'sortClauses' => [new SortClause\ContentId()],
946
                ],
947
                $fixtureDir . 'FieldRelationAll.php',
948
            ],
949
            2 => [
950
                [
951
                    'filter' => new Criterion\FieldRelation(
952
                        'image',
953
                        Criterion\Operator::IN,
954
                        [4]
955
                    ),
956
                    'sortClauses' => [new SortClause\ContentId()],
957
                ],
958
                $fixtureDir . 'FieldRelation.php',
959
            ],
960
            3 => [
961
                [
962
                    'filter' => new Criterion\FieldRelation(
963
                        'image',
964
                        Criterion\Operator::CONTAINS,
965
                        [1, 4, 10]
966
                    ),
967
                    'sortClauses' => [new SortClause\ContentId()],
968
                ],
969
                $fixtureDir . 'MatchNone.php',
970
            ],
971
            4 => [
972
                [
973
                    'filter' => new Criterion\FieldRelation(
974
                        'image',
975
                        Criterion\Operator::CONTAINS,
976
                        [4, 49]
977
                    ),
978
                    'sortClauses' => [new SortClause\ContentId()],
979
                ],
980
                $fixtureDir . 'MatchNone.php',
981
            ],
982
            5 => [
983
                [
984
                    'filter' => new Criterion\FieldRelation(
985
                        'image',
986
                        Criterion\Operator::CONTAINS,
987
                        [4]
988
                    ),
989
                    'sortClauses' => [new SortClause\ContentId()],
990
                ],
991
                $fixtureDir . 'FieldRelation.php',
992
            ],
993
        ];
994
    }
995
996
    /**
997
     * Purely for creating relation data needed for testFindRelationFieldContentInfoFiltered()
998
     * and testFindRelationFieldLocationsFiltered().
999
     */
1000
    public function testRelationContentCreation()
1001
    {
1002
        $repository = $this->getRepository();
1003
        $galleryType = $repository->getContentTypeService()->loadContentTypeByIdentifier('gallery');
1004
        $contentService = $repository->getContentService();
1005
        $locationService = $repository->getLocationService();
1006
1007
        $locationCreateStruct = $locationService->newLocationCreateStruct(2); // Home
1008
1009
        $createStruct = $contentService->newContentCreateStruct($galleryType, 'eng-GB');
1010
        $createStruct->setField('name', 'Image gallery');
1011
        $createStruct->setField('image', 49); // Images folder
1012
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
1013
        $contentService->publishVersion($draft->getVersionInfo());
1014
1015
        $createStruct = $contentService->newContentCreateStruct($galleryType, 'eng-GB');
1016
        $createStruct->setField('name', 'User gallery');
1017
        $createStruct->setField('image', 4); // User folder
1018
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
1019
        $contentService->publishVersion($draft->getVersionInfo());
1020
1021
        $this->refreshSearch($repository);
1022
    }
1023
1024
    /**
1025
     * Test for FieldRelation using findContentInfo() method.
1026
     *
1027
     * @dataProvider getRelationFieldFilterSearches
1028
     *
1029
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
1030
     * @depends eZ\Publish\API\Repository\Tests\SearchServiceTest::testRelationContentCreation
1031
     */
1032
    public function testFindRelationFieldContentInfoFiltered($queryData, $fixture)
1033
    {
1034
        $this->getRepository(false); // To make sure repo is setup w/o removing data from getRelationFieldFilterContentSearches
1035
        $query = new Query($queryData);
1036
        $this->assertQueryFixture($query, $fixture, null, true, true, false);
1037
    }
1038
1039
    /**
1040
     * Test for FieldRelation using findLocations() method.
1041
     *
1042
     * @dataProvider getRelationFieldFilterSearches
1043
     *
1044
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
1045
     * @depends eZ\Publish\API\Repository\Tests\SearchServiceTest::testRelationContentCreation
1046
     */
1047
    public function testFindRelationFieldLocationsFiltered($queryData, $fixture)
1048
    {
1049
        $this->getRepository(false); // To make sure repo is setup w/o removing data from getRelationFieldFilterContentSearches
1050
        $query = new LocationQuery($queryData);
1051
        $this->assertQueryFixture($query, $fixture, null, true, false, false);
1052
    }
1053
1054 View Code Duplication
    public function testFindSingle()
1055
    {
1056
        $repository = $this->getRepository();
1057
        $searchService = $repository->getSearchService();
1058
1059
        $content = $searchService->findSingle(
1060
            new Criterion\ContentId(
1061
                [4]
1062
            )
1063
        );
1064
1065
        $this->assertEquals(
1066
            4,
1067
            $content->id
1068
        );
1069
    }
1070
1071 View Code Duplication
    public function testFindNoPerformCount()
1072
    {
1073
        $repository = $this->getRepository();
1074
        $searchService = $repository->getSearchService();
1075
1076
        $query = new Query();
1077
        $query->performCount = false;
1078
        $query->query = new Criterion\ContentTypeId(
1079
            [4]
1080
        );
1081
1082
        $searchHit = $searchService->findContent($query);
1083
1084
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1085
            $this->assertNull(
1086
                $searchHit->totalCount
1087
            );
1088
        } else {
1089
            $this->assertEquals(
1090
                2,
1091
                $searchHit->totalCount
1092
            );
1093
        }
1094
    }
1095
1096
    /**
1097
     * @expectedException \RuntimeException
1098
     */
1099 View Code Duplication
    public function testFindNoPerformCountException()
1100
    {
1101
        if (ltrim(get_class($this->getSetupFactory()), '\\') !== 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1102
            $this->markTestSkipped('Only applicable to Legacy/DB based search');
1103
        }
1104
1105
        $repository = $this->getRepository();
1106
        $searchService = $repository->getSearchService();
1107
1108
        $query = new Query();
1109
        $query->performCount = false;
1110
        $query->limit = 0;
1111
        $query->query = new Criterion\ContentTypeId(
1112
            [4]
1113
        );
1114
1115
        $searchService->findContent($query);
1116
    }
1117
1118 View Code Duplication
    public function testFindLocationsNoPerformCount()
1119
    {
1120
        $repository = $this->getRepository();
1121
        $searchService = $repository->getSearchService();
1122
1123
        $query = new LocationQuery();
1124
        $query->performCount = false;
1125
        $query->query = new Criterion\ContentTypeId(
1126
            [4]
1127
        );
1128
1129
        $searchHit = $searchService->findLocations($query);
1130
1131
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1132
            $this->assertNull(
1133
                $searchHit->totalCount
1134
            );
1135
        } else {
1136
            $this->assertEquals(
1137
                2,
1138
                $searchHit->totalCount
1139
            );
1140
        }
1141
    }
1142
1143
    /**
1144
     * @expectedException \RuntimeException
1145
     */
1146 View Code Duplication
    public function testFindLocationsNoPerformCountException()
1147
    {
1148
        if (ltrim(get_class($this->getSetupFactory()), '\\') !== 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1149
            $this->markTestSkipped('Only applicable to Legacy/DB based search');
1150
        }
1151
1152
        $repository = $this->getRepository();
1153
        $searchService = $repository->getSearchService();
1154
1155
        $query = new LocationQuery();
1156
        $query->performCount = false;
1157
        $query->limit = 0;
1158
        $query->query = new Criterion\ContentTypeId(
1159
            [4]
1160
        );
1161
1162
        $searchService->findLocations($query);
1163
    }
1164
1165
    /**
1166
     * Create movie Content with subtitle field set to null.
1167
     *
1168
     * @return \eZ\Publish\API\Repository\Values\Content\Content[]
1169
     */
1170
    protected function createMovieContent()
1171
    {
1172
        $movies = [];
1173
1174
        $repository = $this->getRepository();
1175
        $contentTypeService = $repository->getContentTypeService();
1176
        $contentService = $repository->getContentService();
1177
1178
        $createStruct = $contentTypeService->newContentTypeCreateStruct('movie');
1179
        $createStruct->mainLanguageCode = 'eng-GB';
1180
        $createStruct->remoteId = 'movie-123';
1181
        $createStruct->names = ['eng-GB' => 'Movie'];
1182
        $createStruct->creatorId = 14;
1183
        $createStruct->creationDate = new \DateTime();
1184
1185
        $fieldTitle = $contentTypeService->newFieldDefinitionCreateStruct('title', 'ezstring');
1186
        $fieldTitle->names = ['eng-GB' => 'Title'];
1187
        $fieldTitle->fieldGroup = 'main';
1188
        $fieldTitle->position = 1;
1189
        $fieldTitle->isTranslatable = false;
1190
        $fieldTitle->isSearchable = true;
1191
        $fieldTitle->isRequired = true;
1192
        $createStruct->addFieldDefinition($fieldTitle);
1193
1194
        $fieldSubtitle = $contentTypeService->newFieldDefinitionCreateStruct('subtitle', 'ezstring');
1195
        $fieldSubtitle->names = ['eng-GB' => 'Subtitle'];
1196
        $fieldSubtitle->fieldGroup = 'main';
1197
        $fieldSubtitle->position = 2;
1198
        $fieldSubtitle->isTranslatable = false;
1199
        $fieldSubtitle->isSearchable = true;
1200
        $fieldSubtitle->isRequired = false;
1201
        $createStruct->addFieldDefinition($fieldSubtitle);
1202
1203
        $contentTypeGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
1204
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentTypeGroup]);
1205
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
1206
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
1207
1208
        $createStructRambo = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1209
        $createStructRambo->remoteId = 'movie-456';
1210
        $createStructRambo->alwaysAvailable = false;
1211
        $createStructRambo->setField('title', 'Rambo');
1212
1213
        $ramboDraft = $contentService->createContent($createStructRambo);
1214
        $movies[] = $contentService->publishVersion($ramboDraft->getVersionInfo());
1215
        $this->refreshSearch($repository);
1216
        $createStructRobocop = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1217
        $createStructRobocop->remoteId = 'movie-789';
1218
        $createStructRobocop->alwaysAvailable = false;
1219
        $createStructRobocop->setField('title', 'Robocop');
1220
        $createStructRobocop->setField('subtitle', '');
1221
1222
        $robocopDraft = $contentService->createContent($createStructRobocop);
1223
        $movies[] = $contentService->publishVersion($robocopDraft->getVersionInfo());
1224
        $this->refreshSearch($repository);
1225
        $createStructLastHope = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1226
        $createStructLastHope->remoteId = 'movie-101112';
1227
        $createStructLastHope->alwaysAvailable = false;
1228
        $createStructLastHope->setField('title', 'Star Wars');
1229
        $createStructLastHope->setField('subtitle', 'Last Hope');
1230
1231
        $lastHopeDraft = $contentService->createContent($createStructLastHope);
1232
        $movies[] = $contentService->publishVersion($lastHopeDraft->getVersionInfo());
1233
1234
        $this->refreshSearch($repository);
1235
1236
        return $movies;
1237
    }
1238
1239
    /**
1240
     * Create test Content with ezcountry field having multiple countries selected.
1241
     *
1242
     * @return \eZ\Publish\API\Repository\Values\Content\Content[]
1243
     */
1244
    protected function createMultipleCountriesContent()
1245
    {
1246
        $repository = $this->getRepository();
1247
        $contentTypeService = $repository->getContentTypeService();
1248
        $contentService = $repository->getContentService();
1249
1250
        $createStruct = $contentTypeService->newContentTypeCreateStruct('countries-multiple');
1251
        $createStruct->mainLanguageCode = 'eng-GB';
1252
        $createStruct->remoteId = 'countries-multiple-123';
1253
        $createStruct->names = ['eng-GB' => 'Multiple countries'];
1254
        $createStruct->creatorId = 14;
1255
        $createStruct->creationDate = new \DateTime();
1256
1257
        $fieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('countries', 'ezcountry');
1258
        $fieldCreate->names = ['eng-GB' => 'Countries'];
1259
        $fieldCreate->fieldGroup = 'main';
1260
        $fieldCreate->position = 1;
1261
        $fieldCreate->isTranslatable = false;
1262
        $fieldCreate->isSearchable = true;
1263
        $fieldCreate->fieldSettings = ['isMultiple' => true];
1264
1265
        $createStruct->addFieldDefinition($fieldCreate);
1266
1267
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
1268
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
1269
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
1270
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
1271
1272
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1273
        $createStruct->remoteId = 'countries-multiple-456';
1274
        $createStruct->alwaysAvailable = false;
1275
        $createStruct->setField(
1276
            'countries',
1277
            ['BE', 'DE', 'FR', 'HR', 'NO', 'PT', 'RU']
1278
        );
1279
1280
        $draft = $contentService->createContent($createStruct);
1281
        $content = $contentService->publishVersion($draft->getVersionInfo());
1282
1283
        $this->refreshSearch($repository);
1284
1285
        return $content;
1286
    }
1287
1288
    /**
1289
     * Test for the findContent() method.
1290
     *
1291
     * @return \eZ\Publish\API\Repository\Values\Content\Content[]
1292
     *
1293
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
1294
     */
1295 View Code Duplication
    public function testFieldIsEmpty()
1296
    {
1297
        $testContents = $this->createMovieContent();
1298
1299
        $query = new Query(
1300
            [
1301
                'query' => new Criterion\IsFieldEmpty('subtitle'),
1302
            ]
1303
        );
1304
1305
        $repository = $this->getRepository();
1306
        $searchService = $repository->getSearchService();
1307
        $result = $searchService->findContent($query, ['eng-GB']);
1308
1309
        $this->assertEquals(2, $result->totalCount);
1310
1311
        $this->assertEquals(
1312
            $testContents[0]->id,
1313
            $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...
1314
        );
1315
        $this->assertEquals(
1316
            $testContents[1]->id,
1317
            $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...
1318
        );
1319
1320
        return $testContents;
1321
    }
1322
1323
    /**
1324
     * Test for the findContent() method.
1325
     *
1326
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
1327
     */
1328 View Code Duplication
    public function testFieldIsNotEmpty()
1329
    {
1330
        $testContents = $this->createMovieContent();
1331
1332
        $query = new Query(
1333
            [
1334
                'query' => new Criterion\IsFieldEmpty(
1335
                    'subtitle',
1336
                    false
1337
                ),
1338
            ]
1339
        );
1340
1341
        $repository = $this->getRepository();
1342
        $searchService = $repository->getSearchService();
1343
        $result = $searchService->findContent($query, ['eng-GB']);
1344
1345
        $this->assertEquals(1, $result->totalCount);
1346
        $this->assertEquals(
1347
            $testContents[2]->id,
1348
            $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...
1349
        );
1350
    }
1351
1352
    /**
1353
     * Test for the findContent() method.
1354
     *
1355
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
1356
     */
1357 View Code Duplication
    public function testFieldCollectionContains()
1358
    {
1359
        $testContent = $this->createMultipleCountriesContent();
1360
1361
        $query = new Query(
1362
            [
1363
                'query' => new Criterion\Field(
1364
                    'countries',
1365
                    Criterion\Operator::CONTAINS,
1366
                    'Belgium'
1367
                ),
1368
            ]
1369
        );
1370
1371
        $repository = $this->getRepository();
1372
        $searchService = $repository->getSearchService();
1373
        $result = $searchService->findContent($query);
1374
1375
        $this->assertEquals(1, $result->totalCount);
1376
        $this->assertEquals(
1377
            $testContent->id,
1378
            $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...
1379
        );
1380
    }
1381
1382
    /**
1383
     * Test for the findContent() method.
1384
     *
1385
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
1386
     * @depends eZ\Publish\API\Repository\Tests\SearchServiceTest::testFieldCollectionContains
1387
     */
1388 View Code Duplication
    public function testFieldCollectionContainsNoMatch()
1389
    {
1390
        $this->createMultipleCountriesContent();
1391
        $query = new Query(
1392
            [
1393
                'query' => new Criterion\Field(
1394
                    'countries',
1395
                    Criterion\Operator::CONTAINS,
1396
                    'Netherlands Antilles'
1397
                ),
1398
            ]
1399
        );
1400
1401
        $repository = $this->getRepository();
1402
        $searchService = $repository->getSearchService();
1403
        $result = $searchService->findContent($query);
1404
1405
        $this->assertEquals(0, $result->totalCount);
1406
    }
1407
1408
    /**
1409
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1410
     * @expectedExceptionMessage Argument '$criterion->target' is invalid: No searchable fields found for the given criterion target 'some_hopefully_unknown_field'
1411
     */
1412 View Code Duplication
    public function testInvalidFieldIdentifierRange()
1413
    {
1414
        $repository = $this->getRepository();
1415
        $searchService = $repository->getSearchService();
1416
1417
        $searchService->findContent(
1418
            new Query(
1419
                [
1420
                    'filter' => new Criterion\Field(
1421
                        'some_hopefully_unknown_field',
1422
                        Criterion\Operator::BETWEEN,
1423
                        [10, 1000]
1424
                    ),
1425
                    'sortClauses' => [new SortClause\ContentId()],
1426
                ]
1427
            )
1428
        );
1429
    }
1430
1431
    /**
1432
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1433
     * @expectedExceptionMessage Argument '$criterion->target' is invalid: No searchable fields found for the given criterion target 'some_hopefully_unknown_field'
1434
     */
1435 View Code Duplication
    public function testInvalidFieldIdentifierIn()
1436
    {
1437
        $repository = $this->getRepository();
1438
        $searchService = $repository->getSearchService();
1439
1440
        $searchService->findContent(
1441
            new Query(
1442
                [
1443
                    'filter' => new Criterion\Field(
1444
                        'some_hopefully_unknown_field',
1445
                        Criterion\Operator::EQ,
1446
                        1000
1447
                    ),
1448
                    'sortClauses' => [new SortClause\ContentId()],
1449
                ]
1450
            )
1451
        );
1452
    }
1453
1454
    /**
1455
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1456
     * @expectedExceptionMessage Argument '$criterion->target' is invalid: No searchable fields found for the given criterion target 'tag_cloud_url'
1457
     */
1458 View Code Duplication
    public function testFindContentWithNonSearchableField()
1459
    {
1460
        $repository = $this->getRepository();
1461
        $searchService = $repository->getSearchService();
1462
1463
        $searchService->findContent(
1464
            new Query(
1465
                [
1466
                    'filter' => new Criterion\Field(
1467
                        'tag_cloud_url',
1468
                        Criterion\Operator::EQ,
1469
                        'http://nimbus.com'
1470
                    ),
1471
                    'sortClauses' => [new SortClause\ContentId()],
1472
                ]
1473
            )
1474
        );
1475
    }
1476
1477
    /**
1478
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1479
     * @expectedExceptionMessage Argument '$sortClause->targetData' is invalid: No searchable fields found for the given sort clause target 'title' on 'template_look'
1480
     */
1481 View Code Duplication
    public function testSortFieldWithNonSearchableField()
1482
    {
1483
        $repository = $this->getRepository();
1484
        $searchService = $repository->getSearchService();
1485
1486
        $searchService->findContent(
1487
            new Query(
1488
                [
1489
                    'sortClauses' => [new SortClause\Field('template_look', 'title')],
1490
                ]
1491
            )
1492
        );
1493
    }
1494
1495
    /**
1496
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1497
     * @expectedExceptionMessage Argument '$sortClause->targetData' is invalid: No searchable fields found for the given sort clause target 'title' on 'template_look'
1498
     */
1499 View Code Duplication
    public function testSortMapLocationDistanceWithNonSearchableField()
1500
    {
1501
        $repository = $this->getRepository();
1502
        $searchService = $repository->getSearchService();
1503
1504
        $searchService->findContent(
1505
            new Query(
1506
                [
1507
                    'sortClauses' => [
1508
                        new SortClause\MapLocationDistance(
1509
                            'template_look',
1510
                            'title',
1511
                            1,
1512
                            2
1513
                        ),
1514
                    ],
1515
                ]
1516
            )
1517
        );
1518
    }
1519
1520
    /**
1521
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1522
     */
1523 View Code Duplication
    public function testFindSingleFailMultiple()
1524
    {
1525
        $repository = $this->getRepository();
1526
        $searchService = $repository->getSearchService();
1527
1528
        $searchService->findSingle(
1529
            new Criterion\ContentId(
1530
                [4, 10]
1531
            )
1532
        );
1533
    }
1534
1535
    /**
1536
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1537
     */
1538
    public function testFindSingleWithNonSearchableField()
1539
    {
1540
        $repository = $this->getRepository();
1541
        $searchService = $repository->getSearchService();
1542
1543
        $searchService->findSingle(
1544
            new Criterion\Field(
1545
                'tag_cloud_url',
1546
                Criterion\Operator::EQ,
1547
                'http://nimbus.com'
1548
            )
1549
        );
1550
    }
1551
1552
    public function getSortedContentSearches()
1553
    {
1554
        $fixtureDir = $this->getFixtureDir();
1555
1556
        return [
1557
            0 => [
1558
                [
1559
                    'filter' => new Criterion\SectionId([2]),
1560
                    'offset' => 0,
1561
                    'limit' => 10,
1562
                    'sortClauses' => [],
1563
                ],
1564
                $fixtureDir . 'SortNone.php',
1565
                // Result having the same sort level should be sorted between them to be system independent
1566
                function (&$data) {
1567
                    usort(
1568
                        $data->searchHits,
1569
                        function ($a, $b) {
1570
                            return ($a->valueObject['id'] < $b->valueObject['id']) ? -1 : 1;
1571
                        }
1572
                    );
1573
                },
1574
            ],
1575
            1 => [
1576
                [
1577
                    'filter' => new Criterion\SectionId([2]),
1578
                    'offset' => 0,
1579
                    'limit' => 10,
1580
                    'sortClauses' => [
1581
                        new SortClause\DatePublished(),
1582
                        new SortClause\ContentId(),
1583
                    ],
1584
                ],
1585
                $fixtureDir . 'SortDatePublished.php',
1586
            ],
1587
            2 => [
1588
                [
1589
                    'filter' => new Criterion\SectionId([2]),
1590
                    'offset' => 0,
1591
                    'limit' => 50,
1592
                    'sortClauses' => [
1593
                        new SortClause\DateModified(),
1594
                        new SortClause\ContentId(),
1595
                    ],
1596
                ],
1597
                $fixtureDir . 'SortDateModified.php',
1598
            ],
1599
            3 => [
1600
                [
1601
                    'filter' => new Criterion\SectionId([4, 2, 6, 3]),
1602
                    'offset' => 0,
1603
                    'limit' => 50,
1604
                    'sortClauses' => [
1605
                        new SortClause\SectionIdentifier(),
1606
                        new SortClause\ContentId(),
1607
                    ],
1608
                ],
1609
                $fixtureDir . 'SortSectionIdentifier.php',
1610
            ],
1611
            4 => [
1612
                [
1613
                    'filter' => new Criterion\SectionId([4, 2, 6, 3]),
1614
                    'offset' => 0,
1615
                    'limit' => 50,
1616
                    'sortClauses' => [
1617
                        new SortClause\SectionName(),
1618
                        new SortClause\ContentId(),
1619
                    ],
1620
                ],
1621
                $fixtureDir . 'SortSectionName.php',
1622
            ],
1623
            5 => [
1624
                [
1625
                    'filter' => new Criterion\SectionId([2, 3]),
1626
                    'offset' => 0,
1627
                    'limit' => 50,
1628
                    'sortClauses' => [
1629
                        new SortClause\ContentName(),
1630
                        new SortClause\ContentId(),
1631
                    ],
1632
                ],
1633
                $fixtureDir . 'SortContentName.php',
1634
            ],
1635
            6 => [
1636
                [
1637
                    'filter' => new Criterion\ContentTypeId(1),
1638
                    'offset' => 0,
1639
                    'limit' => 50,
1640
                    'sortClauses' => [
1641
                        new SortClause\Field('folder', 'name', Query::SORT_ASC),
1642
                        new SortClause\ContentId(),
1643
                    ],
1644
                ],
1645
                $fixtureDir . 'SortFolderName.php',
1646
            ],
1647
            7 => [
1648
                [
1649
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1650
                    'offset' => 0,
1651
                    'limit' => 50,
1652
                    'sortClauses' => [
1653
                        new SortClause\Field('folder', 'name', Query::SORT_ASC),
1654
                        new SortClause\ContentId(),
1655
                    ],
1656
                ],
1657
                $fixtureDir . 'SortFieldMultipleTypes.php',
1658
            ],
1659
            8 => [
1660
                [
1661
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1662
                    'offset' => 0,
1663
                    'limit' => 50,
1664
                    'sortClauses' => [
1665
                        new SortClause\Field('folder', 'name', Query::SORT_DESC),
1666
                        new SortClause\ContentId(),
1667
                    ],
1668
                ],
1669
                $fixtureDir . 'SortFieldMultipleTypesReverse.php',
1670
            ],
1671
            9 => [
1672
                [
1673
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1674
                    'offset' => 3,
1675
                    'limit' => 5,
1676
                    'sortClauses' => [
1677
                        new SortClause\Field('folder', 'name', Query::SORT_ASC),
1678
                        new SortClause\Field('user', 'first_name', Query::SORT_ASC),
1679
                        new SortClause\ContentId(),
1680
                    ],
1681
                ],
1682
                $fixtureDir . 'SortFieldMultipleTypesSlice.php',
1683
            ],
1684
            10 => [
1685
                [
1686
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1687
                    'offset' => 3,
1688
                    'limit' => 5,
1689
                    'sortClauses' => [
1690
                        new SortClause\Field('folder', 'name', Query::SORT_DESC),
1691
                        new SortClause\Field('user', 'first_name', Query::SORT_ASC),
1692
                        new SortClause\ContentId(),
1693
                    ],
1694
                ],
1695
                $fixtureDir . 'SortFieldMultipleTypesSliceReverse.php',
1696
            ],
1697
        ];
1698
    }
1699
1700
    public function getSortedLocationSearches()
1701
    {
1702
        $fixtureDir = $this->getFixtureDir();
1703
1704
        return [
1705
            [
1706
                [
1707
                    'filter' => new Criterion\SectionId([2]),
1708
                    'offset' => 0,
1709
                    'limit' => 10,
1710
                    'sortClauses' => [new SortClause\Location\Path(Query::SORT_DESC)],
1711
                ],
1712
                $fixtureDir . 'SortPathString.php',
1713
            ],
1714
            [
1715
                [
1716
                    'filter' => new Criterion\SectionId([2]),
1717
                    'offset' => 0,
1718
                    'limit' => 10,
1719
                    'sortClauses' => [new SortClause\Location\Depth(Query::SORT_ASC)],
1720
                ],
1721
                $fixtureDir . 'SortLocationDepth.php',
1722
                // Result having the same sort level should be sorted between them to be system independent
1723
                function (&$data) {
1724
                    // Result with ids:
1725
                    //     4 has depth = 1
1726
                    //     11, 12, 13, 42, 59 have depth = 2
1727
                    //     10, 14 have depth = 3
1728
                    $map = [
1729
                        4 => 0,
1730
                        11 => 1,
1731
                        12 => 2,
1732
                        13 => 3,
1733
                        42 => 4,
1734
                        59 => 5,
1735
                        10 => 6,
1736
                        14 => 7,
1737
                    ];
1738
                    usort(
1739
                        $data->searchHits,
1740
                        function ($a, $b) use ($map) {
1741
                            return ($map[$a->valueObject['id']] < $map[$b->valueObject['id']]) ? -1 : 1;
1742
                        }
1743
                    );
1744
                },
1745
            ],
1746
            [
1747
                [
1748
                    'filter' => new Criterion\SectionId([3]),
1749
                    'offset' => 0,
1750
                    'limit' => 10,
1751
                    'sortClauses' => [
1752
                        new SortClause\Location\Path(Query::SORT_DESC),
1753
                        new SortClause\ContentName(Query::SORT_ASC),
1754
                    ],
1755
                ],
1756
                $fixtureDir . 'SortMultiple.php',
1757
            ],
1758
            [
1759
                [
1760
                    'filter' => new Criterion\SectionId([2]),
1761
                    'offset' => 0,
1762
                    'limit' => 10,
1763
                    'sortClauses' => [
1764
                        new SortClause\Location\Priority(Query::SORT_DESC),
1765
                        new SortClause\ContentId(),
1766
                    ],
1767
                ],
1768
                $fixtureDir . 'SortDesc.php',
1769
            ],
1770
        ];
1771
    }
1772
1773
    /**
1774
     * @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
1775
     */
1776 View Code Duplication
    protected function createTestContentType()
1777
    {
1778
        $repository = $this->getRepository();
1779
        $contentTypeService = $repository->getContentTypeService();
1780
1781
        $createStruct = $contentTypeService->newContentTypeCreateStruct('test-type');
1782
        $createStruct->mainLanguageCode = 'eng-GB';
1783
        $createStruct->names = ['eng-GB' => 'Test type'];
1784
        $createStruct->creatorId = 14;
1785
        $createStruct->creationDate = new \DateTime();
1786
1787
        $translatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('integer', 'ezinteger');
1788
        $translatableFieldCreate->names = ['eng-GB' => 'Simple translatable integer field'];
1789
        $translatableFieldCreate->fieldGroup = 'main';
1790
        $translatableFieldCreate->position = 1;
1791
        $translatableFieldCreate->isTranslatable = true;
1792
        $translatableFieldCreate->isSearchable = true;
1793
1794
        $createStruct->addFieldDefinition($translatableFieldCreate);
1795
1796
        $nonTranslatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('integer2', 'ezinteger');
1797
        $nonTranslatableFieldCreate->names = ['eng-GB' => 'Simple non-translatable integer field'];
1798
        $nonTranslatableFieldCreate->fieldGroup = 'main';
1799
        $nonTranslatableFieldCreate->position = 2;
1800
        $nonTranslatableFieldCreate->isTranslatable = false;
1801
        $nonTranslatableFieldCreate->isSearchable = true;
1802
1803
        $createStruct->addFieldDefinition($nonTranslatableFieldCreate);
1804
1805
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
1806
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
1807
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
1808
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
1809
1810
        return $contentType;
1811
    }
1812
1813
    /**
1814
     * @param \eZ\Publish\API\Repository\Values\ContentType\ContentType $contentType
1815
     * @param int $fieldValue11 Value for translatable field in first language
1816
     * @param int $fieldValue12 Value for translatable field in second language
1817
     * @param int $fieldValue2 Value for non translatable field
1818
     * @param string $mainLanguageCode
1819
     * @param bool $alwaysAvailable
1820
     *
1821
     * @return Content
1822
     */
1823
    protected function createMultilingualContent(
1824
        $contentType,
1825
        $fieldValue11 = null,
1826
        $fieldValue12 = null,
1827
        $fieldValue2 = null,
1828
        $mainLanguageCode = 'eng-GB',
1829
        $alwaysAvailable = false
1830
    ) {
1831
        $repository = $this->getRepository();
1832
        $contentService = $repository->getContentService();
1833
1834
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1835
        $createStruct->alwaysAvailable = $alwaysAvailable;
1836
        $createStruct->mainLanguageCode = $mainLanguageCode;
1837
        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...
1838
            $createStruct->setField('integer', $fieldValue11, 'eng-GB');
1839
        }
1840
        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...
1841
            $createStruct->setField('integer', $fieldValue12, 'ger-DE');
1842
        }
1843
        $createStruct->setField('integer2', $fieldValue2, $mainLanguageCode);
1844
1845
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
1846
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
1847
        $content = $contentService->publishVersion($draft->getVersionInfo());
1848
1849
        $this->refreshSearch($repository);
1850
1851
        return $content;
1852
    }
1853
1854
    protected function checkPrioritizedLanguagesSupport()
1855
    {
1856
        $setupFactory = $this->getSetupFactory();
1857
        if ($setupFactory instanceof LegacyElasticsearch) {
1858
            $this->markTestIncomplete('Prioritized languages are not supported with Elasticsearch engine');
1859
        }
1860
    }
1861
1862
    public function providerForTestMultilingualFieldSort()
1863
    {
1864
        return [
1865
            0 => [
1866
                [
1867
                    1 => [1, 2, 1],
1868
                    2 => [2, 1, 2],
1869
                    3 => [2, 1, 3],
1870
                    4 => [1, 2, 4],
1871
                ],
1872
                [
1873
                    'languages' => [
1874
                        'eng-GB',
1875
                        'ger-DE',
1876
                    ],
1877
                ],
1878
                [
1879
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
1880
                    new SortClause\Field('test-type', 'integer2', Query::SORT_DESC),
1881
                ],
1882
                /**
1883
                 * Expected order, Value eng-GB, Value ger-DE.
1884
                 *
1885
                 * Content 4, 1, 2, 4
1886
                 * Content 1, 1, 2, 1
1887
                 * Content 3, 2, 1, 3
1888
                 * Content 2, 2, 1, 2
1889
                 */
1890
                [4, 1, 3, 2],
1891
            ],
1892
            1 => [
1893
                [
1894
                    1 => [1, 2, 1],
1895
                    2 => [2, 1, 2],
1896
                    3 => [2, 1, 3],
1897
                    4 => [1, 2, 4],
1898
                ],
1899
                [
1900
                    'languages' => [
1901
                        'ger-DE',
1902
                        'eng-GB',
1903
                    ],
1904
                ],
1905
                [
1906
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
1907
                    new SortClause\Field('test-type', 'integer2', Query::SORT_DESC),
1908
                ],
1909
                /**
1910
                 * Expected order, Value eng-GB, Value ger-DE.
1911
                 *
1912
                 * Content 3, 2, 1, 3
1913
                 * Content 2, 2, 1, 2
1914
                 * Content 4, 1, 2, 4
1915
                 * Content 1, 1, 2, 1
1916
                 */
1917
                [3, 2, 4, 1],
1918
            ],
1919
            2 => [
1920
                [
1921
                    1 => [null, 2, null, 'ger-DE'],
1922
                    2 => [3, null, null, 'eng-GB'],
1923
                    3 => [4, null, null, 'eng-GB'],
1924
                    4 => [null, 1, null, 'ger-DE'],
1925
                ],
1926
                [
1927
                    'languages' => [
1928
                        'eng-GB',
1929
                    ],
1930
                ],
1931
                [
1932
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1933
                ],
1934
                /**
1935
                 * Expected order, Value eng-GB, Value ger-DE.
1936
                 *
1937
                 * Content 3, 4, -
1938
                 * Content 2, 3, -
1939
                 */
1940
                [3, 2],
1941
            ],
1942
            3 => [
1943
                [
1944
                    1 => [null, 2, null, 'ger-DE'],
1945
                    2 => [3, null, null, 'eng-GB'],
1946
                    3 => [4, null, null, 'eng-GB'],
1947
                    4 => [null, 1, null, 'ger-DE'],
1948
                ],
1949
                [
1950
                    'languages' => [
1951
                        'ger-DE',
1952
                    ],
1953
                ],
1954
                [
1955
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1956
                ],
1957
                /**
1958
                 * Expected order, Value eng-GB, Value ger-DE.
1959
                 *
1960
                 * Content 1, -, 2
1961
                 * Content 4, -, 1
1962
                 */
1963
                [1, 4],
1964
            ],
1965
            4 => [
1966
                [
1967
                    1 => [null, 2, null, 'ger-DE'],
1968
                    2 => [3, null, null, 'eng-GB'],
1969
                    3 => [4, null, null, 'eng-GB'],
1970
                    4 => [null, 1, null, 'ger-DE'],
1971
                ],
1972
                [
1973
                    'languages' => [
1974
                        'eng-GB',
1975
                        'ger-DE',
1976
                    ],
1977
                ],
1978
                [
1979
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1980
                ],
1981
                /**
1982
                 * Expected order, Value eng-GB, Value ger-DE.
1983
                 *
1984
                 * Content 3, 4, -
1985
                 * Content 2, 3, -
1986
                 * Content 1, -, 2
1987
                 * Content 4, -, 1
1988
                 */
1989
                [3, 2, 1, 4],
1990
            ],
1991
            5 => [
1992
                [
1993
                    1 => [null, 2, null, 'ger-DE'],
1994
                    2 => [3, null, null, 'eng-GB'],
1995
                    3 => [4, null, null, 'eng-GB'],
1996
                    4 => [null, 1, null, 'ger-DE'],
1997
                ],
1998
                [
1999
                    'languages' => [
2000
                        'ger-DE',
2001
                        'eng-GB',
2002
                    ],
2003
                ],
2004
                [
2005
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
2006
                ],
2007
                /**
2008
                 * Expected order, Value eng-GB, Value ger-DE.
2009
                 *
2010
                 * Content 3, 4, -
2011
                 * Content 2, 3, -
2012
                 * Content 1, -, 2
2013
                 * Content 4, -, 1
2014
                 */
2015
                [3, 2, 1, 4],
2016
            ],
2017
            6 => [
2018
                [
2019
                    1 => [null, 2, null, 'ger-DE'],
2020
                    2 => [3, 4, null, 'eng-GB'],
2021
                    3 => [4, 3, null, 'eng-GB'],
2022
                    4 => [null, 1, null, 'ger-DE'],
2023
                ],
2024
                [
2025
                    'languages' => [
2026
                        'eng-GB',
2027
                        'ger-DE',
2028
                    ],
2029
                ],
2030
                [
2031
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
2032
                ],
2033
                /**
2034
                 * Expected order, Value eng-GB, Value ger-DE.
2035
                 *
2036
                 * Content 3, 4, 3
2037
                 * Content 2, 3, 4
2038
                 * Content 1, -, 2
2039
                 * Content 4, -, 1
2040
                 */
2041
                [3, 2, 1, 4],
2042
            ],
2043
            7 => [
2044
                [
2045
                    1 => [null, 2, null, 'ger-DE'],
2046
                    2 => [3, 4, null, 'eng-GB'],
2047
                    3 => [4, 3, null, 'eng-GB'],
2048
                    4 => [null, 1, null, 'ger-DE'],
2049
                ],
2050
                [
2051
                    'languages' => [
2052
                        'ger-DE',
2053
                        'eng-GB',
2054
                    ],
2055
                ],
2056
                [
2057
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
2058
                ],
2059
                /**
2060
                 * Expected order, Value eng-GB, Value ger-DE.
2061
                 *
2062
                 * Content 2, 3, 4
2063
                 * Content 3, 4, 3
2064
                 * Content 1, -, 2
2065
                 * Content 4, -, 1
2066
                 */
2067
                [2, 3, 1, 4],
2068
            ],
2069
            8 => [
2070
                [
2071
                    1 => [null, 1, null, 'ger-DE', true],
2072
                    2 => [4, null, null, 'eng-GB', true],
2073
                    3 => [3, null, null, 'eng-GB', false],
2074
                    4 => [null, 2, null, 'ger-DE', false],
2075
                ],
2076
                [
2077
                    'languages' => [
2078
                        'eng-GB',
2079
                    ],
2080
                ],
2081
                [
2082
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
2083
                ],
2084
                /**
2085
                 * Expected order, Value eng-GB, Value ger-DE.
2086
                 *
2087
                 * Content 1, -, 1
2088
                 * Content 3, 3, -
2089
                 * Content 2, 4, -
2090
                 */
2091
                [1, 3, 2],
2092
            ],
2093
            9 => [
2094
                [
2095
                    1 => [null, 1, null, 'ger-DE', true],
2096
                    2 => [4, null, null, 'eng-GB', true],
2097
                    3 => [3, null, null, 'eng-GB', false],
2098
                    4 => [null, 2, null, 'ger-DE', false],
2099
                ],
2100
                [
2101
                    'languages' => [
2102
                        'ger-DE',
2103
                    ],
2104
                ],
2105
                [
2106
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
2107
                ],
2108
                /**
2109
                 * Expected order, Value eng-GB, Value ger-DE.
2110
                 *
2111
                 * Content 2, 4, -
2112
                 * Content 4, -, 2
2113
                 * Content 1, -, 1
2114
                 */
2115
                [2, 4, 1],
2116
            ],
2117
            10 => [
2118
                [
2119
                    1 => [null, 1, null, 'ger-DE', true],
2120
                    2 => [4, null, null, 'eng-GB', true],
2121
                    3 => [3, null, null, 'eng-GB', false],
2122
                    4 => [null, 2, null, 'ger-DE', false],
2123
                ],
2124
                [
2125
                    'languages' => [
2126
                        'eng-GB',
2127
                    ],
2128
                    'useAlwaysAvailable' => false,
2129
                ],
2130
                [
2131
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
2132
                ],
2133
                /**
2134
                 * Expected order, Value eng-GB, Value ger-DE.
2135
                 *
2136
                 * Content 3, 3, -
2137
                 * Content 2, 4, -
2138
                 */
2139
                [3, 2],
2140
            ],
2141
            11 => [
2142
                [
2143
                    1 => [null, 1, null, 'ger-DE', true],
2144
                    2 => [4, null, null, 'eng-GB', true],
2145
                    3 => [3, null, null, 'eng-GB', false],
2146
                    4 => [null, 2, null, 'ger-DE', false],
2147
                ],
2148
                [
2149
                    'languages' => [
2150
                        'ger-DE',
2151
                    ],
2152
                    'useAlwaysAvailable' => false,
2153
                ],
2154
                [
2155
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
2156
                ],
2157
                /**
2158
                 * Expected order, Value eng-GB, Value ger-DE.
2159
                 *
2160
                 * Content 4, -, 2
2161
                 * Content 1, -, 1
2162
                 */
2163
                [4, 1],
2164
            ],
2165
        ];
2166
    }
2167
2168
    /**
2169
     * Test for the findContent() method.
2170
     *
2171
     * @group rrr
2172
     * @dataProvider providerForTestMultilingualFieldSort
2173
     *
2174
     * @param array $contentDataList
2175
     * @param array $languageSettings
2176
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] $sortClauses
2177
     * @param array $expected
2178
     */
2179
    public function testMultilingualFieldSortContent(
2180
        array $contentDataList,
2181
        $languageSettings,
2182
        array $sortClauses,
2183
        $expected
2184
    ) {
2185
        $this->assertMultilingualFieldSort(
2186
            $contentDataList,
2187
            $languageSettings,
2188
            $sortClauses,
2189
            $expected
2190
        );
2191
    }
2192
2193
    /**
2194
     * Test for the findLocations() method.
2195
     *
2196
     * @group rrr
2197
     * @dataProvider providerForTestMultilingualFieldSort
2198
     *
2199
     * @param array $contentDataList
2200
     * @param array $languageSettings
2201
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] $sortClauses
2202
     * @param array $expected
2203
     */
2204
    public function testMultilingualFieldSortLocation(
2205
        array $contentDataList,
2206
        $languageSettings,
2207
        array $sortClauses,
2208
        $expected
2209
    ) {
2210
        $this->assertMultilingualFieldSort(
2211
            $contentDataList,
2212
            $languageSettings,
2213
            $sortClauses,
2214
            $expected,
2215
            false
2216
        );
2217
    }
2218
2219
    /**
2220
     * @param array $contentDataList
2221
     * @param array $languageSettings
2222
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] $sortClauses
2223
     * @param array $expected
2224
     * @param bool $contentSearch
2225
     */
2226
    protected function assertMultilingualFieldSort(
2227
        array $contentDataList,
2228
        $languageSettings,
2229
        array $sortClauses,
2230
        $expected,
2231
        $contentSearch = true
2232
    ) {
2233
        $this->checkPrioritizedLanguagesSupport();
2234
        $contentType = $this->createTestContentType();
2235
2236
        // Create a draft to account for behaviour with ContentType in different states
2237
        $repository = $this->getRepository();
2238
        $contentTypeService = $repository->getContentTypeService();
2239
        $contentTypeService->createContentTypeDraft($contentType);
2240
2241
        $defaults = [null, null, null, 'eng-GB', false];
2242
        $contentIdList = [];
2243 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...
2244
            $contentData = $contentData + $defaults;
2245
            list(
2246
                $fieldValue11,
2247
                $fieldValue12,
2248
                $fieldValue2,
2249
                $mainLanguageCode,
2250
                $alwaysAvailable
2251
            ) = $contentData;
2252
2253
            $contentIdList[$key] = $this->createMultilingualContent(
2254
                $contentType,
2255
                $fieldValue11,
2256
                $fieldValue12,
2257
                $fieldValue2,
2258
                $mainLanguageCode,
2259
                $alwaysAvailable
2260
            )->id;
2261
        }
2262
2263
        // "article" type Content is not matched, this ensures that non-matched
2264
        // field does not affect sort
2265
        $dummySortClause = new SortClause\Field('article', 'title', Query::SORT_ASC);
2266
        array_unshift($sortClauses, $dummySortClause);
2267
        $sortClauses[] = $dummySortClause;
2268
2269
        $searchService = $repository->getSearchService();
2270
        if ($contentSearch) {
2271
            $query = new Query(
2272
                [
2273
                    'query' => new Criterion\ContentTypeId($contentType->id),
2274
                    'sortClauses' => $sortClauses,
2275
                ]
2276
            );
2277
            $result = $searchService->findContent($query, $languageSettings);
2278
        } else {
2279
            $query = new LocationQuery(
2280
                [
2281
                    'query' => new Criterion\ContentTypeId($contentType->id),
2282
                    'sortClauses' => $sortClauses,
2283
                ]
2284
            );
2285
            $result = $searchService->findLocations($query, $languageSettings);
2286
        }
2287
2288
        $this->assertEquals(count($expected), $result->totalCount);
2289
2290
        $expectedIdList = [];
2291
        foreach ($expected as $contentNumber) {
2292
            $expectedIdList[] = $contentIdList[$contentNumber];
2293
        }
2294
2295
        $this->assertEquals($expectedIdList, $this->mapResultContentIds($result));
2296
    }
2297
2298
    public function providerForTestMultilingualFieldFilter()
2299
    {
2300
        return [
2301
            0 => [
2302
                $fixture = [
2303
                    1 => [null, 1, null, 'ger-DE', true],
2304
                    2 => [4, null, null, 'eng-GB', true],
2305
                    3 => [3, null, null, 'eng-GB', false],
2306
                    4 => [null, 2, null, 'ger-DE', false],
2307
                    5 => [5, null, null, 'eng-GB', true],
2308
                ],
2309
                $languageSettings = [
2310
                    'languages' => [
2311
                        'ger-DE',
2312
                    ],
2313
                ],
2314
                new Criterion\Field('integer', Criterion\Operator::LT, 5),
2315
                /**
2316
                 * Expected order, Value eng-GB, Value ger-DE.
2317
                 *
2318
                 * Content 2, 4, -
2319
                 * Content 4, -, 2
2320
                 * Content 1, -, 1
2321
                 */
2322
                [2, 4, 1],
2323
            ],
2324
            1 => [
2325
                $fixture,
2326
                [
2327
                    'languages' => [
2328
                        'ger-DE',
2329
                    ],
2330
                    'useAlwaysAvailable' => false,
2331
                ],
2332
                new Criterion\Field('integer', Criterion\Operator::LT, 2),
2333
                /**
2334
                 * Expected order, Value eng-GB, Value ger-DE.
2335
                 *
2336
                 * Content 1, -, 1
2337
                 */
2338
                [1],
2339
            ],
2340
            2 => [
2341
                $fixture,
2342
                [
2343
                    'languages' => [
2344
                        'eng-GB',
2345
                    ],
2346
                ],
2347
                new Criterion\Field('integer', Criterion\Operator::LTE, 4),
2348
                /**
2349
                 * Expected order, Value eng-GB, Value ger-DE.
2350
                 *
2351
                 * Content 5, 5, -
2352
                 * Content 2, 4, -
2353
                 * Content 3, 3, -
2354
                 * Content 1, -, 1
2355
                 */
2356
                [2, 3, 1],
2357
            ],
2358
            3 => [
2359
                $fixture,
2360
                [
2361
                    'languages' => [
2362
                        'eng-GB',
2363
                    ],
2364
                    'useAlwaysAvailable' => false,
2365
                ],
2366
                new Criterion\Field('integer', Criterion\Operator::LTE, 4),
2367
                /**
2368
                 * Expected order, Value eng-GB, Value ger-DE.
2369
                 *
2370
                 * Content 2, 4, -
2371
                 * Content 3, 3, -
2372
                 */
2373
                [2, 3],
2374
            ],
2375
            4 => [
2376
                $fixture,
2377
                $languageSettings,
2378
                new Criterion\Field('integer', Criterion\Operator::LTE, 4),
2379
                /**
2380
                 * Expected order, Value eng-GB, Value ger-DE.
2381
                 *
2382
                 * Content 2, 4, -
2383
                 * Content 4, -, 2
2384
                 * Content 1, -, 1
2385
                 */
2386
                [2, 4, 1],
2387
            ],
2388
            5 => [
2389
                $fixture,
2390
                $languageSettings,
2391
                new Criterion\Field('integer', Criterion\Operator::GT, 1),
2392
                /**
2393
                 * Expected order, Value eng-GB, Value ger-DE.
2394
                 *
2395
                 * Content 5, 5, -
2396
                 * Content 2, 4, -
2397
                 * Content 4, -, 2
2398
                 */
2399
                [5, 2, 4],
2400
            ],
2401
            6 => [
2402
                $fixture,
2403
                $languageSettings,
2404
                new Criterion\Field('integer', Criterion\Operator::GTE, 2),
2405
                /**
2406
                 * Expected order, Value eng-GB, Value ger-DE.
2407
                 *
2408
                 * Content 5, 5, -
2409
                 * Content 2, 4, -
2410
                 * Content 4, -, 2
2411
                 */
2412
                [5, 2, 4],
2413
            ],
2414
            7 => [
2415
                $fixture,
2416
                $languageSettings,
2417
                new Criterion\Field('integer', Criterion\Operator::BETWEEN, [2, 4]),
2418
                /**
2419
                 * Expected order, Value eng-GB, Value ger-DE.
2420
                 *
2421
                 * Content 2, 4, -
2422
                 * Content 4, -, 2
2423
                 */
2424
                [2, 4],
2425
            ],
2426
            8 => [
2427
                $fixture,
2428
                $languageSettings,
2429
                new Criterion\Field('integer', Criterion\Operator::BETWEEN, [4, 2]),
2430
                [],
2431
            ],
2432
            9 => [
2433
                $fixture,
2434
                $languageSettings,
2435
                new Criterion\Field('integer', Criterion\Operator::EQ, 4),
2436
                /**
2437
                 * Expected order, Value eng-GB, Value ger-DE.
2438
                 *
2439
                 * Content 4, -, 2
2440
                 */
2441
                [2],
2442
            ],
2443
            10 => [
2444
                $fixture,
2445
                $languageSettings,
2446
                new Criterion\Field('integer', Criterion\Operator::EQ, 2),
2447
                /**
2448
                 * Expected order, Value eng-GB, Value ger-DE.
2449
                 *
2450
                 * Content 2, 4, -
2451
                 */
2452
                [4],
2453
            ],
2454
        ];
2455
    }
2456
2457
    /**
2458
     * Test for the findContent() method.
2459
     *
2460
     * @group ttt
2461
     * @dataProvider providerForTestMultilingualFieldFilter
2462
     *
2463
     * @param array $contentDataList
2464
     * @param array $languageSettings
2465
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
2466
     * @param array $expected
2467
     */
2468
    public function testMultilingualFieldFilterContent(
2469
        array $contentDataList,
2470
        $languageSettings,
2471
        Criterion $criterion,
2472
        $expected
2473
    ) {
2474
        $this->assertMultilingualFieldFilter(
2475
            $contentDataList,
2476
            $languageSettings,
2477
            $criterion,
2478
            $expected
2479
        );
2480
    }
2481
2482
    /**
2483
     * Test for the findLocations() method.
2484
     *
2485
     * @group ttt
2486
     * @dataProvider providerForTestMultilingualFieldFilter
2487
     *
2488
     * @param array $contentDataList
2489
     * @param array $languageSettings
2490
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
2491
     * @param array $expected
2492
     */
2493
    public function testMultilingualFieldFilterLocation(
2494
        array $contentDataList,
2495
        $languageSettings,
2496
        Criterion $criterion,
2497
        $expected
2498
    ) {
2499
        $this->assertMultilingualFieldFilter(
2500
            $contentDataList,
2501
            $languageSettings,
2502
            $criterion,
2503
            $expected,
2504
            false
2505
        );
2506
    }
2507
2508
    /**
2509
     * @param array $contentDataList
2510
     * @param array $languageSettings
2511
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
2512
     * @param array $expected
2513
     * @param bool $contentSearch
2514
     */
2515
    protected function assertMultilingualFieldFilter(
2516
        array $contentDataList,
2517
        $languageSettings,
2518
        Criterion $criterion,
2519
        $expected,
2520
        $contentSearch = true
2521
    ) {
2522
        $this->checkPrioritizedLanguagesSupport();
2523
        $contentType = $this->createTestContentType();
2524
2525
        // Create a draft to account for behaviour with ContentType in different states
2526
        $repository = $this->getRepository();
2527
        $contentTypeService = $repository->getContentTypeService();
2528
        $contentTypeService->createContentTypeDraft($contentType);
2529
2530
        $defaults = [null, null, null, 'eng-GB', false];
2531
        $contentIdList = [];
2532 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...
2533
            $contentData = $contentData + $defaults;
2534
            list(
2535
                $fieldValue11,
2536
                $fieldValue12,
2537
                $fieldValue2,
2538
                $mainLanguageCode,
2539
                $alwaysAvailable
2540
            ) = $contentData;
2541
2542
            $contentIdList[$key] = $this->createMultilingualContent(
2543
                $contentType,
2544
                $fieldValue11,
2545
                $fieldValue12,
2546
                $fieldValue2,
2547
                $mainLanguageCode,
2548
                $alwaysAvailable
2549
            )->id;
2550
        }
2551
2552
        $sortClause = new SortClause\Field('test-type', 'integer', Query::SORT_DESC);
2553
        $searchService = $repository->getSearchService();
2554
        if ($contentSearch) {
2555
            $query = new Query(
2556
                [
2557
                    'query' => new Criterion\LogicalAnd(
2558
                        [
2559
                            new Criterion\ContentTypeId($contentType->id),
2560
                            $criterion,
2561
                        ]
2562
                    ),
2563
                    'sortClauses' => [$sortClause],
2564
                ]
2565
            );
2566
            $result = $searchService->findContent($query, $languageSettings);
2567
        } else {
2568
            $query = new LocationQuery(
2569
                [
2570
                    'query' => new Criterion\LogicalAnd(
2571
                        [
2572
                            new Criterion\ContentTypeId($contentType->id),
2573
                            $criterion,
2574
                        ]
2575
                    ),
2576
                    'sortClauses' => [$sortClause],
2577
                ]
2578
            );
2579
            $result = $searchService->findLocations($query, $languageSettings);
2580
        }
2581
2582
        $this->assertEquals(count($expected), $result->totalCount);
2583
2584
        $expectedIdList = [];
2585
        foreach ($expected as $contentNumber) {
2586
            $expectedIdList[] = $contentIdList[$contentNumber];
2587
        }
2588
2589
        $this->assertEquals($expectedIdList, $this->mapResultContentIds($result));
2590
    }
2591
2592
    /**
2593
     * @param \eZ\Publish\API\Repository\Values\Content\Search\SearchResult $result
2594
     *
2595
     * @return array
2596
     */
2597
    protected function mapResultContentIds(SearchResult $result)
2598
    {
2599
        return array_map(
2600
            function (SearchHit $searchHit) {
2601
                if ($searchHit->valueObject instanceof Location) {
2602
                    return $searchHit->valueObject->contentInfo->id;
2603
                }
2604
2605
                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...
2606
            },
2607
            $result->searchHits
2608
        );
2609
    }
2610
2611
    /**
2612
     * Test for the findContent() method.
2613
     *
2614
     * @dataProvider getSortedContentSearches
2615
     *
2616
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2617
     */
2618
    public function testFindAndSortContent($queryData, $fixture, $closure = null)
2619
    {
2620
        $query = new Query($queryData);
2621
        $this->assertQueryFixture($query, $fixture, $closure);
2622
    }
2623
2624
    /**
2625
     * Test for the findContentInfo() method.
2626
     *
2627
     * @dataProvider getSortedContentSearches
2628
     *
2629
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
2630
     */
2631
    public function testFindAndSortContentInfo($queryData, $fixture, $closure = null)
2632
    {
2633
        $query = new Query($queryData);
2634
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure($closure), true);
2635
    }
2636
2637
    /**
2638
     * Test for the findLocations() method.
2639
     *
2640
     * @dataProvider getSortedContentSearches
2641
     *
2642
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
2643
     */
2644
    public function testFindAndSortContentLocations($queryData, $fixture, $closure = null)
2645
    {
2646
        $query = new LocationQuery($queryData);
2647
        $this->assertQueryFixture($query, $fixture, $closure);
2648
    }
2649
2650
    /**
2651
     * Test for the findLocations() method.
2652
     *
2653
     * @dataProvider getSortedLocationSearches
2654
     *
2655
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
2656
     */
2657
    public function testFindAndSortLocations($queryData, $fixture, $closure = null)
2658
    {
2659
        $query = new LocationQuery($queryData);
2660
        $this->assertQueryFixture($query, $fixture, $closure);
2661
    }
2662
2663
    /**
2664
     * Test for the findContent() method.
2665
     *
2666
     * @dataProvider getFacetedSearches
2667
     *
2668
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2669
     */
2670
    public function testFindFacetedContent(Query $query, $fixture)
2671
    {
2672
        $this->assertQueryFixture($query, $fixture);
2673
    }
2674
2675
    /**
2676
     * Test for the findContentInfo() method.
2677
     *
2678
     * @dataProvider getFacetedSearches
2679
     *
2680
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
2681
     */
2682
    public function testFindFacetedContentInfo(Query $query, $fixture)
2683
    {
2684
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure(), true);
2685
    }
2686
2687
    /**
2688
     * Test for the findContent() method.
2689
     *
2690
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2691
     */
2692 View Code Duplication
    public function testQueryCustomField()
2693
    {
2694
        $query = new Query(
2695
            [
2696
                'query' => new Criterion\CustomField(
2697
                    'custom_field',
2698
                    Criterion\Operator::EQ,
2699
                    'AdMiNiStRaToR'
2700
                ),
2701
                'offset' => 0,
2702
                'limit' => 10,
2703
                'sortClauses' => [new SortClause\ContentId()],
2704
            ]
2705
        );
2706
        $this->assertQueryFixture(
2707
            $query,
2708
            $this->getFixtureDir() . '/QueryCustomField.php'
2709
        );
2710
    }
2711
2712
    /**
2713
     * Test for the findContent() method.
2714
     *
2715
     * This tests explicitely queries the first_name while user is contained in
2716
     * the last_name of admin and anonymous. This is done to show the custom
2717
     * copy field working.
2718
     *
2719
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2720
     */
2721 View Code Duplication
    public function testQueryModifiedField()
2722
    {
2723
        // Check using get_class since the others extend SetupFactory\Legacy
2724
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
2725
            $this->markTestIncomplete(
2726
                'Custom fields not supported by LegacySE ' .
2727
                '(@todo: Legacy should fallback to just querying normal field so this should be tested here)'
2728
            );
2729
        }
2730
2731
        $query = new Query(
2732
            [
2733
                'query' => new Criterion\Field(
2734
                    'first_name',
2735
                    Criterion\Operator::EQ,
2736
                    'User'
2737
                ),
2738
                'offset' => 0,
2739
                'limit' => 10,
2740
                'sortClauses' => [new SortClause\ContentId()],
2741
            ]
2742
        );
2743
        $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...
2744
2745
        $this->assertQueryFixture(
2746
            $query,
2747
            $this->getFixtureDir() . '/QueryModifiedField.php'
2748
        );
2749
    }
2750
2751
    /**
2752
     * Test for the findContent() method.
2753
     *
2754
     * This tests first explicitly creates sort clause on the 'short_name' which is empty
2755
     * for all Content instances of 'folder' ContentType. Custom sort field is then set
2756
     * to the index storage name of folder's 'name' field, in order to show the custom
2757
     * sort field working.
2758
     *
2759
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2760
     */
2761
    public function testSortModifiedField()
2762
    {
2763
        // Check using get_class since the others extend SetupFactory\Legacy
2764
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
2765
            $this->markTestIncomplete(
2766
                'Custom field sort not supported by LegacySE ' .
2767
                '(@todo: Legacy should fallback to just querying normal field so this should be tested here)'
2768
            );
2769
        }
2770
2771
        $sortClause = new SortClause\Field('folder', 'short_name', Query::SORT_ASC);
2772
        $sortClause->setCustomField('folder', 'short_name', 'folder_name_value_s');
2773
2774
        $query = new Query(
2775
            [
2776
                'filter' => new Criterion\ContentTypeId(1),
2777
                'offset' => 0,
2778
                'limit' => 10,
2779
                'sortClauses' => [
2780
                    $sortClause,
2781
                    new SortClause\ContentId(),
2782
                ],
2783
            ]
2784
        );
2785
2786
        $this->assertQueryFixture(
2787
            $query,
2788
            $this->getFixtureDir() . '/SortFolderName.php'
2789
        );
2790
    }
2791
2792
    /**
2793
     * @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
2794
     */
2795 View Code Duplication
    protected function createTestPlaceContentType()
2796
    {
2797
        $repository = $this->getRepository();
2798
        $contentTypeService = $repository->getContentTypeService();
2799
2800
        $createStruct = $contentTypeService->newContentTypeCreateStruct('testtype');
2801
        $createStruct->mainLanguageCode = 'eng-GB';
2802
        $createStruct->names = ['eng-GB' => 'Test type'];
2803
        $createStruct->creatorId = 14;
2804
        $createStruct->creationDate = new \DateTime();
2805
2806
        $translatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('maplocation', 'ezgmaplocation');
2807
        $translatableFieldCreate->names = ['eng-GB' => 'Map location field'];
2808
        $translatableFieldCreate->fieldGroup = 'main';
2809
        $translatableFieldCreate->position = 1;
2810
        $translatableFieldCreate->isTranslatable = false;
2811
        $translatableFieldCreate->isSearchable = true;
2812
2813
        $createStruct->addFieldDefinition($translatableFieldCreate);
2814
2815
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
2816
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
2817
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
2818
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
2819
2820
        return $contentType;
2821
    }
2822
2823
    /**
2824
     * Test for the findContent() method.
2825
     *
2826
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2827
     * @group maplocation
2828
     */
2829 View Code Duplication
    public function testMapLocationDistanceLessThanOrEqual()
2830
    {
2831
        $contentType = $this->createTestPlaceContentType();
2832
2833
        // Create a draft to account for behaviour with ContentType in different states
2834
        $repository = $this->getRepository();
2835
        $contentTypeService = $repository->getContentTypeService();
2836
        $contentService = $repository->getContentService();
2837
        $contentTypeService->createContentTypeDraft($contentType);
2838
2839
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2840
        $createStruct->alwaysAvailable = false;
2841
        $createStruct->mainLanguageCode = 'eng-GB';
2842
        $createStruct->setField(
2843
            'maplocation',
2844
            [
2845
                'latitude' => 45.894877,
2846
                'longitude' => 15.972699,
2847
                'address' => 'Here be wild boars',
2848
            ],
2849
            'eng-GB'
2850
        );
2851
2852
        $draft = $contentService->createContent($createStruct);
2853
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
2854
2855
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2856
        $createStruct->alwaysAvailable = false;
2857
        $createStruct->mainLanguageCode = 'eng-GB';
2858
        $createStruct->setField(
2859
            'maplocation',
2860
            [
2861
                'latitude' => 45.927334,
2862
                'longitude' => 15.934847,
2863
                'address' => 'A lone tree',
2864
            ],
2865
            'eng-GB'
2866
        );
2867
2868
        $draft = $contentService->createContent($createStruct);
2869
        $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...
2870
2871
        $this->refreshSearch($repository);
2872
2873
        $query = new Query(
2874
            [
2875
                'filter' => new Criterion\LogicalAnd(
2876
                    [
2877
                        new Criterion\ContentTypeId($contentType->id),
2878
                        new Criterion\MapLocationDistance(
2879
                            'maplocation',
2880
                            Criterion\Operator::LTE,
2881
                            240,
2882
                            43.756825,
2883
                            15.775074
2884
                        ),
2885
                    ]
2886
                ),
2887
                'offset' => 0,
2888
                'limit' => 10,
2889
                'sortClauses' => [],
2890
            ]
2891
        );
2892
2893
        $searchService = $repository->getSearchService();
2894
        $result = $searchService->findContent($query);
2895
2896
        $this->assertEquals(1, $result->totalCount);
2897
        $this->assertEquals(
2898
            $wildBoars->id,
2899
            $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...
2900
        );
2901
    }
2902
2903
    /**
2904
     * Test for the findContent() method.
2905
     *
2906
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2907
     * @group maplocation
2908
     */
2909 View Code Duplication
    public function testMapLocationDistanceGreaterThanOrEqual()
2910
    {
2911
        $contentType = $this->createTestPlaceContentType();
2912
2913
        // Create a draft to account for behaviour with ContentType in different states
2914
        $repository = $this->getRepository();
2915
        $contentTypeService = $repository->getContentTypeService();
2916
        $contentService = $repository->getContentService();
2917
        $contentTypeService->createContentTypeDraft($contentType);
2918
2919
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2920
        $createStruct->alwaysAvailable = false;
2921
        $createStruct->mainLanguageCode = 'eng-GB';
2922
        $createStruct->setField(
2923
            'maplocation',
2924
            [
2925
                'latitude' => 45.894877,
2926
                'longitude' => 15.972699,
2927
                'address' => 'Here be wild boars',
2928
            ],
2929
            'eng-GB'
2930
        );
2931
2932
        $draft = $contentService->createContent($createStruct);
2933
        $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...
2934
2935
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2936
        $createStruct->alwaysAvailable = false;
2937
        $createStruct->mainLanguageCode = 'eng-GB';
2938
        $createStruct->setField(
2939
            'maplocation',
2940
            [
2941
                'latitude' => 45.927334,
2942
                'longitude' => 15.934847,
2943
                'address' => 'A lone tree',
2944
            ],
2945
            'eng-GB'
2946
        );
2947
2948
        $draft = $contentService->createContent($createStruct);
2949
        $tree = $contentService->publishVersion($draft->getVersionInfo());
2950
2951
        $this->refreshSearch($repository);
2952
2953
        $query = new Query(
2954
            [
2955
                'filter' => new Criterion\LogicalAnd(
2956
                    [
2957
                        new Criterion\ContentTypeId($contentType->id),
2958
                        new Criterion\MapLocationDistance(
2959
                            'maplocation',
2960
                            Criterion\Operator::GTE,
2961
                            240,
2962
                            43.756825,
2963
                            15.775074
2964
                        ),
2965
                    ]
2966
                ),
2967
                'offset' => 0,
2968
                'limit' => 10,
2969
                'sortClauses' => [],
2970
            ]
2971
        );
2972
2973
        $searchService = $repository->getSearchService();
2974
        $result = $searchService->findContent($query);
2975
2976
        $this->assertEquals(1, $result->totalCount);
2977
        $this->assertEquals(
2978
            $tree->id,
2979
            $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...
2980
        );
2981
    }
2982
2983
    /**
2984
     * Test for the findContent() method.
2985
     *
2986
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2987
     * @group maplocation
2988
     */
2989
    public function testMapLocationDistanceBetween()
2990
    {
2991
        $contentType = $this->createTestPlaceContentType();
2992
2993
        // Create a draft to account for behaviour with ContentType in different states
2994
        $repository = $this->getRepository();
2995
        $contentTypeService = $repository->getContentTypeService();
2996
        $contentService = $repository->getContentService();
2997
        $contentTypeService->createContentTypeDraft($contentType);
2998
2999
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3000
        $createStruct->alwaysAvailable = false;
3001
        $createStruct->mainLanguageCode = 'eng-GB';
3002
        $createStruct->setField(
3003
            'maplocation',
3004
            [
3005
                'latitude' => 45.894877,
3006
                'longitude' => 15.972699,
3007
                'address' => 'Here be wild boars',
3008
            ],
3009
            'eng-GB'
3010
        );
3011
3012
        $draft = $contentService->createContent($createStruct);
3013
        $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...
3014
3015
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3016
        $createStruct->alwaysAvailable = false;
3017
        $createStruct->mainLanguageCode = 'eng-GB';
3018
        $createStruct->setField(
3019
            'maplocation',
3020
            [
3021
                'latitude' => 45.927334,
3022
                'longitude' => 15.934847,
3023
                'address' => 'A lone tree',
3024
            ],
3025
            'eng-GB'
3026
        );
3027
3028
        $draft = $contentService->createContent($createStruct);
3029
        $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...
3030
3031
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3032
        $createStruct->alwaysAvailable = false;
3033
        $createStruct->mainLanguageCode = 'eng-GB';
3034
        $createStruct->setField(
3035
            'maplocation',
3036
            [
3037
                'latitude' => 45.903777,
3038
                'longitude' => 15.958788,
3039
                'address' => 'Meadow with mushrooms',
3040
            ],
3041
            'eng-GB'
3042
        );
3043
3044
        $draft = $contentService->createContent($createStruct);
3045
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
3046
3047
        $this->refreshSearch($repository);
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::BETWEEN,
3057
                            [239, 241],
3058
                            43.756825,
3059
                            15.775074
3060
                        ),
3061
                    ]
3062
                ),
3063
                'offset' => 0,
3064
                'limit' => 10,
3065
                'sortClauses' => [],
3066
            ]
3067
        );
3068
3069
        $searchService = $repository->getSearchService();
3070
        $result = $searchService->findContent($query);
3071
3072
        $this->assertEquals(1, $result->totalCount);
3073
        $this->assertEquals(
3074
            $mushrooms->id,
3075
            $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...
3076
        );
3077
    }
3078
3079
    /**
3080
     * Test for the findContent() method.
3081
     *
3082
     * This tests the distance over the pole. The tests intentionally uses large range,
3083
     * as the flat Earth model used in Legacy Storage Search is not precise for the use case.
3084
     * What is tested here is that outer bounding box is correctly calculated, so that
3085
     * location is not excluded.
3086
     *
3087
     * Range between 222km and 350km shows the magnitude of error between great-circle
3088
     * (always very precise) and flat Earth (very imprecise for this use case) models.
3089
     *
3090
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3091
     * @group maplocation
3092
     */
3093
    public function testMapLocationDistanceBetweenPolar()
3094
    {
3095
        $contentType = $this->createTestPlaceContentType();
3096
3097
        // Create a draft to account for behaviour with ContentType in different states
3098
        $repository = $this->getRepository();
3099
        $contentTypeService = $repository->getContentTypeService();
3100
        $contentService = $repository->getContentService();
3101
        $contentTypeService->createContentTypeDraft($contentType);
3102
3103
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3104
        $createStruct->alwaysAvailable = false;
3105
        $createStruct->mainLanguageCode = 'eng-GB';
3106
        $createStruct->setField(
3107
            'maplocation',
3108
            [
3109
                'latitude' => 89,
3110
                'longitude' => -164,
3111
                'address' => 'Polar bear media tower',
3112
            ],
3113
            'eng-GB'
3114
        );
3115
3116
        $draft = $contentService->createContent($createStruct);
3117
        $polarBear = $contentService->publishVersion($draft->getVersionInfo());
3118
3119
        $this->refreshSearch($repository);
3120
3121
        $query = new Query(
3122
            [
3123
                'filter' => new Criterion\LogicalAnd(
3124
                    [
3125
                        new Criterion\ContentTypeId($contentType->id),
3126
                        new Criterion\MapLocationDistance(
3127
                            'maplocation',
3128
                            Criterion\Operator::BETWEEN,
3129
                            [221, 350],
3130
                            89,
3131
                            16
3132
                        ),
3133
                    ]
3134
                ),
3135
                'offset' => 0,
3136
                'limit' => 10,
3137
                'sortClauses' => [],
3138
            ]
3139
        );
3140
3141
        $searchService = $repository->getSearchService();
3142
        $result = $searchService->findContent($query);
3143
3144
        $this->assertEquals(1, $result->totalCount);
3145
        $this->assertEquals(
3146
            $polarBear->id,
3147
            $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...
3148
        );
3149
    }
3150
3151
    /**
3152
     * Test for the findContent() method.
3153
     *
3154
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3155
     * @group maplocation
3156
     */
3157 View Code Duplication
    public function testMapLocationDistanceSortAscending()
3158
    {
3159
        $contentType = $this->createTestPlaceContentType();
3160
3161
        // Create a draft to account for behaviour with ContentType in different states
3162
        $repository = $this->getRepository();
3163
        $contentTypeService = $repository->getContentTypeService();
3164
        $contentService = $repository->getContentService();
3165
        $contentTypeService->createContentTypeDraft($contentType);
3166
3167
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3168
        $createStruct->alwaysAvailable = false;
3169
        $createStruct->mainLanguageCode = 'eng-GB';
3170
        $createStruct->setField(
3171
            'maplocation',
3172
            [
3173
                'latitude' => 45.894877,
3174
                'longitude' => 15.972699,
3175
                'address' => 'Here be wild boars',
3176
            ],
3177
            'eng-GB'
3178
        );
3179
3180
        $draft = $contentService->createContent($createStruct);
3181
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3182
3183
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3184
        $createStruct->alwaysAvailable = false;
3185
        $createStruct->mainLanguageCode = 'eng-GB';
3186
        $createStruct->setField(
3187
            'maplocation',
3188
            [
3189
                'latitude' => 45.927334,
3190
                'longitude' => 15.934847,
3191
                'address' => 'A lone tree',
3192
            ],
3193
            'eng-GB'
3194
        );
3195
3196
        $draft = $contentService->createContent($createStruct);
3197
        $tree = $contentService->publishVersion($draft->getVersionInfo());
3198
3199
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3200
        $createStruct->alwaysAvailable = false;
3201
        $createStruct->mainLanguageCode = 'eng-GB';
3202
        $createStruct->setField(
3203
            'maplocation',
3204
            [
3205
                'latitude' => 45.903777,
3206
                'longitude' => 15.958788,
3207
                'address' => 'Meadow with mushrooms',
3208
            ],
3209
            'eng-GB'
3210
        );
3211
3212
        $draft = $contentService->createContent($createStruct);
3213
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
3214
3215
        $this->refreshSearch($repository);
3216
3217
        $wellInVodice = [
3218
            'latitude' => 43.756825,
3219
            'longitude' => 15.775074,
3220
        ];
3221
3222
        $query = new Query(
3223
            [
3224
                'filter' => new Criterion\LogicalAnd(
3225
                    [
3226
                        new Criterion\ContentTypeId($contentType->id),
3227
                        new Criterion\MapLocationDistance(
3228
                            'maplocation',
3229
                            Criterion\Operator::GTE,
3230
                            235,
3231
                            $wellInVodice['latitude'],
3232
                            $wellInVodice['longitude']
3233
                        ),
3234
                    ]
3235
                ),
3236
                'offset' => 0,
3237
                'limit' => 10,
3238
                'sortClauses' => [
3239
                    new SortClause\MapLocationDistance(
3240
                        'testtype',
3241
                        'maplocation',
3242
                        $wellInVodice['latitude'],
3243
                        $wellInVodice['longitude'],
3244
                        Query::SORT_ASC
3245
                    ),
3246
                ],
3247
            ]
3248
        );
3249
3250
        $searchService = $repository->getSearchService();
3251
        $result = $searchService->findContent($query);
3252
3253
        $this->assertEquals(3, $result->totalCount);
3254
        $this->assertEquals(
3255
            $wildBoars->id,
3256
            $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...
3257
        );
3258
        $this->assertEquals(
3259
            $mushrooms->id,
3260
            $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...
3261
        );
3262
        $this->assertEquals(
3263
            $tree->id,
3264
            $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...
3265
        );
3266
    }
3267
3268
    /**
3269
     * Test for the findContent() method.
3270
     *
3271
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3272
     * @group maplocation
3273
     */
3274 View Code Duplication
    public function testMapLocationDistanceSortDescending()
3275
    {
3276
        $contentType = $this->createTestPlaceContentType();
3277
3278
        // Create a draft to account for behaviour with ContentType in different states
3279
        $repository = $this->getRepository();
3280
        $contentTypeService = $repository->getContentTypeService();
3281
        $contentService = $repository->getContentService();
3282
        $contentTypeService->createContentTypeDraft($contentType);
3283
3284
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3285
        $createStruct->alwaysAvailable = false;
3286
        $createStruct->mainLanguageCode = 'eng-GB';
3287
        $createStruct->setField(
3288
            'maplocation',
3289
            [
3290
                'latitude' => 45.894877,
3291
                'longitude' => 15.972699,
3292
                'address' => 'Here be wild boars',
3293
            ],
3294
            'eng-GB'
3295
        );
3296
3297
        $draft = $contentService->createContent($createStruct);
3298
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3299
3300
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3301
        $createStruct->alwaysAvailable = false;
3302
        $createStruct->mainLanguageCode = 'eng-GB';
3303
        $createStruct->setField(
3304
            'maplocation',
3305
            [
3306
                'latitude' => 45.927334,
3307
                'longitude' => 15.934847,
3308
                'address' => 'A lone tree',
3309
            ],
3310
            'eng-GB'
3311
        );
3312
3313
        $draft = $contentService->createContent($createStruct);
3314
        $tree = $contentService->publishVersion($draft->getVersionInfo());
3315
3316
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3317
        $createStruct->alwaysAvailable = false;
3318
        $createStruct->mainLanguageCode = 'eng-GB';
3319
        $createStruct->setField(
3320
            'maplocation',
3321
            [
3322
                'latitude' => 45.903777,
3323
                'longitude' => 15.958788,
3324
                'address' => 'Meadow with mushrooms',
3325
            ],
3326
            'eng-GB'
3327
        );
3328
3329
        $draft = $contentService->createContent($createStruct);
3330
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
3331
3332
        $this->refreshSearch($repository);
3333
3334
        $well = [
3335
            'latitude' => 43.756825,
3336
            'longitude' => 15.775074,
3337
        ];
3338
3339
        $query = new Query(
3340
            [
3341
                'filter' => new Criterion\LogicalAnd(
3342
                    [
3343
                        new Criterion\ContentTypeId($contentType->id),
3344
                        new Criterion\MapLocationDistance(
3345
                            'maplocation',
3346
                            Criterion\Operator::GTE,
3347
                            235,
3348
                            $well['latitude'],
3349
                            $well['longitude']
3350
                        ),
3351
                    ]
3352
                ),
3353
                'offset' => 0,
3354
                'limit' => 10,
3355
                'sortClauses' => [
3356
                    new SortClause\MapLocationDistance(
3357
                        'testtype',
3358
                        'maplocation',
3359
                        $well['latitude'],
3360
                        $well['longitude'],
3361
                        Query::SORT_DESC
3362
                    ),
3363
                ],
3364
            ]
3365
        );
3366
3367
        $searchService = $repository->getSearchService();
3368
        $result = $searchService->findContent($query);
3369
3370
        $this->assertEquals(3, $result->totalCount);
3371
        $this->assertEquals(
3372
            $wildBoars->id,
3373
            $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...
3374
        );
3375
        $this->assertEquals(
3376
            $mushrooms->id,
3377
            $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...
3378
        );
3379
        $this->assertEquals(
3380
            $tree->id,
3381
            $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...
3382
        );
3383
    }
3384
3385
    /**
3386
     * Test for the findContent() method.
3387
     *
3388
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3389
     * @group maplocation
3390
     */
3391
    public function testMapLocationDistanceWithCustomField()
3392
    {
3393
        $setupFactory = $this->getSetupFactory();
3394
        if ($setupFactory instanceof LegacyElasticsearch) {
3395
            $this->markTestIncomplete("TODO: Some issues with 'copy_to' and 'geo_point'");
3396
        }
3397
3398
        $contentType = $this->createTestPlaceContentType();
3399
3400
        // Create a draft to account for behaviour with ContentType in different states
3401
        $repository = $this->getRepository();
3402
        $contentTypeService = $repository->getContentTypeService();
3403
        $contentService = $repository->getContentService();
3404
        $contentTypeService->createContentTypeDraft($contentType);
3405
3406
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3407
        $createStruct->alwaysAvailable = false;
3408
        $createStruct->mainLanguageCode = 'eng-GB';
3409
        $createStruct->setField(
3410
            'maplocation',
3411
            [
3412
                'latitude' => 45.894877,
3413
                'longitude' => 15.972699,
3414
                'address' => 'Here be wild boars',
3415
            ],
3416
            'eng-GB'
3417
        );
3418
3419
        $draft = $contentService->createContent($createStruct);
3420
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3421
3422
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3423
        $createStruct->alwaysAvailable = false;
3424
        $createStruct->mainLanguageCode = 'eng-GB';
3425
        $createStruct->setField(
3426
            'maplocation',
3427
            [
3428
                'latitude' => 45.927334,
3429
                'longitude' => 15.934847,
3430
                'address' => 'A lone tree',
3431
            ],
3432
            'eng-GB'
3433
        );
3434
3435
        $draft = $contentService->createContent($createStruct);
3436
        $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...
3437
3438
        $this->refreshSearch($repository);
3439
3440
        $distanceCriterion = new Criterion\MapLocationDistance(
3441
            'maplocation',
3442
            Criterion\Operator::LTE,
3443
            240,
3444
            43.756825,
3445
            15.775074
3446
        );
3447
        $distanceCriterion->setCustomField('testtype', 'maplocation', 'custom_geolocation_field');
3448
3449
        $query = new Query(
3450
            [
3451
                'filter' => new Criterion\LogicalAnd(
3452
                    [
3453
                        new Criterion\ContentTypeId($contentType->id),
3454
                        $distanceCriterion,
3455
                    ]
3456
                ),
3457
                'offset' => 0,
3458
                'limit' => 10,
3459
                'sortClauses' => [],
3460
            ]
3461
        );
3462
3463
        $searchService = $repository->getSearchService();
3464
        $result = $searchService->findContent($query);
3465
3466
        $this->assertEquals(1, $result->totalCount);
3467
        $this->assertEquals(
3468
            $wildBoars->id,
3469
            $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...
3470
        );
3471
    }
3472
3473
    /**
3474
     * Test for the findContent() method.
3475
     *
3476
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3477
     * @group maplocation
3478
     */
3479
    public function testMapLocationDistanceWithCustomFieldSort()
3480
    {
3481
        $setupFactory = $this->getSetupFactory();
3482
        if ($setupFactory instanceof LegacyElasticsearch) {
3483
            $this->markTestIncomplete("TODO: Some issues with 'copy_to' and 'geo_point'");
3484
        }
3485
3486
        $contentType = $this->createTestPlaceContentType();
3487
3488
        // Create a draft to account for behaviour with ContentType in different states
3489
        $repository = $this->getRepository();
3490
        $contentTypeService = $repository->getContentTypeService();
3491
        $contentService = $repository->getContentService();
3492
        $contentTypeService->createContentTypeDraft($contentType);
3493
3494
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3495
        $createStruct->alwaysAvailable = false;
3496
        $createStruct->mainLanguageCode = 'eng-GB';
3497
        $createStruct->setField(
3498
            'maplocation',
3499
            [
3500
                'latitude' => 45.894877,
3501
                'longitude' => 15.972699,
3502
                'address' => 'Here be wild boars',
3503
            ],
3504
            'eng-GB'
3505
        );
3506
3507
        $draft = $contentService->createContent($createStruct);
3508
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3509
3510
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3511
        $createStruct->alwaysAvailable = false;
3512
        $createStruct->mainLanguageCode = 'eng-GB';
3513
        $createStruct->setField(
3514
            'maplocation',
3515
            [
3516
                'latitude' => 45.927334,
3517
                'longitude' => 15.934847,
3518
                'address' => 'A lone tree',
3519
            ],
3520
            'eng-GB'
3521
        );
3522
3523
        $draft = $contentService->createContent($createStruct);
3524
        $tree = $contentService->publishVersion($draft->getVersionInfo());
3525
3526
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3527
        $createStruct->alwaysAvailable = false;
3528
        $createStruct->mainLanguageCode = 'eng-GB';
3529
        $createStruct->setField(
3530
            'maplocation',
3531
            [
3532
                'latitude' => 45.903777,
3533
                'longitude' => 15.958788,
3534
                'address' => 'Meadow with mushrooms',
3535
            ],
3536
            'eng-GB'
3537
        );
3538
3539
        $draft = $contentService->createContent($createStruct);
3540
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
3541
3542
        $this->refreshSearch($repository);
3543
3544
        $well = [
3545
            'latitude' => 43.756825,
3546
            'longitude' => 15.775074,
3547
        ];
3548
3549
        $sortClause = new SortClause\MapLocationDistance(
3550
            'testtype',
3551
            'maplocation',
3552
            $well['latitude'],
3553
            $well['longitude'],
3554
            Query::SORT_DESC
3555
        );
3556
        $sortClause->setCustomField('testtype', 'maplocation', 'custom_geolocation_field');
3557
3558
        $query = new Query(
3559
            [
3560
                'filter' => new Criterion\LogicalAnd(
3561
                    [
3562
                        new Criterion\ContentTypeId($contentType->id),
3563
                        new Criterion\MapLocationDistance(
3564
                            'maplocation',
3565
                            Criterion\Operator::GTE,
3566
                            235,
3567
                            $well['latitude'],
3568
                            $well['longitude']
3569
                        ),
3570
                    ]
3571
                ),
3572
                'offset' => 0,
3573
                'limit' => 10,
3574
                'sortClauses' => [
3575
                    $sortClause,
3576
                ],
3577
            ]
3578
        );
3579
3580
        $searchService = $repository->getSearchService();
3581
        $result = $searchService->findContent($query);
3582
3583
        $this->assertEquals(3, $result->totalCount);
3584
        $this->assertEquals(
3585
            $wildBoars->id,
3586
            $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...
3587
        );
3588
        $this->assertEquals(
3589
            $mushrooms->id,
3590
            $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...
3591
        );
3592
        $this->assertEquals(
3593
            $tree->id,
3594
            $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...
3595
        );
3596
    }
3597
3598
    /**
3599
     * Test for the findLocations() method.
3600
     *
3601
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3602
     */
3603 View Code Duplication
    public function testFindMainLocation()
3604
    {
3605
        $plainSiteLocationId = 56;
3606
        $designLocationId = 58;
3607
        $partnersContentId = 59;
3608
        $repository = $this->getRepository();
3609
        $locationService = $repository->getLocationService();
3610
        $contentService = $repository->getContentService();
3611
3612
        // Add secondary Location for "Partners" user group, under "Design" page
3613
        $locationService->createLocation(
3614
            $contentService->loadContentInfo($partnersContentId),
3615
            $locationService->newLocationCreateStruct($designLocationId)
3616
        );
3617
3618
        $this->refreshSearch($repository);
3619
3620
        $query = new LocationQuery(
3621
            [
3622
                'filter' => new Criterion\LogicalAnd(
3623
                    [
3624
                        new Criterion\ParentLocationId($designLocationId),
3625
                        new Criterion\Location\IsMainLocation(
3626
                            Criterion\Location\IsMainLocation::MAIN
3627
                        ),
3628
                    ]
3629
                ),
3630
                'offset' => 0,
3631
                'limit' => 10,
3632
                'sortClauses' => [],
3633
            ]
3634
        );
3635
3636
        $searchService = $repository->getSearchService();
3637
        $result = $searchService->findLocations($query);
3638
3639
        $this->assertEquals(1, $result->totalCount);
3640
        $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...
3641
    }
3642
3643
    /**
3644
     * Test for the findLocations() method.
3645
     *
3646
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3647
     */
3648 View Code Duplication
    public function testFindNonMainLocation()
3649
    {
3650
        $designLocationId = 58;
3651
        $partnersContentId = 59;
3652
        $repository = $this->getRepository();
3653
        $locationService = $repository->getLocationService();
3654
        $contentService = $repository->getContentService();
3655
3656
        // Add secondary Location for "Partners" user group, under "Design" page
3657
        $newLocation = $locationService->createLocation(
3658
            $contentService->loadContentInfo($partnersContentId),
3659
            $locationService->newLocationCreateStruct($designLocationId)
3660
        );
3661
3662
        $this->refreshSearch($repository);
3663
3664
        $query = new LocationQuery(
3665
            [
3666
                'filter' => new Criterion\LogicalAnd(
3667
                    [
3668
                        new Criterion\ParentLocationId($designLocationId),
3669
                        new Criterion\Location\IsMainLocation(
3670
                            Criterion\Location\IsMainLocation::NOT_MAIN
3671
                        ),
3672
                    ]
3673
                ),
3674
                'offset' => 0,
3675
                'limit' => 10,
3676
                'sortClauses' => [],
3677
            ]
3678
        );
3679
3680
        $searchService = $repository->getSearchService();
3681
        $result = $searchService->findLocations($query);
3682
3683
        $this->assertEquals(1, $result->totalCount);
3684
        $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...
3685
    }
3686
3687
    /**
3688
     * Test for the findLocations() method.
3689
     *
3690
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3691
     */
3692 View Code Duplication
    public function testSortMainLocationAscending()
3693
    {
3694
        $plainSiteLocationId = 56;
3695
        $designLocationId = 58;
3696
        $partnersContentId = 59;
3697
        $repository = $this->getRepository();
3698
        $locationService = $repository->getLocationService();
3699
        $contentService = $repository->getContentService();
3700
3701
        // Add secondary Location for "Partners" user group, under "Design" page
3702
        $newLocation = $locationService->createLocation(
3703
            $contentService->loadContentInfo($partnersContentId),
3704
            $locationService->newLocationCreateStruct($designLocationId)
3705
        );
3706
3707
        $this->refreshSearch($repository);
3708
3709
        $query = new LocationQuery(
3710
            [
3711
                'filter' => new Criterion\ParentLocationId($designLocationId),
3712
                'offset' => 0,
3713
                'limit' => 10,
3714
                'sortClauses' => [
3715
                    new SortClause\Location\IsMainLocation(
3716
                        LocationQuery::SORT_ASC
3717
                    ),
3718
                ],
3719
            ]
3720
        );
3721
3722
        $searchService = $repository->getSearchService();
3723
        $result = $searchService->findLocations($query);
3724
3725
        $this->assertEquals(2, $result->totalCount);
3726
        $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...
3727
        $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...
3728
    }
3729
3730
    /**
3731
     * Test for the findLocations() method.
3732
     *
3733
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3734
     */
3735 View Code Duplication
    public function testSortMainLocationDescending()
3736
    {
3737
        $plainSiteLocationId = 56;
3738
        $designLocationId = 58;
3739
        $partnersContentId = 59;
3740
        $repository = $this->getRepository();
3741
        $locationService = $repository->getLocationService();
3742
        $contentService = $repository->getContentService();
3743
3744
        // Add secondary Location for "Partners" user group, under "Design" page
3745
        $newLocation = $locationService->createLocation(
3746
            $contentService->loadContentInfo($partnersContentId),
3747
            $locationService->newLocationCreateStruct($designLocationId)
3748
        );
3749
3750
        $this->refreshSearch($repository);
3751
3752
        $query = new LocationQuery(
3753
            [
3754
                'filter' => new Criterion\ParentLocationId($designLocationId),
3755
                'offset' => 0,
3756
                'limit' => 10,
3757
                'sortClauses' => [
3758
                    new SortClause\Location\IsMainLocation(
3759
                        LocationQuery::SORT_DESC
3760
                    ),
3761
                ],
3762
            ]
3763
        );
3764
3765
        $searchService = $repository->getSearchService();
3766
        $result = $searchService->findLocations($query);
3767
3768
        $this->assertEquals(2, $result->totalCount);
3769
        $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...
3770
        $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...
3771
    }
3772
3773
    /**
3774
     * Test for the findLocations() method.
3775
     *
3776
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3777
     */
3778
    public function testContentWithMultipleLocations()
3779
    {
3780
        $repository = $this->getRepository();
3781
        $contentService = $repository->getContentService();
3782
        $contentTypeService = $repository->getContentTypeService();
3783
        $locationService = $repository->getLocationService();
3784
3785
        $forumType = $contentTypeService->loadContentTypeByIdentifier('forum');
3786
3787
        $createStruct = $contentService->newContentCreateStruct($forumType, 'eng-GB');
3788
        $createStruct->alwaysAvailable = false;
3789
        $createStruct->setField('name', 'An awesome duplicate forum');
3790
3791
        $draft = $contentService->createContent($createStruct);
3792
        $content = $contentService->publishVersion($draft->getVersionInfo());
3793
3794
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
3795
        $location1 = $locationService->createLocation($content->contentInfo, $locationCreateStruct);
3796
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(5);
3797
        $location2 = $locationService->createLocation($content->contentInfo, $locationCreateStruct);
3798
3799
        $this->refreshSearch($repository);
3800
3801
        $query = new LocationQuery(
3802
            [
3803
                'filter' => new Criterion\ContentId($content->id),
3804
                'sortClauses' => [
3805
                    new SortClause\Location\Id(LocationQuery::SORT_ASC),
3806
                ],
3807
            ]
3808
        );
3809
3810
        $searchService = $repository->getSearchService();
3811
        $result = $searchService->findLocations($query);
3812
3813
        $this->assertEquals(2, $result->totalCount);
3814
        $this->assertEquals(
3815
            $location1->id,
3816
            $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...
3817
        );
3818
        $this->assertEquals(
3819
            $location2->id,
3820
            $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...
3821
        );
3822
    }
3823
3824
    protected function createContentForTestUserMetadataGroupHorizontal()
3825
    {
3826
        $repository = $this->getRepository();
3827
        $contentService = $repository->getContentService();
3828
        $contentTypeService = $repository->getContentTypeService();
3829
        $locationService = $repository->getLocationService();
3830
        $userService = $repository->getUserService();
3831
        $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...
3832
        // ID of the "Administrators" user group in an eZ Publish demo installation
3833
        $administratorsUserGroupId = 12;
3834
        // ID of the "Editors" user group in an eZ Publish demo installation
3835
        $editorsUserGroupId = 13;
3836
3837
        $administratorsUserGroup = $userService->loadUserGroup($administratorsUserGroupId);
3838
        $editorsUserGroup = $userService->loadUserGroup($editorsUserGroupId);
3839
3840
        // Add additional Location for Administrators UserGroup under Editors UserGroup Location
3841
        $locationCreateStruct = $locationService->newLocationCreateStruct(
3842
            $editorsUserGroup->contentInfo->mainLocationId
3843
        );
3844
        $newAdministratorsUserGroupLocation = $locationService->createLocation(
3845
            $administratorsUserGroup->contentInfo,
3846
            $locationCreateStruct
3847
        );
3848
3849
        // Add additional Location for administrator user under newly created UserGroup Location
3850
        $locationCreateStruct = $locationService->newLocationCreateStruct(
3851
            $newAdministratorsUserGroupLocation->id
3852
        );
3853
        $locationService->createLocation(
3854
            $administratorUser->contentInfo,
3855
            $locationCreateStruct
3856
        );
3857
3858
        // Create a Content to be found through Editors UserGroup id.
3859
        // This ensures data is indexed, it could also be done by updating metadata of
3860
        // an existing Content, but slot would need to reindex Content and that should
3861
        // be tested elsewhere (dedicated indexing integration tests, missing ATM).
3862
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
3863
3864
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3865
        $createStruct->setField('name', 'test');
3866
3867
        $locationCreateStruct = $locationService->newLocationCreateStruct(2);
3868
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
3869
        $content = $contentService->publishVersion($draft->getVersionInfo());
3870
        $contentTypeService->createContentTypeDraft($contentType);
3871
3872
        $this->refreshSearch($repository);
3873
3874
        return $content;
3875
    }
3876
3877
    /**
3878
     * Test for the findContent() method.
3879
     *
3880
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3881
     */
3882
    public function testUserMetadataGroupHorizontalFilterContent($queryType = null)
3883
    {
3884
        if ($queryType === null) {
3885
            $queryType = 'filter';
3886
        }
3887
3888
        $repository = $this->getRepository();
3889
        $searchService = $repository->getSearchService();
3890
        $editorsUserGroupId = 13;
3891
3892
        $content = $this->createContentForTestUserMetadataGroupHorizontal();
3893
3894
        $criteria = [];
3895
        $setupFactory = $this->getSetupFactory();
3896
3897
        // Do not limit for LSE, as it does not not require reindexing.
3898
        // See explanation below.
3899
        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...
3900
            $criteria[] = new Criterion\ContentTypeIdentifier('folder');
3901
        }
3902
3903
        $criteria[] = new Criterion\UserMetadata(
3904
            Criterion\UserMetadata::GROUP,
3905
            Criterion\Operator::EQ,
3906
            $editorsUserGroupId
3907
        );
3908
3909
        $query = new Query(
3910
            [
3911
                $queryType => new Criterion\LogicalAnd($criteria),
3912
                'sortClauses' => [
3913
                    new SortClause\ContentId(),
3914
                ],
3915
                'limit' => 50,
3916
            ]
3917
        );
3918
3919
        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...
3920
            $result = $searchService->findContent($query);
3921
3922
            // Administrator User is owned by itself, when additional Locations are added
3923
            // it should be reindexed and its UserGroups will updated, which means it should
3924
            // also be found as a Content of Editors UserGroup. However we do not handle this
3925
            // in slots yet, and also miss SPI methods to do it without using Search (also
3926
            // needed to decouple services), because as indexing is asynchronous Search
3927
            // should not eat its own dog food for reindexing.
3928
            $this->assertEquals(1, $result->totalCount);
3929
3930
            $this->assertEquals(
3931
                $content->id,
3932
                $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...
3933
            );
3934
        } else {
3935
            // This is how it should eventually work for all search engines,
3936
            // with required reindexing slots properly implemented.
3937
3938
            $result = $searchService->findContent($query);
3939
3940
            // Assert last hit manually, as id will change because it is created in test
3941
            // and not present it base fixture.
3942
            $foundContent1 = array_pop($result->searchHits);
3943
            $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...
3944
            $this->assertEquals($content->id, $foundContent1->valueObject->id);
3945
3946
            $this->simplifySearchResult($result);
3947
            $this->assertEquals(
3948
                include $this->getFixtureDir() . '/UserMetadata.php',
3949
                $result,
3950
                'Search results do not match.',
3951
                .1 // Be quite generous regarding delay -- most important for scores
3952
            );
3953
        }
3954
    }
3955
3956
    /**
3957
     * Test for the findContent() method.
3958
     *
3959
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3960
     */
3961
    public function testUserMetadataGroupHorizontalQueryContent()
3962
    {
3963
        $this->testUserMetadataGroupHorizontalFilterContent('query');
3964
    }
3965
3966
    /**
3967
     * Test for the findLocations() method.
3968
     *
3969
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3970
     */
3971
    public function testUserMetadataGroupHorizontalFilterLocation($queryType = null)
3972
    {
3973
        if ($queryType === null) {
3974
            $queryType = 'filter';
3975
        }
3976
3977
        $repository = $this->getRepository();
3978
        $searchService = $repository->getSearchService();
3979
        $editorsUserGroupId = 13;
3980
3981
        $content = $this->createContentForTestUserMetadataGroupHorizontal();
3982
3983
        $criteria = [];
3984
        $setupFactory = $this->getSetupFactory();
3985
3986
        // Do not limit for LSE, as it does not not require reindexing.
3987
        // See explanation below.
3988
        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...
3989
            $criteria[] = new Criterion\ContentTypeIdentifier('folder');
3990
        }
3991
3992
        $criteria[] = new Criterion\UserMetadata(
3993
            Criterion\UserMetadata::GROUP,
3994
            Criterion\Operator::EQ,
3995
            $editorsUserGroupId
3996
        );
3997
3998
        $query = new LocationQuery(
3999
            [
4000
                $queryType => new Criterion\LogicalAnd($criteria),
4001
                'sortClauses' => [
4002
                    new SortClause\Location\Id(),
4003
                ],
4004
                'limit' => 50,
4005
            ]
4006
        );
4007
4008
        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...
4009
            $result = $searchService->findLocations($query);
4010
4011
            // Administrator User is owned by itself, when additional Locations are added
4012
            // it should be reindexed and its UserGroups will updated, which means it should
4013
            // also be found as a Content of Editors UserGroup. However we do not handle this
4014
            // in slots yet, and also miss SPI methods to do it without using Search (also
4015
            // needed to decouple services), because as indexing is asynchronous Search
4016
            // should not eat its own dog food for reindexing.
4017
            $this->assertEquals(1, $result->totalCount);
4018
4019
            $this->assertEquals(
4020
                $content->contentInfo->mainLocationId,
4021
                $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...
4022
            );
4023
        } else {
4024
            // This is how it should eventually work for all search engines,
4025
            // with required reindexing slots properly implemented.
4026
4027
            $result = $searchService->findLocations($query);
4028
4029
            // Assert last two hits manually, as ids will change because they are created
4030
            // in test and not present in base fixture.
4031
            $foundLocation1 = array_pop($result->searchHits);
4032
            $foundLocation2 = array_pop($result->searchHits);
4033
            // Remove additional Administrators UserGroup Location
4034
            array_pop($result->searchHits);
4035
            $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...
4036
            $this->assertEquals(
4037
                $content->versionInfo->contentInfo->mainLocationId,
4038
                $foundLocation1->valueObject->id
4039
            );
4040
            $this->assertEquals(
4041
                $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...
4042
                $foundLocation2->valueObject->contentId
4043
            );
4044
4045
            $this->simplifySearchResult($result);
4046
            $this->assertEquals(
4047
                include $this->getFixtureDir() . '/UserMetadataLocation.php',
4048
                $result,
4049
                'Search results do not match.',
4050
                .1 // Be quite generous regarding delay -- most important for scores
4051
            );
4052
        }
4053
    }
4054
4055
    /**
4056
     * Test for the findLocations() method.
4057
     *
4058
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
4059
     */
4060
    public function testUserMetadataGroupHorizontalQueryLocation()
4061
    {
4062
        $this->testUserMetadataGroupHorizontalFilterLocation('query');
4063
    }
4064
4065
    /**
4066
     * Test for FullText on the findContent() method.
4067
     *
4068
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4069
     */
4070
    public function testFullTextOnNewContent()
4071
    {
4072
        $repository = $this->getRepository();
4073
        $contentService = $repository->getContentService();
4074
        $contentTypeService = $repository->getContentTypeService();
4075
        $locationService = $repository->getLocationService();
4076
        $searchService = $repository->getSearchService();
4077
4078
        $contentCreateStruct = $contentService->newContentCreateStruct(
4079
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4080
            'eng-GB'
4081
        );
4082
4083
        $contentCreateStruct->setField('name', 'foxes');
4084
4085
        $englishContent = $contentService->publishVersion(
4086
            $contentService->createContent(
4087
                $contentCreateStruct,
4088
                [$locationService->newLocationCreateStruct(2)]
4089
            )->versionInfo
4090
        );
4091
4092
        $this->refreshSearch($repository);
4093
4094
        $query = new Query(
4095
            [
4096
                'query' => new Criterion\FullText('foxes'),
4097
            ]
4098
        );
4099
4100
        $searchResult = $searchService->findContentInfo($query);
4101
4102
        $this->assertEquals(1, $searchResult->totalCount);
4103
        $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...
4104
    }
4105
4106
    /**
4107
     * Test for the findContent() method.
4108
     *
4109
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4110
     */
4111
    public function testLanguageAnalysisSeparateContent()
4112
    {
4113
        $setupFactory = $this->getSetupFactory();
4114
        if (!$setupFactory instanceof LegacyElasticsearch) {
4115
            $this->markTestSkipped('Language analysis is implemented only for Elasticsearch storage');
4116
        }
4117
4118
        $repository = $this->getRepository();
4119
        $contentService = $repository->getContentService();
4120
        $contentTypeService = $repository->getContentTypeService();
4121
        $locationService = $repository->getLocationService();
4122
        $searchService = $repository->getSearchService();
4123
        $languageService = $repository->getContentLanguageService();
4124
4125
        $languageCreateStruct = $languageService->newLanguageCreateStruct();
4126
        $languageCreateStruct->languageCode = 'rus-RU';
4127
        $languageCreateStruct->name = 'Russian';
4128
4129
        $languageService->createLanguage($languageCreateStruct);
4130
4131
        $contentCreateStruct = $contentService->newContentCreateStruct(
4132
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4133
            'eng-GB'
4134
        );
4135
4136
        $contentCreateStruct->setField('name', 'foxes');
4137
4138
        $englishContent = $contentService->publishVersion(
4139
            $contentService->createContent(
4140
                $contentCreateStruct,
4141
                [$locationService->newLocationCreateStruct(2)]
4142
            )->versionInfo
4143
        );
4144
4145
        $contentCreateStruct = $contentService->newContentCreateStruct(
4146
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4147
            'rus-RU'
4148
        );
4149
4150
        $contentCreateStruct->setField('name', 'foxes');
4151
4152
        $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...
4153
            $contentService->createContent(
4154
                $contentCreateStruct,
4155
                [$locationService->newLocationCreateStruct(2)]
4156
            )->versionInfo
4157
        );
4158
4159
        // Only Content in English should be found, because Content in Russian
4160
        // will not be correctly stemmed
4161
        $query = new Query(
4162
            [
4163
                'query' => new Criterion\FullText('foxing'),
4164
            ]
4165
        );
4166
4167
        $searchResult = $searchService->findContent($query);
4168
4169
        $this->assertEquals(1, $searchResult->totalCount);
4170
        $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...
4171
    }
4172
4173
    /**
4174
     * Test for the findContent() method.
4175
     *
4176
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4177
     */
4178
    public function testLanguageAnalysisSameContent()
4179
    {
4180
        $setupFactory = $this->getSetupFactory();
4181
        if (!$setupFactory instanceof LegacyElasticsearch) {
4182
            $this->markTestSkipped('Language analysis is implemented only for Elasticsearch storage');
4183
        }
4184
4185
        $repository = $this->getRepository();
4186
        $contentService = $repository->getContentService();
4187
        $contentTypeService = $repository->getContentTypeService();
4188
        $locationService = $repository->getLocationService();
4189
        $searchService = $repository->getSearchService();
4190
        $languageService = $repository->getContentLanguageService();
4191
4192
        $languageCreateStruct = $languageService->newLanguageCreateStruct();
4193
        $languageCreateStruct->languageCode = 'rus-RU';
4194
        $languageCreateStruct->name = 'Russian';
4195
4196
        $languageService->createLanguage($languageCreateStruct);
4197
4198
        $contentCreateStruct = $contentService->newContentCreateStruct(
4199
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4200
            'eng-GB'
4201
        );
4202
4203
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'eng-GB');
4204
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'rus-RU');
4205
4206
        $mixedContent = $contentService->publishVersion(
4207
            $contentService->createContent(
4208
                $contentCreateStruct,
4209
                [$locationService->newLocationCreateStruct(2)]
4210
            )->versionInfo
4211
        );
4212
4213
        // Content will be found because translation in Russian will be correctly stemmed
4214
        $query = new Query(
4215
            [
4216
                'query' => new Criterion\FullText('важнее'),
4217
            ]
4218
        );
4219
4220
        $searchResult = $searchService->findContent($query);
4221
4222
        $this->assertEquals(1, $searchResult->totalCount);
4223
        $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...
4224
    }
4225
4226
    /**
4227
     * Test for the findContent() method.
4228
     *
4229
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4230
     */
4231
    public function testLanguageAnalysisSameContentNotFound()
4232
    {
4233
        $setupFactory = $this->getSetupFactory();
4234
        if (!$setupFactory instanceof LegacyElasticsearch) {
4235
            $this->markTestSkipped('Language analysis is implemented only for Elasticsearch storage');
4236
        }
4237
4238
        $repository = $this->getRepository();
4239
        $contentService = $repository->getContentService();
4240
        $contentTypeService = $repository->getContentTypeService();
4241
        $locationService = $repository->getLocationService();
4242
        $searchService = $repository->getSearchService();
4243
        $languageService = $repository->getContentLanguageService();
4244
4245
        $languageCreateStruct = $languageService->newLanguageCreateStruct();
4246
        $languageCreateStruct->languageCode = 'rus-RU';
4247
        $languageCreateStruct->name = 'Russian';
4248
4249
        $languageService->createLanguage($languageCreateStruct);
4250
4251
        $contentCreateStruct = $contentService->newContentCreateStruct(
4252
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4253
            'eng-GB'
4254
        );
4255
4256
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'eng-GB');
4257
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'rus-RU');
4258
4259
        $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...
4260
            $contentService->createContent(
4261
                $contentCreateStruct,
4262
                [$locationService->newLocationCreateStruct(2)]
4263
            )->versionInfo
4264
        );
4265
4266
        // Content should be found because translation in Russian will be correctly stemmed
4267
        $query = new Query(
4268
            [
4269
                'query' => new Criterion\FullText('важнее'),
4270
            ]
4271
        );
4272
4273
        // Filtering fields for only English will cause no match because the term will
4274
        // not be correctly stemmed
4275
        $searchResult = $searchService->findContent($query, ['languages' => ['eng-GB']]);
4276
4277
        $this->assertEquals(0, $searchResult->totalCount);
4278
    }
4279
4280
    /**
4281
     * Test for the findContent() method searching for content filtered by languages.
4282
     *
4283
     * @covers \eZ\Publish\Core\Repository\SearchService::findContent
4284
     */
4285
    public function testFindContentWithLanguageFilter()
4286
    {
4287
        $repository = $this->getRepository();
4288
        $searchService = $repository->getSearchService();
4289
4290
        $query = new Query(
4291
            [
4292
                'filter' => new Criterion\ContentId([4]),
4293
                'offset' => 0,
4294
            ]
4295
        );
4296
        $searchResult = $searchService->findContent(
4297
            $query,
4298
            ['languages' => ['eng-US']],
4299
            false
4300
        );
4301
        /* END: Use Case */
4302
4303
        $this->assertInstanceOf(
4304
            SearchResult::class,
4305
            $searchResult
4306
        );
4307
4308
        $this->assertEquals(1, $searchResult->totalCount);
4309
        $this->assertCount($searchResult->totalCount, $searchResult->searchHits);
4310
        foreach ($searchResult->searchHits as $searchHit) {
4311
            $this->assertInstanceOf(
4312
                SearchHit::class,
4313
                $searchHit
4314
            );
4315
        }
4316
    }
4317
4318
    /**
4319
     * This test prepares data for other tests.
4320
     *
4321
     * @see testFulltextContentSearchComplex
4322
     * @see testFulltextLocationSearchComplex
4323
     *
4324
     * @return array
4325
     */
4326
    public function testFulltextComplex()
4327
    {
4328
        $repository = $this->getRepository();
4329
        $contentService = $repository->getContentService();
4330
        $contentTypeService = $repository->getContentTypeService();
4331
        $locationService = $repository->getLocationService();
4332
4333
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
4334
        $contentCreateStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
4335
4336
        $contentCreateStruct->setField('name', 'red');
4337
        $contentCreateStruct->setField('short_name', 'red apple');
4338
        $content1 = $contentService->publishVersion(
4339
            $contentService->createContent(
4340
                $contentCreateStruct,
4341
                [$locationService->newLocationCreateStruct(2)]
4342
            )->versionInfo
4343
        );
4344
4345
        $contentCreateStruct->setField('name', 'apple');
4346
        $contentCreateStruct->setField('short_name', 'two');
4347
        $content2 = $contentService->publishVersion(
4348
            $contentService->createContent(
4349
                $contentCreateStruct,
4350
                [$locationService->newLocationCreateStruct(2)]
4351
            )->versionInfo
4352
        );
4353
4354
        $contentCreateStruct->setField('name', 'red apple');
4355
        $contentCreateStruct->setField('short_name', 'three');
4356
        $content3 = $contentService->publishVersion(
4357
            $contentService->createContent(
4358
                $contentCreateStruct,
4359
                [$locationService->newLocationCreateStruct(2)]
4360
            )->versionInfo
4361
        );
4362
4363
        $contentCreateStruct->setField('name', 'four');
4364
        $contentCreateStruct->setField('name', 'german red apple', 'ger-DE');
4365
        $contentCreateStruct->setField('short_name', 'four');
4366
        $contentCreateStruct->setField('short_name', 'german red apple', 'ger-DE');
4367
        $contentService->publishVersion(
4368
            $contentService->createContent(
4369
                $contentCreateStruct,
4370
                [$locationService->newLocationCreateStruct(2)]
4371
            )->versionInfo
4372
        );
4373
4374
        $this->refreshSearch($repository);
4375
4376
        $criterion = new Criterion\FullText(
4377
            'red apple',
4378
            [
4379
                'boost' => [
4380
                    'short_name' => 2,
4381
                ],
4382
                'fuzziness' => .1,
4383
            ]
4384
        );
4385
4386
        return [$criterion, $content1, $content2, $content3];
4387
    }
4388
4389
    /**
4390
     * Test for the findContent() method.
4391
     *
4392
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4393
     * @depends testFulltextComplex
4394
     *
4395
     * @param array $data
4396
     */
4397
    public function testFulltextContentSearchComplex(array $data)
4398
    {
4399
        // Do not initialize from scratch
4400
        $repository = $this->getRepository(false);
4401
        $searchService = $repository->getSearchService();
4402
        list($criterion, $content1, $content2, $content3) = $data;
4403
4404
        $searchResult = $searchService->findContent(
4405
            new Query(['query' => $criterion]),
4406
            ['languages' => ['eng-GB']]
4407
        );
4408
        $searchHits = $searchResult->searchHits;
4409
4410
        $this->assertEquals(3, $searchResult->totalCount);
4411
4412
        // Legacy search engine does have scoring, sorting the results by ID in that case
4413
        $setupFactory = $this->getSetupFactory();
4414 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...
4415
            $this->sortSearchHitsById($searchHits);
4416
4417
            $this->assertEquals($content1->id, $searchHits[0]->valueObject->id);
4418
            $this->assertEquals($content2->id, $searchHits[1]->valueObject->id);
4419
            $this->assertEquals($content3->id, $searchHits[2]->valueObject->id);
4420
4421
            return;
4422
        }
4423
4424
        // Assert scores are descending
4425
        $this->assertGreaterThan($searchHits[1]->score, $searchHits[0]->score);
4426
        $this->assertGreaterThan($searchHits[2]->score, $searchHits[1]->score);
4427
4428
        // Assert order
4429
        $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...
4430
        $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...
4431
        $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...
4432
    }
4433
4434
    /**
4435
     * Test for the findContent() method.
4436
     *
4437
     * @covers \eZ\Publish\API\Repository\SearchService::findContent()
4438
     * @depends testFulltextComplex
4439
     *
4440
     * @param array $data
4441
     */
4442
    public function testFulltextContentTranslationSearch(array $data)
4443
    {
4444
        $criterion = $data[0];
4445
        $query = new Query(['query' => $criterion]);
4446
4447
        $this->assertFulltextSearchForTranslations(self::FIND_CONTENT_METHOD, $query);
4448
    }
4449
4450
    /**
4451
     * Test for the findLocations() method.
4452
     *
4453
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
4454
     * @depends testFulltextComplex
4455
     *
4456
     * @param array $data
4457
     */
4458
    public function testFulltextLocationSearchComplex(array $data)
4459
    {
4460
        $setupFactory = $this->getSetupFactory();
4461
        if ($setupFactory instanceof LegacyElasticsearch) {
4462
            $this->markTestIncomplete(
4463
                'Fulltext criterion is not supported with Location search in Elasticsearch engine'
4464
            );
4465
        }
4466
4467
        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...
4468
            $this->markTestSkipped('Skipping location search score test on Solr 4.10, you need Solr 6 for this!');
4469
        }
4470
4471
        // Do not initialize from scratch
4472
        $repository = $this->getRepository(false);
4473
        list($criterion, $content1, $content2, $content3) = $data;
4474
        $searchService = $repository->getSearchService();
4475
4476
        $searchResult = $searchService->findLocations(
4477
            new LocationQuery(['query' => $criterion]),
4478
            ['languages' => ['eng-GB']]
4479
        );
4480
        $searchHits = $searchResult->searchHits;
4481
4482
        $this->assertEquals(3, $searchResult->totalCount);
4483
4484
        // Legacy search engine does have scoring, sorting the results by ID in that case
4485
        $setupFactory = $this->getSetupFactory();
4486 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...
4487
            $this->sortSearchHitsById($searchHits);
4488
4489
            $this->assertEquals($content1->id, $searchHits[0]->valueObject->contentId);
4490
            $this->assertEquals($content2->id, $searchHits[1]->valueObject->contentId);
4491
            $this->assertEquals($content3->id, $searchHits[2]->valueObject->contentId);
4492
4493
            return;
4494
        }
4495
4496
        // Assert scores are descending
4497
        $this->assertGreaterThan($searchHits[1]->score, $searchHits[0]->score);
4498
        $this->assertGreaterThan($searchHits[2]->score, $searchHits[1]->score);
4499
4500
        // Assert order
4501
        $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...
4502
        $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...
4503
        $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...
4504
    }
4505
4506
    /**
4507
     * Test for the findLocations() method.
4508
     *
4509
     * @covers \eZ\Publish\API\Repository\SearchService::findLocations()
4510
     * @depends testFulltextComplex
4511
     *
4512
     * @param array $data
4513
     */
4514
    public function testFulltextLocationTranslationSearch(array $data): void
4515
    {
4516
        $criterion = $data[0];
4517
        $query = new LocationQuery(['query' => $criterion]);
4518
4519
        $this->assertFulltextSearchForTranslations(self::FIND_LOCATION_METHOD, $query);
4520
    }
4521
4522
    /**
4523
     * Assert that query result matches the given fixture.
4524
     *
4525
     * @param Query $query
4526
     * @param string $fixture
4527
     * @param callable|null $closure
4528
     * @param bool $info
4529
     * @param bool $id
4530
     */
4531
    protected function assertQueryFixture(Query $query, $fixture, $closure = null, $ignoreScore = true, $info = false, $id = true)
4532
    {
4533
        $repository = $this->getRepository();
4534
        $searchService = $repository->getSearchService();
4535
4536
        try {
4537
            if ($query instanceof LocationQuery) {
4538
                $setupFactory = $this->getSetupFactory();
4539
                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...
4540
                    // @todo When we want to test score again by default we will need fixtures for Solr
4541
                }
4542
4543
                if ($setupFactory instanceof LegacyElasticsearch) {
4544
                    $position = strrpos($fixture, '/');
4545
                    $fixture = substr_replace($fixture, '/Location', $position, 0);
4546
                }
4547
4548
                $result = $searchService->findLocations($query);
4549
            } elseif ($query instanceof Query) {
4550
                if ($info) {
4551
                    $result = $searchService->findContentInfo($query);
4552
                } else {
4553
                    $result = $searchService->findContent($query);
4554
                }
4555
            } else {
4556
                $this->fail('Expected instance of LocationQuery or Query, got: ' . gettype($query));
4557
            }
4558
            $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...
4559
        } catch (NotImplementedException $e) {
4560
            $this->markTestSkipped(
4561
                'This feature is not supported by the current search backend: ' . $e->getMessage()
4562
            );
4563
        }
4564
4565 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...
4566
            if (isset($_ENV['ez_tests_record'])) {
4567
                file_put_contents(
4568
                    $record = $fixture . '.recording',
4569
                    "<?php\n\nreturn " . var_export($result, true) . ";\n\n"
4570
                );
4571
                $this->markTestIncomplete("No fixture available. Result recorded at $record. Result: \n" . $this->printResult($result));
4572
            } else {
4573
                $this->markTestIncomplete("No fixture available. Set \$_ENV['ez_tests_record'] to generate:\n " . $fixture);
4574
            }
4575
        }
4576
4577
        $fixture = include $fixture;
4578
4579
        if ($closure !== null) {
4580
            $closure($fixture);
4581
            $closure($result);
4582
        }
4583
4584 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...
4585
            foreach ([$fixture, $result] as $set) {
4586
                $property = new \ReflectionProperty(get_class($set), 'maxScore');
4587
                $property->setAccessible(true);
4588
                $property->setValue($set, 0.0);
4589
4590
                foreach ($set->searchHits as $hit) {
4591
                    $property = new \ReflectionProperty(get_class($hit), 'score');
4592
                    $property->setAccessible(true);
4593
                    $property->setValue($hit, 0.0);
4594
                }
4595
            }
4596
        }
4597
4598
        foreach ([$fixture, $result] as $set) {
4599
            foreach ($set->searchHits as $hit) {
4600
                $property = new \ReflectionProperty(get_class($hit), 'index');
4601
                $property->setAccessible(true);
4602
                $property->setValue($hit, null);
4603
4604
                $property = new \ReflectionProperty(get_class($hit), 'matchedTranslation');
4605
                $property->setAccessible(true);
4606
                $property->setValue($hit, null);
4607
4608
                if (!$id) {
4609
                    $hit->valueObject['id'] = null;
4610
                }
4611
            }
4612
        }
4613
4614
        $this->assertEquals(
4615
            $fixture,
4616
            $result,
4617
            'Search results do not match.',
4618
            .99 // Be quite generous regarding delay -- most important for scores
4619
        );
4620
    }
4621
4622
    /**
4623
     * Show a simplified view of the search result for manual introspection.
4624
     *
4625
     * @param SearchResult $result
4626
     *
4627
     * @return string
4628
     */
4629 View Code Duplication
    protected function printResult(SearchResult $result)
4630
    {
4631
        $printed = '';
4632
        foreach ($result->searchHits as $hit) {
4633
            $printed .= sprintf(" - %s (%s)\n", $hit->valueObject['title'], $hit->valueObject['id']);
4634
        }
4635
4636
        return $printed;
4637
    }
4638
4639
    /**
4640
     * Simplify search result.
4641
     *
4642
     * This leads to saner comparisons of results, since we do not get the full
4643
     * content objects every time.
4644
     *
4645
     * @param SearchResult $result
4646
     */
4647
    protected function simplifySearchResult(SearchResult $result)
4648
    {
4649
        $result->time = 1;
4650
4651
        foreach ($result->searchHits as $hit) {
4652
            switch (true) {
4653
                case $hit->valueObject instanceof Content:
4654 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...
4655
                    $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...
4656
                        'id' => $hit->valueObject->contentInfo->id,
4657
                        'title' => $hit->valueObject->contentInfo->name,
4658
                    ];
4659
                    break;
4660
4661
                case $hit->valueObject instanceof ContentInfo:
4662
                    $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...
4663
                        'id' => $hit->valueObject->id,
4664
                        'title' => $hit->valueObject->name,
4665
                    ];
4666
                    break;
4667
4668
                default:
4669
                    throw new \RuntimeException('Unknown search result hit type: ' . get_class($hit->valueObject));
4670
            }
4671
        }
4672
    }
4673
4674
    /**
4675
     * Get fixture directory.
4676
     *
4677
     * @return string
4678
     */
4679
    protected function getFixtureDir()
4680
    {
4681
        return __DIR__ . '/_fixtures/' . getenv('fixtureDir') . '/';
4682
    }
4683
4684
    /**
4685
     * For findContentInfo tests, to reuse fixtures for findContent tests.
4686
     *
4687
     * @param callable|null $closure
4688
     *
4689
     * @return callable
4690
     */
4691
    private function getContentInfoFixtureClosure($closure = null)
4692
    {
4693
        /** @var $data \eZ\Publish\API\Repository\Values\Content\Search\SearchResult */
4694
        return function (&$data) use ($closure) {
4695
            foreach ($data->searchHits as $searchHit) {
4696
                if ($searchHit->valueObject instanceof Content) {
4697
                    $searchHit->valueObject = $searchHit->valueObject->getVersionInfo()->getContentInfo();
4698
                }
4699
            }
4700
4701
            if (isset($closure)) {
4702
                $closure($data);
4703
            }
4704
        };
4705
    }
4706
4707
    /**
4708
     * Test searching using Field Criterion where the given Field Identifier exists in
4709
     * both searchable and non-searchable Fields.
4710
     * Number of returned results depends on used storage.
4711
     *
4712
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4713
     */
4714
    public function testFieldCriterionForContentsWithIdenticalFieldIdentifiers()
4715
    {
4716
        $this->createContentWithFieldType(
4717
            'url',
4718
            'title',
4719
            'foo'
4720
        );
4721
        $this->createContentWithFieldType(
4722
            'string',
4723
            'title',
4724
            'foo'
4725
        );
4726
        $query = new Query(
4727
            [
4728
                'query' => new Criterion\Field(
4729
                    'title',
4730
                    Criterion\Operator::EQ,
4731
                    'foo'
4732
                ),
4733
            ]
4734
        );
4735
4736
        $repository = $this->getRepository();
4737
        $searchService = $repository->getSearchService();
4738
        $result = $searchService->findContent($query);
4739
4740
        $this->assertTrue(($result->totalCount === 1 || $result->totalCount === 2));
4741
    }
4742
4743
    private function createContentWithFieldType(
4744
        string $fieldType,
4745
        string $fieldName,
4746
        string $fieldValue
4747
    ) {
4748
        $repository = $this->getRepository();
4749
        $contentTypeService = $repository->getContentTypeService();
4750
        $contentService = $repository->getContentService();
4751
4752
        $createStruct = $contentTypeService->newContentTypeCreateStruct($fieldType . uniqid());
4753
        $createStruct->mainLanguageCode = 'eng-GB';
4754
        $createStruct->remoteId = $fieldType . '-123';
4755
        $createStruct->names = ['eng-GB' => $fieldType];
4756
        $createStruct->creatorId = 14;
4757
        $createStruct->creationDate = new \DateTime();
4758
4759
        $fieldCreate = $contentTypeService->newFieldDefinitionCreateStruct($fieldName, 'ez' . $fieldType);
4760
        $fieldCreate->names = ['eng-GB' => $fieldName];
4761
        $fieldCreate->fieldGroup = 'main';
4762
        $fieldCreate->position = 1;
4763
4764
        $createStruct->addFieldDefinition($fieldCreate);
4765
4766
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
4767
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
4768
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
4769
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
4770
4771
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
4772
        $createStruct->remoteId = $fieldType . '-456';
4773
        $createStruct->alwaysAvailable = false;
4774
        $createStruct->setField(
4775
            $fieldName,
4776
            $fieldValue
4777
        );
4778
4779
        $draft = $contentService->createContent($createStruct);
4780
        $content = $contentService->publishVersion($draft->getVersionInfo());
4781
4782
        $this->refreshSearch($repository);
4783
4784
        return $content;
4785
    }
4786
4787
    /**
4788
     * @param string $findMethod
4789
     * @param \eZ\Publish\API\Repository\Values\Content\Query $query
4790
     * @param array $languages
4791
     * @param bool $useAlwaysAvailable
4792
     *
4793
     * @throws \InvalidArgumentException
4794
     *
4795
     * @return \eZ\Publish\API\Repository\Values\Content\Search\SearchResult
4796
     */
4797
    private function find(
4798
        string $findMethod,
4799
        Query $query,
4800
        array $languages,
4801
        bool $useAlwaysAvailable
4802
    ): SearchResult {
4803
        if (false === in_array($findMethod, self::AVAILABLE_FIND_METHODS, true)) {
4804
            throw new InvalidArgumentException(
4805
                'Allowed find methods are: '
4806
                . implode(',', self::AVAILABLE_FIND_METHODS)
4807
            );
4808
        }
4809
4810
        $repository = $this->getRepository(false);
4811
        $searchService = $repository->getSearchService();
4812
4813
        return $searchService->{$findMethod}(
4814
            $query,
4815
            [
4816
                'languages' => $languages,
4817
                'useAlwaysAvailable' => $useAlwaysAvailable,
4818
            ]
4819
        );
4820
    }
4821
4822
    /**
4823
     * @param string $findMethod
4824
     * @param \eZ\Publish\API\Repository\Values\Content\Query $query
4825
     */
4826
    private function assertFulltextSearchForTranslations(string $findMethod, Query $query): void
4827
    {
4828
        /*
4829
         * Search in German translations without always available
4830
         */
4831
        $searchResult = $this->find($findMethod, $query, ['ger-DE'], false);
4832
        $this->assertEquals(1, $searchResult->totalCount);
4833
        $this->assertSearchResultMatchTranslations($searchResult, ['ger-DE']);
4834
4835
        /*
4836
         * Search in German translations with always available
4837
         */
4838
        $searchResult = $this->find($findMethod, $query, ['ger-DE'], true);
4839
        $this->assertEquals(4, $searchResult->totalCount);
4840
        $this->assertSearchResultMatchTranslations($searchResult, ['eng-GB', 'eng-GB', 'eng-GB', 'ger-DE']);
4841
4842
        /*
4843
         * Search in multiple (ger-DE, eng-GB) translations without always available
4844
         */
4845
        $searchResult = $this->find($findMethod, $query, ['ger-DE', 'eng-GB'], false);
4846
        $this->assertEquals(4, $searchResult->totalCount);
4847
        $this->assertSearchResultMatchTranslations($searchResult, ['eng-GB', 'eng-GB', 'eng-GB', 'ger-DE']);
4848
4849
        /*
4850
         * Search in multiple (eng-US, ger-DE) translations without always available
4851
         */
4852
        $searchResult = $this->find($findMethod, $query, ['eng-US', 'ger-DE'], false);
4853
        $this->assertEquals(1, $searchResult->totalCount);
4854
        $this->assertSearchResultMatchTranslations($searchResult, ['ger-DE']);
4855
4856
        /*
4857
         * Search in eng-US translations without always available
4858
         */
4859
        $searchResult = $this->find($findMethod, $query, ['eng-US'], false);
4860
        $this->assertEquals(0, $searchResult->totalCount);
4861
4862
        /*
4863
         * Search in eng-US translations with always available
4864
         */
4865
        $searchResult = $this->find($findMethod, $query, ['eng-US'], true);
4866
        $this->assertEquals(3, $searchResult->totalCount);
4867
        $this->assertSearchResultMatchTranslations($searchResult, ['eng-GB', 'eng-GB', 'eng-GB']);
4868
    }
4869
4870
    /**
4871
     * @param \eZ\Publish\API\Repository\Values\Content\Search\SearchResult $searchResult
4872
     * @param string[] $translationsToMatch
4873
     *
4874
     * @throws \InvalidArgumentException
4875
     */
4876
    private function assertSearchResultMatchTranslations(
4877
        SearchResult $searchResult,
4878
        array $translationsToMatch
4879
    ): void {
4880
        $translationsToMatchCount = count($translationsToMatch);
4881
4882
        if ($searchResult->totalCount < $translationsToMatchCount
4883
            || $searchResult->totalCount > $translationsToMatchCount
4884
        ) {
4885
            throw new InvalidArgumentException(
4886
                'Argument `translationsToMatch` must be equal to the search result total count!'
4887
            );
4888
        }
4889
4890
        $searchHits = $searchResult->searchHits;
4891
        $this->sortSearchHitsById($searchHits);
4892
4893
        for ($i = 0; $i < $searchResult->totalCount; ++$i) {
4894
            $this->assertEquals(
4895
                $translationsToMatch[$i],
4896
                $searchHits[$i]->matchedTranslation
4897
            );
4898
        }
4899
    }
4900
4901
    private function sortSearchHitsById(array &$searchHits): void
4902
    {
4903
        usort(
4904
           $searchHits,
4905
           static function (SearchHit $a, SearchHit $b): int {
4906
               return $a->valueObject->id <=> $b->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...
4907
           }
4908
        );
4909
    }
4910
}
4911