testFindLowerThanOrEqualTwo()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 6
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
5
 * @license For full copyright and license information view LICENSE file distributed with this source code.
6
 */
7
namespace eZ\Publish\API\Repository\Tests\FieldType;
8
9
use eZ\Publish\API\Repository\Repository;
10
use eZ\Publish\API\Repository\Tests\SetupFactory\Legacy;
11
use eZ\Publish\API\Repository\Values\Content\Content;
12
use eZ\Publish\API\Repository\Values\Content\Location;
13
use eZ\Publish\API\Repository\Values\Content\Query;
14
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
15
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
16
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\Operator;
17
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\Field;
18
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalNot;
19
use eZ\Publish\API\Repository\Values\Content\Query\Criterion\LogicalOperator;
20
use eZ\Publish\API\Repository\Values\Content\Query\CustomFieldInterface;
21
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
22
use eZ\Publish\API\Repository\Values\Content\Query\SortClause\Field as FieldSortClause;
23
use eZ\Publish\API\Repository\Values\Content\Search\SearchResult;
24
25
/**
26
 * Integration test for searching and sorting with Field criterion and Field sort clause.
27
 *
28
 * This abstract test case should be used as a base for a specific field type search
29
 * integration tests. It will first create two Content objects with two distinct field
30
 * values, then execute a series of tests for Field criterion and Field sort clause,
31
 * explicitly limited on these two values.
32
 *
33
 * Field criterion will be tested for each supported operator in all possible ways,
34
 * combined with LogicalNot criterion, while Field sort clause will be tested in
35
 * ascending and descending order.
36
 *
37
 * Same set of tests will be executed for each type of search (Content search, Location
38
 * search), and in case of a criterion separately for a filtering and querying type of
39
 * Query.
40
 *
41
 * To get the test working extend it in a concrete field type test and implement
42
 * methods:
43
 *
44
 * - getValidSearchValueOne()
45
 * - getValidSearchValueTwo()
46
 *
47
 * In the test descriptions Content object created with values One and Two are referred to
48
 * as Content One, and Content Two. See the descriptions of the abstract declarations of
49
 * these methods for more details on how to choose proper values.
50
 *
51
 * If needed you can override the methods that provide Field criterion target value and
52
 * which by default fall back to the methods mentioned above:
53
 *
54
 * - getSearchTargetValueOne()
55
 * - getSearchTargetValueTwo()
56
 *
57
 * In order to test fields additionally indexed by the field type, provide the required
58
 * data by overriding method:
59
 *
60
 * - getAdditionallyIndexedFieldData()
61
 *
62
 * The method must return an array of field data for each additionally indexed field,
63
 * consisting of field's name, as defined in field type's Indexable definition, value One
64
 * and value Two, corresponding to the data indexed by getValidSearchValueOne() and
65
 * getValidSearchValueTwo() methods described above. For example:
66
 *
67
 * <code>
68
 *  array(
69
 *      array(
70
 *          'file_size',
71
 *          1024,
72
 *          4096
73
 *      ),
74
 *      ...
75
 *  )
76
 * </code>
77
 *
78
 * In order to test full text search, provide the required data by overriding method:
79
 *
80
 * - getFullTextIndexedFieldData()
81
 *
82
 * This method must return an array of search values, consisting of search strings for
83
 * value One and value Two, corresponding to the data the field type indexes
84
 * for full text search from what is provided by getValidSearchValueOne() and
85
 * getValidSearchValueTwo(). By default the method skips tests, you should override
86
 * it in the concrete test case as required by the field type. For example:
87
 *
88
 * <code>
89
 *  array(
90
 *      array(
91
 *          'one',
92
 *          'two'
93
 *      ),
94
 *      ...
95
 *  )
96
 * </code>
97
 *
98
 * Note: this test case does not concern itself with testing field filters, behaviour
99
 * of multiple sort clauses or combination with other criteria. These are tested
100
 * elsewhere as a general field search cases, which enables keeping this test case
101
 * simple.
102
 */
103
abstract class SearchBaseIntegrationTest extends BaseIntegrationTest
104
{
105
    /**
106
     * Get search field value One.
107
     *
108
     * The value must be valid for Content creation.
109
     *
110
     * When Field sort clause with ascending order is used on the tested field,
111
     * Content containing the field with this value must come before the Content
112
     * with value One.
113
     *
114
     * Opposite should be the case when using descending order.
115
     *
116
     * @return mixed
117
     */
118
    abstract protected function getValidSearchValueOne();
119
120
    /**
121
     * Get search target field value One.
122
     *
123
     * Returns the Field criterion target value for the field value One.
124
     * Default implementation falls back on {@link getValidSearchValueOne}.
125
     *
126
     * @return mixed
127
     */
128
    protected function getSearchTargetValueOne()
129
    {
130
        return $this->getValidSearchValueOne();
131
    }
132
133
    /**
134
     * Get search field value Two.
135
     *
136
     * The value must be valid for Content creation.
137
     *
138
     * When Field sort clause with ascending order is used on the tested field,
139
     * Content containing the field with this value must come after the Content
140
     * with value One.
141
     *
142
     * Opposite should be the case when using descending order.
143
     *
144
     * @return mixed
145
     */
146
    abstract protected function getValidSearchValueTwo();
147
148
    /**
149
     * Get search target field value Two.
150
     *
151
     * Returns the Field criterion target value for the field value Two.
152
     * Default implementation falls back on {@link getValidSearchValueTwo}.
153
     *
154
     * @return mixed
155
     */
156
    protected function getSearchTargetValueTwo()
157
    {
158
        return $this->getValidSearchValueTwo();
159
    }
160
161
    /**
162
     * Returns test data for field type's additionally indexed fields.
163
     *
164
     * An array of field data is returned for each additionally indexed field,
165
     * consisting of field's name, as defined in field type's Indexable
166
     * definition, value One, and value Two, corresponding to the data indexed
167
     * by {@link getValidSearchValueOne()} and {@link getValidSearchValueTwo()}
168
     * methods. For example:
169
     *
170
     * <code>
171
     *  array(
172
     *      array(
173
     *          'file_size',
174
     *          1024,
175
     *          4096
176
     *      ),
177
     *      ...
178
     *  )
179
     * </code>
180
     *
181
     * @return array
182
     */
183
    protected function getAdditionallyIndexedFieldData()
184
    {
185
        return [];
186
    }
187
188
    /**
189
     * Returns tests data for full text search.
190
     *
191
     * An array of search values is returned, consisting of search strings for
192
     * value One and value Two, corresponding to the data the field type indexes
193
     * for full text search from what is provided by {@link getValidSearchValueOne()}
194
     * and {@link getValidSearchValueTwo()}. By default the tests are skipped here,
195
     * override in the concrete test case as required by the field type.
196
     * For example:
197
     *
198
     * <code>
199
     *  array(
200
     *      array(
201
     *          'one',
202
     *          'two'
203
     *      ),
204
     *      ...
205
     *  )
206
     * </code>
207
     *
208
     * @return array
209
     */
210
    protected function getFullTextIndexedFieldData()
211
    {
212
        $this->markTestSkipped(
213
            'Skipped by default, override in the concrete test case as required by the field type.'
214
        );
215
    }
216
217
    public function checkFullTextSupport()
218
    {
219
        // Does nothing by default, override in a concrete test case as needed
220
    }
221
222
    /**
223
     * Overload for field types that does not support wildcards in LIKE Field criteria.
224
     *
225
     * E.g. Any field type that needs to be matched as a whole: Email, bool, date/time, (singular) relation, integer.
226
     *
227
     * @param mixed $value
228
     *
229
     * @return bool
230
     */
231
    protected function supportsLikeWildcard($value)
232
    {
233
        return !is_numeric($value) && !is_bool($value);
234
    }
235
236
    /**
237
     * Used to control test execution by search engine.
238
     *
239
     * WARNING: Using this will block testing on a given search engine for FieldType, if partial limited on LegacySE use:
240
     * checkCustomFieldsSupport(), checkFullTextSupport(), supportsLikeWildcard(), $legacyUnsupportedOperators, (...).
241
     */
242
    protected function checkSearchEngineSupport()
243
    {
244
        // Does nothing by default, override in a concrete test case as needed
245
    }
246
247
    protected function checkCustomFieldsSupport()
248
    {
249
        if (get_class($this->getSetupFactory()) === Legacy::class) {
250
            $this->markTestSkipped('Legacy Search Engine does not support custom fields');
251
        }
252
    }
253
254
    /**
255
     * Creates and returns content with given $fieldData.
256
     *
257
     * @param mixed $fieldData
258
     * @param \eZ\Publish\API\Repository\Repository $repository
259
     * @param \eZ\Publish\API\Repository\Values\ContentType\ContentType $contentType
260
     *
261
     * @return \eZ\Publish\API\Repository\Values\Content\Content
262
     */
263
    protected function createTestSearchContent($fieldData, Repository $repository, $contentType)
264
    {
265
        $contentService = $repository->getContentService();
266
        $locationService = $repository->getLocationService();
267
268
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-US');
269
        $createStruct->setField('name', 'Test object');
270
        $createStruct->setField(
271
            'data',
272
            $fieldData
273
        );
274
275
        $locationCreateStruct = $locationService->newLocationCreateStruct(2);
276
277
        return $contentService->publishVersion(
278
            $contentService->createContent(
279
                $createStruct,
280
                [
281
                    $locationCreateStruct,
282
                ]
283
            )->versionInfo
284
        );
285
    }
286
287
    /**
288
     * Creates test Content and Locations and returns the context for subsequent testing.
289
     *
290
     * Context consists of repository instance and created Content IDs.
291
     *
292
     * @return \eZ\Publish\API\Repository\Repository
293
     */
294 View Code Duplication
    public function testCreateTestContent()
295
    {
296
        $repository = $this->getRepository();
297
        $fieldTypeService = $repository->getFieldTypeService();
298
        $fieldType = $fieldTypeService->getFieldType($this->getTypeName());
299
300
        if (!$fieldType->isSearchable()) {
301
            $this->markTestSkipped("Field type '{$this->getTypeName()}' is not searchable.");
302
        }
303
304
        $this->checkSearchEngineSupport();
305
306
        $contentType = $this->testCreateContentType();
307
308
        $context = [
309
            $repository,
310
            $this->createTestSearchContent(
311
                $this->getValidSearchValueOne(),
312
                $repository,
313
                $contentType
314
            )->id,
315
            $this->createTestSearchContent(
316
                $this->getValidSearchValueTwo(),
317
                $repository,
318
                $contentType
319
            )->id,
320
        ];
321
322
        $this->refreshSearch($repository);
323
324
        return $context;
325
    }
326
327
    /**
328
     * Provider method for testFind* methods.
329
     *
330
     * Do not use directly, use getAdditionallyIndexedFieldData() instead.
331
     *
332
     * @return array
333
     */
334 View Code Duplication
    public function findProvider()
335
    {
336
        $additionalFields = $this->getAdditionallyIndexedFieldData();
337
        $additionalFields[] = [
338
            null,
339
            $this->getSearchTargetValueOne(),
340
            $this->getSearchTargetValueTwo(),
341
        ];
342
        $templates = [
343
            [true, true],
344
            [true, false],
345
            [false, true],
346
            [false, false],
347
        ];
348
349
        $fixture = [];
350
351
        foreach ($additionalFields as $additionalField) {
352
            foreach ($templates as $template) {
353
                $template[] = $additionalField[0];
354
                array_unshift($template, $additionalField[2]);
355
                array_unshift($template, $additionalField[1]);
356
357
                $fixture[] = $template;
358
            }
359
        }
360
361
        return $fixture;
362
    }
363
364
    /**
365
     * Tests search with EQ operator.
366
     *
367
     * Simplified representation:
368
     *
369
     *     value EQ One
370
     *
371
     * The result should contain Content One.
372
     *
373
     * @dataProvider findProvider
374
     * @depends testCreateTestContent
375
     */
376
    public function testFindEqualsOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
377
    {
378
        $criteria = new Field('data', Operator::EQ, $valueOne);
379
380
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
381
    }
382
383
    /**
384
     * Tests search with EQ operator.
385
     *
386
     * Simplified representation:
387
     *
388
     *     NOT( value EQ One )
389
     *
390
     * The result should contain Content Two.
391
     *
392
     * @dataProvider findProvider
393
     * @depends testCreateTestContent
394
     */
395
    public function testFindNotEqualsOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
396
    {
397
        $criteria = new LogicalNot(new Field('data', Operator::EQ, $valueOne));
398
399
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
400
    }
401
402
    /**
403
     * Tests search with EQ operator.
404
     *
405
     * Simplified representation:
406
     *
407
     *     value EQ Two
408
     *
409
     * The result should contain Content Two.
410
     *
411
     * @dataProvider findProvider
412
     * @depends testCreateTestContent
413
     */
414
    public function testFindEqualsTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
415
    {
416
        $criteria = new Field('data', Operator::EQ, $valueTwo);
417
418
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
419
    }
420
421
    /**
422
     * Tests search with EQ operator.
423
     *
424
     * Simplified representation:
425
     *
426
     *     NOT( value EQ Two )
427
     *
428
     * The result should contain Content One.
429
     *
430
     * @dataProvider findProvider
431
     * @depends testCreateTestContent
432
     */
433
    public function testFindNotEqualsTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
434
    {
435
        $criteria = new LogicalNot(new Field('data', Operator::EQ, $valueTwo));
436
437
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
438
    }
439
440
    /**
441
     * Tests search with IN operator.
442
     *
443
     * Simplified representation:
444
     *
445
     *     value IN [One]
446
     *
447
     * The result should contain Content One.
448
     *
449
     * @dataProvider findProvider
450
     * @depends testCreateTestContent
451
     */
452
    public function testFindInOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
453
    {
454
        $criteria = new Field('data', Operator::IN, [$valueOne]);
455
456
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
457
    }
458
459
    /**
460
     * Tests search with IN operator.
461
     *
462
     * Simplified representation:
463
     *
464
     *     NOT( value IN [One] )
465
     *
466
     * The result should contain Content Two.
467
     *
468
     * @dataProvider findProvider
469
     * @depends testCreateTestContent
470
     */
471
    public function testFindNotInOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
472
    {
473
        $criteria = new LogicalNot(
474
            new Field('data', Operator::IN, [$valueOne])
475
        );
476
477
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
478
    }
479
480
    /**
481
     * Tests search with IN operator.
482
     *
483
     * Simplified representation:
484
     *
485
     *     value IN [Two]
486
     *
487
     * The result should contain Content Two.
488
     *
489
     * @dataProvider findProvider
490
     * @depends testCreateTestContent
491
     */
492
    public function testFindInTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
493
    {
494
        $criteria = new Field('data', Operator::IN, [$valueTwo]);
495
496
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
497
    }
498
499
    /**
500
     * Tests search with IN operator.
501
     *
502
     * Simplified representation:
503
     *
504
     *     NOT( value IN [Two] )
505
     *
506
     * The result should contain Content One.
507
     *
508
     * @dataProvider findProvider
509
     * @depends testCreateTestContent
510
     */
511
    public function testFindNotInTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
512
    {
513
        $criteria = new LogicalNot(
514
            new Field('data', Operator::IN, [$valueTwo])
515
        );
516
517
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
518
    }
519
520
    /**
521
     * Tests search with IN operator.
522
     *
523
     * Simplified representation:
524
     *
525
     *     value IN [One,Two]
526
     *
527
     * The result should contain both Content One and Content Two.
528
     *
529
     * @dataProvider findProvider
530
     * @depends testCreateTestContent
531
     */
532
    public function testFindInOneTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
533
    {
534
        $criteria = new Field(
535
            'data',
536
            Operator::IN,
537
            [
538
                $valueOne,
539
                $valueTwo,
540
            ]
541
        );
542
543
        $this->assertFindResult($context, $criteria, true, true, $filter, $content, $modifyField);
544
    }
545
546
    /**
547
     * Tests search with IN operator.
548
     *
549
     * Simplified representation:
550
     *
551
     *     NOT( value IN [One,Two] )
552
     *
553
     * The result should be empty.
554
     *
555
     * @dataProvider findProvider
556
     * @depends testCreateTestContent
557
     */
558
    public function testFindNotInOneTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
559
    {
560
        $criteria = new LogicalNot(
561
            new Field(
562
                'data',
563
                Operator::IN,
564
                [
565
                    $valueOne,
566
                    $valueTwo,
567
                ]
568
            )
569
        );
570
571
        $this->assertFindResult($context, $criteria, false, false, $filter, $content, $modifyField);
572
    }
573
574
    /**
575
     * Tests search with GT operator.
576
     *
577
     * Simplified representation:
578
     *
579
     *     value GT One
580
     *
581
     * The result should contain Content Two.
582
     *
583
     * @dataProvider findProvider
584
     * @depends testCreateTestContent
585
     */
586
    public function testFindGreaterThanOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
587
    {
588
        $criteria = new Field('data', Operator::GT, $valueOne);
589
590
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
591
    }
592
593
    /**
594
     * Tests search with GT operator.
595
     *
596
     * Simplified representation:
597
     *
598
     *     NOT( value GT One )
599
     *
600
     * The result should contain Content One.
601
     *
602
     * @dataProvider findProvider
603
     * @depends testCreateTestContent
604
     */
605
    public function testFindNotGreaterThanOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
606
    {
607
        $criteria = new LogicalNot(new Field('data', Operator::GT, $valueOne));
608
609
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
610
    }
611
612
    /**
613
     * Tests search with GT operator.
614
     *
615
     * Simplified representation:
616
     *
617
     *     value GT Two
618
     *
619
     * The result should be empty.
620
     *
621
     * @dataProvider findProvider
622
     * @depends testCreateTestContent
623
     */
624
    public function testFindGreaterThanTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
625
    {
626
        $criteria = new Field('data', Operator::GT, $valueTwo);
627
628
        $this->assertFindResult($context, $criteria, false, false, $filter, $content, $modifyField);
629
    }
630
631
    /**
632
     * Tests search with GT operator.
633
     *
634
     * Simplified representation:
635
     *
636
     *     NOT( value GT Two )
637
     *
638
     * The result should contain both Content One and Content Two.
639
     *
640
     * @dataProvider findProvider
641
     * @depends testCreateTestContent
642
     */
643
    public function testFindNotGreaterThanTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
644
    {
645
        $criteria = new LogicalNot(new Field('data', Operator::GT, $valueTwo));
646
647
        $this->assertFindResult($context, $criteria, true, true, $filter, $content, $modifyField);
648
    }
649
650
    /**
651
     * Tests search with GTE operator.
652
     *
653
     * Simplified representation:
654
     *
655
     *     value GTE One
656
     *
657
     * The result should contain both Content One and Content Two.
658
     *
659
     * @dataProvider findProvider
660
     * @depends testCreateTestContent
661
     */
662
    public function testFindGreaterThanOrEqualOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
663
    {
664
        $criteria = new Field('data', Operator::GTE, $valueOne);
665
666
        $this->assertFindResult($context, $criteria, true, true, $filter, $content, $modifyField);
667
    }
668
669
    /**
670
     * Tests search with GTE operator.
671
     *
672
     * Simplified representation:
673
     *
674
     *     NOT( value GTE One )
675
     *
676
     * The result should be empty.
677
     *
678
     * @dataProvider findProvider
679
     * @depends testCreateTestContent
680
     */
681
    public function testFindNotGreaterThanOrEqual($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
682
    {
683
        $criteria = new LogicalNot(new Field('data', Operator::GTE, $valueOne));
684
685
        $this->assertFindResult($context, $criteria, false, false, $filter, $content, $modifyField);
686
    }
687
688
    /**
689
     * Tests search with GTE operator.
690
     *
691
     * Simplified representation:
692
     *
693
     *     value GTE Two
694
     *
695
     * The result should contain Content Two.
696
     *
697
     * @dataProvider findProvider
698
     * @depends testCreateTestContent
699
     */
700
    public function testFindGreaterThanOrEqualTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
701
    {
702
        $criteria = new Field('data', Operator::GTE, $valueTwo);
703
704
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
705
    }
706
707
    /**
708
     * Tests search with GTE operator.
709
     *
710
     * Simplified representation:
711
     *
712
     *     NOT( value GTE Two )
713
     *
714
     * The result should contain Content One.
715
     *
716
     * @dataProvider findProvider
717
     * @depends testCreateTestContent
718
     */
719
    public function testFindNotGreaterThanOrEqualTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
720
    {
721
        $criteria = new LogicalNot(new Field('data', Operator::GTE, $valueTwo));
722
723
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
724
    }
725
726
    /**
727
     * Tests search with LT operator.
728
     *
729
     * Simplified representation:
730
     *
731
     *     value LT One
732
     *
733
     * The result should be empty.
734
     *
735
     * @dataProvider findProvider
736
     * @depends testCreateTestContent
737
     */
738
    public function testFindLowerThanOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
739
    {
740
        $criteria = new Field('data', Operator::LT, $valueOne);
741
742
        $this->assertFindResult($context, $criteria, false, false, $filter, $content, $modifyField);
743
    }
744
745
    /**
746
     * Tests search with LT operator.
747
     *
748
     * Simplified representation:
749
     *
750
     *     NOT( value LT One )
751
     *
752
     * The result should contain both Content One and Content Two.
753
     *
754
     * @dataProvider findProvider
755
     * @depends testCreateTestContent
756
     */
757
    public function testFindNotLowerThanOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
758
    {
759
        $criteria = new LogicalNot(new Field('data', Operator::LT, $valueOne));
760
761
        $this->assertFindResult($context, $criteria, true, true, $filter, $content, $modifyField);
762
    }
763
764
    /**
765
     * Tests search with LT operator.
766
     *
767
     * Simplified representation:
768
     *
769
     *     value LT Two
770
     *
771
     * The result should contain Content One.
772
     *
773
     * @dataProvider findProvider
774
     * @depends testCreateTestContent
775
     */
776
    public function testFindLowerThanTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
777
    {
778
        $criteria = new Field('data', Operator::LT, $valueTwo);
779
780
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
781
    }
782
783
    /**
784
     * Tests search with LT operator.
785
     *
786
     * Simplified representation:
787
     *
788
     *     NOT( value LT Two )
789
     *
790
     * The result should contain Content Two.
791
     *
792
     * @dataProvider findProvider
793
     * @depends testCreateTestContent
794
     */
795
    public function testFindNotLowerThanTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
796
    {
797
        $criteria = new LogicalNot(new Field('data', Operator::LT, $valueTwo));
798
799
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
800
    }
801
802
    /**
803
     * Tests search with LTE operator.
804
     *
805
     * Simplified representation:
806
     *
807
     *     value LTE One
808
     *
809
     * The result should contain Content One.
810
     *
811
     * @dataProvider findProvider
812
     * @depends testCreateTestContent
813
     */
814
    public function testFindLowerThanOrEqualOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
815
    {
816
        $criteria = new Field('data', Operator::LTE, $valueOne);
817
818
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
819
    }
820
821
    /**
822
     * Tests search with LTE operator.
823
     *
824
     * Simplified representation:
825
     *
826
     *     NOT( value LTE One )
827
     *
828
     * The result should contain Content Two.
829
     *
830
     * @dataProvider findProvider
831
     * @depends testCreateTestContent
832
     */
833
    public function testFindNotLowerThanOrEqualOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
834
    {
835
        $criteria = new LogicalNot(new Field('data', Operator::LTE, $valueOne));
836
837
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
838
    }
839
840
    /**
841
     * Tests search with LTE operator.
842
     *
843
     * Simplified representation:
844
     *
845
     *     value LTE Two
846
     *
847
     * The result should contain both Content One and Content Two.
848
     *
849
     * @dataProvider findProvider
850
     * @depends testCreateTestContent
851
     */
852
    public function testFindLowerThanOrEqualTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
853
    {
854
        $criteria = new Field('data', Operator::LTE, $valueTwo);
855
856
        $this->assertFindResult($context, $criteria, true, true, $filter, $content, $modifyField);
857
    }
858
859
    /**
860
     * Tests search with LTE operator.
861
     *
862
     * Simplified representation:
863
     *
864
     *     NOT( value LTE Two )
865
     *
866
     * The result should be empty.
867
     *
868
     * @dataProvider findProvider
869
     * @depends testCreateTestContent
870
     */
871
    public function testFindNotLowerThanOrEqualTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
872
    {
873
        $criteria = new LogicalNot(new Field('data', Operator::LTE, $valueTwo));
874
875
        $this->assertFindResult($context, $criteria, false, false, $filter, $content, $modifyField);
876
    }
877
878
    /**
879
     * Tests search with BETWEEN operator.
880
     *
881
     * Simplified representation:
882
     *
883
     *     value BETWEEN [One,Two]
884
     *
885
     * The result should contain both Content One and Content Two.
886
     *
887
     * @dataProvider findProvider
888
     * @depends testCreateTestContent
889
     */
890
    public function testFindBetweenOneTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
891
    {
892
        $criteria = new Field(
893
            'data',
894
            Operator::BETWEEN,
895
            [
896
                $valueOne,
897
                $valueTwo,
898
            ]
899
        );
900
901
        $this->assertFindResult($context, $criteria, true, true, $filter, $content, $modifyField);
902
    }
903
904
    /**
905
     * Tests search with BETWEEN operator.
906
     *
907
     * Simplified representation:
908
     *
909
     *     NOT( value BETWEEN [One,Two] )
910
     *
911
     * The result should contain both Content One and Content Two.
912
     *
913
     * @dataProvider findProvider
914
     * @depends testCreateTestContent
915
     */
916
    public function testFindNotBetweenOneTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
917
    {
918
        $criteria = new LogicalNot(
919
            new Field(
920
                'data',
921
                Operator::BETWEEN,
922
                [
923
                    $valueOne,
924
                    $valueTwo,
925
                ]
926
            )
927
        );
928
929
        $this->assertFindResult($context, $criteria, false, false, $filter, $content, $modifyField);
930
    }
931
932
    /**
933
     * Tests search with BETWEEN operator.
934
     *
935
     * Simplified representation:
936
     *
937
     *     value BETWEEN [Two,One]
938
     *
939
     * The result should be empty.
940
     *
941
     * @dataProvider findProvider
942
     * @depends testCreateTestContent
943
     */
944
    public function testFindBetweenTwoOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
945
    {
946
        $criteria = new Field(
947
            'data',
948
            Operator::BETWEEN,
949
            [
950
                $valueTwo,
951
                $valueOne,
952
            ]
953
        );
954
955
        $this->assertFindResult($context, $criteria, false, false, $filter, $content, $modifyField);
956
    }
957
958
    /**
959
     * Tests search with BETWEEN operator.
960
     *
961
     * Simplified representation:
962
     *
963
     *     NOT( value BETWEEN [Two,One] )
964
     *
965
     * The result should contain both Content One and Content Two.
966
     *
967
     * @dataProvider findProvider
968
     * @depends testCreateTestContent
969
     */
970
    public function testFindNotBetweenTwoOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
971
    {
972
        $criteria = new LogicalNot(
973
            new Field(
974
                'data',
975
                Operator::BETWEEN,
976
                [
977
                    $valueTwo,
978
                    $valueOne,
979
                ]
980
            )
981
        );
982
983
        $this->assertFindResult($context, $criteria, true, true, $filter, $content, $modifyField);
984
    }
985
986
    /**
987
     * Tests search with CONTAINS operator.
988
     *
989
     * Simplified representation:
990
     *
991
     *     value CONTAINS One
992
     *
993
     * The result should contain Content One.
994
     *
995
     * @dataProvider findProvider
996
     * @depends testCreateTestContent
997
     */
998
    public function testFindContainsOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
999
    {
1000
        $criteria = new Field('data', Operator::CONTAINS, $valueOne);
1001
1002
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
1003
    }
1004
1005
    /**
1006
     * Tests search with CONTAINS operator.
1007
     *
1008
     * Simplified representation:
1009
     *
1010
     *     NOT( value CONTAINS One )
1011
     *
1012
     * The result should contain Content Two.
1013
     *
1014
     * @dataProvider findProvider
1015
     * @depends testCreateTestContent
1016
     */
1017
    public function testFindNotContainsOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1018
    {
1019
        $criteria = new LogicalNot(new Field('data', Operator::CONTAINS, $valueOne));
1020
1021
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
1022
    }
1023
1024
    /**
1025
     * Tests search with CONTAINS operator.
1026
     *
1027
     * Simplified representation:
1028
     *
1029
     *     value CONTAINS Two
1030
     *
1031
     * The result should contain Content Two.
1032
     *
1033
     * @dataProvider findProvider
1034
     * @depends testCreateTestContent
1035
     */
1036
    public function testFindContainsTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1037
    {
1038
        $criteria = new Field('data', Operator::CONTAINS, $valueTwo);
1039
1040
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
1041
    }
1042
1043
    /**
1044
     * Tests search with CONTAINS operator.
1045
     *
1046
     * Simplified representation:
1047
     *
1048
     *     NOT( value CONTAINS Two )
1049
     *
1050
     * The result should contain Content One.
1051
     *
1052
     * @dataProvider findProvider
1053
     * @depends testCreateTestContent
1054
     */
1055 View Code Duplication
    public function testFindNotContainsTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1056
    {
1057
        $criteria = new LogicalNot(
1058
            new Field('data', Operator::CONTAINS, $valueTwo)
1059
        );
1060
1061
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
1062
    }
1063
1064
    /**
1065
     * Tests search with LIKE operator, with NO wildcard.
1066
     *
1067
     * @dataProvider findProvider
1068
     * @depends testCreateTestContent
1069
     */
1070 View Code Duplication
    public function testFindLikeOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1071
    {
1072
        // (in case test is skipped for current search engine)
1073
        $this->supportsLikeWildcard($valueOne);
1074
1075
        $criteria = new Field('data', Operator::LIKE, $valueOne);
1076
1077
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
1078
    }
1079
1080
    /**
1081
     * Tests search with LIKE operator, with wildcard at the end (on strings).
1082
     *
1083
     * @dataProvider findProvider
1084
     * @depends testCreateTestContent
1085
     */
1086 View Code Duplication
    public function testFindNotLikeOne($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1087
    {
1088
        if ($this->supportsLikeWildcard($valueOne)) {
1089
            $valueOne = substr_replace($valueOne, '*', -1, 1);
1090
        }
1091
1092
        $criteria = new LogicalNot(
1093
            new Field('data', Operator::LIKE, $valueOne)
1094
        );
1095
1096
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
1097
    }
1098
1099
    /**
1100
     * Tests search with LIKE operator, with wildcard at the start (on strings).
1101
     *
1102
     * @dataProvider findProvider
1103
     * @depends testCreateTestContent
1104
     */
1105
    public function testFindLikeTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1106
    {
1107
        if ($this->supportsLikeWildcard($valueTwo)) {
1108
            $valueTwo = substr_replace($valueTwo, '*', 1, 1);
1109
        }
1110
1111
        $criteria = new Field('data', Operator::LIKE, $valueTwo);
1112
1113
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
1114
1115
        // BC support for "%" for Legacy Storage engine only
1116
        // @deprecated In 6.13.x/7.3.x and higher, to be removed in 8.0
1117
        if (!$this->supportsLikeWildcard($valueTwo) || get_class($this->getSetupFactory()) !== Legacy::class) {
1118
            return;
1119
        }
1120
1121
        $criteria = new Field('data', Operator::LIKE, substr_replace($valueTwo, '%', 1, 1));
1122
1123
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, $modifyField);
1124
    }
1125
1126
    /**
1127
     * Tests search with LIKE operator, with wildcard in the middle (on strings).
1128
     *
1129
     * @dataProvider findProvider
1130
     * @depends testCreateTestContent
1131
     */
1132 View Code Duplication
    public function testFindNotLikeTwo($valueOne, $valueTwo, $filter, $content, $modifyField, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1133
    {
1134
        if ($this->supportsLikeWildcard($valueTwo)) {
1135
            $valueTwo = substr_replace($valueTwo, '*', 2, 1);
1136
        }
1137
1138
        $criteria = new LogicalNot(
1139
            new Field('data', Operator::LIKE, $valueTwo)
1140
        );
1141
1142
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, $modifyField);
1143
    }
1144
1145
    /**
1146
     * Sets given custom field $fieldName on a Field criteria.
1147
     *
1148
     * $fieldName refers to additional field (to the default field) defined in Indexable definition,
1149
     * and is resolved using FieldNameResolver.
1150
     *
1151
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
1152
     * @param string $fieldName
1153
     */
1154 View Code Duplication
    protected function modifyFieldCriterion(Criterion $criterion, $fieldName)
1155
    {
1156
        $setupFactory = $this->getSetupFactory();
1157
        /** @var \Symfony\Component\DependencyInjection\ContainerBuilder $container */
1158
        $container = $setupFactory->getServiceContainer()->getInnerContainer();
1159
1160
        /** @var \eZ\Publish\Core\Search\Common\FieldNameResolver $fieldNameResolver */
1161
        $fieldNameResolver = $container->get('ezpublish.search.common.field_name_resolver');
1162
        $resolvedFieldNames = $fieldNameResolver->getFieldNames(
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\Core\Search\C...solver::getFieldNames() has been deprecated with message: since 6.2, use getFieldTypes instead

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...
1163
            $criterion,
1164
            'data',
1165
            $this->getTypeName(),
1166
            $fieldName
1167
        );
1168
        $resolvedFieldName = reset($resolvedFieldNames);
1169
        $criterion = [$criterion];
1170
1171
        $this->doModifyField($criterion, $resolvedFieldName);
1172
    }
1173
1174
    /**
1175
     * Sets given custom field $fieldName on a Field sort clause.
1176
     *
1177
     * $fieldName refers to additional field (to the default field) defined in Indexable definition,
1178
     * and is resolved using FieldNameResolver.
1179
     *
1180
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause $sortClause
1181
     * @param string $fieldName
1182
     */
1183 View Code Duplication
    protected function modifyFieldSortClause(SortClause $sortClause, $fieldName)
1184
    {
1185
        $setupFactory = $this->getSetupFactory();
1186
        /** @var \Symfony\Component\DependencyInjection\ContainerBuilder $container */
1187
        $container = $setupFactory->getServiceContainer()->getInnerContainer();
1188
1189
        /** @var \eZ\Publish\Core\Search\Common\FieldNameResolver $fieldNameResolver */
1190
        $fieldNameResolver = $container->get('ezpublish.search.common.field_name_resolver');
1191
        $resolvedFieldName = $fieldNameResolver->getSortFieldName(
1192
            $sortClause,
1193
            'test-' . $this->getTypeName(),
1194
            'data',
1195
            $fieldName
1196
        );
1197
        $sortClause = [$sortClause];
1198
1199
        $this->doModifyField($sortClause, $resolvedFieldName);
0 ignored issues
show
Bug introduced by
It seems like $resolvedFieldName defined by $fieldNameResolver->getS...(), 'data', $fieldName) on line 1191 can also be of type false or null; however, eZ\Publish\API\Repositor...onTest::doModifyField() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1200
    }
1201
1202
    /**
1203
     * Sets given custom field $fieldName on a Field criteria or sort clauses.
1204
     *
1205
     * Implemented separately to utilize recursion.
1206
     *
1207
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion[]|\eZ\Publish\API\Repository\Values\Content\Query\SortClause[] $criteriaOrSortClauses
1208
     * @param string $fieldName
1209
     */
1210
    protected function doModifyField(array $criteriaOrSortClauses, $fieldName)
1211
    {
1212
        foreach ($criteriaOrSortClauses as $criterionOrSortClause) {
1213
            if ($criterionOrSortClause instanceof LogicalOperator) {
1214
                $this->doModifyField($criterionOrSortClause->criteria, $fieldName);
1215
            } elseif ($criterionOrSortClause instanceof CustomFieldInterface) {
1216
                $criterionOrSortClause->setCustomField(
1217
                    'test-' . $this->getTypeName(),
1218
                    'data',
1219
                    $fieldName
1220
                );
1221
            }
1222
        }
1223
    }
1224
1225
    public function sortProvider()
1226
    {
1227
        $additionalFields = $this->getAdditionallyIndexedFieldData();
1228
        $additionalFields[] = null;
1229
        $templates = [
1230
            [true, true],
1231
            [true, false],
1232
            [false, true],
1233
            [false, false],
1234
        ];
1235
1236
        $fixture = [];
1237
1238
        foreach ($additionalFields as $additionalField) {
1239
            foreach ($templates as $template) {
1240
                $template[] = $additionalField[0] ?? null;
1241
                $fixture[] = $template;
1242
            }
1243
        }
1244
1245
        return $fixture;
1246
    }
1247
1248
    /**
1249
     * Tests Content Search sort with Field sort clause on a field of specific field type.
1250
     *
1251
     * @dataProvider sortProvider
1252
     * @depends testCreateTestContent
1253
     */
1254
    public function testSort($ascending, $content, $modifyField, array $context)
1255
    {
1256
        list($repository, $contentOneId, $contentTwoId) = $context;
1257
        $sortClause = new FieldSortClause(
1258
            'test-' . $this->getTypeName(),
1259
            'data',
1260
            $ascending ? Query::SORT_ASC : Query::SORT_DESC
1261
        );
1262
1263
        if ($content) {
1264
            $searchResult = $this->sortContent($repository, $sortClause);
1265
        } else {
1266
            $searchResult = $this->sortLocations($repository, $sortClause);
1267
        }
1268
1269
        if ($modifyField !== null) {
1270
            $this->checkCustomFieldsSupport();
1271
            $this->modifyFieldSortClause($sortClause, $modifyField);
1272
        }
1273
1274
        $this->assertSortResult($searchResult, $ascending, $contentOneId, $contentTwoId);
1275
    }
1276
1277
    public function fullTextFindProvider()
1278
    {
1279
        $templates = [
1280
            [true, true],
1281
            [true, false],
1282
            [false, true],
1283
            [false, false],
1284
        ];
1285
1286
        $fixture = [];
1287
1288
        foreach ($this->getFullTextIndexedFieldData() as $valueSet) {
0 ignored issues
show
Bug introduced by
The expression $this->getFullTextIndexedFieldData() of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1289
            foreach ($templates as $template) {
1290
                array_unshift($template, $valueSet[1]);
1291
                array_unshift($template, $valueSet[0]);
1292
1293
                $fixture[] = $template;
1294
            }
1295
        }
1296
1297
        return $fixture;
1298
    }
1299
1300
    /**
1301
     * @dataProvider fullTextFindProvider
1302
     * @depends testCreateTestContent
1303
     */
1304 View Code Duplication
    public function testFullTextFindOne($valueOne, $valueTwo, $filter, $content, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueTwo is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1305
    {
1306
        $this->checkFullTextSupport();
1307
1308
        $criteria = new Criterion\FullText($valueOne);
1309
1310
        $this->assertFindResult($context, $criteria, true, false, $filter, $content, null);
1311
    }
1312
1313
    /**
1314
     * @dataProvider fullTextFindProvider
1315
     * @depends testCreateTestContent
1316
     */
1317 View Code Duplication
    public function testFullTextFindTwo($valueOne, $valueTwo, $filter, $content, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $valueOne is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1318
    {
1319
        $this->checkFullTextSupport();
1320
1321
        $criteria = new Criterion\FullText($valueTwo);
1322
1323
        $this->assertFindResult($context, $criteria, false, true, $filter, $content, null);
1324
    }
1325
1326
    /**
1327
     * Returns SearchResult of the tested Content for the given $criterion.
1328
     *
1329
     * @param \eZ\Publish\API\Repository\Repository $repository
1330
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
1331
     * @param bool $filter Denotes search by filtering if true, search by querying if false
1332
     *
1333
     * @return \eZ\Publish\API\Repository\Values\Content\Search\SearchResult
1334
     */
1335 View Code Duplication
    protected function findContent(Repository $repository, Criterion $criterion, $filter)
1336
    {
1337
        $searchService = $repository->getSearchService();
1338
1339
        if ($filter) {
1340
            $criteriaProperty = 'filter';
1341
        } else {
1342
            $criteriaProperty = 'query';
1343
        }
1344
1345
        $query = new Query(
1346
            [
1347
                $criteriaProperty => new Criterion\LogicalAnd(
1348
                    [
1349
                        new Criterion\ContentTypeIdentifier('test-' . $this->getTypeName()),
1350
                        $criterion,
1351
                    ]
1352
                ),
1353
            ]
1354
        );
1355
1356
        return $searchService->findContent($query);
1357
    }
1358
1359
    /**
1360
     * Returns SearchResult of the tested Content for the given $sortClause.
1361
     *
1362
     * @param \eZ\Publish\API\Repository\Repository $repository
1363
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause $sortClause
1364
     *
1365
     * @return \eZ\Publish\API\Repository\Values\Content\Search\SearchResult
1366
     */
1367 View Code Duplication
    protected function sortContent(Repository $repository, SortClause $sortClause)
1368
    {
1369
        $searchService = $repository->getSearchService();
1370
1371
        $query = new Query(
1372
            [
1373
                'filter' => new Criterion\ContentTypeIdentifier('test-' . $this->getTypeName()),
1374
                'sortClauses' => [
1375
                    $sortClause,
1376
                ],
1377
            ]
1378
        );
1379
1380
        return $searchService->findContent($query);
1381
    }
1382
1383
    /**
1384
     * Returns SearchResult of the tested Locations for the given $criterion.
1385
     *
1386
     * @param \eZ\Publish\API\Repository\Repository $repository
1387
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
1388
     * @param bool $filter Denotes search by filtering if true, search by querying if false
1389
     *
1390
     * @return \eZ\Publish\API\Repository\Values\Content\Search\SearchResult
1391
     */
1392 View Code Duplication
    protected function findLocations(Repository $repository, Criterion $criterion, $filter)
1393
    {
1394
        $searchService = $repository->getSearchService();
1395
1396
        if ($filter) {
1397
            $criteriaProperty = 'filter';
1398
        } else {
1399
            $criteriaProperty = 'query';
1400
        }
1401
1402
        $query = new LocationQuery(
1403
            [
1404
                $criteriaProperty => new Criterion\LogicalAnd(
1405
                    [
1406
                        new Criterion\ContentTypeIdentifier('test-' . $this->getTypeName()),
1407
                        $criterion,
1408
                    ]
1409
                ),
1410
            ]
1411
        );
1412
1413
        return $searchService->findLocations($query);
1414
    }
1415
1416
    /**
1417
     * Returns SearchResult of the tested Locations for the given $sortClause.
1418
     *
1419
     * @param \eZ\Publish\API\Repository\Repository $repository
1420
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause $sortClause
1421
     *
1422
     * @return \eZ\Publish\API\Repository\Values\Content\Search\SearchResult
1423
     */
1424 View Code Duplication
    protected function sortLocations(Repository $repository, SortClause $sortClause)
1425
    {
1426
        $searchService = $repository->getSearchService();
1427
1428
        $query = new LocationQuery(
1429
            [
1430
                'filter' => new Criterion\ContentTypeIdentifier('test-' . $this->getTypeName()),
1431
                'sortClauses' => [
1432
                    $sortClause,
1433
                ],
1434
            ]
1435
        );
1436
1437
        return $searchService->findLocations($query);
1438
    }
1439
1440
    /**
1441
     * Returns a list of Content IDs from given $searchResult, with order preserved.
1442
     *
1443
     * @param \eZ\Publish\API\Repository\Values\Content\Search\SearchResult $searchResult
1444
     *
1445
     * @return array
1446
     */
1447
    protected function getResultContentIdList(SearchResult $searchResult)
1448
    {
1449
        $contentIdList = [];
1450
1451
        foreach ($searchResult->searchHits as $searchHit) {
1452
            $valueObject = $searchHit->valueObject;
1453
1454
            switch (true) {
1455
                case $valueObject instanceof Content:
1456
                    $contentIdList[] = $valueObject->id;
1457
                    break;
1458
1459
                case $valueObject instanceof Location:
1460
                    $contentIdList[] = $valueObject->contentId;
1461
                    break;
1462
1463
                default:
1464
                    throw new \RuntimeException(
1465
                        'Unknown search result hit type: ' . get_class($searchHit->valueObject)
1466
                    );
1467
            }
1468
        }
1469
1470
        return $contentIdList;
1471
    }
1472
1473
    /**
1474
     * Asserts expected result, deliberately ignoring order.
1475
     *
1476
     * Search result can be empty, contain both Content One and Content Two or only one of them.
1477
     *
1478
     * @param array $context
1479
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
1480
     * @param bool $includesOne
1481
     * @param bool $includesTwo
1482
     * @param bool $filter
1483
     * @param bool $content
1484
     * @param string|null $modifyField
1485
     */
1486
    protected function assertFindResult(
1487
        array $context,
1488
        Criterion $criterion,
1489
        $includesOne,
1490
        $includesTwo,
1491
        $filter,
1492
        $content,
1493
        $modifyField
1494
    ) {
1495
        list($repository, $contentOneId, $contentTwoId) = $context;
1496
1497
        if ($modifyField !== null) {
1498
            $this->checkCustomFieldsSupport();
1499
            $this->modifyFieldCriterion($criterion, $modifyField);
1500
        }
1501
1502
        if ($content) {
1503
            $searchResult = $this->findContent($repository, $criterion, $filter);
1504
        } else {
1505
            $searchResult = $this->findLocations($repository, $criterion, $filter);
1506
        }
1507
1508
        $contentIdList = $this->getResultContentIdList($searchResult);
1509
1510
        if ($includesOne && $includesTwo) {
1511
            $this->assertEquals(2, $searchResult->totalCount);
1512
            $this->assertNotEquals($contentIdList[0], $contentIdList[1]);
1513
1514
            $this->assertThat(
1515
                $contentIdList[0],
1516
                $this->logicalOr($this->equalTo($contentOneId), $this->equalTo($contentTwoId))
1517
            );
1518
1519
            $this->assertThat(
1520
                $contentIdList[1],
1521
                $this->logicalOr($this->equalTo($contentOneId), $this->equalTo($contentTwoId))
1522
            );
1523
        } elseif (!$includesOne && !$includesTwo) {
1524
            $this->assertEquals(0, $searchResult->totalCount);
1525
        } else {
1526
            $this->assertEquals(1, $searchResult->totalCount);
1527
1528
            if ($includesOne) {
1529
                $this->assertEquals($contentOneId, $contentIdList[0]);
1530
            }
1531
1532
            if ($includesTwo) {
1533
                $this->assertEquals($contentTwoId, $contentIdList[0]);
1534
            }
1535
        }
1536
    }
1537
1538
    /**
1539
     * Asserts order of the given $searchResult, both Content One and Two are always expected.
1540
     *
1541
     * @param \eZ\Publish\API\Repository\Values\Content\Search\SearchResult $searchResult
1542
     * @param bool $ascending Denotes ascending order if true, descending order if false
1543
     * @param string|int $contentOneId
1544
     * @param string|int $contentTwoId
1545
     */
1546
    protected function assertSortResult(
1547
        SearchResult $searchResult,
1548
        $ascending,
1549
        $contentOneId,
1550
        $contentTwoId
1551
    ) {
1552
        $contentIdList = $this->getResultContentIdList($searchResult);
1553
1554
        $indexOne = 0;
1555
        $indexTwo = 1;
1556
1557
        if (!$ascending) {
1558
            $indexOne = 1;
1559
            $indexTwo = 0;
1560
        }
1561
1562
        $this->assertEquals(2, $searchResult->totalCount);
1563
        $this->assertEquals($contentOneId, $contentIdList[$indexOne]);
1564
        $this->assertEquals($contentTwoId, $contentIdList[$indexTwo]);
1565
    }
1566
}
1567