Test Failed
Push — master ( 1c5165...b7ef6a )
by Kirill
03:37
created

Processor   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 186
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 76.79%

Importance

Changes 0
Metric Value
wmc 18
lcom 1
cbo 5
dl 0
loc 186
ccs 43
cts 56
cp 0.7679
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A getClassMetadata() 0 4 1
A getEntityManager() 0 4 1
A getRepository() 0 4 1
A forEach() 0 8 2
A getBuilder() 0 21 3
A bypass() 0 16 2
A yieldThrough() 0 24 5
A applyField() 0 4 1
A applyFieldWithValue() 0 8 1
1
<?php
2
/**
3
 * This file is part of Hydrogen package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace RDS\Hydrogen\Processor;
11
12
use Doctrine\Common\Persistence\ObjectRepository;
13
use Doctrine\ORM\EntityManagerInterface;
14
use Doctrine\ORM\EntityRepository;
15
use Doctrine\ORM\Mapping\ClassMetadata;
16
use RDS\Hydrogen\Criteria\Common\Field;
17
use RDS\Hydrogen\Criteria\CriterionInterface;
18
use RDS\Hydrogen\Query;
19
20
/**
21
 * Class Processor
22
 */
23
abstract class Processor implements ProcessorInterface
24
{
25
    /**
26
     * @var string[]|BuilderInterface[]
27
     */
28
    protected const CRITERIA_MAPPINGS = [];
29
30
    /**
31
     * @var ObjectRepository|EntityRepository
32
     */
33
    protected $repository;
34
35
    /**
36
     * @var EntityManagerInterface
37
     */
38
    protected $em;
39
40
    /**
41
     * @var ClassMetadata
42
     */
43
    protected $meta;
44
45
    /**
46
     * @var array|BuilderInterface[]
47
     */
48
    private $builderInstances = [];
49
50
    /**
51
     * DatabaseProcessor constructor.
52
     * @param ObjectRepository $repository
53
     * @param EntityManagerInterface $em
54
     */
55 30
    public function __construct(ObjectRepository $repository, EntityManagerInterface $em)
56
    {
57 30
        $this->em = $em;
58 30
        $this->meta = $em->getClassMetadata($repository->getClassName());
59 30
        $this->repository = $repository;
60
61 30
        \assert(\count(static::CRITERIA_MAPPINGS));
62 30
    }
63
64
    /**
65
     * @return ClassMetadata
66
     */
67
    public function getClassMetadata(): ClassMetadata
68
    {
69
        return $this->meta;
70
    }
71
72
    /**
73
     * @return EntityManagerInterface
74
     */
75
    public function getEntityManager(): EntityManagerInterface
76
    {
77
        return $this->em;
78
    }
79
80
    /**
81
     * @return EntityRepository
82
     */
83
    public function getRepository(): EntityRepository
84
    {
85
        return $this->repository;
86
    }
87
88
    /**
89
     * @param mixed $context
90
     * @param Query $query
91
     * @return \Generator
92
     */
93 30
    protected function forEach($context, Query $query): \Generator
94
    {
95 30
        foreach ($query->getCriteria() as $criterion) {
96 28
            $builder = $this->getBuilder($criterion);
97
98 28
            yield from $builder->apply($context, $criterion);
99
        }
100 30
    }
101
102
    /**
103
     * @param CriterionInterface $criterion
104
     * @return BuilderInterface
105
     */
106 28
    protected function getBuilder(CriterionInterface $criterion): BuilderInterface
107
    {
108 28
        $key = \get_class($criterion);
109
110 28
        if (isset($this->builderInstances[$key])) {
111 2
            return $this->builderInstances[$key];
112
        }
113
114 28
        $processor = static::CRITERIA_MAPPINGS[\get_class($criterion)] ?? null;
115
116 28
        if ($processor === null) {
117
            $error = \vsprintf('%s processor does not support the "%s" criterion', [
118
                \str_replace_last('Processor', '', \class_basename($this)),
119
                \class_basename($criterion),
120
            ]);
121
122
            throw new \InvalidArgumentException($error);
123
        }
124
125 28
        return $this->builderInstances[$key] = new $processor($this->meta, $this);
126
    }
127
128
    /**
129
     * @param \Generator $generator
130
     * @param Query $query
131
     * @param \Closure $each
132
     * @return \Generator
133
     */
134 30
    protected function bypass(\Generator $generator, Query $query, \Closure $each): \Generator
135
    {
136 30
        $this->builderInstances = [];
137
138 30
        while ($generator->valid()) {
139 24
            [$key, $value] = [$generator->key(), $generator->current()];
0 ignored issues
show
Bug introduced by
The variable $key does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $value does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
140
141 24
            yield from $result = $this->yieldThrough($key, $value, $query, $each);
142
143 24
            $response = $result->getReturn();
144
145 24
            \assert($response !== null);
146
147 24
            $generator->send($response);
148
        }
149 30
    }
150
151
    /**
152
     * @param mixed $key
153
     * @param mixed $value
154
     * @param Query $query
155
     * @param \Closure $each
156
     * @return \Generator
157
     */
158 24
    private function yieldThrough($key, $value, Query $query, \Closure $each): \Generator
159
    {
160
        switch (true) {
161 24
            case $value instanceof Field:
162 22
                return $this->applyField($query, $value);
163
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
164
165 10
            case $key instanceof Field:
166 8
                yield from $co = $this->applyFieldWithValue($query, $key, $value);
167 8
                return $co->getReturn();
168
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
169
170 2
            case $value instanceof \Closure:
171
                yield $value;
172
                return $value;
173
174 2
            case $value instanceof Query:
175 2
                $query->merge($value);
176 2
                return $query;
177
178
            default:
179
                return $each($value, $key);
180
        }
181
    }
182
183
    /**
184
     * @param Query $query
185
     * @param Field $field
186
     * @return string
187
     */
188 22
    private function applyField(Query $query, Field $field): string
189
    {
190 22
        return $field->withQuery($query)->toString();
191
    }
192
193
    /**
194
     * @param Query $query
195
     * @param Field $field
196
     * @param $value
197
     * @return \Generator
198
     * @throws \Exception
199
     */
200 8
    private function applyFieldWithValue(Query $query, Field $field, $value): \Generator
201
    {
202 8
        $placeholder = $query->placeholder($field->getName());
203
204 8
        yield $placeholder => $value;
205
206 8
        return $placeholder;
207
    }
208
}
209