Completed
Push — ezp-30936-edit-content-new-req... ( 953d44...df9d75 )
by
unknown
19:03
created

SearchServiceTest::testFieldIsNotEmpty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 21
rs 9.584
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the SearchServiceTest class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\API\Repository\Tests;
10
11
use eZ\Publish\API\Repository\Tests\SetupFactory\LegacyElasticsearch;
12
use EzSystems\EzPlatformSolrSearchEngine\Tests\SetupFactory\LegacySetupFactory as LegacySolrSetupFactory;
13
use eZ\Publish\API\Repository\Values\Content\Content;
14
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
15
use eZ\Publish\API\Repository\Values\Content\Query;
16
use eZ\Publish\API\Repository\Values\Content\Location;
17
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
18
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
19
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
20
use eZ\Publish\API\Repository\Values\Content\Search\SearchResult;
21
use eZ\Publish\API\Repository\Values\Content\Search\SearchHit;
22
use eZ\Publish\API\Repository\Exceptions\NotImplementedException;
23
24
/**
25
 * Test case for operations in the SearchService.
26
 *
27
 * @see eZ\Publish\API\Repository\SearchService
28
 * @group integration
29
 * @group search
30
 */
31
class SearchServiceTest extends BaseTest
32
{
33
    const QUERY_CLASS = Query::class;
34
35
    use Common\FacetedSearchProvider;
36
37
    public function getFilterContentSearches()
38
    {
39
        $fixtureDir = $this->getFixtureDir();
40
41
        return [
42
            0 => [
43
                [
44
                    'filter' => new Criterion\ContentId(
45
                        [1, 4, 10]
46
                    ),
47
                    'sortClauses' => [new SortClause\ContentId()],
48
                ],
49
                $fixtureDir . 'ContentId.php',
50
            ],
51
            1 => [
52
                [
53
                    'filter' => new Criterion\LogicalAnd(
54
                        [
55
                            new Criterion\ContentId(
56
                                [1, 4, 10]
57
                            ),
58
                            new Criterion\ContentId(
59
                                [4, 12]
60
                            ),
61
                        ]
62
                    ),
63
                    'sortClauses' => [new SortClause\ContentId()],
64
                ],
65
                $fixtureDir . 'LogicalAnd.php',
66
            ],
67
            2 => [
68
                [
69
                    'filter' => new Criterion\LogicalOr(
70
                        [
71
                            new Criterion\ContentId(
72
                                [1, 4, 10]
73
                            ),
74
                            new Criterion\ContentId(
75
                                [4, 12]
76
                            ),
77
                        ]
78
                    ),
79
                    'sortClauses' => [new SortClause\ContentId()],
80
                ],
81
                $fixtureDir . 'LogicalOr.php',
82
            ],
83
            3 => [
84
                [
85
                    'filter' => new Criterion\LogicalAnd(
86
                        [
87
                            new Criterion\ContentId(
88
                                [1, 4, 10]
89
                            ),
90
                            new Criterion\LogicalNot(
91
                                new Criterion\ContentId(
92
                                    [10, 12]
93
                                )
94
                            ),
95
                        ]
96
                    ),
97
                    'sortClauses' => [new SortClause\ContentId()],
98
                ],
99
                $fixtureDir . 'LogicalNot.php',
100
            ],
101
            4 => [
102
                [
103
                    'filter' => new Criterion\LogicalAnd(
104
                        [
105
                            new Criterion\ContentId(
106
                                [1, 4, 10]
107
                            ),
108
                            new Criterion\LogicalAnd(
109
                                [
110
                                    new Criterion\LogicalNot(
111
                                        new Criterion\ContentId(
112
                                            [10, 12]
113
                                        )
114
                                    ),
115
                                ]
116
                            ),
117
                        ]
118
                    ),
119
                    'sortClauses' => [new SortClause\ContentId()],
120
                ],
121
                $fixtureDir . 'LogicalNot.php',
122
            ],
123
            5 => [
124
                [
125
                    'filter' => new Criterion\ContentTypeId(
126
                        4
127
                    ),
128
                    'sortClauses' => [new SortClause\ContentId()],
129
                ],
130
                $fixtureDir . 'ContentTypeId.php',
131
            ],
132
            6 => [
133
                [
134
                    'filter' => new Criterion\ContentTypeIdentifier(
135
                        'user'
136
                    ),
137
                    'sortClauses' => [new SortClause\ContentId()],
138
                ],
139
                $fixtureDir . 'ContentTypeId.php',
140
            ],
141
            7 => [
142
                [
143
                    'filter' => new Criterion\MatchNone(),
144
                    'sortClauses' => [new SortClause\ContentId()],
145
                ],
146
                $fixtureDir . 'MatchNone.php',
147
            ],
148
            8 => [
149
                [
150
                    'filter' => new Criterion\ContentTypeGroupId(
151
                        2
152
                    ),
153
                    'sortClauses' => [new SortClause\ContentId()],
154
                ],
155
                $fixtureDir . 'ContentTypeGroupId.php',
156
            ],
157
            9 => [
158
                [
159
                    'filter' => new Criterion\DateMetadata(
160
                        Criterion\DateMetadata::MODIFIED,
161
                        Criterion\Operator::GT,
162
                        1343140540
163
                    ),
164
                    'sortClauses' => [new SortClause\ContentId()],
165
                ],
166
                $fixtureDir . 'DateMetadataGt.php',
167
            ],
168
            10 => [
169
                [
170
                    'filter' => new Criterion\DateMetadata(
171
                        Criterion\DateMetadata::MODIFIED,
172
                        Criterion\Operator::GTE,
173
                        1311154215
174
                    ),
175
                    'sortClauses' => [new SortClause\ContentId()],
176
                ],
177
                $fixtureDir . 'DateMetadataGte.php',
178
            ],
179
            11 => [
180
                [
181
                    'filter' => new Criterion\DateMetadata(
182
                        Criterion\DateMetadata::MODIFIED,
183
                        Criterion\Operator::LTE,
184
                        1311154215
185
                    ),
186
                    'limit' => 10,
187
                    'sortClauses' => [new SortClause\ContentId()],
188
                ],
189
                $fixtureDir . 'DateMetadataLte.php',
190
            ],
191
            12 => [
192
                [
193
                    'filter' => new Criterion\DateMetadata(
194
                        Criterion\DateMetadata::MODIFIED,
195
                        Criterion\Operator::IN,
196
                        [1033920794, 1060695457, 1343140540]
197
                    ),
198
                    'sortClauses' => [new SortClause\ContentId()],
199
                ],
200
                $fixtureDir . 'DateMetadataIn.php',
201
            ],
202
            13 => [
203
                [
204
                    'filter' => new Criterion\DateMetadata(
205
                        Criterion\DateMetadata::MODIFIED,
206
                        Criterion\Operator::BETWEEN,
207
                        [1033920776, 1072180276]
208
                    ),
209
                    'sortClauses' => [new SortClause\ContentId()],
210
                ],
211
                $fixtureDir . 'DateMetadataBetween.php',
212
            ],
213
            14 => [
214
                [
215
                    'filter' => new Criterion\DateMetadata(
216
                        Criterion\DateMetadata::CREATED,
217
                        Criterion\Operator::BETWEEN,
218
                        [1033920776, 1072180278]
219
                    ),
220
                    'sortClauses' => [new SortClause\ContentId()],
221
                ],
222
                $fixtureDir . 'DateMetadataCreated.php',
223
            ],
224
            15 => [
225
                [
226
                    'filter' => new Criterion\CustomField(
227
                        'user_group_name_value_s',
228
                        Criterion\Operator::EQ,
229
                        'Members'
230
                    ),
231
                    'sortClauses' => [new SortClause\ContentId()],
232
                ],
233
                $fixtureDir . 'Field.php',
234
            ],
235
            16 => [
236
                [
237
                    'filter' => new Criterion\CustomField(
238
                        'user_group_name_value_s',
239
                        Criterion\Operator::CONTAINS,
240
                        'Members'
241
                    ),
242
                    'sortClauses' => [new SortClause\ContentId()],
243
                ],
244
                $fixtureDir . 'Field.php',
245
            ],
246
            17 => [
247
                [
248
                    'filter' => new Criterion\CustomField(
249
                        'user_group_name_value_s',
250
                        Criterion\Operator::LT,
251
                        'Members'
252
                    ),
253
                    'sortClauses' => [new SortClause\ContentId()],
254
                ],
255
                $fixtureDir . 'CustomFieldLt.php',
256
            ],
257
            18 => [
258
                [
259
                    'filter' => new Criterion\CustomField(
260
                        'user_group_name_value_s',
261
                        Criterion\Operator::LTE,
262
                        'Members'
263
                    ),
264
                    'sortClauses' => [new SortClause\ContentId()],
265
                ],
266
                $fixtureDir . 'CustomFieldLte.php',
267
            ],
268
            19 => [
269
                [
270
                    'filter' => new Criterion\CustomField(
271
                        'user_group_name_value_s',
272
                        Criterion\Operator::GT,
273
                        'Members'
274
                    ),
275
                    'sortClauses' => [new SortClause\ContentId()],
276
                ],
277
                $fixtureDir . 'CustomFieldGt.php',
278
            ],
279
            20 => [
280
                [
281
                    'filter' => new Criterion\CustomField(
282
                        'user_group_name_value_s',
283
                        Criterion\Operator::GTE,
284
                        'Members'
285
                    ),
286
                    'sortClauses' => [new SortClause\ContentId()],
287
                ],
288
                $fixtureDir . 'CustomFieldGte.php',
289
            ],
290
            21 => [
291
                [
292
                    'filter' => new Criterion\CustomField(
293
                        'user_group_name_value_s',
294
                        Criterion\Operator::BETWEEN,
295
                        ['Administrator users', 'Members']
296
                    ),
297
                    'sortClauses' => [new SortClause\ContentId()],
298
                ],
299
                $fixtureDir . 'CustomFieldBetween.php',
300
            ],
301
            22 => [
302
                [
303
                    'filter' => new Criterion\RemoteId(
304
                        ['f5c88a2209584891056f987fd965b0ba', 'faaeb9be3bd98ed09f606fc16d144eca']
305
                    ),
306
                    'sortClauses' => [new SortClause\ContentId()],
307
                ],
308
                $fixtureDir . 'RemoteId.php',
309
            ],
310
            23 => [
311
                [
312
                    'filter' => new Criterion\SectionId(
313
                        [2]
314
                    ),
315
                    'sortClauses' => [new SortClause\ContentId()],
316
                ],
317
                $fixtureDir . 'SectionId.php',
318
            ],
319
            24 => [
320
                [
321
                    'filter' => new Criterion\Field(
322
                        'name',
323
                        Criterion\Operator::EQ,
324
                        'Members'
325
                    ),
326
                    'sortClauses' => [new SortClause\ContentId()],
327
                ],
328
                $fixtureDir . 'Field.php',
329
            ],
330
            25 => [
331
                [
332
                    'filter' => new Criterion\Field(
333
                        'name',
334
                        Criterion\Operator::IN,
335
                        ['Members', 'Anonymous Users']
336
                    ),
337
                    'sortClauses' => [new SortClause\ContentId()],
338
                ],
339
                $fixtureDir . 'FieldIn.php',
340
            ],
341
            26 => [
342
                [
343
                    'filter' => new Criterion\DateMetadata(
344
                        Criterion\DateMetadata::MODIFIED,
345
                        Criterion\Operator::BETWEEN,
346
                        [1033920275, 1033920794]
347
                    ),
348
                    'sortClauses' => [new SortClause\ContentId()],
349
                ],
350
                $fixtureDir . 'FieldBetween.php',
351
            ],
352
            27 => [
353
                [
354
                    'filter' => new Criterion\LogicalOr(
355
                        [
356
                            new Criterion\Field(
357
                                'name',
358
                                Criterion\Operator::EQ,
359
                                'Members'
360
                            ),
361
                            new Criterion\DateMetadata(
362
                                Criterion\DateMetadata::MODIFIED,
363
                                Criterion\Operator::BETWEEN,
364
                                [1033920275, 1033920794]
365
                            ),
366
                        ]
367
                    ),
368
                    'sortClauses' => [new SortClause\ContentId()],
369
                ],
370
                $fixtureDir . 'FieldOr.php',
371
            ],
372
            28 => [
373
                [
374
                    'filter' => new Criterion\Subtree(
375
                        '/1/5/'
376
                    ),
377
                    'sortClauses' => [new SortClause\ContentId()],
378
                ],
379
                $fixtureDir . 'Subtree.php',
380
            ],
381
            29 => [
382
                [
383
                    'filter' => new Criterion\LocationId(
384
                        [1, 2, 5]
385
                    ),
386
                    'sortClauses' => [new SortClause\ContentId()],
387
                ],
388
                $fixtureDir . 'LocationId.php',
389
            ],
390
            30 => [
391
                [
392
                    'filter' => new Criterion\ParentLocationId(
393
                        [1]
394
                    ),
395
                    'sortClauses' => [new SortClause\ContentId()],
396
                ],
397
                $fixtureDir . 'ParentLocationId.php',
398
            ],
399
            31 => [
400
                [
401
                    'filter' => new Criterion\LocationRemoteId(
402
                        ['3f6d92f8044aed134f32153517850f5a', 'f3e90596361e31d496d4026eb624c983']
403
                    ),
404
                    'sortClauses' => [new SortClause\ContentId()],
405
                ],
406
                $fixtureDir . 'LocationRemoteId.php',
407
            ],
408
            32 => [
409
                [
410
                    // There is no Status Criterion anymore, this should match all published as well
411
                    'filter' => new Criterion\Subtree(
412
                        '/1/'
413
                    ),
414
                    'sortClauses' => [new SortClause\ContentId()],
415
                    'limit' => 50,
416
                ],
417
                $fixtureDir . 'Status.php',
418
                // Result having the same sort level should be sorted between them to be system independent
419
                function (&$data) {
420
                    usort(
421
                        $data->searchHits,
422
                        function ($a, $b) {
423
                            if ($a->score == $b->score) {
424
                                if ($a->valueObject['id'] == $b->valueObject['id']) {
425
                                    return 0;
426
                                }
427
428
                                // Order by ascending ID
429
                                return ($a->valueObject['id'] < $b->valueObject['id']) ? -1 : 1;
430
                            }
431
432
                            // Order by descending score
433
                            return ($a->score > $b->score) ? -1 : 1;
434
                        }
435
                    );
436
                },
437
            ],
438
            33 => [
439
                [
440
                    'filter' => new Criterion\UserMetadata(
441
                        Criterion\UserMetadata::MODIFIER,
442
                        Criterion\Operator::EQ,
443
                        14
444
                    ),
445
                    'sortClauses' => [
446
                        new SortClause\ContentId(),
447
                    ],
448
                    'limit' => 50,
449
                ],
450
                $fixtureDir . 'UserMetadata.php',
451
            ],
452
            34 => [
453
                [
454
                    'filter' => new Criterion\UserMetadata(
455
                        Criterion\UserMetadata::MODIFIER,
456
                        Criterion\Operator::IN,
457
                        [14]
458
                    ),
459
                    'sortClauses' => [
460
                        new SortClause\ContentId(),
461
                    ],
462
                    'limit' => 50,
463
                ],
464
                $fixtureDir . 'UserMetadata.php',
465
            ],
466
            35 => [
467
                [
468
                    'filter' => new Criterion\UserMetadata(
469
                        Criterion\UserMetadata::OWNER,
470
                        Criterion\Operator::EQ,
471
                        14
472
                    ),
473
                    'sortClauses' => [
474
                        new SortClause\ContentId(),
475
                    ],
476
                    'limit' => 50,
477
                ],
478
                $fixtureDir . 'UserMetadata.php',
479
            ],
480
            36 => [
481
                [
482
                    'filter' => new Criterion\UserMetadata(
483
                        Criterion\UserMetadata::OWNER,
484
                        Criterion\Operator::IN,
485
                        [14]
486
                    ),
487
                    'sortClauses' => [
488
                        new SortClause\ContentId(),
489
                    ],
490
                    'limit' => 50,
491
                ],
492
                $fixtureDir . 'UserMetadata.php',
493
            ],
494
            37 => [
495
                [
496
                    'filter' => new Criterion\UserMetadata(
497
                        Criterion\UserMetadata::GROUP,
498
                        Criterion\Operator::EQ,
499
                        12
500
                    ),
501
                    'sortClauses' => [
502
                        new SortClause\ContentId(),
503
                    ],
504
                    'limit' => 50,
505
                ],
506
                $fixtureDir . 'UserMetadata.php',
507
            ],
508
            38 => [
509
                [
510
                    'filter' => new Criterion\UserMetadata(
511
                        Criterion\UserMetadata::GROUP,
512
                        Criterion\Operator::IN,
513
                        [12]
514
                    ),
515
                    'sortClauses' => [
516
                        new SortClause\ContentId(),
517
                    ],
518
                    'limit' => 50,
519
                ],
520
                $fixtureDir . 'UserMetadata.php',
521
            ],
522
            39 => [
523
                [
524
                    'filter' => new Criterion\UserMetadata(
525
                        Criterion\UserMetadata::GROUP,
526
                        Criterion\Operator::EQ,
527
                        4
528
                    ),
529
                    'sortClauses' => [
530
                        new SortClause\ContentId(),
531
                    ],
532
                    'limit' => 50,
533
                ],
534
                $fixtureDir . 'UserMetadata.php',
535
            ],
536
            40 => [
537
                [
538
                    'filter' => new Criterion\UserMetadata(
539
                        Criterion\UserMetadata::GROUP,
540
                        Criterion\Operator::IN,
541
                        [4]
542
                    ),
543
                    'sortClauses' => [
544
                        new SortClause\ContentId(),
545
                    ],
546
                    'limit' => 50,
547
                ],
548
                $fixtureDir . 'UserMetadata.php',
549
            ],
550
            41 => [
551
                [
552
                    'filter' => new Criterion\Ancestor(
553
                        [
554
                            '/1/5/44/',
555
                            '/1/5/44/45/',
556
                        ]
557
                    ),
558
                    'sortClauses' => [
559
                        new SortClause\ContentId(),
560
                    ],
561
                    'limit' => 50,
562
                ],
563
                $fixtureDir . 'AncestorContent.php',
564
            ],
565
        ];
566
    }
567
568
    public function getContentQuerySearches()
569
    {
570
        $fixtureDir = $this->getFixtureDir();
571
572
        return [
573
            [
574
                [
575
                    'filter' => new Criterion\ContentId(
576
                        [58, 10]
577
                    ),
578
                    'query' => new Criterion\FullText('contact'),
579
                    'sortClauses' => [new SortClause\ContentId()],
580
                ],
581
                $fixtureDir . 'FullTextFiltered.php',
582
            ],
583
            [
584
                [
585
                    'query' => new Criterion\FullText(
586
                        'contact',
587
                        [
588
                            'boost' => [
589
                                'title' => 2,
590
                            ],
591
                            'fuzziness' => .5,
592
                        ]
593
                    ),
594
                    'sortClauses' => [new SortClause\ContentId()],
595
                ],
596
                $fixtureDir . 'FullText.php',
597
            ],
598
            [
599
                [
600
                    'query' => new Criterion\FullText(
601
                        'Contact*'
602
                    ),
603
                    'sortClauses' => [new SortClause\ContentId()],
604
                ],
605
                $fixtureDir . 'FullTextWildcard.php',
606
            ],
607
            [
608
                [
609
                    'query' => new Criterion\LanguageCode('eng-GB', false),
610
                    'sortClauses' => [new SortClause\ContentId()],
611
                ],
612
                $fixtureDir . 'LanguageCode.php',
613
            ],
614
            [
615
                [
616
                    'query' => new Criterion\LanguageCode(['eng-US', 'eng-GB']),
617
                    'offset' => 10,
618
                    'sortClauses' => [new SortClause\ContentId()],
619
                ],
620
                $fixtureDir . 'LanguageCodeIn.php',
621
            ],
622
            [
623
                [
624
                    'query' => new Criterion\LanguageCode('eng-GB'),
625
                    'offset' => 10,
626
                    'sortClauses' => [new SortClause\ContentId()],
627
                ],
628
                $fixtureDir . 'LanguageCodeAlwaysAvailable.php',
629
            ],
630
            [
631
                [
632
                    'query' => new Criterion\Visibility(
633
                        Criterion\Visibility::VISIBLE
634
                    ),
635
                    'sortClauses' => [new SortClause\ContentId()],
636
                    'limit' => 50,
637
                ],
638
                $fixtureDir . 'Visibility.php',
639
            ],
640
        ];
641
    }
642
643
    public function getLocationQuerySearches()
644
    {
645
        $fixtureDir = $this->getFixtureDir();
646
647
        return [
648
            [
649
                [
650
                    'query' => new Criterion\Location\Depth(Criterion\Operator::EQ, 1),
651
                    'sortClauses' => [new SortClause\ContentId()],
652
                ],
653
                $fixtureDir . 'Depth.php',
654
            ],
655
            [
656
                [
657
                    'query' => new Criterion\Location\Depth(Criterion\Operator::IN, [1, 3]),
658
                    'sortClauses' => [new SortClause\ContentId()],
659
                ],
660
                $fixtureDir . 'DepthIn.php',
661
            ],
662
            [
663
                [
664
                    'query' => new Criterion\Location\Depth(Criterion\Operator::GT, 2),
665
                    'sortClauses' => [new SortClause\ContentId()],
666
                ],
667
                $fixtureDir . 'DepthGt.php',
668
            ],
669
            [
670
                [
671
                    'query' => new Criterion\Location\Depth(Criterion\Operator::GTE, 2),
672
                    'sortClauses' => [new SortClause\ContentId()],
673
                    'limit' => 50,
674
                ],
675
                $fixtureDir . 'DepthGte.php',
676
            ],
677
            [
678
                [
679
                    'query' => new Criterion\Location\Depth(Criterion\Operator::LT, 2),
680
                    'sortClauses' => [new SortClause\ContentId()],
681
                ],
682
                $fixtureDir . 'Depth.php',
683
            ],
684
            [
685
                [
686
                    'query' => new Criterion\Location\Depth(Criterion\Operator::LTE, 2),
687
                    'sortClauses' => [new SortClause\ContentId()],
688
                    'limit' => 50,
689
                ],
690
                $fixtureDir . 'DepthLte.php',
691
            ],
692
            [
693
                [
694
                    'query' => new Criterion\Location\Depth(Criterion\Operator::BETWEEN, [1, 2]),
695
                    'sortClauses' => [new SortClause\ContentId()],
696
                    'limit' => 50,
697
                ],
698
                $fixtureDir . 'DepthLte.php',
699
            ],
700
            [
701
                [
702
                    'filter' => new Criterion\Ancestor('/1/5/44/45/'),
703
                    'sortClauses' => [
704
                        new SortClause\Location\Depth(),
705
                    ],
706
                    'limit' => 50,
707
                ],
708
                $fixtureDir . 'AncestorLocation.php',
709
            ],
710
        ];
711
    }
712
713
    /**
714
     * Test for the findContent() method.
715
     *
716
     * @dataProvider getFilterContentSearches
717
     *
718
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
719
     */
720
    public function testFindContentFiltered($queryData, $fixture, $closure = null)
721
    {
722
        $query = new Query($queryData);
723
        $this->assertQueryFixture($query, $fixture, $closure);
724
    }
725
726
    /**
727
     * Test for the findContentInfo() method.
728
     *
729
     * @dataProvider getFilterContentSearches
730
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
731
     */
732
    public function testFindContentInfoFiltered($queryData, $fixture, $closure = null)
733
    {
734
        $query = new Query($queryData);
735
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure($closure), true);
736
    }
737
738
    /**
739
     * Test for the findLocations() method.
740
     *
741
     * @dataProvider getFilterContentSearches
742
     *
743
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
744
     */
745
    public function testFindLocationsContentFiltered($queryData, $fixture, $closure = null)
746
    {
747
        $query = new LocationQuery($queryData);
748
        $this->assertQueryFixture($query, $fixture, $closure);
749
    }
750
751
    /**
752
     * Test for deprecated $criterion property on query object.
753
     *
754
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
755
     * @deprecated
756
     */
757
    public function testDeprecatedCriteriaProperty()
758
    {
759
        $this->assertQueryFixture(
760
            new Query(
761
                [
762
                    'query' => new Criterion\ContentId(
763
                        [1, 4, 10]
764
                    ),
765
                    'sortClauses' => [new SortClause\ContentId()],
766
                ]
767
            ),
768
            $this->getFixtureDir() . 'DeprecatedContentIdQuery.php'
769
        );
770
    }
771
772
    /**
773
     * Test for the findContent() method.
774
     *
775
     * @dataProvider getContentQuerySearches
776
     *
777
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
778
     */
779
    public function testQueryContent($queryData, $fixture, $closure = null)
780
    {
781
        $query = new Query($queryData);
782
        $this->assertQueryFixture($query, $fixture, $closure);
783
    }
784
785
    /**
786
     * Test for the findContentInfo() method.
787
     *
788
     * @dataProvider getContentQuerySearches
789
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
790
     */
791
    public function testQueryContentInfo($queryData, $fixture, $closure = null)
792
    {
793
        $query = new Query($queryData);
794
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure($closure), true);
795
    }
796
797
    /**
798
     * Test for the findLocations() method.
799
     *
800
     * @dataProvider getContentQuerySearches
801
     *
802
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
803
     */
804
    public function testQueryContentLocations($queryData, $fixture, $closure = null)
805
    {
806
        $query = new LocationQuery($queryData);
807
        $this->assertQueryFixture($query, $fixture, $closure);
808
    }
809
810
    /**
811
     * Test for the findLocations() method.
812
     *
813
     * @dataProvider getLocationQuerySearches
814
     *
815
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
816
     */
817
    public function testQueryLocations($queryData, $fixture, $closure = null)
818
    {
819
        $query = new LocationQuery($queryData);
820
        $this->assertQueryFixture($query, $fixture, $closure);
821
    }
822
823
    public function getCaseInsensitiveSearches()
824
    {
825
        return [
826
            [
827
                [
828
                    'filter' => new Criterion\Field(
829
                        'name',
830
                        Criterion\Operator::EQ,
831
                        'Members'
832
                    ),
833
                    'sortClauses' => [new SortClause\ContentId()],
834
                ],
835
            ],
836
            [
837
                [
838
                    'filter' => new Criterion\Field(
839
                        'name',
840
                        Criterion\Operator::EQ,
841
                        'members'
842
                    ),
843
                    'sortClauses' => [new SortClause\ContentId()],
844
                ],
845
            ],
846
            [
847
                [
848
                    'filter' => new Criterion\Field(
849
                        'name',
850
                        Criterion\Operator::EQ,
851
                        'MEMBERS'
852
                    ),
853
                    'sortClauses' => [new SortClause\ContentId()],
854
                ],
855
            ],
856
        ];
857
    }
858
859
    /**
860
     * Test for the findContent() method.
861
     *
862
     * @dataProvider getCaseInsensitiveSearches
863
     *
864
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
865
     */
866
    public function testFindContentFieldFiltersCaseSensitivity($queryData)
867
    {
868
        $query = new Query($queryData);
869
        $this->assertQueryFixture(
870
            $query,
871
            $this->getFixtureDir() . 'Field.php'
872
        );
873
    }
874
875
    /**
876
     * Test for the findLocations() method.
877
     *
878
     * @dataProvider getCaseInsensitiveSearches
879
     *
880
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
881
     */
882
    public function testFindLocationsFieldFiltersCaseSensitivity($queryData)
883
    {
884
        $query = new LocationQuery($queryData);
885
        $this->assertQueryFixture(
886
            $query,
887
            $this->getFixtureDir() . 'Field.php'
888
        );
889
    }
890
891
    public function getRelationFieldFilterSearches()
892
    {
893
        $fixtureDir = $this->getFixtureDir();
894
895
        return [
896
            0 => [
897
                [
898
                    'filter' => new Criterion\FieldRelation(
899
                        'image',
900
                        Criterion\Operator::IN,
901
                        [1, 4, 10]
902
                    ),
903
                    'sortClauses' => [new SortClause\ContentId()],
904
                ],
905
                $fixtureDir . 'FieldRelation.php',
906
            ],
907
            1 => [
908
                [
909
                    'filter' => new Criterion\FieldRelation(
910
                        'image',
911
                        Criterion\Operator::IN,
912
                        [4, 49]
913
                    ),
914
                    'sortClauses' => [new SortClause\ContentId()],
915
                ],
916
                $fixtureDir . 'FieldRelationAll.php',
917
            ],
918
            2 => [
919
                [
920
                    'filter' => new Criterion\FieldRelation(
921
                        'image',
922
                        Criterion\Operator::IN,
923
                        [4]
924
                    ),
925
                    'sortClauses' => [new SortClause\ContentId()],
926
                ],
927
                $fixtureDir . 'FieldRelation.php',
928
            ],
929
            3 => [
930
                [
931
                    'filter' => new Criterion\FieldRelation(
932
                        'image',
933
                        Criterion\Operator::CONTAINS,
934
                        [1, 4, 10]
935
                    ),
936
                    'sortClauses' => [new SortClause\ContentId()],
937
                ],
938
                $fixtureDir . 'MatchNone.php',
939
            ],
940
            4 => [
941
                [
942
                    'filter' => new Criterion\FieldRelation(
943
                        'image',
944
                        Criterion\Operator::CONTAINS,
945
                        [4, 49]
946
                    ),
947
                    'sortClauses' => [new SortClause\ContentId()],
948
                ],
949
                $fixtureDir . 'MatchNone.php',
950
            ],
951
            5 => [
952
                [
953
                    'filter' => new Criterion\FieldRelation(
954
                        'image',
955
                        Criterion\Operator::CONTAINS,
956
                        [4]
957
                    ),
958
                    'sortClauses' => [new SortClause\ContentId()],
959
                ],
960
                $fixtureDir . 'FieldRelation.php',
961
            ],
962
        ];
963
    }
964
965
    /**
966
     * Purely for creating relation data needed for testFindRelationFieldContentInfoFiltered()
967
     * and testFindRelationFieldLocationsFiltered().
968
     */
969
    public function testRelationContentCreation()
970
    {
971
        $repository = $this->getRepository();
972
        $galleryType = $repository->getContentTypeService()->loadContentTypeByIdentifier('gallery');
973
        $contentService = $repository->getContentService();
974
        $locationService = $repository->getLocationService();
975
976
        $locationCreateStruct = $locationService->newLocationCreateStruct(2); // Home
977
978
        $createStruct = $contentService->newContentCreateStruct($galleryType, 'eng-GB');
979
        $createStruct->setField('name', 'Image gallery');
980
        $createStruct->setField('image', 49); // Images folder
981
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
982
        $contentService->publishVersion($draft->getVersionInfo());
983
984
        $createStruct = $contentService->newContentCreateStruct($galleryType, 'eng-GB');
985
        $createStruct->setField('name', 'User gallery');
986
        $createStruct->setField('image', 4); // User folder
987
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
988
        $contentService->publishVersion($draft->getVersionInfo());
989
990
        $this->refreshSearch($repository);
991
    }
992
993
    /**
994
     * Test for FieldRelation using findContentInfo() method.
995
     *
996
     * @dataProvider getRelationFieldFilterSearches
997
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
998
     * @depends eZ\Publish\API\Repository\Tests\SearchServiceTest::testRelationContentCreation
999
     */
1000
    public function testFindRelationFieldContentInfoFiltered($queryData, $fixture)
1001
    {
1002
        $this->getRepository(false); // To make sure repo is setup w/o removing data from getRelationFieldFilterContentSearches
1003
        $query = new Query($queryData);
1004
        $this->assertQueryFixture($query, $fixture, null, true, true, false);
1005
    }
1006
1007
    /**
1008
     * Test for FieldRelation using findLocations() method.
1009
     *
1010
     * @dataProvider getRelationFieldFilterSearches
1011
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
1012
     * @depends eZ\Publish\API\Repository\Tests\SearchServiceTest::testRelationContentCreation
1013
     */
1014
    public function testFindRelationFieldLocationsFiltered($queryData, $fixture)
1015
    {
1016
        $this->getRepository(false); // To make sure repo is setup w/o removing data from getRelationFieldFilterContentSearches
1017
        $query = new LocationQuery($queryData);
1018
        $this->assertQueryFixture($query, $fixture, null, true, false, false);
1019
    }
1020
1021 View Code Duplication
    public function testFindSingle()
1022
    {
1023
        $repository = $this->getRepository();
1024
        $searchService = $repository->getSearchService();
1025
1026
        $content = $searchService->findSingle(
1027
            new Criterion\ContentId(
1028
                [4]
1029
            )
1030
        );
1031
1032
        $this->assertEquals(
1033
            4,
1034
            $content->id
1035
        );
1036
    }
1037
1038 View Code Duplication
    public function testFindNoPerformCount()
1039
    {
1040
        $repository = $this->getRepository();
1041
        $searchService = $repository->getSearchService();
1042
1043
        $query = new Query();
1044
        $query->performCount = false;
1045
        $query->query = new Criterion\ContentTypeId(
1046
            [4]
1047
        );
1048
1049
        $searchHit = $searchService->findContent($query);
1050
1051
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1052
            $this->assertNull(
1053
                $searchHit->totalCount
1054
            );
1055
        } else {
1056
            $this->assertEquals(
1057
                2,
1058
                $searchHit->totalCount
1059
            );
1060
        }
1061
    }
1062
1063
    /**
1064
     * @expectedException \RuntimeException
1065
     */
1066 View Code Duplication
    public function testFindNoPerformCountException()
1067
    {
1068
        if (ltrim(get_class($this->getSetupFactory()), '\\') !== 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1069
            $this->markTestSkipped('Only applicable to Legacy/DB based search');
1070
        }
1071
1072
        $repository = $this->getRepository();
1073
        $searchService = $repository->getSearchService();
1074
1075
        $query = new Query();
1076
        $query->performCount = false;
1077
        $query->limit = 0;
1078
        $query->query = new Criterion\ContentTypeId(
1079
            [4]
1080
        );
1081
1082
        $searchService->findContent($query);
1083
    }
1084
1085 View Code Duplication
    public function testFindLocationsNoPerformCount()
1086
    {
1087
        $repository = $this->getRepository();
1088
        $searchService = $repository->getSearchService();
1089
1090
        $query = new LocationQuery();
1091
        $query->performCount = false;
1092
        $query->query = new Criterion\ContentTypeId(
1093
            [4]
1094
        );
1095
1096
        $searchHit = $searchService->findLocations($query);
1097
1098
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1099
            $this->assertNull(
1100
                $searchHit->totalCount
1101
            );
1102
        } else {
1103
            $this->assertEquals(
1104
                2,
1105
                $searchHit->totalCount
1106
            );
1107
        }
1108
    }
1109
1110
    /**
1111
     * @expectedException \RuntimeException
1112
     */
1113 View Code Duplication
    public function testFindLocationsNoPerformCountException()
1114
    {
1115
        if (ltrim(get_class($this->getSetupFactory()), '\\') !== 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
1116
            $this->markTestSkipped('Only applicable to Legacy/DB based search');
1117
        }
1118
1119
        $repository = $this->getRepository();
1120
        $searchService = $repository->getSearchService();
1121
1122
        $query = new LocationQuery();
1123
        $query->performCount = false;
1124
        $query->limit = 0;
1125
        $query->query = new Criterion\ContentTypeId(
1126
            [4]
1127
        );
1128
1129
        $searchService->findLocations($query);
1130
    }
1131
1132
    /**
1133
     * Create movie Content with subtitle field set to null.
1134
     *
1135
     * @return \eZ\Publish\API\Repository\Values\Content\Content[]
1136
     */
1137
    protected function createMovieContent()
1138
    {
1139
        $movies = [];
1140
1141
        $repository = $this->getRepository();
1142
        $contentTypeService = $repository->getContentTypeService();
1143
        $contentService = $repository->getContentService();
1144
1145
        $createStruct = $contentTypeService->newContentTypeCreateStruct('movie');
1146
        $createStruct->mainLanguageCode = 'eng-GB';
1147
        $createStruct->remoteId = 'movie-123';
1148
        $createStruct->names = ['eng-GB' => 'Movie'];
1149
        $createStruct->creatorId = 14;
1150
        $createStruct->creationDate = new \DateTime();
1151
1152
        $fieldTitle = $contentTypeService->newFieldDefinitionCreateStruct('title', 'ezstring');
1153
        $fieldTitle->names = ['eng-GB' => 'Title'];
1154
        $fieldTitle->fieldGroup = 'main';
1155
        $fieldTitle->position = 1;
1156
        $fieldTitle->isTranslatable = false;
1157
        $fieldTitle->isSearchable = true;
1158
        $fieldTitle->isRequired = true;
1159
        $createStruct->addFieldDefinition($fieldTitle);
1160
1161
        $fieldSubtitle = $contentTypeService->newFieldDefinitionCreateStruct('subtitle', 'ezstring');
1162
        $fieldSubtitle->names = ['eng-GB' => 'Subtitle'];
1163
        $fieldSubtitle->fieldGroup = 'main';
1164
        $fieldSubtitle->position = 2;
1165
        $fieldSubtitle->isTranslatable = false;
1166
        $fieldSubtitle->isSearchable = true;
1167
        $fieldSubtitle->isRequired = false;
1168
        $createStruct->addFieldDefinition($fieldSubtitle);
1169
1170
        $contentTypeGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
1171
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentTypeGroup]);
1172
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
1173
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
1174
1175
        $createStructRambo = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1176
        $createStructRambo->remoteId = 'movie-456';
1177
        $createStructRambo->alwaysAvailable = false;
1178
        $createStructRambo->setField('title', 'Rambo');
1179
1180
        $ramboDraft = $contentService->createContent($createStructRambo);
1181
        $movies[] = $contentService->publishVersion($ramboDraft->getVersionInfo());
1182
        $this->refreshSearch($repository);
1183
        $createStructRobocop = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1184
        $createStructRobocop->remoteId = 'movie-789';
1185
        $createStructRobocop->alwaysAvailable = false;
1186
        $createStructRobocop->setField('title', 'Robocop');
1187
        $createStructRobocop->setField('subtitle', '');
1188
1189
        $robocopDraft = $contentService->createContent($createStructRobocop);
1190
        $movies[] = $contentService->publishVersion($robocopDraft->getVersionInfo());
1191
        $this->refreshSearch($repository);
1192
        $createStructLastHope = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1193
        $createStructLastHope->remoteId = 'movie-101112';
1194
        $createStructLastHope->alwaysAvailable = false;
1195
        $createStructLastHope->setField('title', 'Star Wars');
1196
        $createStructLastHope->setField('subtitle', 'Last Hope');
1197
1198
        $lastHopeDraft = $contentService->createContent($createStructLastHope);
1199
        $movies[] = $contentService->publishVersion($lastHopeDraft->getVersionInfo());
1200
1201
        $this->refreshSearch($repository);
1202
1203
        return $movies;
1204
    }
1205
1206
    /**
1207
     * Create test Content with ezcountry field having multiple countries selected.
1208
     *
1209
     * @return \eZ\Publish\API\Repository\Values\Content\Content[]
1210
     */
1211
    protected function createMultipleCountriesContent()
1212
    {
1213
        $repository = $this->getRepository();
1214
        $contentTypeService = $repository->getContentTypeService();
1215
        $contentService = $repository->getContentService();
1216
1217
        $createStruct = $contentTypeService->newContentTypeCreateStruct('countries-multiple');
1218
        $createStruct->mainLanguageCode = 'eng-GB';
1219
        $createStruct->remoteId = 'countries-multiple-123';
1220
        $createStruct->names = ['eng-GB' => 'Multiple countries'];
1221
        $createStruct->creatorId = 14;
1222
        $createStruct->creationDate = new \DateTime();
1223
1224
        $fieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('countries', 'ezcountry');
1225
        $fieldCreate->names = ['eng-GB' => 'Countries'];
1226
        $fieldCreate->fieldGroup = 'main';
1227
        $fieldCreate->position = 1;
1228
        $fieldCreate->isTranslatable = false;
1229
        $fieldCreate->isSearchable = true;
1230
        $fieldCreate->fieldSettings = ['isMultiple' => true];
1231
1232
        $createStruct->addFieldDefinition($fieldCreate);
1233
1234
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
1235
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
1236
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
1237
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
1238
1239
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1240
        $createStruct->remoteId = 'countries-multiple-456';
1241
        $createStruct->alwaysAvailable = false;
1242
        $createStruct->setField(
1243
            'countries',
1244
            ['BE', 'DE', 'FR', 'HR', 'NO', 'PT', 'RU']
1245
        );
1246
1247
        $draft = $contentService->createContent($createStruct);
1248
        $content = $contentService->publishVersion($draft->getVersionInfo());
1249
1250
        $this->refreshSearch($repository);
1251
1252
        return $content;
1253
    }
1254
1255
    /**
1256
     * Test for the findContent() method.
1257
     *
1258
     * @return \eZ\Publish\API\Repository\Values\Content\Content[]
1259
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
1260
     */
1261
    public function testFieldIsEmpty()
1262
    {
1263
        $testContents = $this->createMovieContent();
1264
1265
        $query = new Query(
1266
            [
1267
                'query' => new Criterion\IsFieldEmpty('subtitle'),
1268
            ]
1269
        );
1270
1271
        $repository = $this->getRepository();
1272
        $searchService = $repository->getSearchService();
1273
        $result = $searchService->findContent($query, ['eng-GB']);
1274
1275
        $this->assertEquals(2, $result->totalCount);
1276
1277
        $this->assertEquals(
1278
            $testContents[0]->id,
1279
            $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...
1280
        );
1281
        $this->assertEquals(
1282
            $testContents[1]->id,
1283
            $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...
1284
        );
1285
1286
        return $testContents;
1287
    }
1288
1289
    /**
1290
     * Test for the findContent() method.
1291
     *
1292
     * @param \eZ\Publish\API\Repository\Values\Content\Content[]
1293
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
1294
     * @depends \eZ\Publish\API\Repository\Tests\SearchServiceTest::testFieldIsEmpty
1295
     */
1296
    public function testFieldIsNotEmpty(array $testContents)
1297
    {
1298
        $query = new Query(
1299
            [
1300
                'query' => new Criterion\IsFieldEmpty(
1301
                    'subtitle',
1302
                    false
1303
                ),
1304
            ]
1305
        );
1306
1307
        $repository = $this->getRepository();
1308
        $searchService = $repository->getSearchService();
1309
        $result = $searchService->findContent($query, ['eng-GB']);
1310
1311
        $this->assertEquals(1, $result->totalCount);
1312
        $this->assertEquals(
1313
            $testContents[2]->id,
1314
            $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...
1315
        );
1316
    }
1317
1318
    /**
1319
     * Test for the findContent() method.
1320
     *
1321
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
1322
     */
1323 View Code Duplication
    public function testFieldCollectionContains()
1324
    {
1325
        $testContent = $this->createMultipleCountriesContent();
1326
1327
        $query = new Query(
1328
            [
1329
                'query' => new Criterion\Field(
1330
                    'countries',
1331
                    Criterion\Operator::CONTAINS,
1332
                    'Belgium'
1333
                ),
1334
            ]
1335
        );
1336
1337
        $repository = $this->getRepository();
1338
        $searchService = $repository->getSearchService();
1339
        $result = $searchService->findContent($query);
1340
1341
        $this->assertEquals(1, $result->totalCount);
1342
        $this->assertEquals(
1343
            $testContent->id,
1344
            $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...
1345
        );
1346
    }
1347
1348
    /**
1349
     * Test for the findContent() method.
1350
     *
1351
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
1352
     * @depends eZ\Publish\API\Repository\Tests\SearchServiceTest::testFieldCollectionContains
1353
     */
1354 View Code Duplication
    public function testFieldCollectionContainsNoMatch()
1355
    {
1356
        $this->createMultipleCountriesContent();
1357
        $query = new Query(
1358
            [
1359
                'query' => new Criterion\Field(
1360
                    'countries',
1361
                    Criterion\Operator::CONTAINS,
1362
                    'Netherlands Antilles'
1363
                ),
1364
            ]
1365
        );
1366
1367
        $repository = $this->getRepository();
1368
        $searchService = $repository->getSearchService();
1369
        $result = $searchService->findContent($query);
1370
1371
        $this->assertEquals(0, $result->totalCount);
1372
    }
1373
1374
    /**
1375
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1376
     * @expectedExceptionMessage Argument '$criterion->target' is invalid: No searchable fields found for the given criterion target 'some_hopefully_unknown_field'
1377
     */
1378 View Code Duplication
    public function testInvalidFieldIdentifierRange()
1379
    {
1380
        $repository = $this->getRepository();
1381
        $searchService = $repository->getSearchService();
1382
1383
        $searchService->findContent(
1384
            new Query(
1385
                [
1386
                    'filter' => new Criterion\Field(
1387
                        'some_hopefully_unknown_field',
1388
                        Criterion\Operator::BETWEEN,
1389
                        [10, 1000]
1390
                    ),
1391
                    'sortClauses' => [new SortClause\ContentId()],
1392
                ]
1393
            )
1394
        );
1395
    }
1396
1397
    /**
1398
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1399
     * @expectedExceptionMessage Argument '$criterion->target' is invalid: No searchable fields found for the given criterion target 'some_hopefully_unknown_field'
1400
     */
1401 View Code Duplication
    public function testInvalidFieldIdentifierIn()
1402
    {
1403
        $repository = $this->getRepository();
1404
        $searchService = $repository->getSearchService();
1405
1406
        $searchService->findContent(
1407
            new Query(
1408
                [
1409
                    'filter' => new Criterion\Field(
1410
                        'some_hopefully_unknown_field',
1411
                        Criterion\Operator::EQ,
1412
                        1000
1413
                    ),
1414
                    'sortClauses' => [new SortClause\ContentId()],
1415
                ]
1416
            )
1417
        );
1418
    }
1419
1420
    /**
1421
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1422
     * @expectedExceptionMessage Argument '$criterion->target' is invalid: No searchable fields found for the given criterion target 'tag_cloud_url'
1423
     */
1424 View Code Duplication
    public function testFindContentWithNonSearchableField()
1425
    {
1426
        $repository = $this->getRepository();
1427
        $searchService = $repository->getSearchService();
1428
1429
        $searchService->findContent(
1430
            new Query(
1431
                [
1432
                    'filter' => new Criterion\Field(
1433
                        'tag_cloud_url',
1434
                        Criterion\Operator::EQ,
1435
                        'http://nimbus.com'
1436
                    ),
1437
                    'sortClauses' => [new SortClause\ContentId()],
1438
                ]
1439
            )
1440
        );
1441
    }
1442
1443
    /**
1444
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1445
     * @expectedExceptionMessage Argument '$sortClause->targetData' is invalid: No searchable fields found for the given sort clause target 'title' on 'template_look'
1446
     */
1447 View Code Duplication
    public function testSortFieldWithNonSearchableField()
1448
    {
1449
        $repository = $this->getRepository();
1450
        $searchService = $repository->getSearchService();
1451
1452
        $searchService->findContent(
1453
            new Query(
1454
                [
1455
                    'sortClauses' => [new SortClause\Field('template_look', 'title')],
1456
                ]
1457
            )
1458
        );
1459
    }
1460
1461
    /**
1462
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1463
     * @expectedExceptionMessage Argument '$sortClause->targetData' is invalid: No searchable fields found for the given sort clause target 'title' on 'template_look'
1464
     */
1465 View Code Duplication
    public function testSortMapLocationDistanceWithNonSearchableField()
1466
    {
1467
        $repository = $this->getRepository();
1468
        $searchService = $repository->getSearchService();
1469
1470
        $searchService->findContent(
1471
            new Query(
1472
                [
1473
                    'sortClauses' => [
1474
                        new SortClause\MapLocationDistance(
1475
                            'template_look',
1476
                            'title',
1477
                            1,
1478
                            2
1479
                        ),
1480
                    ],
1481
                ]
1482
            )
1483
        );
1484
    }
1485
1486
    /**
1487
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1488
     */
1489 View Code Duplication
    public function testFindSingleFailMultiple()
1490
    {
1491
        $repository = $this->getRepository();
1492
        $searchService = $repository->getSearchService();
1493
1494
        $searchService->findSingle(
1495
            new Criterion\ContentId(
1496
                [4, 10]
1497
            )
1498
        );
1499
    }
1500
1501
    /**
1502
     * @expectedException \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
1503
     */
1504
    public function testFindSingleWithNonSearchableField()
1505
    {
1506
        $repository = $this->getRepository();
1507
        $searchService = $repository->getSearchService();
1508
1509
        $searchService->findSingle(
1510
            new Criterion\Field(
1511
                'tag_cloud_url',
1512
                Criterion\Operator::EQ,
1513
                'http://nimbus.com'
1514
            )
1515
        );
1516
    }
1517
1518
    public function getSortedContentSearches()
1519
    {
1520
        $fixtureDir = $this->getFixtureDir();
1521
1522
        return [
1523
            0 => [
1524
                [
1525
                    'filter' => new Criterion\SectionId([2]),
1526
                    'offset' => 0,
1527
                    'limit' => 10,
1528
                    'sortClauses' => [],
1529
                ],
1530
                $fixtureDir . 'SortNone.php',
1531
                // Result having the same sort level should be sorted between them to be system independent
1532
                function (&$data) {
1533
                    usort(
1534
                        $data->searchHits,
1535
                        function ($a, $b) {
1536
                            return ($a->valueObject['id'] < $b->valueObject['id']) ? -1 : 1;
1537
                        }
1538
                    );
1539
                },
1540
            ],
1541
            1 => [
1542
                [
1543
                    'filter' => new Criterion\SectionId([2]),
1544
                    'offset' => 0,
1545
                    'limit' => 10,
1546
                    'sortClauses' => [
1547
                        new SortClause\DatePublished(),
1548
                        new SortClause\ContentId(),
1549
                    ],
1550
                ],
1551
                $fixtureDir . 'SortDatePublished.php',
1552
            ],
1553
            2 => [
1554
                [
1555
                    'filter' => new Criterion\SectionId([2]),
1556
                    'offset' => 0,
1557
                    'limit' => 50,
1558
                    'sortClauses' => [
1559
                        new SortClause\DateModified(),
1560
                        new SortClause\ContentId(),
1561
                    ],
1562
                ],
1563
                $fixtureDir . 'SortDateModified.php',
1564
            ],
1565
            3 => [
1566
                [
1567
                    'filter' => new Criterion\SectionId([4, 2, 6, 3]),
1568
                    'offset' => 0,
1569
                    'limit' => 50,
1570
                    'sortClauses' => [
1571
                        new SortClause\SectionIdentifier(),
1572
                        new SortClause\ContentId(),
1573
                    ],
1574
                ],
1575
                $fixtureDir . 'SortSectionIdentifier.php',
1576
            ],
1577
            4 => [
1578
                [
1579
                    'filter' => new Criterion\SectionId([4, 2, 6, 3]),
1580
                    'offset' => 0,
1581
                    'limit' => 50,
1582
                    'sortClauses' => [
1583
                        new SortClause\SectionName(),
1584
                        new SortClause\ContentId(),
1585
                    ],
1586
                ],
1587
                $fixtureDir . 'SortSectionName.php',
1588
            ],
1589
            5 => [
1590
                [
1591
                    'filter' => new Criterion\SectionId([2, 3]),
1592
                    'offset' => 0,
1593
                    'limit' => 50,
1594
                    'sortClauses' => [
1595
                        new SortClause\ContentName(),
1596
                        new SortClause\ContentId(),
1597
                    ],
1598
                ],
1599
                $fixtureDir . 'SortContentName.php',
1600
            ],
1601
            6 => [
1602
                [
1603
                    'filter' => new Criterion\ContentTypeId(1),
1604
                    'offset' => 0,
1605
                    'limit' => 50,
1606
                    'sortClauses' => [
1607
                        new SortClause\Field('folder', 'name', Query::SORT_ASC),
1608
                        new SortClause\ContentId(),
1609
                    ],
1610
                ],
1611
                $fixtureDir . 'SortFolderName.php',
1612
            ],
1613
            7 => [
1614
                [
1615
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1616
                    'offset' => 0,
1617
                    'limit' => 50,
1618
                    'sortClauses' => [
1619
                        new SortClause\Field('folder', 'name', Query::SORT_ASC),
1620
                        new SortClause\ContentId(),
1621
                    ],
1622
                ],
1623
                $fixtureDir . 'SortFieldMultipleTypes.php',
1624
            ],
1625
            8 => [
1626
                [
1627
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1628
                    'offset' => 0,
1629
                    'limit' => 50,
1630
                    'sortClauses' => [
1631
                        new SortClause\Field('folder', 'name', Query::SORT_DESC),
1632
                        new SortClause\ContentId(),
1633
                    ],
1634
                ],
1635
                $fixtureDir . 'SortFieldMultipleTypesReverse.php',
1636
            ],
1637
            9 => [
1638
                [
1639
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1640
                    'offset' => 3,
1641
                    'limit' => 5,
1642
                    'sortClauses' => [
1643
                        new SortClause\Field('folder', 'name', Query::SORT_ASC),
1644
                        new SortClause\Field('user', 'first_name', Query::SORT_ASC),
1645
                        new SortClause\ContentId(),
1646
                    ],
1647
                ],
1648
                $fixtureDir . 'SortFieldMultipleTypesSlice.php',
1649
            ],
1650
            10 => [
1651
                [
1652
                    'filter' => new Criterion\ContentTypeId([1, 3]),
1653
                    'offset' => 3,
1654
                    'limit' => 5,
1655
                    'sortClauses' => [
1656
                        new SortClause\Field('folder', 'name', Query::SORT_DESC),
1657
                        new SortClause\Field('user', 'first_name', Query::SORT_ASC),
1658
                        new SortClause\ContentId(),
1659
                    ],
1660
                ],
1661
                $fixtureDir . 'SortFieldMultipleTypesSliceReverse.php',
1662
            ],
1663
        ];
1664
    }
1665
1666
    public function getSortedLocationSearches()
1667
    {
1668
        $fixtureDir = $this->getFixtureDir();
1669
1670
        return [
1671
            [
1672
                [
1673
                    'filter' => new Criterion\SectionId([2]),
1674
                    'offset' => 0,
1675
                    'limit' => 10,
1676
                    'sortClauses' => [new SortClause\Location\Path(Query::SORT_DESC)],
1677
                ],
1678
                $fixtureDir . 'SortPathString.php',
1679
            ],
1680
            [
1681
                [
1682
                    'filter' => new Criterion\SectionId([2]),
1683
                    'offset' => 0,
1684
                    'limit' => 10,
1685
                    'sortClauses' => [new SortClause\Location\Depth(Query::SORT_ASC)],
1686
                ],
1687
                $fixtureDir . 'SortLocationDepth.php',
1688
                // Result having the same sort level should be sorted between them to be system independent
1689
                function (&$data) {
1690
                    // Result with ids:
1691
                    //     4 has depth = 1
1692
                    //     11, 12, 13, 42, 59 have depth = 2
1693
                    //     10, 14 have depth = 3
1694
                    $map = [
1695
                        4 => 0,
1696
                        11 => 1,
1697
                        12 => 2,
1698
                        13 => 3,
1699
                        42 => 4,
1700
                        59 => 5,
1701
                        10 => 6,
1702
                        14 => 7,
1703
                    ];
1704
                    usort(
1705
                        $data->searchHits,
1706
                        function ($a, $b) use ($map) {
1707
                            return ($map[$a->valueObject['id']] < $map[$b->valueObject['id']]) ? -1 : 1;
1708
                        }
1709
                    );
1710
                },
1711
            ],
1712
            [
1713
                [
1714
                    'filter' => new Criterion\SectionId([3]),
1715
                    'offset' => 0,
1716
                    'limit' => 10,
1717
                    'sortClauses' => [
1718
                        new SortClause\Location\Path(Query::SORT_DESC),
1719
                        new SortClause\ContentName(Query::SORT_ASC),
1720
                    ],
1721
                ],
1722
                $fixtureDir . 'SortMultiple.php',
1723
            ],
1724
            [
1725
                [
1726
                    'filter' => new Criterion\SectionId([2]),
1727
                    'offset' => 0,
1728
                    'limit' => 10,
1729
                    'sortClauses' => [
1730
                        new SortClause\Location\Priority(Query::SORT_DESC),
1731
                        new SortClause\ContentId(),
1732
                    ],
1733
                ],
1734
                $fixtureDir . 'SortDesc.php',
1735
            ],
1736
        ];
1737
    }
1738
1739
    /**
1740
     * @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
1741
     */
1742 View Code Duplication
    protected function createTestContentType()
1743
    {
1744
        $repository = $this->getRepository();
1745
        $contentTypeService = $repository->getContentTypeService();
1746
1747
        $createStruct = $contentTypeService->newContentTypeCreateStruct('test-type');
1748
        $createStruct->mainLanguageCode = 'eng-GB';
1749
        $createStruct->names = ['eng-GB' => 'Test type'];
1750
        $createStruct->creatorId = 14;
1751
        $createStruct->creationDate = new \DateTime();
1752
1753
        $translatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('integer', 'ezinteger');
1754
        $translatableFieldCreate->names = ['eng-GB' => 'Simple translatable integer field'];
1755
        $translatableFieldCreate->fieldGroup = 'main';
1756
        $translatableFieldCreate->position = 1;
1757
        $translatableFieldCreate->isTranslatable = true;
1758
        $translatableFieldCreate->isSearchable = true;
1759
1760
        $createStruct->addFieldDefinition($translatableFieldCreate);
1761
1762
        $nonTranslatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('integer2', 'ezinteger');
1763
        $nonTranslatableFieldCreate->names = ['eng-GB' => 'Simple non-translatable integer field'];
1764
        $nonTranslatableFieldCreate->fieldGroup = 'main';
1765
        $nonTranslatableFieldCreate->position = 2;
1766
        $nonTranslatableFieldCreate->isTranslatable = false;
1767
        $nonTranslatableFieldCreate->isSearchable = true;
1768
1769
        $createStruct->addFieldDefinition($nonTranslatableFieldCreate);
1770
1771
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
1772
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
1773
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
1774
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
1775
1776
        return $contentType;
1777
    }
1778
1779
    /**
1780
     * @param \eZ\Publish\API\Repository\Values\ContentType\ContentType $contentType
1781
     * @param int $fieldValue11 Value for translatable field in first language
1782
     * @param int $fieldValue12 Value for translatable field in second language
1783
     * @param int $fieldValue2 Value for non translatable field
1784
     * @param string $mainLanguageCode
1785
     * @param bool $alwaysAvailable
1786
     *
1787
     * @return Content
1788
     */
1789
    protected function createMultilingualContent(
1790
        $contentType,
1791
        $fieldValue11 = null,
1792
        $fieldValue12 = null,
1793
        $fieldValue2 = null,
1794
        $mainLanguageCode = 'eng-GB',
1795
        $alwaysAvailable = false
1796
    ) {
1797
        $repository = $this->getRepository();
1798
        $contentService = $repository->getContentService();
1799
1800
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
1801
        $createStruct->alwaysAvailable = $alwaysAvailable;
1802
        $createStruct->mainLanguageCode = $mainLanguageCode;
1803
        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...
1804
            $createStruct->setField('integer', $fieldValue11, 'eng-GB');
1805
        }
1806
        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...
1807
            $createStruct->setField('integer', $fieldValue12, 'ger-DE');
1808
        }
1809
        $createStruct->setField('integer2', $fieldValue2, $mainLanguageCode);
1810
1811
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
1812
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
1813
        $content = $contentService->publishVersion($draft->getVersionInfo());
1814
1815
        $this->refreshSearch($repository);
1816
1817
        return $content;
1818
    }
1819
1820
    protected function checkPrioritizedLanguagesSupport()
1821
    {
1822
        $setupFactory = $this->getSetupFactory();
1823
        if ($setupFactory instanceof LegacyElasticsearch) {
1824
            $this->markTestIncomplete('Prioritized languages are not supported with Elasticsearch engine');
1825
        }
1826
    }
1827
1828
    public function providerForTestMultilingualFieldSort()
1829
    {
1830
        return [
1831
            0 => [
1832
                [
1833
                    1 => [1, 2, 1],
1834
                    2 => [2, 1, 2],
1835
                    3 => [2, 1, 3],
1836
                    4 => [1, 2, 4],
1837
                ],
1838
                [
1839
                    'languages' => [
1840
                        'eng-GB',
1841
                        'ger-DE',
1842
                    ],
1843
                ],
1844
                [
1845
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
1846
                    new SortClause\Field('test-type', 'integer2', Query::SORT_DESC),
1847
                ],
1848
                /**
1849
                 * Expected order, Value eng-GB, Value ger-DE.
1850
                 *
1851
                 * Content 4, 1, 2, 4
1852
                 * Content 1, 1, 2, 1
1853
                 * Content 3, 2, 1, 3
1854
                 * Content 2, 2, 1, 2
1855
                 */
1856
                [4, 1, 3, 2],
1857
            ],
1858
            1 => [
1859
                [
1860
                    1 => [1, 2, 1],
1861
                    2 => [2, 1, 2],
1862
                    3 => [2, 1, 3],
1863
                    4 => [1, 2, 4],
1864
                ],
1865
                [
1866
                    'languages' => [
1867
                        'ger-DE',
1868
                        'eng-GB',
1869
                    ],
1870
                ],
1871
                [
1872
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
1873
                    new SortClause\Field('test-type', 'integer2', Query::SORT_DESC),
1874
                ],
1875
                /**
1876
                 * Expected order, Value eng-GB, Value ger-DE.
1877
                 *
1878
                 * Content 3, 2, 1, 3
1879
                 * Content 2, 2, 1, 2
1880
                 * Content 4, 1, 2, 4
1881
                 * Content 1, 1, 2, 1
1882
                 */
1883
                [3, 2, 4, 1],
1884
            ],
1885
            2 => [
1886
                [
1887
                    1 => [null, 2, null, 'ger-DE'],
1888
                    2 => [3, null, null, 'eng-GB'],
1889
                    3 => [4, null, null, 'eng-GB'],
1890
                    4 => [null, 1, null, 'ger-DE'],
1891
                ],
1892
                [
1893
                    'languages' => [
1894
                        'eng-GB',
1895
                    ],
1896
                ],
1897
                [
1898
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1899
                ],
1900
                /**
1901
                 * Expected order, Value eng-GB, Value ger-DE.
1902
                 *
1903
                 * Content 3, 4, -
1904
                 * Content 2, 3, -
1905
                 */
1906
                [3, 2],
1907
            ],
1908
            3 => [
1909
                [
1910
                    1 => [null, 2, null, 'ger-DE'],
1911
                    2 => [3, null, null, 'eng-GB'],
1912
                    3 => [4, null, null, 'eng-GB'],
1913
                    4 => [null, 1, null, 'ger-DE'],
1914
                ],
1915
                [
1916
                    'languages' => [
1917
                        'ger-DE',
1918
                    ],
1919
                ],
1920
                [
1921
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1922
                ],
1923
                /**
1924
                 * Expected order, Value eng-GB, Value ger-DE.
1925
                 *
1926
                 * Content 1, -, 2
1927
                 * Content 4, -, 1
1928
                 */
1929
                [1, 4],
1930
            ],
1931
            4 => [
1932
                [
1933
                    1 => [null, 2, null, 'ger-DE'],
1934
                    2 => [3, null, null, 'eng-GB'],
1935
                    3 => [4, null, null, 'eng-GB'],
1936
                    4 => [null, 1, null, 'ger-DE'],
1937
                ],
1938
                [
1939
                    'languages' => [
1940
                        'eng-GB',
1941
                        'ger-DE',
1942
                    ],
1943
                ],
1944
                [
1945
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1946
                ],
1947
                /**
1948
                 * Expected order, Value eng-GB, Value ger-DE.
1949
                 *
1950
                 * Content 3, 4, -
1951
                 * Content 2, 3, -
1952
                 * Content 1, -, 2
1953
                 * Content 4, -, 1
1954
                 */
1955
                [3, 2, 1, 4],
1956
            ],
1957
            5 => [
1958
                [
1959
                    1 => [null, 2, null, 'ger-DE'],
1960
                    2 => [3, null, null, 'eng-GB'],
1961
                    3 => [4, null, null, 'eng-GB'],
1962
                    4 => [null, 1, null, 'ger-DE'],
1963
                ],
1964
                [
1965
                    'languages' => [
1966
                        'ger-DE',
1967
                        'eng-GB',
1968
                    ],
1969
                ],
1970
                [
1971
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1972
                ],
1973
                /**
1974
                 * Expected order, Value eng-GB, Value ger-DE.
1975
                 *
1976
                 * Content 3, 4, -
1977
                 * Content 2, 3, -
1978
                 * Content 1, -, 2
1979
                 * Content 4, -, 1
1980
                 */
1981
                [3, 2, 1, 4],
1982
            ],
1983
            6 => [
1984
                [
1985
                    1 => [null, 2, null, 'ger-DE'],
1986
                    2 => [3, 4, null, 'eng-GB'],
1987
                    3 => [4, 3, null, 'eng-GB'],
1988
                    4 => [null, 1, null, 'ger-DE'],
1989
                ],
1990
                [
1991
                    'languages' => [
1992
                        'eng-GB',
1993
                        'ger-DE',
1994
                    ],
1995
                ],
1996
                [
1997
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
1998
                ],
1999
                /**
2000
                 * Expected order, Value eng-GB, Value ger-DE.
2001
                 *
2002
                 * Content 3, 4, 3
2003
                 * Content 2, 3, 4
2004
                 * Content 1, -, 2
2005
                 * Content 4, -, 1
2006
                 */
2007
                [3, 2, 1, 4],
2008
            ],
2009
            7 => [
2010
                [
2011
                    1 => [null, 2, null, 'ger-DE'],
2012
                    2 => [3, 4, null, 'eng-GB'],
2013
                    3 => [4, 3, null, 'eng-GB'],
2014
                    4 => [null, 1, null, 'ger-DE'],
2015
                ],
2016
                [
2017
                    'languages' => [
2018
                        'ger-DE',
2019
                        'eng-GB',
2020
                    ],
2021
                ],
2022
                [
2023
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
2024
                ],
2025
                /**
2026
                 * Expected order, Value eng-GB, Value ger-DE.
2027
                 *
2028
                 * Content 2, 3, 4
2029
                 * Content 3, 4, 3
2030
                 * Content 1, -, 2
2031
                 * Content 4, -, 1
2032
                 */
2033
                [2, 3, 1, 4],
2034
            ],
2035
            8 => [
2036
                [
2037
                    1 => [null, 1, null, 'ger-DE', true],
2038
                    2 => [4, null, null, 'eng-GB', true],
2039
                    3 => [3, null, null, 'eng-GB', false],
2040
                    4 => [null, 2, null, 'ger-DE', false],
2041
                ],
2042
                [
2043
                    'languages' => [
2044
                        'eng-GB',
2045
                    ],
2046
                ],
2047
                [
2048
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
2049
                ],
2050
                /**
2051
                 * Expected order, Value eng-GB, Value ger-DE.
2052
                 *
2053
                 * Content 1, -, 1
2054
                 * Content 3, 3, -
2055
                 * Content 2, 4, -
2056
                 */
2057
                [1, 3, 2],
2058
            ],
2059
            9 => [
2060
                [
2061
                    1 => [null, 1, null, 'ger-DE', true],
2062
                    2 => [4, null, null, 'eng-GB', true],
2063
                    3 => [3, null, null, 'eng-GB', false],
2064
                    4 => [null, 2, null, 'ger-DE', false],
2065
                ],
2066
                [
2067
                    'languages' => [
2068
                        'ger-DE',
2069
                    ],
2070
                ],
2071
                [
2072
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
2073
                ],
2074
                /**
2075
                 * Expected order, Value eng-GB, Value ger-DE.
2076
                 *
2077
                 * Content 2, 4, -
2078
                 * Content 4, -, 2
2079
                 * Content 1, -, 1
2080
                 */
2081
                [2, 4, 1],
2082
            ],
2083
            10 => [
2084
                [
2085
                    1 => [null, 1, null, 'ger-DE', true],
2086
                    2 => [4, null, null, 'eng-GB', true],
2087
                    3 => [3, null, null, 'eng-GB', false],
2088
                    4 => [null, 2, null, 'ger-DE', false],
2089
                ],
2090
                [
2091
                    'languages' => [
2092
                        'eng-GB',
2093
                    ],
2094
                    'useAlwaysAvailable' => false,
2095
                ],
2096
                [
2097
                    new SortClause\Field('test-type', 'integer', Query::SORT_ASC),
2098
                ],
2099
                /**
2100
                 * Expected order, Value eng-GB, Value ger-DE.
2101
                 *
2102
                 * Content 3, 3, -
2103
                 * Content 2, 4, -
2104
                 */
2105
                [3, 2],
2106
            ],
2107
            11 => [
2108
                [
2109
                    1 => [null, 1, null, 'ger-DE', true],
2110
                    2 => [4, null, null, 'eng-GB', true],
2111
                    3 => [3, null, null, 'eng-GB', false],
2112
                    4 => [null, 2, null, 'ger-DE', false],
2113
                ],
2114
                [
2115
                    'languages' => [
2116
                        'ger-DE',
2117
                    ],
2118
                    'useAlwaysAvailable' => false,
2119
                ],
2120
                [
2121
                    new SortClause\Field('test-type', 'integer', Query::SORT_DESC),
2122
                ],
2123
                /**
2124
                 * Expected order, Value eng-GB, Value ger-DE.
2125
                 *
2126
                 * Content 4, -, 2
2127
                 * Content 1, -, 1
2128
                 */
2129
                [4, 1],
2130
            ],
2131
        ];
2132
    }
2133
2134
    /**
2135
     * Test for the findContent() method.
2136
     *
2137
     * @group rrr
2138
     * @dataProvider providerForTestMultilingualFieldSort
2139
     *
2140
     * @param array $contentDataList
2141
     * @param array $languageSettings
2142
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] $sortClauses
2143
     * @param array $expected
2144
     */
2145
    public function testMultilingualFieldSortContent(
2146
        array $contentDataList,
2147
        $languageSettings,
2148
        array $sortClauses,
2149
        $expected
2150
    ) {
2151
        $this->assertMultilingualFieldSort(
2152
            $contentDataList,
2153
            $languageSettings,
2154
            $sortClauses,
2155
            $expected
2156
        );
2157
    }
2158
2159
    /**
2160
     * Test for the findLocations() method.
2161
     *
2162
     * @group rrr
2163
     * @dataProvider providerForTestMultilingualFieldSort
2164
     *
2165
     * @param array $contentDataList
2166
     * @param array $languageSettings
2167
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] $sortClauses
2168
     * @param array $expected
2169
     */
2170
    public function testMultilingualFieldSortLocation(
2171
        array $contentDataList,
2172
        $languageSettings,
2173
        array $sortClauses,
2174
        $expected
2175
    ) {
2176
        $this->assertMultilingualFieldSort(
2177
            $contentDataList,
2178
            $languageSettings,
2179
            $sortClauses,
2180
            $expected,
2181
            false
2182
        );
2183
    }
2184
2185
    /**
2186
     * @param array $contentDataList
2187
     * @param array $languageSettings
2188
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause[] $sortClauses
2189
     * @param array $expected
2190
     * @param bool $contentSearch
2191
     */
2192
    protected function assertMultilingualFieldSort(
2193
        array $contentDataList,
2194
        $languageSettings,
2195
        array $sortClauses,
2196
        $expected,
2197
        $contentSearch = true
2198
    ) {
2199
        $this->checkPrioritizedLanguagesSupport();
2200
        $contentType = $this->createTestContentType();
2201
2202
        // Create a draft to account for behaviour with ContentType in different states
2203
        $repository = $this->getRepository();
2204
        $contentTypeService = $repository->getContentTypeService();
2205
        $contentTypeService->createContentTypeDraft($contentType);
2206
2207
        $defaults = [null, null, null, 'eng-GB', false];
2208
        $contentIdList = [];
2209 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...
2210
            $contentData = $contentData + $defaults;
2211
            list(
2212
                $fieldValue11,
2213
                $fieldValue12,
2214
                $fieldValue2,
2215
                $mainLanguageCode,
2216
                $alwaysAvailable
2217
            ) = $contentData;
2218
2219
            $contentIdList[$key] = $this->createMultilingualContent(
2220
                $contentType,
2221
                $fieldValue11,
2222
                $fieldValue12,
2223
                $fieldValue2,
2224
                $mainLanguageCode,
2225
                $alwaysAvailable
2226
            )->id;
2227
        }
2228
2229
        // "article" type Content is not matched, this ensures that non-matched
2230
        // field does not affect sort
2231
        $dummySortClause = new SortClause\Field('article', 'title', Query::SORT_ASC);
2232
        array_unshift($sortClauses, $dummySortClause);
2233
        $sortClauses[] = $dummySortClause;
2234
2235
        $searchService = $repository->getSearchService();
2236
        if ($contentSearch) {
2237
            $query = new Query(
2238
                [
2239
                    'query' => new Criterion\ContentTypeId($contentType->id),
2240
                    'sortClauses' => $sortClauses,
2241
                ]
2242
            );
2243
            $result = $searchService->findContent($query, $languageSettings);
2244
        } else {
2245
            $query = new LocationQuery(
2246
                [
2247
                    'query' => new Criterion\ContentTypeId($contentType->id),
2248
                    'sortClauses' => $sortClauses,
2249
                ]
2250
            );
2251
            $result = $searchService->findLocations($query, $languageSettings);
2252
        }
2253
2254
        $this->assertEquals(count($expected), $result->totalCount);
2255
2256
        $expectedIdList = [];
2257
        foreach ($expected as $contentNumber) {
2258
            $expectedIdList[] = $contentIdList[$contentNumber];
2259
        }
2260
2261
        $this->assertEquals($expectedIdList, $this->mapResultContentIds($result));
2262
    }
2263
2264
    public function providerForTestMultilingualFieldFilter()
2265
    {
2266
        return [
2267
            0 => [
2268
                $fixture = [
2269
                    1 => [null, 1, null, 'ger-DE', true],
2270
                    2 => [4, null, null, 'eng-GB', true],
2271
                    3 => [3, null, null, 'eng-GB', false],
2272
                    4 => [null, 2, null, 'ger-DE', false],
2273
                    5 => [5, null, null, 'eng-GB', true],
2274
                ],
2275
                $languageSettings = [
2276
                    'languages' => [
2277
                        'ger-DE',
2278
                    ],
2279
                ],
2280
                new Criterion\Field('integer', Criterion\Operator::LT, 5),
2281
                /**
2282
                 * Expected order, Value eng-GB, Value ger-DE.
2283
                 *
2284
                 * Content 2, 4, -
2285
                 * Content 4, -, 2
2286
                 * Content 1, -, 1
2287
                 */
2288
                [2, 4, 1],
2289
            ],
2290
            1 => [
2291
                $fixture,
2292
                [
2293
                    'languages' => [
2294
                        'ger-DE',
2295
                    ],
2296
                    'useAlwaysAvailable' => false,
2297
                ],
2298
                new Criterion\Field('integer', Criterion\Operator::LT, 2),
2299
                /**
2300
                 * Expected order, Value eng-GB, Value ger-DE.
2301
                 *
2302
                 * Content 1, -, 1
2303
                 */
2304
                [1],
2305
            ],
2306
            2 => [
2307
                $fixture,
2308
                [
2309
                    'languages' => [
2310
                        'eng-GB',
2311
                    ],
2312
                ],
2313
                new Criterion\Field('integer', Criterion\Operator::LTE, 4),
2314
                /**
2315
                 * Expected order, Value eng-GB, Value ger-DE.
2316
                 *
2317
                 * Content 5, 5, -
2318
                 * Content 2, 4, -
2319
                 * Content 3, 3, -
2320
                 * Content 1, -, 1
2321
                 */
2322
                [2, 3, 1],
2323
            ],
2324
            3 => [
2325
                $fixture,
2326
                [
2327
                    'languages' => [
2328
                        'eng-GB',
2329
                    ],
2330
                    'useAlwaysAvailable' => false,
2331
                ],
2332
                new Criterion\Field('integer', Criterion\Operator::LTE, 4),
2333
                /**
2334
                 * Expected order, Value eng-GB, Value ger-DE.
2335
                 *
2336
                 * Content 2, 4, -
2337
                 * Content 3, 3, -
2338
                 */
2339
                [2, 3],
2340
            ],
2341
            4 => [
2342
                $fixture,
2343
                $languageSettings,
2344
                new Criterion\Field('integer', Criterion\Operator::LTE, 4),
2345
                /**
2346
                 * Expected order, Value eng-GB, Value ger-DE.
2347
                 *
2348
                 * Content 2, 4, -
2349
                 * Content 4, -, 2
2350
                 * Content 1, -, 1
2351
                 */
2352
                [2, 4, 1],
2353
            ],
2354
            5 => [
2355
                $fixture,
2356
                $languageSettings,
2357
                new Criterion\Field('integer', Criterion\Operator::GT, 1),
2358
                /**
2359
                 * Expected order, Value eng-GB, Value ger-DE.
2360
                 *
2361
                 * Content 5, 5, -
2362
                 * Content 2, 4, -
2363
                 * Content 4, -, 2
2364
                 */
2365
                [5, 2, 4],
2366
            ],
2367
            6 => [
2368
                $fixture,
2369
                $languageSettings,
2370
                new Criterion\Field('integer', Criterion\Operator::GTE, 2),
2371
                /**
2372
                 * Expected order, Value eng-GB, Value ger-DE.
2373
                 *
2374
                 * Content 5, 5, -
2375
                 * Content 2, 4, -
2376
                 * Content 4, -, 2
2377
                 */
2378
                [5, 2, 4],
2379
            ],
2380
            7 => [
2381
                $fixture,
2382
                $languageSettings,
2383
                new Criterion\Field('integer', Criterion\Operator::BETWEEN, [2, 4]),
2384
                /**
2385
                 * Expected order, Value eng-GB, Value ger-DE.
2386
                 *
2387
                 * Content 2, 4, -
2388
                 * Content 4, -, 2
2389
                 */
2390
                [2, 4],
2391
            ],
2392
            8 => [
2393
                $fixture,
2394
                $languageSettings,
2395
                new Criterion\Field('integer', Criterion\Operator::BETWEEN, [4, 2]),
2396
                [],
2397
            ],
2398
            9 => [
2399
                $fixture,
2400
                $languageSettings,
2401
                new Criterion\Field('integer', Criterion\Operator::EQ, 4),
2402
                /**
2403
                 * Expected order, Value eng-GB, Value ger-DE.
2404
                 *
2405
                 * Content 4, -, 2
2406
                 */
2407
                [2],
2408
            ],
2409
            10 => [
2410
                $fixture,
2411
                $languageSettings,
2412
                new Criterion\Field('integer', Criterion\Operator::EQ, 2),
2413
                /**
2414
                 * Expected order, Value eng-GB, Value ger-DE.
2415
                 *
2416
                 * Content 2, 4, -
2417
                 */
2418
                [4],
2419
            ],
2420
        ];
2421
    }
2422
2423
    /**
2424
     * Test for the findContent() method.
2425
     *
2426
     * @group ttt
2427
     * @dataProvider providerForTestMultilingualFieldFilter
2428
     *
2429
     * @param array $contentDataList
2430
     * @param array $languageSettings
2431
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
2432
     * @param array $expected
2433
     */
2434
    public function testMultilingualFieldFilterContent(
2435
        array $contentDataList,
2436
        $languageSettings,
2437
        Criterion $criterion,
2438
        $expected
2439
    ) {
2440
        $this->assertMultilingualFieldFilter(
2441
            $contentDataList,
2442
            $languageSettings,
2443
            $criterion,
2444
            $expected
2445
        );
2446
    }
2447
2448
    /**
2449
     * Test for the findLocations() method.
2450
     *
2451
     * @group ttt
2452
     * @dataProvider providerForTestMultilingualFieldFilter
2453
     *
2454
     * @param array $contentDataList
2455
     * @param array $languageSettings
2456
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
2457
     * @param array $expected
2458
     */
2459
    public function testMultilingualFieldFilterLocation(
2460
        array $contentDataList,
2461
        $languageSettings,
2462
        Criterion $criterion,
2463
        $expected
2464
    ) {
2465
        $this->assertMultilingualFieldFilter(
2466
            $contentDataList,
2467
            $languageSettings,
2468
            $criterion,
2469
            $expected,
2470
            false
2471
        );
2472
    }
2473
2474
    /**
2475
     * @param array $contentDataList
2476
     * @param array $languageSettings
2477
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
2478
     * @param array $expected
2479
     * @param bool $contentSearch
2480
     */
2481
    protected function assertMultilingualFieldFilter(
2482
        array $contentDataList,
2483
        $languageSettings,
2484
        Criterion $criterion,
2485
        $expected,
2486
        $contentSearch = true
2487
    ) {
2488
        $this->checkPrioritizedLanguagesSupport();
2489
        $contentType = $this->createTestContentType();
2490
2491
        // Create a draft to account for behaviour with ContentType in different states
2492
        $repository = $this->getRepository();
2493
        $contentTypeService = $repository->getContentTypeService();
2494
        $contentTypeService->createContentTypeDraft($contentType);
2495
2496
        $defaults = [null, null, null, 'eng-GB', false];
2497
        $contentIdList = [];
2498 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...
2499
            $contentData = $contentData + $defaults;
2500
            list(
2501
                $fieldValue11,
2502
                $fieldValue12,
2503
                $fieldValue2,
2504
                $mainLanguageCode,
2505
                $alwaysAvailable
2506
            ) = $contentData;
2507
2508
            $contentIdList[$key] = $this->createMultilingualContent(
2509
                $contentType,
2510
                $fieldValue11,
2511
                $fieldValue12,
2512
                $fieldValue2,
2513
                $mainLanguageCode,
2514
                $alwaysAvailable
2515
            )->id;
2516
        }
2517
2518
        $sortClause = new SortClause\Field('test-type', 'integer', Query::SORT_DESC);
2519
        $searchService = $repository->getSearchService();
2520
        if ($contentSearch) {
2521
            $query = new Query(
2522
                [
2523
                    'query' => new Criterion\LogicalAnd(
2524
                        [
2525
                            new Criterion\ContentTypeId($contentType->id),
2526
                            $criterion,
2527
                        ]
2528
                    ),
2529
                    'sortClauses' => [$sortClause],
2530
                ]
2531
            );
2532
            $result = $searchService->findContent($query, $languageSettings);
2533
        } else {
2534
            $query = new LocationQuery(
2535
                [
2536
                    'query' => new Criterion\LogicalAnd(
2537
                        [
2538
                            new Criterion\ContentTypeId($contentType->id),
2539
                            $criterion,
2540
                        ]
2541
                    ),
2542
                    'sortClauses' => [$sortClause],
2543
                ]
2544
            );
2545
            $result = $searchService->findLocations($query, $languageSettings);
2546
        }
2547
2548
        $this->assertEquals(count($expected), $result->totalCount);
2549
2550
        $expectedIdList = [];
2551
        foreach ($expected as $contentNumber) {
2552
            $expectedIdList[] = $contentIdList[$contentNumber];
2553
        }
2554
2555
        $this->assertEquals($expectedIdList, $this->mapResultContentIds($result));
2556
    }
2557
2558
    /**
2559
     * @param \eZ\Publish\API\Repository\Values\Content\Search\SearchResult $result
2560
     *
2561
     * @return array
2562
     */
2563
    protected function mapResultContentIds(SearchResult $result)
2564
    {
2565
        return array_map(
2566
            function (SearchHit $searchHit) {
2567
                if ($searchHit->valueObject instanceof Location) {
2568
                    return $searchHit->valueObject->contentInfo->id;
2569
                }
2570
2571
                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...
2572
            },
2573
            $result->searchHits
2574
        );
2575
    }
2576
2577
    /**
2578
     * Test for the findContent() method.
2579
     *
2580
     * @dataProvider getSortedContentSearches
2581
     *
2582
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2583
     */
2584
    public function testFindAndSortContent($queryData, $fixture, $closure = null)
2585
    {
2586
        $query = new Query($queryData);
2587
        $this->assertQueryFixture($query, $fixture, $closure);
2588
    }
2589
2590
    /**
2591
     * Test for the findContentInfo() method.
2592
     *
2593
     * @dataProvider getSortedContentSearches
2594
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
2595
     */
2596
    public function testFindAndSortContentInfo($queryData, $fixture, $closure = null)
2597
    {
2598
        $query = new Query($queryData);
2599
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure($closure), true);
2600
    }
2601
2602
    /**
2603
     * Test for the findLocations() method.
2604
     *
2605
     * @dataProvider getSortedContentSearches
2606
     *
2607
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
2608
     */
2609
    public function testFindAndSortContentLocations($queryData, $fixture, $closure = null)
2610
    {
2611
        $query = new LocationQuery($queryData);
2612
        $this->assertQueryFixture($query, $fixture, $closure);
2613
    }
2614
2615
    /**
2616
     * Test for the findLocations() method.
2617
     *
2618
     * @dataProvider getSortedLocationSearches
2619
     *
2620
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
2621
     */
2622
    public function testFindAndSortLocations($queryData, $fixture, $closure = null)
2623
    {
2624
        $query = new LocationQuery($queryData);
2625
        $this->assertQueryFixture($query, $fixture, $closure);
2626
    }
2627
2628
    /**
2629
     * Test for the findContent() method.
2630
     *
2631
     * @dataProvider getFacetedSearches
2632
     *
2633
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2634
     */
2635
    public function testFindFacetedContent(Query $query, $fixture)
2636
    {
2637
        $this->assertQueryFixture($query, $fixture);
2638
    }
2639
2640
    /**
2641
     * Test for the findContentInfo() method.
2642
     *
2643
     * @dataProvider getFacetedSearches
2644
     * @see \eZ\Publish\API\Repository\SearchService::findContentInfo()
2645
     */
2646
    public function testFindFacetedContentInfo(Query $query, $fixture)
2647
    {
2648
        $this->assertQueryFixture($query, $fixture, $this->getContentInfoFixtureClosure(), true);
2649
    }
2650
2651
    /**
2652
     * Test for the findContent() method.
2653
     *
2654
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2655
     */
2656 View Code Duplication
    public function testQueryCustomField()
2657
    {
2658
        $query = new Query(
2659
            [
2660
                'query' => new Criterion\CustomField(
2661
                    'custom_field',
2662
                    Criterion\Operator::EQ,
2663
                    'AdMiNiStRaToR'
2664
                ),
2665
                'offset' => 0,
2666
                'limit' => 10,
2667
                'sortClauses' => [new SortClause\ContentId()],
2668
            ]
2669
        );
2670
        $this->assertQueryFixture(
2671
            $query,
2672
            $this->getFixtureDir() . '/QueryCustomField.php'
2673
        );
2674
    }
2675
2676
    /**
2677
     * Test for the findContent() method.
2678
     *
2679
     * This tests explicitely queries the first_name while user is contained in
2680
     * the last_name of admin and anonymous. This is done to show the custom
2681
     * copy field working.
2682
     *
2683
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2684
     */
2685 View Code Duplication
    public function testQueryModifiedField()
2686
    {
2687
        // Check using get_class since the others extend SetupFactory\Legacy
2688
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
2689
            $this->markTestIncomplete(
2690
                'Custom fields not supported by LegacySE ' .
2691
                '(@todo: Legacy should fallback to just querying normal field so this should be tested here)'
2692
            );
2693
        }
2694
2695
        $query = new Query(
2696
            [
2697
                'query' => new Criterion\Field(
2698
                    'first_name',
2699
                    Criterion\Operator::EQ,
2700
                    'User'
2701
                ),
2702
                'offset' => 0,
2703
                'limit' => 10,
2704
                'sortClauses' => [new SortClause\ContentId()],
2705
            ]
2706
        );
2707
        $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...
2708
2709
        $this->assertQueryFixture(
2710
            $query,
2711
            $this->getFixtureDir() . '/QueryModifiedField.php'
2712
        );
2713
    }
2714
2715
    /**
2716
     * Test for the findContent() method.
2717
     *
2718
     * This tests first explicitly creates sort clause on the 'short_name' which is empty
2719
     * for all Content instances of 'folder' ContentType. Custom sort field is then set
2720
     * to the index storage name of folder's 'name' field, in order to show the custom
2721
     * sort field working.
2722
     *
2723
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2724
     */
2725
    public function testSortModifiedField()
2726
    {
2727
        // Check using get_class since the others extend SetupFactory\Legacy
2728
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
2729
            $this->markTestIncomplete(
2730
                'Custom field sort not supported by LegacySE ' .
2731
                '(@todo: Legacy should fallback to just querying normal field so this should be tested here)'
2732
            );
2733
        }
2734
2735
        $sortClause = new SortClause\Field('folder', 'short_name', Query::SORT_ASC);
2736
        $sortClause->setCustomField('folder', 'short_name', 'folder_name_value_s');
2737
2738
        $query = new Query(
2739
            [
2740
                'filter' => new Criterion\ContentTypeId(1),
2741
                'offset' => 0,
2742
                'limit' => 10,
2743
                'sortClauses' => [
2744
                    $sortClause,
2745
                    new SortClause\ContentId(),
2746
                ],
2747
            ]
2748
        );
2749
2750
        $this->assertQueryFixture(
2751
            $query,
2752
            $this->getFixtureDir() . '/SortFolderName.php'
2753
        );
2754
    }
2755
2756
    /**
2757
     * @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
2758
     */
2759 View Code Duplication
    protected function createTestPlaceContentType()
2760
    {
2761
        $repository = $this->getRepository();
2762
        $contentTypeService = $repository->getContentTypeService();
2763
2764
        $createStruct = $contentTypeService->newContentTypeCreateStruct('testtype');
2765
        $createStruct->mainLanguageCode = 'eng-GB';
2766
        $createStruct->names = ['eng-GB' => 'Test type'];
2767
        $createStruct->creatorId = 14;
2768
        $createStruct->creationDate = new \DateTime();
2769
2770
        $translatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('maplocation', 'ezgmaplocation');
2771
        $translatableFieldCreate->names = ['eng-GB' => 'Map location field'];
2772
        $translatableFieldCreate->fieldGroup = 'main';
2773
        $translatableFieldCreate->position = 1;
2774
        $translatableFieldCreate->isTranslatable = false;
2775
        $translatableFieldCreate->isSearchable = true;
2776
2777
        $createStruct->addFieldDefinition($translatableFieldCreate);
2778
2779
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
2780
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
2781
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
2782
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
2783
2784
        return $contentType;
2785
    }
2786
2787
    /**
2788
     * Test for the findContent() method.
2789
     *
2790
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2791
     * @group maplocation
2792
     */
2793 View Code Duplication
    public function testMapLocationDistanceLessThanOrEqual()
2794
    {
2795
        $contentType = $this->createTestPlaceContentType();
2796
2797
        // Create a draft to account for behaviour with ContentType in different states
2798
        $repository = $this->getRepository();
2799
        $contentTypeService = $repository->getContentTypeService();
2800
        $contentService = $repository->getContentService();
2801
        $contentTypeService->createContentTypeDraft($contentType);
2802
2803
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2804
        $createStruct->alwaysAvailable = false;
2805
        $createStruct->mainLanguageCode = 'eng-GB';
2806
        $createStruct->setField(
2807
            'maplocation',
2808
            [
2809
                'latitude' => 45.894877,
2810
                'longitude' => 15.972699,
2811
                'address' => 'Here be wild boars',
2812
            ],
2813
            'eng-GB'
2814
        );
2815
2816
        $draft = $contentService->createContent($createStruct);
2817
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
2818
2819
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2820
        $createStruct->alwaysAvailable = false;
2821
        $createStruct->mainLanguageCode = 'eng-GB';
2822
        $createStruct->setField(
2823
            'maplocation',
2824
            [
2825
                'latitude' => 45.927334,
2826
                'longitude' => 15.934847,
2827
                'address' => 'A lone tree',
2828
            ],
2829
            'eng-GB'
2830
        );
2831
2832
        $draft = $contentService->createContent($createStruct);
2833
        $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...
2834
2835
        $this->refreshSearch($repository);
2836
2837
        $query = new Query(
2838
            [
2839
                'filter' => new Criterion\LogicalAnd(
2840
                    [
2841
                        new Criterion\ContentTypeId($contentType->id),
2842
                        new Criterion\MapLocationDistance(
2843
                            'maplocation',
2844
                            Criterion\Operator::LTE,
2845
                            240,
2846
                            43.756825,
2847
                            15.775074
2848
                        ),
2849
                    ]
2850
                ),
2851
                'offset' => 0,
2852
                'limit' => 10,
2853
                'sortClauses' => [],
2854
            ]
2855
        );
2856
2857
        $searchService = $repository->getSearchService();
2858
        $result = $searchService->findContent($query);
2859
2860
        $this->assertEquals(1, $result->totalCount);
2861
        $this->assertEquals(
2862
            $wildBoars->id,
2863
            $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...
2864
        );
2865
    }
2866
2867
    /**
2868
     * Test for the findContent() method.
2869
     *
2870
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2871
     * @group maplocation
2872
     */
2873 View Code Duplication
    public function testMapLocationDistanceGreaterThanOrEqual()
2874
    {
2875
        $contentType = $this->createTestPlaceContentType();
2876
2877
        // Create a draft to account for behaviour with ContentType in different states
2878
        $repository = $this->getRepository();
2879
        $contentTypeService = $repository->getContentTypeService();
2880
        $contentService = $repository->getContentService();
2881
        $contentTypeService->createContentTypeDraft($contentType);
2882
2883
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2884
        $createStruct->alwaysAvailable = false;
2885
        $createStruct->mainLanguageCode = 'eng-GB';
2886
        $createStruct->setField(
2887
            'maplocation',
2888
            [
2889
                'latitude' => 45.894877,
2890
                'longitude' => 15.972699,
2891
                'address' => 'Here be wild boars',
2892
            ],
2893
            'eng-GB'
2894
        );
2895
2896
        $draft = $contentService->createContent($createStruct);
2897
        $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...
2898
2899
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2900
        $createStruct->alwaysAvailable = false;
2901
        $createStruct->mainLanguageCode = 'eng-GB';
2902
        $createStruct->setField(
2903
            'maplocation',
2904
            [
2905
                'latitude' => 45.927334,
2906
                'longitude' => 15.934847,
2907
                'address' => 'A lone tree',
2908
            ],
2909
            'eng-GB'
2910
        );
2911
2912
        $draft = $contentService->createContent($createStruct);
2913
        $tree = $contentService->publishVersion($draft->getVersionInfo());
2914
2915
        $this->refreshSearch($repository);
2916
2917
        $query = new Query(
2918
            [
2919
                'filter' => new Criterion\LogicalAnd(
2920
                    [
2921
                        new Criterion\ContentTypeId($contentType->id),
2922
                        new Criterion\MapLocationDistance(
2923
                            'maplocation',
2924
                            Criterion\Operator::GTE,
2925
                            240,
2926
                            43.756825,
2927
                            15.775074
2928
                        ),
2929
                    ]
2930
                ),
2931
                'offset' => 0,
2932
                'limit' => 10,
2933
                'sortClauses' => [],
2934
            ]
2935
        );
2936
2937
        $searchService = $repository->getSearchService();
2938
        $result = $searchService->findContent($query);
2939
2940
        $this->assertEquals(1, $result->totalCount);
2941
        $this->assertEquals(
2942
            $tree->id,
2943
            $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...
2944
        );
2945
    }
2946
2947
    /**
2948
     * Test for the findContent() method.
2949
     *
2950
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
2951
     * @group maplocation
2952
     */
2953
    public function testMapLocationDistanceBetween()
2954
    {
2955
        $contentType = $this->createTestPlaceContentType();
2956
2957
        // Create a draft to account for behaviour with ContentType in different states
2958
        $repository = $this->getRepository();
2959
        $contentTypeService = $repository->getContentTypeService();
2960
        $contentService = $repository->getContentService();
2961
        $contentTypeService->createContentTypeDraft($contentType);
2962
2963
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2964
        $createStruct->alwaysAvailable = false;
2965
        $createStruct->mainLanguageCode = 'eng-GB';
2966
        $createStruct->setField(
2967
            'maplocation',
2968
            [
2969
                'latitude' => 45.894877,
2970
                'longitude' => 15.972699,
2971
                'address' => 'Here be wild boars',
2972
            ],
2973
            'eng-GB'
2974
        );
2975
2976
        $draft = $contentService->createContent($createStruct);
2977
        $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...
2978
2979
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2980
        $createStruct->alwaysAvailable = false;
2981
        $createStruct->mainLanguageCode = 'eng-GB';
2982
        $createStruct->setField(
2983
            'maplocation',
2984
            [
2985
                'latitude' => 45.927334,
2986
                'longitude' => 15.934847,
2987
                'address' => 'A lone tree',
2988
            ],
2989
            'eng-GB'
2990
        );
2991
2992
        $draft = $contentService->createContent($createStruct);
2993
        $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...
2994
2995
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
2996
        $createStruct->alwaysAvailable = false;
2997
        $createStruct->mainLanguageCode = 'eng-GB';
2998
        $createStruct->setField(
2999
            'maplocation',
3000
            [
3001
                'latitude' => 45.903777,
3002
                'longitude' => 15.958788,
3003
                'address' => 'Meadow with mushrooms',
3004
            ],
3005
            'eng-GB'
3006
        );
3007
3008
        $draft = $contentService->createContent($createStruct);
3009
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
3010
3011
        $this->refreshSearch($repository);
3012
3013
        $query = new Query(
3014
            [
3015
                'filter' => new Criterion\LogicalAnd(
3016
                    [
3017
                        new Criterion\ContentTypeId($contentType->id),
3018
                        new Criterion\MapLocationDistance(
3019
                            'maplocation',
3020
                            Criterion\Operator::BETWEEN,
3021
                            [239, 241],
3022
                            43.756825,
3023
                            15.775074
3024
                        ),
3025
                    ]
3026
                ),
3027
                'offset' => 0,
3028
                'limit' => 10,
3029
                'sortClauses' => [],
3030
            ]
3031
        );
3032
3033
        $searchService = $repository->getSearchService();
3034
        $result = $searchService->findContent($query);
3035
3036
        $this->assertEquals(1, $result->totalCount);
3037
        $this->assertEquals(
3038
            $mushrooms->id,
3039
            $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...
3040
        );
3041
    }
3042
3043
    /**
3044
     * Test for the findContent() method.
3045
     *
3046
     * This tests the distance over the pole. The tests intentionally uses large range,
3047
     * as the flat Earth model used in Legacy Storage Search is not precise for the use case.
3048
     * What is tested here is that outer bounding box is correctly calculated, so that
3049
     * location is not excluded.
3050
     *
3051
     * Range between 222km and 350km shows the magnitude of error between great-circle
3052
     * (always very precise) and flat Earth (very imprecise for this use case) models.
3053
     *
3054
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3055
     * @group maplocation
3056
     */
3057
    public function testMapLocationDistanceBetweenPolar()
3058
    {
3059
        $contentType = $this->createTestPlaceContentType();
3060
3061
        // Create a draft to account for behaviour with ContentType in different states
3062
        $repository = $this->getRepository();
3063
        $contentTypeService = $repository->getContentTypeService();
3064
        $contentService = $repository->getContentService();
3065
        $contentTypeService->createContentTypeDraft($contentType);
3066
3067
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3068
        $createStruct->alwaysAvailable = false;
3069
        $createStruct->mainLanguageCode = 'eng-GB';
3070
        $createStruct->setField(
3071
            'maplocation',
3072
            [
3073
                'latitude' => 89,
3074
                'longitude' => -164,
3075
                'address' => 'Polar bear media tower',
3076
            ],
3077
            'eng-GB'
3078
        );
3079
3080
        $draft = $contentService->createContent($createStruct);
3081
        $polarBear = $contentService->publishVersion($draft->getVersionInfo());
3082
3083
        $this->refreshSearch($repository);
3084
3085
        $query = new Query(
3086
            [
3087
                'filter' => new Criterion\LogicalAnd(
3088
                    [
3089
                        new Criterion\ContentTypeId($contentType->id),
3090
                        new Criterion\MapLocationDistance(
3091
                            'maplocation',
3092
                            Criterion\Operator::BETWEEN,
3093
                            [221, 350],
3094
                            89,
3095
                            16
3096
                        ),
3097
                    ]
3098
                ),
3099
                'offset' => 0,
3100
                'limit' => 10,
3101
                'sortClauses' => [],
3102
            ]
3103
        );
3104
3105
        $searchService = $repository->getSearchService();
3106
        $result = $searchService->findContent($query);
3107
3108
        $this->assertEquals(1, $result->totalCount);
3109
        $this->assertEquals(
3110
            $polarBear->id,
3111
            $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...
3112
        );
3113
    }
3114
3115
    /**
3116
     * Test for the findContent() method.
3117
     *
3118
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3119
     * @group maplocation
3120
     */
3121 View Code Duplication
    public function testMapLocationDistanceSortAscending()
3122
    {
3123
        $contentType = $this->createTestPlaceContentType();
3124
3125
        // Create a draft to account for behaviour with ContentType in different states
3126
        $repository = $this->getRepository();
3127
        $contentTypeService = $repository->getContentTypeService();
3128
        $contentService = $repository->getContentService();
3129
        $contentTypeService->createContentTypeDraft($contentType);
3130
3131
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3132
        $createStruct->alwaysAvailable = false;
3133
        $createStruct->mainLanguageCode = 'eng-GB';
3134
        $createStruct->setField(
3135
            'maplocation',
3136
            [
3137
                'latitude' => 45.894877,
3138
                'longitude' => 15.972699,
3139
                'address' => 'Here be wild boars',
3140
            ],
3141
            'eng-GB'
3142
        );
3143
3144
        $draft = $contentService->createContent($createStruct);
3145
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3146
3147
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3148
        $createStruct->alwaysAvailable = false;
3149
        $createStruct->mainLanguageCode = 'eng-GB';
3150
        $createStruct->setField(
3151
            'maplocation',
3152
            [
3153
                'latitude' => 45.927334,
3154
                'longitude' => 15.934847,
3155
                'address' => 'A lone tree',
3156
            ],
3157
            'eng-GB'
3158
        );
3159
3160
        $draft = $contentService->createContent($createStruct);
3161
        $tree = $contentService->publishVersion($draft->getVersionInfo());
3162
3163
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3164
        $createStruct->alwaysAvailable = false;
3165
        $createStruct->mainLanguageCode = 'eng-GB';
3166
        $createStruct->setField(
3167
            'maplocation',
3168
            [
3169
                'latitude' => 45.903777,
3170
                'longitude' => 15.958788,
3171
                'address' => 'Meadow with mushrooms',
3172
            ],
3173
            'eng-GB'
3174
        );
3175
3176
        $draft = $contentService->createContent($createStruct);
3177
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
3178
3179
        $this->refreshSearch($repository);
3180
3181
        $wellInVodice = [
3182
            'latitude' => 43.756825,
3183
            'longitude' => 15.775074,
3184
        ];
3185
3186
        $query = new Query(
3187
            [
3188
                'filter' => new Criterion\LogicalAnd(
3189
                    [
3190
                        new Criterion\ContentTypeId($contentType->id),
3191
                        new Criterion\MapLocationDistance(
3192
                            'maplocation',
3193
                            Criterion\Operator::GTE,
3194
                            235,
3195
                            $wellInVodice['latitude'],
3196
                            $wellInVodice['longitude']
3197
                        ),
3198
                    ]
3199
                ),
3200
                'offset' => 0,
3201
                'limit' => 10,
3202
                'sortClauses' => [
3203
                    new SortClause\MapLocationDistance(
3204
                        'testtype',
3205
                        'maplocation',
3206
                        $wellInVodice['latitude'],
3207
                        $wellInVodice['longitude'],
3208
                        Query::SORT_ASC
3209
                    ),
3210
                ],
3211
            ]
3212
        );
3213
3214
        $searchService = $repository->getSearchService();
3215
        $result = $searchService->findContent($query);
3216
3217
        $this->assertEquals(3, $result->totalCount);
3218
        $this->assertEquals(
3219
            $wildBoars->id,
3220
            $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...
3221
        );
3222
        $this->assertEquals(
3223
            $mushrooms->id,
3224
            $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...
3225
        );
3226
        $this->assertEquals(
3227
            $tree->id,
3228
            $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...
3229
        );
3230
    }
3231
3232
    /**
3233
     * Test for the findContent() method.
3234
     *
3235
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3236
     * @group maplocation
3237
     */
3238 View Code Duplication
    public function testMapLocationDistanceSortDescending()
3239
    {
3240
        $contentType = $this->createTestPlaceContentType();
3241
3242
        // Create a draft to account for behaviour with ContentType in different states
3243
        $repository = $this->getRepository();
3244
        $contentTypeService = $repository->getContentTypeService();
3245
        $contentService = $repository->getContentService();
3246
        $contentTypeService->createContentTypeDraft($contentType);
3247
3248
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3249
        $createStruct->alwaysAvailable = false;
3250
        $createStruct->mainLanguageCode = 'eng-GB';
3251
        $createStruct->setField(
3252
            'maplocation',
3253
            [
3254
                'latitude' => 45.894877,
3255
                'longitude' => 15.972699,
3256
                'address' => 'Here be wild boars',
3257
            ],
3258
            'eng-GB'
3259
        );
3260
3261
        $draft = $contentService->createContent($createStruct);
3262
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3263
3264
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3265
        $createStruct->alwaysAvailable = false;
3266
        $createStruct->mainLanguageCode = 'eng-GB';
3267
        $createStruct->setField(
3268
            'maplocation',
3269
            [
3270
                'latitude' => 45.927334,
3271
                'longitude' => 15.934847,
3272
                'address' => 'A lone tree',
3273
            ],
3274
            'eng-GB'
3275
        );
3276
3277
        $draft = $contentService->createContent($createStruct);
3278
        $tree = $contentService->publishVersion($draft->getVersionInfo());
3279
3280
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3281
        $createStruct->alwaysAvailable = false;
3282
        $createStruct->mainLanguageCode = 'eng-GB';
3283
        $createStruct->setField(
3284
            'maplocation',
3285
            [
3286
                'latitude' => 45.903777,
3287
                'longitude' => 15.958788,
3288
                'address' => 'Meadow with mushrooms',
3289
            ],
3290
            'eng-GB'
3291
        );
3292
3293
        $draft = $contentService->createContent($createStruct);
3294
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
3295
3296
        $this->refreshSearch($repository);
3297
3298
        $well = [
3299
            'latitude' => 43.756825,
3300
            'longitude' => 15.775074,
3301
        ];
3302
3303
        $query = new Query(
3304
            [
3305
                'filter' => new Criterion\LogicalAnd(
3306
                    [
3307
                        new Criterion\ContentTypeId($contentType->id),
3308
                        new Criterion\MapLocationDistance(
3309
                            'maplocation',
3310
                            Criterion\Operator::GTE,
3311
                            235,
3312
                            $well['latitude'],
3313
                            $well['longitude']
3314
                        ),
3315
                    ]
3316
                ),
3317
                'offset' => 0,
3318
                'limit' => 10,
3319
                'sortClauses' => [
3320
                    new SortClause\MapLocationDistance(
3321
                        'testtype',
3322
                        'maplocation',
3323
                        $well['latitude'],
3324
                        $well['longitude'],
3325
                        Query::SORT_DESC
3326
                    ),
3327
                ],
3328
            ]
3329
        );
3330
3331
        $searchService = $repository->getSearchService();
3332
        $result = $searchService->findContent($query);
3333
3334
        $this->assertEquals(3, $result->totalCount);
3335
        $this->assertEquals(
3336
            $wildBoars->id,
3337
            $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...
3338
        );
3339
        $this->assertEquals(
3340
            $mushrooms->id,
3341
            $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...
3342
        );
3343
        $this->assertEquals(
3344
            $tree->id,
3345
            $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...
3346
        );
3347
    }
3348
3349
    /**
3350
     * Test for the findContent() method.
3351
     *
3352
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3353
     * @group maplocation
3354
     */
3355
    public function testMapLocationDistanceWithCustomField()
3356
    {
3357
        $setupFactory = $this->getSetupFactory();
3358
        if ($setupFactory instanceof LegacyElasticsearch) {
3359
            $this->markTestIncomplete("TODO: Some issues with 'copy_to' and 'geo_point'");
3360
        }
3361
3362
        $contentType = $this->createTestPlaceContentType();
3363
3364
        // Create a draft to account for behaviour with ContentType in different states
3365
        $repository = $this->getRepository();
3366
        $contentTypeService = $repository->getContentTypeService();
3367
        $contentService = $repository->getContentService();
3368
        $contentTypeService->createContentTypeDraft($contentType);
3369
3370
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3371
        $createStruct->alwaysAvailable = false;
3372
        $createStruct->mainLanguageCode = 'eng-GB';
3373
        $createStruct->setField(
3374
            'maplocation',
3375
            [
3376
                'latitude' => 45.894877,
3377
                'longitude' => 15.972699,
3378
                'address' => 'Here be wild boars',
3379
            ],
3380
            'eng-GB'
3381
        );
3382
3383
        $draft = $contentService->createContent($createStruct);
3384
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3385
3386
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3387
        $createStruct->alwaysAvailable = false;
3388
        $createStruct->mainLanguageCode = 'eng-GB';
3389
        $createStruct->setField(
3390
            'maplocation',
3391
            [
3392
                'latitude' => 45.927334,
3393
                'longitude' => 15.934847,
3394
                'address' => 'A lone tree',
3395
            ],
3396
            'eng-GB'
3397
        );
3398
3399
        $draft = $contentService->createContent($createStruct);
3400
        $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...
3401
3402
        $this->refreshSearch($repository);
3403
3404
        $distanceCriterion = new Criterion\MapLocationDistance(
3405
            'maplocation',
3406
            Criterion\Operator::LTE,
3407
            240,
3408
            43.756825,
3409
            15.775074
3410
        );
3411
        $distanceCriterion->setCustomField('testtype', 'maplocation', 'custom_geolocation_field');
3412
3413
        $query = new Query(
3414
            [
3415
                'filter' => new Criterion\LogicalAnd(
3416
                    [
3417
                        new Criterion\ContentTypeId($contentType->id),
3418
                        $distanceCriterion,
3419
                    ]
3420
                ),
3421
                'offset' => 0,
3422
                'limit' => 10,
3423
                'sortClauses' => [],
3424
            ]
3425
        );
3426
3427
        $searchService = $repository->getSearchService();
3428
        $result = $searchService->findContent($query);
3429
3430
        $this->assertEquals(1, $result->totalCount);
3431
        $this->assertEquals(
3432
            $wildBoars->id,
3433
            $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...
3434
        );
3435
    }
3436
3437
    /**
3438
     * Test for the findContent() method.
3439
     *
3440
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3441
     * @group maplocation
3442
     */
3443
    public function testMapLocationDistanceWithCustomFieldSort()
3444
    {
3445
        $setupFactory = $this->getSetupFactory();
3446
        if ($setupFactory instanceof LegacyElasticsearch) {
3447
            $this->markTestIncomplete("TODO: Some issues with 'copy_to' and 'geo_point'");
3448
        }
3449
3450
        $contentType = $this->createTestPlaceContentType();
3451
3452
        // Create a draft to account for behaviour with ContentType in different states
3453
        $repository = $this->getRepository();
3454
        $contentTypeService = $repository->getContentTypeService();
3455
        $contentService = $repository->getContentService();
3456
        $contentTypeService->createContentTypeDraft($contentType);
3457
3458
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3459
        $createStruct->alwaysAvailable = false;
3460
        $createStruct->mainLanguageCode = 'eng-GB';
3461
        $createStruct->setField(
3462
            'maplocation',
3463
            [
3464
                'latitude' => 45.894877,
3465
                'longitude' => 15.972699,
3466
                'address' => 'Here be wild boars',
3467
            ],
3468
            'eng-GB'
3469
        );
3470
3471
        $draft = $contentService->createContent($createStruct);
3472
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
3473
3474
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3475
        $createStruct->alwaysAvailable = false;
3476
        $createStruct->mainLanguageCode = 'eng-GB';
3477
        $createStruct->setField(
3478
            'maplocation',
3479
            [
3480
                'latitude' => 45.927334,
3481
                'longitude' => 15.934847,
3482
                'address' => 'A lone tree',
3483
            ],
3484
            'eng-GB'
3485
        );
3486
3487
        $draft = $contentService->createContent($createStruct);
3488
        $tree = $contentService->publishVersion($draft->getVersionInfo());
3489
3490
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3491
        $createStruct->alwaysAvailable = false;
3492
        $createStruct->mainLanguageCode = 'eng-GB';
3493
        $createStruct->setField(
3494
            'maplocation',
3495
            [
3496
                'latitude' => 45.903777,
3497
                'longitude' => 15.958788,
3498
                'address' => 'Meadow with mushrooms',
3499
            ],
3500
            'eng-GB'
3501
        );
3502
3503
        $draft = $contentService->createContent($createStruct);
3504
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
3505
3506
        $this->refreshSearch($repository);
3507
3508
        $well = [
3509
            'latitude' => 43.756825,
3510
            'longitude' => 15.775074,
3511
        ];
3512
3513
        $sortClause = new SortClause\MapLocationDistance(
3514
            'testtype',
3515
            'maplocation',
3516
            $well['latitude'],
3517
            $well['longitude'],
3518
            Query::SORT_DESC
3519
        );
3520
        $sortClause->setCustomField('testtype', 'maplocation', 'custom_geolocation_field');
3521
3522
        $query = new Query(
3523
            [
3524
                'filter' => new Criterion\LogicalAnd(
3525
                    [
3526
                        new Criterion\ContentTypeId($contentType->id),
3527
                        new Criterion\MapLocationDistance(
3528
                            'maplocation',
3529
                            Criterion\Operator::GTE,
3530
                            235,
3531
                            $well['latitude'],
3532
                            $well['longitude']
3533
                        ),
3534
                    ]
3535
                ),
3536
                'offset' => 0,
3537
                'limit' => 10,
3538
                'sortClauses' => [
3539
                    $sortClause,
3540
                ],
3541
            ]
3542
        );
3543
3544
        $searchService = $repository->getSearchService();
3545
        $result = $searchService->findContent($query);
3546
3547
        $this->assertEquals(3, $result->totalCount);
3548
        $this->assertEquals(
3549
            $wildBoars->id,
3550
            $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...
3551
        );
3552
        $this->assertEquals(
3553
            $mushrooms->id,
3554
            $result->searchHits[1]->valueObject->id
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

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

<?php

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

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

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

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

}

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

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

See also the PhpDoc documentation for @property.

Loading history...
3555
        );
3556
        $this->assertEquals(
3557
            $tree->id,
3558
            $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...
3559
        );
3560
    }
3561
3562
    /**
3563
     * Test for the findLocations() method.
3564
     *
3565
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3566
     */
3567 View Code Duplication
    public function testFindMainLocation()
3568
    {
3569
        $plainSiteLocationId = 56;
3570
        $designLocationId = 58;
3571
        $partnersContentId = 59;
3572
        $repository = $this->getRepository();
3573
        $locationService = $repository->getLocationService();
3574
        $contentService = $repository->getContentService();
3575
3576
        // Add secondary Location for "Partners" user group, under "Design" page
3577
        $locationService->createLocation(
3578
            $contentService->loadContentInfo($partnersContentId),
3579
            $locationService->newLocationCreateStruct($designLocationId)
3580
        );
3581
3582
        $this->refreshSearch($repository);
3583
3584
        $query = new LocationQuery(
3585
            [
3586
                'filter' => new Criterion\LogicalAnd(
3587
                    [
3588
                        new Criterion\ParentLocationId($designLocationId),
3589
                        new Criterion\Location\IsMainLocation(
3590
                            Criterion\Location\IsMainLocation::MAIN
3591
                        ),
3592
                    ]
3593
                ),
3594
                'offset' => 0,
3595
                'limit' => 10,
3596
                'sortClauses' => [],
3597
            ]
3598
        );
3599
3600
        $searchService = $repository->getSearchService();
3601
        $result = $searchService->findLocations($query);
3602
3603
        $this->assertEquals(1, $result->totalCount);
3604
        $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...
3605
    }
3606
3607
    /**
3608
     * Test for the findLocations() method.
3609
     *
3610
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3611
     */
3612 View Code Duplication
    public function testFindNonMainLocation()
3613
    {
3614
        $designLocationId = 58;
3615
        $partnersContentId = 59;
3616
        $repository = $this->getRepository();
3617
        $locationService = $repository->getLocationService();
3618
        $contentService = $repository->getContentService();
3619
3620
        // Add secondary Location for "Partners" user group, under "Design" page
3621
        $newLocation = $locationService->createLocation(
3622
            $contentService->loadContentInfo($partnersContentId),
3623
            $locationService->newLocationCreateStruct($designLocationId)
3624
        );
3625
3626
        $this->refreshSearch($repository);
3627
3628
        $query = new LocationQuery(
3629
            [
3630
                'filter' => new Criterion\LogicalAnd(
3631
                    [
3632
                        new Criterion\ParentLocationId($designLocationId),
3633
                        new Criterion\Location\IsMainLocation(
3634
                            Criterion\Location\IsMainLocation::NOT_MAIN
3635
                        ),
3636
                    ]
3637
                ),
3638
                'offset' => 0,
3639
                'limit' => 10,
3640
                'sortClauses' => [],
3641
            ]
3642
        );
3643
3644
        $searchService = $repository->getSearchService();
3645
        $result = $searchService->findLocations($query);
3646
3647
        $this->assertEquals(1, $result->totalCount);
3648
        $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...
3649
    }
3650
3651
    /**
3652
     * Test for the findLocations() method.
3653
     *
3654
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3655
     */
3656 View Code Duplication
    public function testSortMainLocationAscending()
3657
    {
3658
        $plainSiteLocationId = 56;
3659
        $designLocationId = 58;
3660
        $partnersContentId = 59;
3661
        $repository = $this->getRepository();
3662
        $locationService = $repository->getLocationService();
3663
        $contentService = $repository->getContentService();
3664
3665
        // Add secondary Location for "Partners" user group, under "Design" page
3666
        $newLocation = $locationService->createLocation(
3667
            $contentService->loadContentInfo($partnersContentId),
3668
            $locationService->newLocationCreateStruct($designLocationId)
3669
        );
3670
3671
        $this->refreshSearch($repository);
3672
3673
        $query = new LocationQuery(
3674
            [
3675
                'filter' => new Criterion\ParentLocationId($designLocationId),
3676
                'offset' => 0,
3677
                'limit' => 10,
3678
                'sortClauses' => [
3679
                    new SortClause\Location\IsMainLocation(
3680
                        LocationQuery::SORT_ASC
3681
                    ),
3682
                ],
3683
            ]
3684
        );
3685
3686
        $searchService = $repository->getSearchService();
3687
        $result = $searchService->findLocations($query);
3688
3689
        $this->assertEquals(2, $result->totalCount);
3690
        $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...
3691
        $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...
3692
    }
3693
3694
    /**
3695
     * Test for the findLocations() method.
3696
     *
3697
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3698
     */
3699 View Code Duplication
    public function testSortMainLocationDescending()
3700
    {
3701
        $plainSiteLocationId = 56;
3702
        $designLocationId = 58;
3703
        $partnersContentId = 59;
3704
        $repository = $this->getRepository();
3705
        $locationService = $repository->getLocationService();
3706
        $contentService = $repository->getContentService();
3707
3708
        // Add secondary Location for "Partners" user group, under "Design" page
3709
        $newLocation = $locationService->createLocation(
3710
            $contentService->loadContentInfo($partnersContentId),
3711
            $locationService->newLocationCreateStruct($designLocationId)
3712
        );
3713
3714
        $this->refreshSearch($repository);
3715
3716
        $query = new LocationQuery(
3717
            [
3718
                'filter' => new Criterion\ParentLocationId($designLocationId),
3719
                'offset' => 0,
3720
                'limit' => 10,
3721
                'sortClauses' => [
3722
                    new SortClause\Location\IsMainLocation(
3723
                        LocationQuery::SORT_DESC
3724
                    ),
3725
                ],
3726
            ]
3727
        );
3728
3729
        $searchService = $repository->getSearchService();
3730
        $result = $searchService->findLocations($query);
3731
3732
        $this->assertEquals(2, $result->totalCount);
3733
        $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...
3734
        $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...
3735
    }
3736
3737
    /**
3738
     * Test for the findLocations() method.
3739
     *
3740
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3741
     */
3742
    public function testContentWithMultipleLocations()
3743
    {
3744
        $repository = $this->getRepository();
3745
        $contentService = $repository->getContentService();
3746
        $contentTypeService = $repository->getContentTypeService();
3747
        $locationService = $repository->getLocationService();
3748
3749
        $forumType = $contentTypeService->loadContentTypeByIdentifier('forum');
3750
3751
        $createStruct = $contentService->newContentCreateStruct($forumType, 'eng-GB');
3752
        $createStruct->alwaysAvailable = false;
3753
        $createStruct->setField('name', 'An awesome duplicate forum');
3754
3755
        $draft = $contentService->createContent($createStruct);
3756
        $content = $contentService->publishVersion($draft->getVersionInfo());
3757
3758
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
3759
        $location1 = $locationService->createLocation($content->contentInfo, $locationCreateStruct);
3760
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(5);
3761
        $location2 = $locationService->createLocation($content->contentInfo, $locationCreateStruct);
3762
3763
        $this->refreshSearch($repository);
3764
3765
        $query = new LocationQuery(
3766
            [
3767
                'filter' => new Criterion\ContentId($content->id),
3768
                'sortClauses' => [
3769
                    new SortClause\Location\Id(LocationQuery::SORT_ASC),
3770
                ],
3771
            ]
3772
        );
3773
3774
        $searchService = $repository->getSearchService();
3775
        $result = $searchService->findLocations($query);
3776
3777
        $this->assertEquals(2, $result->totalCount);
3778
        $this->assertEquals(
3779
            $location1->id,
3780
            $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...
3781
        );
3782
        $this->assertEquals(
3783
            $location2->id,
3784
            $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...
3785
        );
3786
    }
3787
3788
    protected function createContentForTestUserMetadataGroupHorizontal()
3789
    {
3790
        $repository = $this->getRepository();
3791
        $contentService = $repository->getContentService();
3792
        $contentTypeService = $repository->getContentTypeService();
3793
        $locationService = $repository->getLocationService();
3794
        $userService = $repository->getUserService();
3795
        $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...
3796
        // ID of the "Administrators" user group in an eZ Publish demo installation
3797
        $administratorsUserGroupId = 12;
3798
        // ID of the "Editors" user group in an eZ Publish demo installation
3799
        $editorsUserGroupId = 13;
3800
3801
        $administratorsUserGroup = $userService->loadUserGroup($administratorsUserGroupId);
3802
        $editorsUserGroup = $userService->loadUserGroup($editorsUserGroupId);
3803
3804
        // Add additional Location for Administrators UserGroup under Editors UserGroup Location
3805
        $locationCreateStruct = $locationService->newLocationCreateStruct(
3806
            $editorsUserGroup->contentInfo->mainLocationId
3807
        );
3808
        $newAdministratorsUserGroupLocation = $locationService->createLocation(
3809
            $administratorsUserGroup->contentInfo,
3810
            $locationCreateStruct
3811
        );
3812
3813
        // Add additional Location for administrator user under newly created UserGroup Location
3814
        $locationCreateStruct = $locationService->newLocationCreateStruct(
3815
            $newAdministratorsUserGroupLocation->id
3816
        );
3817
        $locationService->createLocation(
3818
            $administratorUser->contentInfo,
3819
            $locationCreateStruct
3820
        );
3821
3822
        // Create a Content to be found through Editors UserGroup id.
3823
        // This ensures data is indexed, it could also be done by updating metadata of
3824
        // an existing Content, but slot would need to reindex Content and that should
3825
        // be tested elsewhere (dedicated indexing integration tests, missing ATM).
3826
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
3827
3828
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
3829
        $createStruct->setField('name', 'test');
3830
3831
        $locationCreateStruct = $locationService->newLocationCreateStruct(2);
3832
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
3833
        $content = $contentService->publishVersion($draft->getVersionInfo());
3834
        $contentTypeService->createContentTypeDraft($contentType);
3835
3836
        $this->refreshSearch($repository);
3837
3838
        return $content;
3839
    }
3840
3841
    /**
3842
     * Test for the findContent() method.
3843
     *
3844
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3845
     */
3846
    public function testUserMetadataGroupHorizontalFilterContent($queryType = null)
3847
    {
3848
        if ($queryType === null) {
3849
            $queryType = 'filter';
3850
        }
3851
3852
        $repository = $this->getRepository();
3853
        $searchService = $repository->getSearchService();
3854
        $editorsUserGroupId = 13;
3855
3856
        $content = $this->createContentForTestUserMetadataGroupHorizontal();
3857
3858
        $criteria = [];
3859
        $setupFactory = $this->getSetupFactory();
3860
3861
        // Do not limit for LSE, as it does not not require reindexing.
3862
        // See explanation below.
3863
        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...
3864
            $criteria[] = new Criterion\ContentTypeIdentifier('folder');
3865
        }
3866
3867
        $criteria[] = new Criterion\UserMetadata(
3868
            Criterion\UserMetadata::GROUP,
3869
            Criterion\Operator::EQ,
3870
            $editorsUserGroupId
3871
        );
3872
3873
        $query = new Query(
3874
            [
3875
                $queryType => new Criterion\LogicalAnd($criteria),
3876
                'sortClauses' => [
3877
                    new SortClause\ContentId(),
3878
                ],
3879
                'limit' => 50,
3880
            ]
3881
        );
3882
3883
        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...
3884
            $result = $searchService->findContent($query);
3885
3886
            // Administrator User is owned by itself, when additional Locations are added
3887
            // it should be reindexed and its UserGroups will updated, which means it should
3888
            // also be found as a Content of Editors UserGroup. However we do not handle this
3889
            // in slots yet, and also miss SPI methods to do it without using Search (also
3890
            // needed to decouple services), because as indexing is asynchronous Search
3891
            // should not eat its own dog food for reindexing.
3892
            $this->assertEquals(1, $result->totalCount);
3893
3894
            $this->assertEquals(
3895
                $content->id,
3896
                $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...
3897
            );
3898
        } else {
3899
            // This is how it should eventually work for all search engines,
3900
            // with required reindexing slots properly implemented.
3901
3902
            $result = $searchService->findContent($query);
3903
3904
            // Assert last hit manually, as id will change because it is created in test
3905
            // and not present it base fixture.
3906
            $foundContent1 = array_pop($result->searchHits);
3907
            $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...
3908
            $this->assertEquals($content->id, $foundContent1->valueObject->id);
3909
3910
            $this->simplifySearchResult($result);
3911
            $this->assertEquals(
3912
                include $this->getFixtureDir() . '/UserMetadata.php',
3913
                $result,
3914
                'Search results do not match.',
3915
                .1 // Be quite generous regarding delay -- most important for scores
3916
            );
3917
        }
3918
    }
3919
3920
    /**
3921
     * Test for the findContent() method.
3922
     *
3923
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
3924
     */
3925
    public function testUserMetadataGroupHorizontalQueryContent()
3926
    {
3927
        $this->testUserMetadataGroupHorizontalFilterContent('query');
3928
    }
3929
3930
    /**
3931
     * Test for the findLocations() method.
3932
     *
3933
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
3934
     */
3935
    public function testUserMetadataGroupHorizontalFilterLocation($queryType = null)
3936
    {
3937
        if ($queryType === null) {
3938
            $queryType = 'filter';
3939
        }
3940
3941
        $repository = $this->getRepository();
3942
        $searchService = $repository->getSearchService();
3943
        $editorsUserGroupId = 13;
3944
3945
        $content = $this->createContentForTestUserMetadataGroupHorizontal();
3946
3947
        $criteria = [];
3948
        $setupFactory = $this->getSetupFactory();
3949
3950
        // Do not limit for LSE, as it does not not require reindexing.
3951
        // See explanation below.
3952
        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...
3953
            $criteria[] = new Criterion\ContentTypeIdentifier('folder');
3954
        }
3955
3956
        $criteria[] = new Criterion\UserMetadata(
3957
            Criterion\UserMetadata::GROUP,
3958
            Criterion\Operator::EQ,
3959
            $editorsUserGroupId
3960
        );
3961
3962
        $query = new LocationQuery(
3963
            [
3964
                $queryType => new Criterion\LogicalAnd($criteria),
3965
                'sortClauses' => [
3966
                    new SortClause\Location\Id(),
3967
                ],
3968
                'limit' => 50,
3969
            ]
3970
        );
3971
3972
        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...
3973
            $result = $searchService->findLocations($query);
3974
3975
            // Administrator User is owned by itself, when additional Locations are added
3976
            // it should be reindexed and its UserGroups will updated, which means it should
3977
            // also be found as a Content of Editors UserGroup. However we do not handle this
3978
            // in slots yet, and also miss SPI methods to do it without using Search (also
3979
            // needed to decouple services), because as indexing is asynchronous Search
3980
            // should not eat its own dog food for reindexing.
3981
            $this->assertEquals(1, $result->totalCount);
3982
3983
            $this->assertEquals(
3984
                $content->contentInfo->mainLocationId,
3985
                $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...
3986
            );
3987
        } else {
3988
            // This is how it should eventually work for all search engines,
3989
            // with required reindexing slots properly implemented.
3990
3991
            $result = $searchService->findLocations($query);
3992
3993
            // Assert last two hits manually, as ids will change because they are created
3994
            // in test and not present in base fixture.
3995
            $foundLocation1 = array_pop($result->searchHits);
3996
            $foundLocation2 = array_pop($result->searchHits);
3997
            // Remove additional Administrators UserGroup Location
3998
            array_pop($result->searchHits);
3999
            $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...
4000
            $this->assertEquals(
4001
                $content->versionInfo->contentInfo->mainLocationId,
4002
                $foundLocation1->valueObject->id
4003
            );
4004
            $this->assertEquals(
4005
                $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...
4006
                $foundLocation2->valueObject->contentId
4007
            );
4008
4009
            $this->simplifySearchResult($result);
4010
            $this->assertEquals(
4011
                include $this->getFixtureDir() . '/UserMetadataLocation.php',
4012
                $result,
4013
                'Search results do not match.',
4014
                .1 // Be quite generous regarding delay -- most important for scores
4015
            );
4016
        }
4017
    }
4018
4019
    /**
4020
     * Test for the findLocations() method.
4021
     *
4022
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
4023
     */
4024
    public function testUserMetadataGroupHorizontalQueryLocation()
4025
    {
4026
        $this->testUserMetadataGroupHorizontalFilterLocation('query');
4027
    }
4028
4029
    /**
4030
     * Test for FullText on the findContent() method.
4031
     *
4032
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4033
     */
4034
    public function testFullTextOnNewContent()
4035
    {
4036
        $repository = $this->getRepository();
4037
        $contentService = $repository->getContentService();
4038
        $contentTypeService = $repository->getContentTypeService();
4039
        $locationService = $repository->getLocationService();
4040
        $searchService = $repository->getSearchService();
4041
4042
        $contentCreateStruct = $contentService->newContentCreateStruct(
4043
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4044
            'eng-GB'
4045
        );
4046
4047
        $contentCreateStruct->setField('name', 'foxes');
4048
4049
        $englishContent = $contentService->publishVersion(
4050
            $contentService->createContent(
4051
                $contentCreateStruct,
4052
                [$locationService->newLocationCreateStruct(2)]
4053
            )->versionInfo
4054
        );
4055
4056
        $this->refreshSearch($repository);
4057
4058
        $query = new Query(
4059
            [
4060
                'query' => new Criterion\FullText('foxes'),
4061
            ]
4062
        );
4063
4064
        $searchResult = $searchService->findContentInfo($query);
4065
4066
        $this->assertEquals(1, $searchResult->totalCount);
4067
        $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...
4068
    }
4069
4070
    /**
4071
     * Test for the findContent() method.
4072
     *
4073
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4074
     */
4075
    public function testLanguageAnalysisSeparateContent()
4076
    {
4077
        $setupFactory = $this->getSetupFactory();
4078
        if (!$setupFactory instanceof LegacyElasticsearch) {
4079
            $this->markTestSkipped('Language analysis is implemented only for Elasticsearch storage');
4080
        }
4081
4082
        $repository = $this->getRepository();
4083
        $contentService = $repository->getContentService();
4084
        $contentTypeService = $repository->getContentTypeService();
4085
        $locationService = $repository->getLocationService();
4086
        $searchService = $repository->getSearchService();
4087
        $languageService = $repository->getContentLanguageService();
4088
4089
        $languageCreateStruct = $languageService->newLanguageCreateStruct();
4090
        $languageCreateStruct->languageCode = 'rus-RU';
4091
        $languageCreateStruct->name = 'Russian';
4092
4093
        $languageService->createLanguage($languageCreateStruct);
4094
4095
        $contentCreateStruct = $contentService->newContentCreateStruct(
4096
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4097
            'eng-GB'
4098
        );
4099
4100
        $contentCreateStruct->setField('name', 'foxes');
4101
4102
        $englishContent = $contentService->publishVersion(
4103
            $contentService->createContent(
4104
                $contentCreateStruct,
4105
                [$locationService->newLocationCreateStruct(2)]
4106
            )->versionInfo
4107
        );
4108
4109
        $contentCreateStruct = $contentService->newContentCreateStruct(
4110
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4111
            'rus-RU'
4112
        );
4113
4114
        $contentCreateStruct->setField('name', 'foxes');
4115
4116
        $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...
4117
            $contentService->createContent(
4118
                $contentCreateStruct,
4119
                [$locationService->newLocationCreateStruct(2)]
4120
            )->versionInfo
4121
        );
4122
4123
        // Only Content in English should be found, because Content in Russian
4124
        // will not be correctly stemmed
4125
        $query = new Query(
4126
            [
4127
                'query' => new Criterion\FullText('foxing'),
4128
            ]
4129
        );
4130
4131
        $searchResult = $searchService->findContent($query);
4132
4133
        $this->assertEquals(1, $searchResult->totalCount);
4134
        $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...
4135
    }
4136
4137
    /**
4138
     * Test for the findContent() method.
4139
     *
4140
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4141
     */
4142
    public function testLanguageAnalysisSameContent()
4143
    {
4144
        $setupFactory = $this->getSetupFactory();
4145
        if (!$setupFactory instanceof LegacyElasticsearch) {
4146
            $this->markTestSkipped('Language analysis is implemented only for Elasticsearch storage');
4147
        }
4148
4149
        $repository = $this->getRepository();
4150
        $contentService = $repository->getContentService();
4151
        $contentTypeService = $repository->getContentTypeService();
4152
        $locationService = $repository->getLocationService();
4153
        $searchService = $repository->getSearchService();
4154
        $languageService = $repository->getContentLanguageService();
4155
4156
        $languageCreateStruct = $languageService->newLanguageCreateStruct();
4157
        $languageCreateStruct->languageCode = 'rus-RU';
4158
        $languageCreateStruct->name = 'Russian';
4159
4160
        $languageService->createLanguage($languageCreateStruct);
4161
4162
        $contentCreateStruct = $contentService->newContentCreateStruct(
4163
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4164
            'eng-GB'
4165
        );
4166
4167
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'eng-GB');
4168
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'rus-RU');
4169
4170
        $mixedContent = $contentService->publishVersion(
4171
            $contentService->createContent(
4172
                $contentCreateStruct,
4173
                [$locationService->newLocationCreateStruct(2)]
4174
            )->versionInfo
4175
        );
4176
4177
        // Content will be found because translation in Russian will be correctly stemmed
4178
        $query = new Query(
4179
            [
4180
                'query' => new Criterion\FullText('важнее'),
4181
            ]
4182
        );
4183
4184
        $searchResult = $searchService->findContent($query);
4185
4186
        $this->assertEquals(1, $searchResult->totalCount);
4187
        $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...
4188
    }
4189
4190
    /**
4191
     * Test for the findContent() method.
4192
     *
4193
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4194
     */
4195
    public function testLanguageAnalysisSameContentNotFound()
4196
    {
4197
        $setupFactory = $this->getSetupFactory();
4198
        if (!$setupFactory instanceof LegacyElasticsearch) {
4199
            $this->markTestSkipped('Language analysis is implemented only for Elasticsearch storage');
4200
        }
4201
4202
        $repository = $this->getRepository();
4203
        $contentService = $repository->getContentService();
4204
        $contentTypeService = $repository->getContentTypeService();
4205
        $locationService = $repository->getLocationService();
4206
        $searchService = $repository->getSearchService();
4207
        $languageService = $repository->getContentLanguageService();
4208
4209
        $languageCreateStruct = $languageService->newLanguageCreateStruct();
4210
        $languageCreateStruct->languageCode = 'rus-RU';
4211
        $languageCreateStruct->name = 'Russian';
4212
4213
        $languageService->createLanguage($languageCreateStruct);
4214
4215
        $contentCreateStruct = $contentService->newContentCreateStruct(
4216
            $contentTypeService->loadContentTypeByIdentifier('folder'),
4217
            'eng-GB'
4218
        );
4219
4220
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'eng-GB');
4221
        $contentCreateStruct->setField('name', 'foxes важнейшими', 'rus-RU');
4222
4223
        $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...
4224
            $contentService->createContent(
4225
                $contentCreateStruct,
4226
                [$locationService->newLocationCreateStruct(2)]
4227
            )->versionInfo
4228
        );
4229
4230
        // Content should be found because translation in Russian will be correctly stemmed
4231
        $query = new Query(
4232
            [
4233
                'query' => new Criterion\FullText('важнее'),
4234
            ]
4235
        );
4236
4237
        // Filtering fields for only English will cause no match because the term will
4238
        // not be correctly stemmed
4239
        $searchResult = $searchService->findContent($query, ['languages' => ['eng-GB']]);
4240
4241
        $this->assertEquals(0, $searchResult->totalCount);
4242
    }
4243
4244
    /**
4245
     * Test for the findContent() method searching for content filtered by languages.
4246
     *
4247
     * @covers \eZ\Publish\Core\Repository\SearchService::findContent
4248
     */
4249
    public function testFindContentWithLanguageFilter()
4250
    {
4251
        $repository = $this->getRepository();
4252
        $searchService = $repository->getSearchService();
4253
4254
        $query = new Query(
4255
            [
4256
                'filter' => new Criterion\ContentId([4]),
4257
                'offset' => 0,
4258
            ]
4259
        );
4260
        $searchResult = $searchService->findContent(
4261
            $query,
4262
            ['languages' => ['eng-US']],
4263
            false
4264
        );
4265
        /* END: Use Case */
4266
4267
        $this->assertInstanceOf(
4268
            SearchResult::class,
4269
            $searchResult
4270
        );
4271
4272
        $this->assertEquals(1, $searchResult->totalCount);
4273
        $this->assertCount($searchResult->totalCount, $searchResult->searchHits);
4274
        foreach ($searchResult->searchHits as $searchHit) {
4275
            $this->assertInstanceOf(
4276
                SearchHit::class,
4277
                $searchHit
4278
            );
4279
        }
4280
    }
4281
4282
    /**
4283
     * This test prepares data for other tests.
4284
     *
4285
     * @see testFulltextContentSearchComplex
4286
     * @see testFulltextLocationSearchComplex
4287
     *
4288
     * @return array
4289
     */
4290
    public function testFulltextComplex()
4291
    {
4292
        $repository = $this->getRepository();
4293
        $contentService = $repository->getContentService();
4294
        $contentTypeService = $repository->getContentTypeService();
4295
        $locationService = $repository->getLocationService();
4296
4297
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
4298
        $contentCreateStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
4299
4300
        $contentCreateStruct->setField('name', 'red');
4301
        $contentCreateStruct->setField('short_name', 'red apple');
4302
        $content1 = $contentService->publishVersion(
4303
            $contentService->createContent(
4304
                $contentCreateStruct,
4305
                [$locationService->newLocationCreateStruct(2)]
4306
            )->versionInfo
4307
        );
4308
4309
        $contentCreateStruct->setField('name', 'apple');
4310
        $contentCreateStruct->setField('short_name', 'two');
4311
        $content2 = $contentService->publishVersion(
4312
            $contentService->createContent(
4313
                $contentCreateStruct,
4314
                [$locationService->newLocationCreateStruct(2)]
4315
            )->versionInfo
4316
        );
4317
4318
        $contentCreateStruct->setField('name', 'red apple');
4319
        $contentCreateStruct->setField('short_name', 'three');
4320
        $content3 = $contentService->publishVersion(
4321
            $contentService->createContent(
4322
                $contentCreateStruct,
4323
                [$locationService->newLocationCreateStruct(2)]
4324
            )->versionInfo
4325
        );
4326
4327
        $this->refreshSearch($repository);
4328
4329
        $criterion = new Criterion\FullText(
4330
            'red apple',
4331
            [
4332
                'boost' => [
4333
                    'short_name' => 2,
4334
                ],
4335
                'fuzziness' => .1,
4336
            ]
4337
        );
4338
4339
        return [$criterion, $content1, $content2, $content3];
4340
    }
4341
4342
    /**
4343
     * Test for the findContent() method.
4344
     *
4345
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4346
     * @depends testFulltextComplex
4347
     *
4348
     * @param array $data
4349
     */
4350
    public function testFulltextContentSearchComplex(array $data)
4351
    {
4352
        // Do not initialize from scratch
4353
        $repository = $this->getRepository(false);
4354
        $searchService = $repository->getSearchService();
4355
        list($criterion, $content1, $content2, $content3) = $data;
4356
4357
        $searchResult = $searchService->findContent(
4358
            new Query(['query' => $criterion]),
4359
            ['languages' => ['eng-GB']]
4360
        );
4361
        $searchHits = $searchResult->searchHits;
4362
4363
        $this->assertEquals(3, $searchResult->totalCount);
4364
4365
        // Legacy search engine does have scoring, sorting the results by ID in that case
4366
        $setupFactory = $this->getSetupFactory();
4367 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...
4368
            usort(
4369
                $searchHits,
4370
                function ($a, $b) {
4371
                    return ($a->valueObject->id < $b->valueObject->id) ? -1 : 1;
4372
                }
4373
            );
4374
4375
            $this->assertEquals($content1->id, $searchHits[0]->valueObject->id);
4376
            $this->assertEquals($content2->id, $searchHits[1]->valueObject->id);
4377
            $this->assertEquals($content3->id, $searchHits[2]->valueObject->id);
4378
4379
            return;
4380
        }
4381
4382
        // Assert scores are descending
4383
        $this->assertGreaterThan($searchHits[1]->score, $searchHits[0]->score);
4384
        $this->assertGreaterThan($searchHits[2]->score, $searchHits[1]->score);
4385
4386
        // Assert order
4387
        $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...
4388
        $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...
4389
        $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...
4390
    }
4391
4392
    /**
4393
     * Test for the findLocations() method.
4394
     *
4395
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
4396
     * @depends testFulltextComplex
4397
     *
4398
     * @param array $data
4399
     */
4400
    public function testFulltextLocationSearchComplex(array $data)
4401
    {
4402
        $setupFactory = $this->getSetupFactory();
4403
        if ($setupFactory instanceof LegacyElasticsearch) {
4404
            $this->markTestIncomplete(
4405
                'Fulltext criterion is not supported with Location search in Elasticsearch engine'
4406
            );
4407
        }
4408
4409
        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...
4410
            $this->markTestSkipped('Skipping location search score test on Solr 4.10, you need Solr 6 for this!');
4411
        }
4412
4413
        // Do not initialize from scratch
4414
        $repository = $this->getRepository(false);
4415
        list($criterion, $content1, $content2, $content3) = $data;
4416
        $searchService = $repository->getSearchService();
4417
4418
        $searchResult = $searchService->findLocations(
4419
            new LocationQuery(['query' => $criterion]),
4420
            ['languages' => ['eng-GB']]
4421
        );
4422
        $searchHits = $searchResult->searchHits;
4423
4424
        $this->assertEquals(3, $searchResult->totalCount);
4425
4426
        // Legacy search engine does have scoring, sorting the results by ID in that case
4427
        $setupFactory = $this->getSetupFactory();
4428 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...
4429
            usort(
4430
                $searchHits,
4431
                function ($a, $b) {
4432
                    return ($a->valueObject->id < $b->valueObject->id) ? -1 : 1;
4433
                }
4434
            );
4435
4436
            $this->assertEquals($content1->id, $searchHits[0]->valueObject->contentId);
4437
            $this->assertEquals($content2->id, $searchHits[1]->valueObject->contentId);
4438
            $this->assertEquals($content3->id, $searchHits[2]->valueObject->contentId);
4439
4440
            return;
4441
        }
4442
4443
        // Assert scores are descending
4444
        $this->assertGreaterThan($searchHits[1]->score, $searchHits[0]->score);
4445
        $this->assertGreaterThan($searchHits[2]->score, $searchHits[1]->score);
4446
4447
        // Assert order
4448
        $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...
4449
        $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...
4450
        $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...
4451
    }
4452
4453
    /**
4454
     * Assert that query result matches the given fixture.
4455
     *
4456
     * @param Query $query
4457
     * @param string $fixture
4458
     * @param null|callable $closure
4459
     * @param bool $info
4460
     * @param bool $id
4461
     */
4462
    protected function assertQueryFixture(Query $query, $fixture, $closure = null, $ignoreScore = true, $info = false, $id = true)
4463
    {
4464
        $repository = $this->getRepository();
4465
        $searchService = $repository->getSearchService();
4466
4467
        try {
4468
            if ($query instanceof LocationQuery) {
4469
                $setupFactory = $this->getSetupFactory();
4470
                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...
4471
                    // @todo When we want to test score again by default we will need fixtures for Solr
4472
                }
4473
4474
                if ($setupFactory instanceof LegacyElasticsearch) {
4475
                    $position = strrpos($fixture, '/');
4476
                    $fixture = substr_replace($fixture, '/Location', $position, 0);
4477
                }
4478
4479
                $result = $searchService->findLocations($query);
4480
            } elseif ($query instanceof Query) {
4481
                if ($info) {
4482
                    $result = $searchService->findContentInfo($query);
4483
                } else {
4484
                    $result = $searchService->findContent($query);
4485
                }
4486
            } else {
4487
                $this->fail('Expected instance of LocationQuery or Query, got: ' . gettype($query));
4488
            }
4489
            $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...
4490
        } catch (NotImplementedException $e) {
4491
            $this->markTestSkipped(
4492
                'This feature is not supported by the current search backend: ' . $e->getMessage()
4493
            );
4494
        }
4495
4496 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...
4497
            if (isset($_ENV['ez_tests_record'])) {
4498
                file_put_contents(
4499
                    $record = $fixture . '.recording',
4500
                    "<?php\n\nreturn " . var_export($result, true) . ";\n\n"
4501
                );
4502
                $this->markTestIncomplete("No fixture available. Result recorded at $record. Result: \n" . $this->printResult($result));
4503
            } else {
4504
                $this->markTestIncomplete("No fixture available. Set \$_ENV['ez_tests_record'] to generate:\n " . $fixture);
4505
            }
4506
        }
4507
4508
        $fixture = include $fixture;
4509
4510
        if ($closure !== null) {
4511
            $closure($fixture);
4512
            $closure($result);
4513
        }
4514
4515 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...
4516
            foreach ([$fixture, $result] as $set) {
4517
                $property = new \ReflectionProperty(get_class($set), 'maxScore');
4518
                $property->setAccessible(true);
4519
                $property->setValue($set, 0.0);
4520
4521
                foreach ($set->searchHits as $hit) {
4522
                    $property = new \ReflectionProperty(get_class($hit), 'score');
4523
                    $property->setAccessible(true);
4524
                    $property->setValue($hit, 0.0);
4525
                }
4526
            }
4527
        }
4528
4529
        foreach ([$fixture, $result] as $set) {
4530
            foreach ($set->searchHits as $hit) {
4531
                $property = new \ReflectionProperty(get_class($hit), 'index');
4532
                $property->setAccessible(true);
4533
                $property->setValue($hit, null);
4534
4535
                $property = new \ReflectionProperty(get_class($hit), 'matchedTranslation');
4536
                $property->setAccessible(true);
4537
                $property->setValue($hit, null);
4538
4539
                if (!$id) {
4540
                    $hit->valueObject['id'] = null;
4541
                }
4542
            }
4543
        }
4544
4545
        $this->assertEquals(
4546
            $fixture,
4547
            $result,
4548
            'Search results do not match.',
4549
            .99 // Be quite generous regarding delay -- most important for scores
4550
        );
4551
    }
4552
4553
    /**
4554
     * Show a simplified view of the search result for manual introspection.
4555
     *
4556
     * @param SearchResult $result
4557
     *
4558
     * @return string
4559
     */
4560 View Code Duplication
    protected function printResult(SearchResult $result)
4561
    {
4562
        $printed = '';
4563
        foreach ($result->searchHits as $hit) {
4564
            $printed .= sprintf(" - %s (%s)\n", $hit->valueObject['title'], $hit->valueObject['id']);
4565
        }
4566
4567
        return $printed;
4568
    }
4569
4570
    /**
4571
     * Simplify search result.
4572
     *
4573
     * This leads to saner comparisons of results, since we do not get the full
4574
     * content objects every time.
4575
     *
4576
     * @param SearchResult $result
4577
     */
4578
    protected function simplifySearchResult(SearchResult $result)
4579
    {
4580
        $result->time = 1;
4581
4582
        foreach ($result->searchHits as $hit) {
4583
            switch (true) {
4584
                case $hit->valueObject instanceof Content:
4585 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...
4586
                    $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...
4587
                        'id' => $hit->valueObject->contentInfo->id,
4588
                        'title' => $hit->valueObject->contentInfo->name,
4589
                    ];
4590
                    break;
4591
4592
                case $hit->valueObject instanceof ContentInfo:
4593
                    $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...
4594
                        'id' => $hit->valueObject->id,
4595
                        'title' => $hit->valueObject->name,
4596
                    ];
4597
                    break;
4598
4599
                default:
4600
                    throw new \RuntimeException('Unknown search result hit type: ' . get_class($hit->valueObject));
4601
            }
4602
        }
4603
    }
4604
4605
    /**
4606
     * Get fixture directory.
4607
     *
4608
     * @return string
4609
     */
4610
    protected function getFixtureDir()
4611
    {
4612
        return __DIR__ . '/_fixtures/' . getenv('fixtureDir') . '/';
4613
    }
4614
4615
    /**
4616
     * For findContentInfo tests, to reuse fixtures for findContent tests.
4617
     *
4618
     * @param null|callable $closure
4619
     *
4620
     * @return callable
4621
     */
4622
    private function getContentInfoFixtureClosure($closure = null)
4623
    {
4624
        /** @var $data \eZ\Publish\API\Repository\Values\Content\Search\SearchResult */
4625
        return function (&$data) use ($closure) {
4626
            foreach ($data->searchHits as $searchHit) {
4627
                if ($searchHit->valueObject instanceof Content) {
4628
                    $searchHit->valueObject = $searchHit->valueObject->getVersionInfo()->getContentInfo();
4629
                }
4630
            }
4631
4632
            if (isset($closure)) {
4633
                $closure($data);
4634
            }
4635
        };
4636
    }
4637
4638
    /**
4639
     * Test searching using Field Criterion where the given Field Identifier exists in
4640
     * both searchable and non-searchable Fields.
4641
     * Number of returned results depends on used storage.
4642
     *
4643
     * @see \eZ\Publish\API\Repository\SearchService::findContent()
4644
     */
4645
    public function testFieldCriterionForContentsWithIdenticalFieldIdentifiers()
4646
    {
4647
        $this->createContentWithFieldType(
4648
            'url',
4649
            'title',
4650
            'foo'
4651
        );
4652
        $this->createContentWithFieldType(
4653
            'string',
4654
            'title',
4655
            'foo'
4656
        );
4657
        $query = new Query(
4658
            [
4659
                'query' => new Criterion\Field(
4660
                    'title',
4661
                    Criterion\Operator::EQ,
4662
                    'foo'
4663
                ),
4664
            ]
4665
        );
4666
4667
        $repository = $this->getRepository();
4668
        $searchService = $repository->getSearchService();
4669
        $result = $searchService->findContent($query);
4670
4671
        $this->assertTrue(($result->totalCount === 1 || $result->totalCount === 2));
4672
    }
4673
4674
    private function createContentWithFieldType(
4675
        string $fieldType,
4676
        string $fieldName,
4677
        string $fieldValue
4678
    ) {
4679
        $repository = $this->getRepository();
4680
        $contentTypeService = $repository->getContentTypeService();
4681
        $contentService = $repository->getContentService();
4682
4683
        $createStruct = $contentTypeService->newContentTypeCreateStruct($fieldType . uniqid());
4684
        $createStruct->mainLanguageCode = 'eng-GB';
4685
        $createStruct->remoteId = $fieldType . '-123';
4686
        $createStruct->names = ['eng-GB' => $fieldType];
4687
        $createStruct->creatorId = 14;
4688
        $createStruct->creationDate = new \DateTime();
4689
4690
        $fieldCreate = $contentTypeService->newFieldDefinitionCreateStruct($fieldName, 'ez' . $fieldType);
4691
        $fieldCreate->names = ['eng-GB' => $fieldName];
4692
        $fieldCreate->fieldGroup = 'main';
4693
        $fieldCreate->position = 1;
4694
4695
        $createStruct->addFieldDefinition($fieldCreate);
4696
4697
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
4698
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
4699
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
4700
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
4701
4702
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
4703
        $createStruct->remoteId = $fieldType . '-456';
4704
        $createStruct->alwaysAvailable = false;
4705
        $createStruct->setField(
4706
            $fieldName,
4707
            $fieldValue
4708
        );
4709
4710
        $draft = $contentService->createContent($createStruct);
4711
        $content = $contentService->publishVersion($draft->getVersionInfo());
4712
4713
        $this->refreshSearch($repository);
4714
4715
        return $content;
4716
    }
4717
}
4718