Passed
Push — master ( e8a696...8de9f1 )
by Artem
12:01
created

AbstractRepository::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 1
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 0
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 1
ccs 0
cts 0
cp 0
crap 2
rs 10
1
<?php
2
3
// ---------------------------------------------------------------------
4
//
5
//  Copyright (C) 2018-2024 Artem Rodygin
6
//
7
//  You should have received a copy of the MIT License along with
8
//  this file. If not, see <http://opensource.org/licenses/MIT>.
9
//
10
// ---------------------------------------------------------------------
11
12
namespace Linode\Internal;
13
14
use GuzzleHttp\Psr7\Response;
15
use Linode\Entity\Entity;
16
use Linode\Exception\LinodeException;
17
use Linode\LinodeClient;
18
use Linode\Repository\EntityCollection;
19
use Linode\Repository\RepositoryInterface;
20
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
21
22
/**
23
 * An abstract Linode repository.
24
 */
25
abstract class AbstractRepository implements RepositoryInterface
26
{
27
    // Response error codes.
28
    public const ERROR_BAD_REQUEST           = 400;
29
    public const ERROR_UNAUTHORIZED          = 401;
30
    public const ERROR_FORBIDDEN             = 403;
31
    public const ERROR_NOT_FOUND             = 404;
32
    public const ERROR_TOO_MANY_REQUESTS     = 429;
33
    public const ERROR_INTERNAL_SERVER_ERROR = 500;
34
35
    // Response success codes.
36
    protected const SUCCESS_OK         = 200;
37
    protected const SUCCESS_NO_CONTENT = 204;
38
39
    /**
40
     * AbstractRepository constructor.
41
     *
42
     * @param LinodeClient $client linode API client
43
     */
44
    public function __construct(protected LinodeClient $client) {}
45
46 1
    public function find($id): Entity
47
    {
48 1
        $response = $this->client->api($this->client::REQUEST_GET, sprintf('%s/%s', $this->getBaseUri(), $id));
49 1
        $contents = $response->getBody()->getContents();
50 1
        $json     = json_decode($contents, true);
51
52 1
        return $this->jsonToEntity($json);
53
    }
54
55 2
    public function findAll(string $orderBy = null, string $orderDir = self::SORT_ASC): EntityCollection
56
    {
57 2
        return $this->findBy([], $orderBy, $orderDir);
58
    }
59
60 9
    public function findBy(array $criteria, string $orderBy = null, string $orderDir = self::SORT_ASC): EntityCollection
61
    {
62 9
        if (null !== $orderBy) {
63 3
            $criteria['+order_by'] = $orderBy;
64 3
            $criteria['+order']    = $orderDir;
65
        }
66
67 9
        return new EntityCollection(
68 9
            fn (int $page) => $this->client->api($this->client::REQUEST_GET, $this->getBaseUri(), ['page' => $page], $criteria),
69 9
            fn (array $json) => $this->jsonToEntity($json)
70 9
        );
71
    }
72
73 3
    public function findOneBy(array $criteria): ?Entity
74
    {
75 3
        $collection = $this->findBy($criteria);
76
77 3
        if (0 === count($collection)) {
78 1
            return null;
79
        }
80
81 2
        if (1 !== count($collection)) {
82 1
            $errors = ['errors' => [['reason' => 'More than one entity was found']]];
83
84 1
            throw new LinodeException(new Response(self::ERROR_BAD_REQUEST, [], json_encode($errors)));
85
        }
86
87 1
        return $collection->current();
88
    }
89
90 3
    public function query(string $query, array $parameters = [], string $orderBy = null, string $orderDir = self::SORT_ASC): EntityCollection
91
    {
92
        try {
93 3
            $parser   = new ExpressionLanguage();
94 3
            $compiler = new QueryCompiler();
95
96 3
            $query    = $compiler->apply($query, $parameters);
97 3
            $ast      = $parser->parse($query, $this->getSupportedFields())->getNodes();
98 3
            $criteria = $compiler->compile($ast);
99 1
        } catch (\Throwable $exception) {
100 1
            $errors = ['errors' => [['reason' => $exception->getMessage()]]];
101
102 1
            throw new LinodeException(new Response(self::ERROR_BAD_REQUEST, [], json_encode($errors)));
103
        }
104
105 2
        return $this->findBy($criteria, $orderBy, $orderDir);
106
    }
107
108
    /**
109
     * Verifies that all specified parameters are supported by the repository.
110
     * An exception is raised when unsupported parameter was found.
111
     *
112
     * @throws LinodeException
113
     */
114 51
    protected function checkParametersSupport(array $parameters): void
115
    {
116 51
        $supported = $this->getSupportedFields();
117 51
        $provided  = array_keys($parameters);
118
119 51
        $unknown = array_diff($provided, $supported);
120
121 51
        if (0 !== count($unknown)) {
122 1
            $errors = ['errors' => [['reason' => sprintf('Unknown field(s): %s', implode(', ', $unknown))]]];
123
124 1
            throw new LinodeException(new Response(self::ERROR_BAD_REQUEST, [], json_encode($errors)));
125
        }
126
    }
127
128
    /**
129
     * Returns base URI to the repository-specific API.
130
     */
131
    abstract protected function getBaseUri(): string;
132
133
    /**
134
     * Returns list of all fields (entity properties) supported by the repository.
135
     *
136
     * @return string[]
137
     */
138
    abstract protected function getSupportedFields(): array;
139
140
    /**
141
     * Creates a repository-specific entity using specified JSON data.
142
     */
143
    abstract protected function jsonToEntity(array $json): Entity;
144
}
145