Passed
Pull Request — master (#1999)
by
unknown
03:10
created

CollectionDataProvider   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 85
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 10
eloc 46
dl 0
loc 85
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
B getCollection() 0 40 6
A supports() 0 15 3
1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace ApiPlatform\Core\Bridge\Elasticsearch\DataProvider;
15
16
use ApiPlatform\Core\Bridge\Elasticsearch\Api\IdentifierExtractorInterface;
17
use ApiPlatform\Core\Bridge\Elasticsearch\DataProvider\Extension\FullBodySearchCollectionExtensionInterface;
18
use ApiPlatform\Core\Bridge\Elasticsearch\Exception\IndexNotFoundException;
19
use ApiPlatform\Core\Bridge\Elasticsearch\Exception\NonUniqueIdentifierException;
20
use ApiPlatform\Core\Bridge\Elasticsearch\Metadata\Document\Factory\DocumentMetadataFactoryInterface;
21
use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface;
22
use ApiPlatform\Core\DataProvider\Pagination;
23
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
24
use Elasticsearch\Client;
25
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
26
27
/**
28
 * Collection data provider for Elasticsearch.
29
 *
30
 * @experimental
31
 *
32
 * @author Baptiste Meyer <[email protected]>
33
 */
34
final class CollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface
35
{
36
    private $client;
37
    private $documentMetadataFactory;
38
    private $identifierExtractor;
39
    private $denormalizer;
40
    private $pagination;
41
    private $collectionExtensions;
42
43
    /**
44
     * @param FullBodySearchCollectionExtensionInterface[] $collectionExtensions
45
     */
46
    public function __construct(Client $client, DocumentMetadataFactoryInterface $documentMetadataFactory, IdentifierExtractorInterface $identifierExtractor, DenormalizerInterface $denormalizer, Pagination $pagination, iterable $collectionExtensions = [])
47
    {
48
        $this->client = $client;
49
        $this->documentMetadataFactory = $documentMetadataFactory;
50
        $this->identifierExtractor = $identifierExtractor;
51
        $this->denormalizer = $denormalizer;
52
        $this->pagination = $pagination;
53
        $this->collectionExtensions = $collectionExtensions;
54
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59
    public function supports(string $resourceClass, ?string $operationName = null, array $context = []): bool
60
    {
61
        try {
62
            $this->documentMetadataFactory->create($resourceClass);
63
        } catch (IndexNotFoundException $e) {
64
            return false;
65
        }
66
67
        try {
68
            $this->identifierExtractor->getIdentifierFromResourceClass($resourceClass);
69
        } catch (NonUniqueIdentifierException $e) {
70
            return false;
71
        }
72
73
        return true;
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79
    public function getCollection(string $resourceClass, ?string $operationName = null, array $context = [])
80
    {
81
        $documentMetadata = $this->documentMetadataFactory->create($resourceClass);
82
        $body = [];
83
84
        foreach ($this->collectionExtensions as $collectionExtension) {
85
            $body = $collectionExtension->applyToCollection($body, $resourceClass, $operationName, $context);
86
        }
87
88
        if (!isset($body['query']) && !isset($body['aggs'])) {
89
            $body = array_merge($body, [
90
                'query' => [
91
                    'match_all' => new \stdClass(),
92
                ],
93
            ]);
94
        }
95
96
        $limit = $body['size'] ?? $this->pagination->getLimit($resourceClass, $operationName);
97
        $offset = $body['offset'] ?? $this->pagination->getOffset($resourceClass, $operationName);
98
99
        if (!isset($body['size'])) {
100
            $body = array_merge($body, ['size' => $limit]);
101
        }
102
103
        if (!isset($body['from'])) {
104
            $body = array_merge($body, ['from' => $offset]);
105
        }
106
107
        $documents = $this->client->search([
108
            'index' => $documentMetadata->getIndex(),
109
            'type' => $documentMetadata->getType(),
110
            'body' => $body,
111
        ]);
112
113
        return new Paginator(
114
            $this->denormalizer,
115
            $documents,
116
            $resourceClass,
117
            $limit,
118
            $offset
119
        );
120
    }
121
}
122