Completed
Push — ezp-30646 ( 66adba...cee0f6 )
by
unknown
16:53
created

SearchServiceLocationTest::assertQueryFixture()   C

Complexity

Conditions 10
Paths 144

Size

Total Lines 65

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
nc 144
nop 4
dl 0
loc 65
rs 6.6036
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * File containing the SearchServiceLocationTest 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\Core\Repository\Values\Content\Location;
12
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
13
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
14
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
15
use eZ\Publish\API\Repository\Values\Content\Search\SearchResult;
16
use eZ\Publish\API\Repository\Values\Content\Search\SearchHit;
17
use eZ\Publish\API\Repository\Exceptions\NotImplementedException;
18
19
/**
20
 * Test case for Location operations in the SearchService.
21
 *
22
 * @see eZ\Publish\API\Repository\SearchService
23
 * @group integration
24
 * @group search
25
 */
26
class SearchServiceLocationTest extends BaseTest
27
{
28
    const QUERY_CLASS = LocationQuery::class;
29
30
    use Common\FacetedSearchProvider;
31
32
    /**
33
     * Test for the findLocation() method.
34
     *
35
     * @dataProvider getFacetedSearches
36
     * @see \eZ\Publish\API\Repository\SearchService::findLoctions()
37
     */
38
    public function testFindFacetedLocation(LocationQuery $query, $fixture)
39
    {
40
        $this->assertQueryFixture($query, $fixture);
41
    }
42
43
    /**
44
     * Create test Content with ezcountry field having multiple countries selected.
45
     *
46
     * @return \eZ\Publish\API\Repository\Values\Content\Content
47
     */
48
    protected function createMultipleCountriesContent()
49
    {
50
        $repository = $this->getRepository();
51
        $contentTypeService = $repository->getContentTypeService();
52
        $contentService = $repository->getContentService();
53
54
        $createStruct = $contentTypeService->newContentTypeCreateStruct('countries-multiple');
55
        $createStruct->mainLanguageCode = 'eng-GB';
56
        $createStruct->remoteId = 'countries-multiple-123';
57
        $createStruct->names = ['eng-GB' => 'Multiple countries'];
58
        $createStruct->creatorId = 14;
59
        $createStruct->creationDate = new \DateTime();
60
61
        $fieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('countries', 'ezcountry');
62
        $fieldCreate->names = ['eng-GB' => 'Countries'];
63
        $fieldCreate->fieldGroup = 'main';
64
        $fieldCreate->position = 1;
65
        $fieldCreate->isTranslatable = false;
66
        $fieldCreate->isSearchable = true;
67
        $fieldCreate->fieldSettings = ['isMultiple' => true];
68
69
        $createStruct->addFieldDefinition($fieldCreate);
70
71
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
72
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
73
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
74
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
75
76
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
77
        $createStruct->remoteId = 'countries-multiple-456';
78
        $createStruct->alwaysAvailable = false;
79
        $createStruct->setField(
80
            'countries',
81
            ['BE', 'DE', 'FR', 'HR', 'NO', 'PT', 'RU']
82
        );
83
84
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
85
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
86
        $content = $contentService->publishVersion($draft->getVersionInfo());
87
88
        $this->refreshSearch($repository);
89
90
        return $content;
91
    }
92
93
    /**
94
     * Test for the findLocations() method.
95
     *
96
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
97
     */
98
    public function testFieldCollectionContains()
99
    {
100
        $testContent = $this->createMultipleCountriesContent();
101
102
        $query = new LocationQuery(
103
            [
104
                'query' => new Criterion\Field(
105
                    'countries',
106
                    Criterion\Operator::CONTAINS,
107
                    'Belgium'
108
                ),
109
            ]
110
        );
111
112
        $repository = $this->getRepository();
113
        $searchService = $repository->getSearchService();
114
        $result = $searchService->findLocations($query);
115
116
        $this->assertEquals(1, $result->totalCount);
117
        $this->assertEquals(
118
            $testContent->contentInfo->mainLocationId,
119
            $result->searchHits[0]->valueObject->id
120
        );
121
    }
122
123
    /**
124
     * Test for the findLocations() method.
125
     *
126
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
127
     * @depends eZ\Publish\API\Repository\Tests\SearchServiceTest::testFieldCollectionContains
128
     */
129
    public function testFieldCollectionContainsNoMatch()
130
    {
131
        $this->createMultipleCountriesContent();
132
        $query = new LocationQuery(
133
            [
134
                'query' => new Criterion\Field(
135
                    'countries',
136
                    Criterion\Operator::CONTAINS,
137
                    'Netherlands Antilles'
138
                ),
139
            ]
140
        );
141
142
        $repository = $this->getRepository();
143
        $searchService = $repository->getSearchService();
144
        $result = $searchService->findLocations($query);
145
146
        $this->assertEquals(0, $result->totalCount);
147
    }
148
149
    public function testInvalidFieldIdentifierRange()
150
    {
151
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
152
153
        $repository = $this->getRepository();
154
        $searchService = $repository->getSearchService();
155
156
        $searchService->findLocations(
157
            new LocationQuery(
158
                [
159
                    'filter' => new Criterion\Field(
160
                        'some_hopefully_unknown_field',
161
                        Criterion\Operator::BETWEEN,
162
                        [10, 1000]
163
                    ),
164
                    'sortClauses' => [new SortClause\ContentId()],
165
                ]
166
            )
167
        );
168
    }
169
170
    public function testInvalidFieldIdentifierIn()
171
    {
172
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
173
174
        $repository = $this->getRepository();
175
        $searchService = $repository->getSearchService();
176
177
        $searchService->findLocations(
178
            new LocationQuery(
179
                [
180
                    'filter' => new Criterion\Field(
181
                        'some_hopefully_unknown_field',
182
                        Criterion\Operator::EQ,
183
                        1000
184
                    ),
185
                    'sortClauses' => [new SortClause\ContentId()],
186
                ]
187
            )
188
        );
189
    }
190
191
    public function testFindLocationsWithNonSearchableField()
192
    {
193
        $this->expectException(\eZ\Publish\API\Repository\Exceptions\InvalidArgumentException::class);
194
195
        $repository = $this->getRepository();
196
        $searchService = $repository->getSearchService();
197
198
        $searchService->findLocations(
199
            new LocationQuery(
200
                [
201
                    'filter' => new Criterion\Field(
202
                        'tag_cloud_url',
203
                        Criterion\Operator::EQ,
204
                        'http://nimbus.com'
205
                    ),
206
                    'sortClauses' => [new SortClause\ContentId()],
207
                ]
208
            )
209
        );
210
    }
211
212
    /**
213
     * @param \eZ\Publish\API\Repository\Values\Content\Search\SearchResult $result
214
     *
215
     * @return array
216
     */
217
    protected function mapResultLocationIds(SearchResult $result)
218
    {
219
        return array_map(
220
            function (SearchHit $searchHit) {
221
                return $searchHit->valueObject->id;
222
            },
223
            $result->searchHits
224
        );
225
    }
226
227
    /**
228
     * Test for the findLocations() method.
229
     *
230
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
231
     */
232
    public function testQueryCustomField()
233
    {
234
        $query = new LocationQuery(
235
            [
236
                'query' => new Criterion\CustomField(
237
                    'custom_field',
238
                    Criterion\Operator::EQ,
239
                    'AdMiNiStRaToR'
240
                ),
241
                'offset' => 0,
242
                'limit' => 10,
243
                'sortClauses' => [new SortClause\ContentId()],
244
            ]
245
        );
246
        $this->assertQueryFixture(
247
            $query,
248
            $this->getFixtureDir() . '/QueryCustomField.php',
249
            null,
250
            true
251
        );
252
    }
253
254
    /**
255
     * Test for the findLocations() method.
256
     *
257
     * This tests explicitly queries the first_name while user is contained in
258
     * the last_name of admin and anonymous. This is done to show the custom
259
     * copy field working.
260
     *
261
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
262
     */
263
    public function testQueryModifiedField()
264
    {
265
        // Check using get_class since the others extend SetupFactory\Legacy
266
        if (ltrim(get_class($this->getSetupFactory()), '\\') === 'eZ\Publish\API\Repository\Tests\SetupFactory\Legacy') {
267
            $this->markTestIncomplete(
268
                'Custom fields not supported by LegacySE ' .
269
                '(@todo: Legacy should fallback to just querying normal field so this should be tested here)'
270
            );
271
        }
272
273
        $query = new LocationQuery(
274
            [
275
                'query' => new Criterion\Field(
276
                    'first_name',
277
                    Criterion\Operator::EQ,
278
                    'User'
279
                ),
280
                'offset' => 0,
281
                'limit' => 10,
282
                'sortClauses' => [new SortClause\ContentId()],
283
            ]
284
        );
285
        $query->query->setCustomField('user', 'first_name', 'custom_field');
286
287
        $this->assertQueryFixture(
288
            $query,
289
            $this->getFixtureDir() . '/QueryModifiedField.php',
290
            null,
291
            true
292
        );
293
    }
294
295
    /**
296
     * @return \eZ\Publish\API\Repository\Values\ContentType\ContentType
297
     */
298
    protected function createTestPlaceContentType()
299
    {
300
        $repository = $this->getRepository();
301
        $contentTypeService = $repository->getContentTypeService();
302
303
        $createStruct = $contentTypeService->newContentTypeCreateStruct('testtype');
304
        $createStruct->mainLanguageCode = 'eng-GB';
305
        $createStruct->names = ['eng-GB' => 'Test type'];
306
        $createStruct->creatorId = 14;
307
        $createStruct->creationDate = new \DateTime();
308
309
        $translatableFieldCreate = $contentTypeService->newFieldDefinitionCreateStruct('maplocation', 'ezgmaplocation');
310
        $translatableFieldCreate->names = ['eng-GB' => 'Map location field'];
311
        $translatableFieldCreate->fieldGroup = 'main';
312
        $translatableFieldCreate->position = 1;
313
        $translatableFieldCreate->isTranslatable = false;
314
        $translatableFieldCreate->isSearchable = true;
315
316
        $createStruct->addFieldDefinition($translatableFieldCreate);
317
318
        $contentGroup = $contentTypeService->loadContentTypeGroupByIdentifier('Content');
319
        $contentTypeDraft = $contentTypeService->createContentType($createStruct, [$contentGroup]);
320
        $contentTypeService->publishContentTypeDraft($contentTypeDraft);
321
        $contentType = $contentTypeService->loadContentType($contentTypeDraft->id);
322
323
        return $contentType;
324
    }
325
326
    /**
327
     * Test for the findLocations() method.
328
     *
329
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
330
     * @group maplocation
331
     */
332
    public function testMapLocationDistanceLessThanOrEqual()
333
    {
334
        $contentType = $this->createTestPlaceContentType();
335
336
        // Create a draft to account for behaviour with ContentType in different states
337
        $repository = $this->getRepository();
338
        $contentTypeService = $repository->getContentTypeService();
339
        $contentService = $repository->getContentService();
340
        $contentTypeService->createContentTypeDraft($contentType);
341
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
342
343
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
344
        $createStruct->alwaysAvailable = false;
345
        $createStruct->mainLanguageCode = 'eng-GB';
346
        $createStruct->setField(
347
            'maplocation',
348
            [
349
                'latitude' => 45.894877,
350
                'longitude' => 15.972699,
351
                'address' => 'Here be wild boars',
352
            ],
353
            'eng-GB'
354
        );
355
356
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
357
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
358
359
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
360
        $createStruct->alwaysAvailable = false;
361
        $createStruct->mainLanguageCode = 'eng-GB';
362
        $createStruct->setField(
363
            'maplocation',
364
            [
365
                'latitude' => 45.927334,
366
                'longitude' => 15.934847,
367
                'address' => 'A lone tree',
368
            ],
369
            'eng-GB'
370
        );
371
372
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
373
        $tree = $contentService->publishVersion($draft->getVersionInfo());
374
375
        $this->refreshSearch($repository);
376
377
        $query = new LocationQuery(
378
            [
379
                'filter' => new Criterion\LogicalAnd(
380
                    [
381
                        new Criterion\ContentTypeId($contentType->id),
382
                        new Criterion\MapLocationDistance(
383
                            'maplocation',
384
                            Criterion\Operator::LTE,
385
                            240,
386
                            43.756825,
387
                            15.775074
388
                        ),
389
                    ]
390
                ),
391
                'offset' => 0,
392
                'limit' => 10,
393
                'sortClauses' => [],
394
            ]
395
        );
396
397
        $searchService = $repository->getSearchService();
398
        $result = $searchService->findLocations($query);
399
400
        $this->assertEquals(1, $result->totalCount);
401
        $this->assertEquals(
402
            $wildBoars->contentInfo->mainLocationId,
403
            $result->searchHits[0]->valueObject->id
404
        );
405
    }
406
407
    /**
408
     * Test for the findLocations() method.
409
     *
410
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
411
     * @group maplocation
412
     */
413
    public function testMapLocationDistanceGreaterThanOrEqual()
414
    {
415
        $contentType = $this->createTestPlaceContentType();
416
417
        // Create a draft to account for behaviour with ContentType in different states
418
        $repository = $this->getRepository();
419
        $contentTypeService = $repository->getContentTypeService();
420
        $contentService = $repository->getContentService();
421
        $contentTypeService->createContentTypeDraft($contentType);
422
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
423
424
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
425
        $createStruct->alwaysAvailable = false;
426
        $createStruct->mainLanguageCode = 'eng-GB';
427
        $createStruct->setField(
428
            'maplocation',
429
            [
430
                'latitude' => 45.894877,
431
                'longitude' => 15.972699,
432
                'address' => 'Here be wild boars',
433
            ],
434
            'eng-GB'
435
        );
436
437
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
438
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
439
440
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
441
        $createStruct->alwaysAvailable = false;
442
        $createStruct->mainLanguageCode = 'eng-GB';
443
        $createStruct->setField(
444
            'maplocation',
445
            [
446
                'latitude' => 45.927334,
447
                'longitude' => 15.934847,
448
                'address' => 'A lone tree',
449
            ],
450
            'eng-GB'
451
        );
452
453
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
454
        $tree = $contentService->publishVersion($draft->getVersionInfo());
455
456
        $this->refreshSearch($repository);
457
458
        $query = new LocationQuery(
459
            [
460
                'filter' => new Criterion\LogicalAnd(
461
                    [
462
                        new Criterion\ContentTypeId($contentType->id),
463
                        new Criterion\MapLocationDistance(
464
                            'maplocation',
465
                            Criterion\Operator::GTE,
466
                            240,
467
                            43.756825,
468
                            15.775074
469
                        ),
470
                    ]
471
                ),
472
                'offset' => 0,
473
                'limit' => 10,
474
                'sortClauses' => [],
475
            ]
476
        );
477
478
        $searchService = $repository->getSearchService();
479
        $result = $searchService->findLocations($query);
480
481
        $this->assertEquals(1, $result->totalCount);
482
        $this->assertEquals(
483
            $tree->contentInfo->mainLocationId,
484
            $result->searchHits[0]->valueObject->id
485
        );
486
    }
487
488
    /**
489
     * Test for the findLocations() method.
490
     *
491
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
492
     * @group maplocation
493
     */
494
    public function testMapLocationDistanceBetween()
495
    {
496
        $contentType = $this->createTestPlaceContentType();
497
498
        // Create a draft to account for behaviour with ContentType in different states
499
        $repository = $this->getRepository();
500
        $contentTypeService = $repository->getContentTypeService();
501
        $contentService = $repository->getContentService();
502
        $contentTypeService->createContentTypeDraft($contentType);
503
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
504
505
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
506
        $createStruct->alwaysAvailable = false;
507
        $createStruct->mainLanguageCode = 'eng-GB';
508
        $createStruct->setField(
509
            'maplocation',
510
            [
511
                'latitude' => 45.894877,
512
                'longitude' => 15.972699,
513
                'address' => 'Here be wild boars',
514
            ],
515
            'eng-GB'
516
        );
517
518
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
519
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
520
521
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
522
        $createStruct->alwaysAvailable = false;
523
        $createStruct->mainLanguageCode = 'eng-GB';
524
        $createStruct->setField(
525
            'maplocation',
526
            [
527
                'latitude' => 45.927334,
528
                'longitude' => 15.934847,
529
                'address' => 'A lone tree',
530
            ],
531
            'eng-GB'
532
        );
533
534
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
535
        $tree = $contentService->publishVersion($draft->getVersionInfo());
536
537
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
538
        $createStruct->alwaysAvailable = false;
539
        $createStruct->mainLanguageCode = 'eng-GB';
540
        $createStruct->setField(
541
            'maplocation',
542
            [
543
                'latitude' => 45.903777,
544
                'longitude' => 15.958788,
545
                'address' => 'Meadow with mushrooms',
546
            ],
547
            'eng-GB'
548
        );
549
550
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
551
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
552
553
        $this->refreshSearch($repository);
554
555
        $query = new LocationQuery(
556
            [
557
                'filter' => new Criterion\LogicalAnd(
558
                    [
559
                        new Criterion\ContentTypeId($contentType->id),
560
                        new Criterion\MapLocationDistance(
561
                            'maplocation',
562
                            Criterion\Operator::BETWEEN,
563
                            [239, 241],
564
                            43.756825,
565
                            15.775074
566
                        ),
567
                    ]
568
                ),
569
                'offset' => 0,
570
                'limit' => 10,
571
                'sortClauses' => [],
572
            ]
573
        );
574
575
        $searchService = $repository->getSearchService();
576
        $result = $searchService->findLocations($query);
577
578
        $this->assertEquals(1, $result->totalCount);
579
        $this->assertEquals(
580
            $mushrooms->contentInfo->mainLocationId,
581
            $result->searchHits[0]->valueObject->id
582
        );
583
    }
584
585
    /**
586
     * Test for the findLocations() method.
587
     *
588
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
589
     * @group maplocation
590
     */
591
    public function testMapLocationDistanceSortAscending()
592
    {
593
        $contentType = $this->createTestPlaceContentType();
594
595
        // Create a draft to account for behaviour with ContentType in different states
596
        $repository = $this->getRepository();
597
        $contentTypeService = $repository->getContentTypeService();
598
        $contentService = $repository->getContentService();
599
        $contentTypeService->createContentTypeDraft($contentType);
600
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
601
602
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
603
        $createStruct->alwaysAvailable = false;
604
        $createStruct->mainLanguageCode = 'eng-GB';
605
        $createStruct->setField(
606
            'maplocation',
607
            [
608
                'latitude' => 45.894877,
609
                'longitude' => 15.972699,
610
                'address' => 'Here be wild boars',
611
            ],
612
            'eng-GB'
613
        );
614
615
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
616
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
617
618
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
619
        $createStruct->alwaysAvailable = false;
620
        $createStruct->mainLanguageCode = 'eng-GB';
621
        $createStruct->setField(
622
            'maplocation',
623
            [
624
                'latitude' => 45.927334,
625
                'longitude' => 15.934847,
626
                'address' => 'A lone tree',
627
            ],
628
            'eng-GB'
629
        );
630
631
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
632
        $tree = $contentService->publishVersion($draft->getVersionInfo());
633
634
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
635
        $createStruct->alwaysAvailable = false;
636
        $createStruct->mainLanguageCode = 'eng-GB';
637
        $createStruct->setField(
638
            'maplocation',
639
            [
640
                'latitude' => 45.903777,
641
                'longitude' => 15.958788,
642
                'address' => 'Meadow with mushrooms',
643
            ],
644
            'eng-GB'
645
        );
646
647
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
648
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
649
650
        $this->refreshSearch($repository);
651
652
        $wellInVodice = [
653
            'latitude' => 43.756825,
654
            'longitude' => 15.775074,
655
        ];
656
657
        $query = new LocationQuery(
658
            [
659
                'filter' => new Criterion\LogicalAnd(
660
                    [
661
                        new Criterion\ContentTypeId($contentType->id),
662
                        new Criterion\MapLocationDistance(
663
                            'maplocation',
664
                            Criterion\Operator::GTE,
665
                            235,
666
                            $wellInVodice['latitude'],
667
                            $wellInVodice['longitude']
668
                        ),
669
                    ]
670
                ),
671
                'offset' => 0,
672
                'limit' => 10,
673
                'sortClauses' => [
674
                    new SortClause\MapLocationDistance(
675
                        'testtype',
676
                        'maplocation',
677
                        $wellInVodice['latitude'],
678
                        $wellInVodice['longitude'],
679
                        LocationQuery::SORT_ASC
680
                    ),
681
                ],
682
            ]
683
        );
684
685
        $searchService = $repository->getSearchService();
686
        $result = $searchService->findLocations($query);
687
688
        $this->assertEquals(3, $result->totalCount);
689
        $this->assertEquals(
690
            $wildBoars->contentInfo->mainLocationId,
691
            $result->searchHits[0]->valueObject->id
692
        );
693
        $this->assertEquals(
694
            $mushrooms->contentInfo->mainLocationId,
695
            $result->searchHits[1]->valueObject->id
696
        );
697
        $this->assertEquals(
698
            $tree->contentInfo->mainLocationId,
699
            $result->searchHits[2]->valueObject->id
700
        );
701
    }
702
703
    /**
704
     * Test for the findLocations() method.
705
     *
706
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
707
     * @group maplocation
708
     */
709
    public function testMapLocationDistanceSortDescending()
710
    {
711
        $contentType = $this->createTestPlaceContentType();
712
713
        // Create a draft to account for behaviour with ContentType in different states
714
        $repository = $this->getRepository();
715
        $contentTypeService = $repository->getContentTypeService();
716
        $contentService = $repository->getContentService();
717
        $contentTypeService->createContentTypeDraft($contentType);
718
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
719
720
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
721
        $createStruct->alwaysAvailable = false;
722
        $createStruct->mainLanguageCode = 'eng-GB';
723
        $createStruct->setField(
724
            'maplocation',
725
            [
726
                'latitude' => 45.894877,
727
                'longitude' => 15.972699,
728
                'address' => 'Here be wild boars',
729
            ],
730
            'eng-GB'
731
        );
732
733
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
734
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
735
736
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
737
        $createStruct->alwaysAvailable = false;
738
        $createStruct->mainLanguageCode = 'eng-GB';
739
        $createStruct->setField(
740
            'maplocation',
741
            [
742
                'latitude' => 45.927334,
743
                'longitude' => 15.934847,
744
                'address' => 'A lone tree',
745
            ],
746
            'eng-GB'
747
        );
748
749
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
750
        $tree = $contentService->publishVersion($draft->getVersionInfo());
751
752
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
753
        $createStruct->alwaysAvailable = false;
754
        $createStruct->mainLanguageCode = 'eng-GB';
755
        $createStruct->setField(
756
            'maplocation',
757
            [
758
                'latitude' => 45.903777,
759
                'longitude' => 15.958788,
760
                'address' => 'Meadow with mushrooms',
761
            ],
762
            'eng-GB'
763
        );
764
765
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
766
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
767
768
        $this->refreshSearch($repository);
769
770
        $well = [
771
            'latitude' => 43.756825,
772
            'longitude' => 15.775074,
773
        ];
774
775
        $query = new LocationQuery(
776
            [
777
                'filter' => new Criterion\LogicalAnd(
778
                    [
779
                        new Criterion\ContentTypeId($contentType->id),
780
                        new Criterion\MapLocationDistance(
781
                            'maplocation',
782
                            Criterion\Operator::GTE,
783
                            235,
784
                            $well['latitude'],
785
                            $well['longitude']
786
                        ),
787
                    ]
788
                ),
789
                'offset' => 0,
790
                'limit' => 10,
791
                'sortClauses' => [
792
                    new SortClause\MapLocationDistance(
793
                        'testtype',
794
                        'maplocation',
795
                        $well['latitude'],
796
                        $well['longitude'],
797
                        LocationQuery::SORT_DESC
798
                    ),
799
                ],
800
            ]
801
        );
802
803
        $searchService = $repository->getSearchService();
804
        $result = $searchService->findLocations($query);
805
806
        $this->assertEquals(3, $result->totalCount);
807
        $this->assertEquals(
808
            $wildBoars->contentInfo->mainLocationId,
809
            $result->searchHits[2]->valueObject->id
810
        );
811
        $this->assertEquals(
812
            $mushrooms->contentInfo->mainLocationId,
813
            $result->searchHits[1]->valueObject->id
814
        );
815
        $this->assertEquals(
816
            $tree->contentInfo->mainLocationId,
817
            $result->searchHits[0]->valueObject->id
818
        );
819
    }
820
821
    /**
822
     * Test for the findLocations() method.
823
     *
824
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
825
     * @group maplocation
826
     */
827
    public function testMapLocationDistanceWithCustomField()
828
    {
829
        $contentType = $this->createTestPlaceContentType();
830
831
        // Create a draft to account for behaviour with ContentType in different states
832
        $repository = $this->getRepository();
833
        $contentTypeService = $repository->getContentTypeService();
834
        $contentService = $repository->getContentService();
835
        $contentTypeService->createContentTypeDraft($contentType);
836
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
837
838
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
839
        $createStruct->alwaysAvailable = false;
840
        $createStruct->mainLanguageCode = 'eng-GB';
841
        $createStruct->setField(
842
            'maplocation',
843
            [
844
                'latitude' => 45.894877,
845
                'longitude' => 15.972699,
846
                'address' => 'Here be wild boars',
847
            ],
848
            'eng-GB'
849
        );
850
851
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
852
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
853
854
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
855
        $createStruct->alwaysAvailable = false;
856
        $createStruct->mainLanguageCode = 'eng-GB';
857
        $createStruct->setField(
858
            'maplocation',
859
            [
860
                'latitude' => 45.927334,
861
                'longitude' => 15.934847,
862
                'address' => 'A lone tree',
863
            ],
864
            'eng-GB'
865
        );
866
867
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
868
        $tree = $contentService->publishVersion($draft->getVersionInfo());
869
870
        $this->refreshSearch($repository);
871
872
        $distanceCriterion = new Criterion\MapLocationDistance(
873
            'maplocation',
874
            Criterion\Operator::LTE,
875
            240,
876
            43.756825,
877
            15.775074
878
        );
879
        $distanceCriterion->setCustomField('testtype', 'maplocation', 'custom_geolocation_field');
880
881
        $query = new LocationQuery(
882
            [
883
                'filter' => new Criterion\LogicalAnd(
884
                    [
885
                        new Criterion\ContentTypeId($contentType->id),
886
                        $distanceCriterion,
887
                    ]
888
                ),
889
                'offset' => 0,
890
                'limit' => 10,
891
                'sortClauses' => [],
892
            ]
893
        );
894
895
        $searchService = $repository->getSearchService();
896
        $result = $searchService->findLocations($query);
897
898
        $this->assertEquals(1, $result->totalCount);
899
        $this->assertEquals(
900
            $wildBoars->contentInfo->mainLocationId,
901
            $result->searchHits[0]->valueObject->id
902
        );
903
    }
904
905
    /**
906
     * Test for the findLocations() method.
907
     *
908
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
909
     * @group maplocation
910
     */
911
    public function testMapLocationDistanceWithCustomFieldSort()
912
    {
913
        $contentType = $this->createTestPlaceContentType();
914
915
        // Create a draft to account for behaviour with ContentType in different states
916
        $repository = $this->getRepository();
917
        $contentTypeService = $repository->getContentTypeService();
918
        $contentService = $repository->getContentService();
919
        $contentTypeService->createContentTypeDraft($contentType);
920
        $locationCreateStruct = $repository->getLocationService()->newLocationCreateStruct(2);
921
922
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
923
        $createStruct->alwaysAvailable = false;
924
        $createStruct->mainLanguageCode = 'eng-GB';
925
        $createStruct->setField(
926
            'maplocation',
927
            [
928
                'latitude' => 45.894877,
929
                'longitude' => 15.972699,
930
                'address' => 'Here be wild boars',
931
            ],
932
            'eng-GB'
933
        );
934
935
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
936
        $wildBoars = $contentService->publishVersion($draft->getVersionInfo());
937
938
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
939
        $createStruct->alwaysAvailable = false;
940
        $createStruct->mainLanguageCode = 'eng-GB';
941
        $createStruct->setField(
942
            'maplocation',
943
            [
944
                'latitude' => 45.927334,
945
                'longitude' => 15.934847,
946
                'address' => 'A lone tree',
947
            ],
948
            'eng-GB'
949
        );
950
951
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
952
        $tree = $contentService->publishVersion($draft->getVersionInfo());
953
954
        $createStruct = $contentService->newContentCreateStruct($contentType, 'eng-GB');
955
        $createStruct->alwaysAvailable = false;
956
        $createStruct->mainLanguageCode = 'eng-GB';
957
        $createStruct->setField(
958
            'maplocation',
959
            [
960
                'latitude' => 45.903777,
961
                'longitude' => 15.958788,
962
                'address' => 'Meadow with mushrooms',
963
            ],
964
            'eng-GB'
965
        );
966
967
        $draft = $contentService->createContent($createStruct, [$locationCreateStruct]);
968
        $mushrooms = $contentService->publishVersion($draft->getVersionInfo());
969
970
        $this->refreshSearch($repository);
971
972
        $well = [
973
            'latitude' => 43.756825,
974
            'longitude' => 15.775074,
975
        ];
976
977
        $sortClause = new SortClause\MapLocationDistance(
978
            'testtype',
979
            'maplocation',
980
            $well['latitude'],
981
            $well['longitude'],
982
            LocationQuery::SORT_DESC
983
        );
984
        $sortClause->setCustomField('testtype', 'maplocation', 'custom_geolocation_field');
985
986
        $query = new LocationQuery(
987
            [
988
                'filter' => new Criterion\LogicalAnd(
989
                    [
990
                        new Criterion\ContentTypeId($contentType->id),
991
                        new Criterion\MapLocationDistance(
992
                            'maplocation',
993
                            Criterion\Operator::GTE,
994
                            235,
995
                            $well['latitude'],
996
                            $well['longitude']
997
                        ),
998
                    ]
999
                ),
1000
                'offset' => 0,
1001
                'limit' => 10,
1002
                'sortClauses' => [
1003
                    $sortClause,
1004
                ],
1005
            ]
1006
        );
1007
1008
        $searchService = $repository->getSearchService();
1009
        $result = $searchService->findLocations($query);
1010
1011
        $this->assertEquals(3, $result->totalCount);
1012
        $this->assertEquals(
1013
            $wildBoars->contentInfo->mainLocationId,
1014
            $result->searchHits[2]->valueObject->id
1015
        );
1016
        $this->assertEquals(
1017
            $mushrooms->contentInfo->mainLocationId,
1018
            $result->searchHits[1]->valueObject->id
1019
        );
1020
        $this->assertEquals(
1021
            $tree->contentInfo->mainLocationId,
1022
            $result->searchHits[0]->valueObject->id
1023
        );
1024
    }
1025
1026
    /**
1027
     * Test for the findLocations() method.
1028
     *
1029
     * @see \eZ\Publish\API\Repository\SearchService::findLocations()
1030
     */
1031
    public function testVisibilityCriterionWithHiddenContent()
1032
    {
1033
        $repository = $this->getRepository();
1034
        $contentTypeService = $repository->getContentTypeService();
1035
        $contentType = $contentTypeService->loadContentTypeByIdentifier('folder');
1036
1037
        $contentService = $repository->getContentService();
1038
        $locationService = $repository->getLocationService();
1039
        $searchService = $repository->getSearchService();
1040
1041
        $testRootContentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
1042
        $testRootContentCreate->setField('name', 'Root for test');
1043
1044
        $rootContent = $contentService->createContent(
1045
            $testRootContentCreate,
1046
            [
1047
                $locationService->newLocationCreateStruct(
1048
                    $this->generateId('location', 2)
1049
                ),
1050
            ]
1051
        );
1052
1053
        $publishedRootContent = $contentService->publishVersion($rootContent->versionInfo);
1054
1055
        $contentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
1056
        $contentCreate->setField('name', 'To Hide');
1057
1058
        $content = $contentService->createContent(
1059
            $contentCreate,
1060
            [
1061
                $locationService->newLocationCreateStruct(
1062
                    $publishedRootContent->contentInfo->mainLocationId
1063
                ),
1064
            ]
1065
        );
1066
        $publishedContent = $contentService->publishVersion($content->versionInfo);
1067
1068
        $childContentCreate = $contentService->newContentCreateStruct($contentType, 'eng-US');
1069
        $childContentCreate->setField('name', 'Invisible Child');
1070
1071
        $childContent = $contentService->createContent(
1072
            $childContentCreate,
1073
            [
1074
                $locationService->newLocationCreateStruct(
1075
                    $publishedContent->contentInfo->mainLocationId
1076
                ),
1077
            ]
1078
        );
1079
        $rootLocation = $locationService->loadLocation($publishedRootContent->contentInfo->mainLocationId);
1080
1081
        $contentService->publishVersion($childContent->versionInfo);
1082
        $this->refreshSearch($repository);
1083
1084
        $query = new LocationQuery([
1085
            'query' => new Criterion\LogicalAnd([
1086
                new Criterion\Visibility(
1087
                    Criterion\Visibility::VISIBLE
1088
                ),
1089
                new Criterion\Subtree(
1090
                    $rootLocation->pathString
1091
                ),
1092
            ]),
1093
        ]);
1094
1095
        //Sanity check for visible locations
1096
        $result = $searchService->findLocations($query);
1097
        $this->assertEquals(3, $result->totalCount);
1098
1099
        //Hide main content
1100
        $contentService->hideContent($publishedContent->contentInfo);
1101
        $this->refreshSearch($repository);
1102
1103
        $result = $searchService->findLocations($query);
1104
        $this->assertEquals(1, $result->totalCount);
1105
1106
        //Query for invisible content
1107
        $hiddenQuery = new LocationQuery([
1108
            'query' => new Criterion\LogicalAnd([
1109
                new Criterion\Visibility(
1110
                    Criterion\Visibility::HIDDEN
1111
                ),
1112
                new Criterion\Subtree(
1113
                    $rootLocation->pathString
1114
                ),
1115
            ]),
1116
        ]);
1117
1118
        $result = $searchService->findLocations($hiddenQuery);
1119
        $this->assertEquals(2, $result->totalCount);
1120
    }
1121
1122
    /**
1123
     * Assert that query result matches the given fixture.
1124
     *
1125
     * @param LocationQuery $query
1126
     * @param string $fixture
1127
     * @param null|callable $closure
1128
     */
1129
    protected function assertQueryFixture(LocationQuery $query, $fixture, $closure = null, $ignoreScore = true)
1130
    {
1131
        $repository = $this->getRepository();
1132
        $searchService = $repository->getSearchService();
1133
1134
        try {
1135
            $result = $searchService->findLocations($query);
1136
            $this->simplifySearchResult($result);
1137
        } catch (NotImplementedException $e) {
1138
            $this->markTestSkipped(
1139
                'This feature is not supported by the current search backend: ' . $e->getMessage()
1140
            );
1141
        }
1142
1143
        if (!is_file($fixture)) {
1144
            if (isset($_ENV['ez_tests_record'])) {
1145
                file_put_contents(
1146
                    $record = $fixture . '.recording',
1147
                    "<?php\n\nreturn " . var_export($result, true) . ";\n\n"
1148
                );
1149
                $this->markTestIncomplete("No fixture available. Result recorded at $record. Result: \n" . $this->printResult($result));
1150
            } else {
1151
                $this->markTestIncomplete("No fixture available. Set \$_ENV['ez_tests_record'] to generate:\n " . $fixture);
1152
            }
1153
        }
1154
1155
        $fixture = include $fixture;
1156
1157
        if ($closure !== null) {
1158
            $closure($result);
1159
        }
1160
1161
        if ($ignoreScore) {
1162
            foreach ([$fixture, $result] as $result) {
1163
                $property = new \ReflectionProperty(get_class($result), 'maxScore');
1164
                $property->setAccessible(true);
1165
                $property->setValue($result, 0.0);
1166
1167
                foreach ($result->searchHits as $hit) {
1168
                    $property = new \ReflectionProperty(get_class($hit), 'score');
1169
                    $property->setAccessible(true);
1170
                    $property->setValue($hit, 0.0);
1171
                }
1172
            }
1173
        }
1174
1175
        foreach ([$fixture, $result] as $set) {
1176
            foreach ($set->searchHits as $hit) {
1177
                $property = new \ReflectionProperty(get_class($hit), 'index');
1178
                $property->setAccessible(true);
1179
                $property->setValue($hit, null);
1180
1181
                $property = new \ReflectionProperty(get_class($hit), 'matchedTranslation');
1182
                $property->setAccessible(true);
1183
                $property->setValue($hit, null);
1184
            }
1185
        }
1186
1187
        $this->assertEqualsWithDelta(
1188
            $fixture,
1189
            $result,
1190
            .2, // Be quite generous regarding delay -- most important for scores
1191
            'Search results do not match.',
1192
        );
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected ')'
Loading history...
1193
    }
1194
1195
    /**
1196
     * Show a simplified view of the search result for manual introspection.
1197
     *
1198
     * @param SearchResult $result
1199
     *
1200
     * @return string
1201
     */
1202
    protected function printResult(SearchResult $result)
1203
    {
1204
        $printed = '';
1205
        foreach ($result->searchHits as $hit) {
1206
            $printed .= sprintf(" - %s (%s)\n", $hit->valueObject['title'], $hit->valueObject['id']);
1207
        }
1208
1209
        return $printed;
1210
    }
1211
1212
    /**
1213
     * Simplify search result.
1214
     *
1215
     * This leads to saner comparisons of results, since we do not get the full
1216
     * content objects every time.
1217
     *
1218
     * @param SearchResult $result
1219
     */
1220
    protected function simplifySearchResult(SearchResult $result)
1221
    {
1222
        $result->time = 1;
1223
1224
        foreach ($result->searchHits as $hit) {
1225
            switch (true) {
1226
                case $hit->valueObject instanceof Location:
1227
                    $hit->valueObject = [
1228
                        'id' => $hit->valueObject->contentInfo->id,
1229
                        'title' => $hit->valueObject->contentInfo->name,
1230
                    ];
1231
                    break;
1232
1233
                default:
1234
                    throw new \RuntimeException('Unknown search result hit type: ' . get_class($hit->valueObject));
1235
            }
1236
        }
1237
    }
1238
1239
    /**
1240
     * Get fixture directory.
1241
     *
1242
     * @return string
1243
     */
1244
    protected function getFixtureDir()
1245
    {
1246
        return __DIR__ . '/_fixtures/' . getenv('fixtureDir') . '/';
1247
    }
1248
}
1249