Passed
Pull Request — master (#10)
by Alex
02:45
created

AbstractFilter::applyFilters()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 2
c 1
b 0
f 0
nc 2
nop 3
dl 0
loc 7
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Arp\DoctrineQueryFilter\Filter;
6
7
use Arp\DoctrineQueryFilter\Enum\WhereType;
8
use Arp\DoctrineQueryFilter\Exception\QueryFilterManagerException;
9
use Arp\DoctrineQueryFilter\Filter\Exception\FilterException;
10
use Arp\DoctrineQueryFilter\Filter\Exception\InvalidArgumentException;
11
use Arp\DoctrineQueryFilter\Metadata\Exception\TypecastException;
12
use Arp\DoctrineQueryFilter\Metadata\MetadataInterface;
13
use Arp\DoctrineQueryFilter\Metadata\ParamNameGeneratorInterface;
14
use Arp\DoctrineQueryFilter\Metadata\TypecasterInterface;
15
use Arp\DoctrineQueryFilter\QueryBuilderInterface;
16
use Arp\DoctrineQueryFilter\QueryFilterManagerInterface;
17
18
abstract class AbstractFilter implements FilterInterface
19
{
20
    public function __construct(
21
        protected QueryFilterManagerInterface $queryFilterManager,
22
        protected TypecasterInterface $typecaster,
23
        protected ParamNameGeneratorInterface $paramNameGenerator,
24
        protected array $options = []
25
    ) {
26
    }
27
28
    public function getOptions(): array
29
    {
30
        return $this->options;
31
    }
32
33
    protected function createParamName(string $param, string $fieldName, string $alias): string
34
    {
35
        return $this->paramNameGenerator->generateName($param, $fieldName, $alias);
36
    }
37
38
    protected function getAlias(QueryBuilderInterface $queryBuilder, ?string $alias = null): string
39
    {
40
        $alias ??= $queryBuilder->getRootAlias();
41
        if (!empty($alias)) {
42
            return $alias;
43
        }
44
45
        return $this->options['alias'] ?? 'x';
46
    }
47
48
    /**
49
     * @throws InvalidArgumentException
50
     */
51
    protected function resolveFieldName(MetadataInterface $metadata, array $criteria): string
52
    {
53
        if (empty($criteria['field'])) {
54
            throw new InvalidArgumentException(
55
                sprintf(
56
                    'The required \'field\' criteria value is missing for filter \'%s\'',
57
                    static::class
58
                )
59
            );
60
        }
61
62
        $parts = explode('.', $criteria['field']);
63
        $fieldName = array_pop($parts);
64
65
        if (!$metadata->hasField($fieldName) && !$metadata->hasAssociation($fieldName)) {
66
            throw new InvalidArgumentException(
67
                sprintf(
68
                    'Unable to apply query filter \'%s\': '
69
                    . 'The entity class \'%s\' has no field or association named \'%s\'',
70
                    static::class,
71
                    $metadata->getName(),
72
                    $fieldName,
73
                )
74
            );
75
        }
76
77
        return $fieldName;
78
    }
79
80
    /**
81
     * @throws FilterException
82
     */
83
    protected function formatValue(
84
        MetadataInterface $metadata,
85
        string $fieldName,
86
        mixed $value,
87
        ?string $type = null,
88
        array $options = []
89
    ): mixed {
90
        try {
91
            return $this->typecaster->typecast($metadata, $fieldName, $value, $type, $options);
92
        } catch (TypecastException $e) {
93
            throw new FilterException(
94
                sprintf('Failed to format the value for field \'%s::%s\'', $metadata->getName(), $fieldName),
95
                $e->getCode(),
96
                $e
97
            );
98
        }
99
    }
100
101
    protected function getWhereType(array $criteria): WhereType
102
    {
103
        if (isset($criteria['where'])) {
104
            if (is_string($criteria['where'])) {
105
                $criteria['where'] = WhereType::tryFrom($criteria['where']);
106
            }
107
108
            if ($criteria['where'] instanceof WhereType) {
109
                return $criteria['where'];
110
            }
111
        }
112
113
        return WhereType::AND;
114
    }
115
116
    /**
117
     * @throws FilterException
118
     */
119
    protected function applyFilters(
120
        QueryBuilderInterface $queryBuilder,
121
        MetadataInterface $metadata,
122
        array $filters,
123
    ): void {
124
        foreach ($filters as $filter) {
125
            $this->applyFilter($queryBuilder, $metadata, $filter);
126
        }
127
    }
128
129
    /**
130
     * @throws FilterException
131
     */
132
    protected function applyFilter(
133
        QueryBuilderInterface $queryBuilder,
134
        MetadataInterface $metadata,
135
        array $criteria,
136
    ): void {
137
        try {
138
            $this->queryFilterManager->applyFilter($queryBuilder, $metadata, $criteria);
139
        } catch (QueryFilterManagerException $e) {
140
            throw new FilterException(
141
                sprintf('Failed to apply query filter for entity \'%s\'', $metadata->getName()),
142
                $e->getCode(),
143
                $e,
144
            );
145
        }
146
    }
147
}
148