Test Failed
Push — master ( b17eba...69b436 )
by Kirill
06:37
created

Processor::yieldThrough()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 24
ccs 0
cts 20
cp 0
rs 9.2248
c 0
b 0
f 0
cc 5
nc 5
nop 4
crap 30
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 RDS\Hydrogen\Criteria\Common\Field;
16
use RDS\Hydrogen\Criteria\CriterionInterface;
17
use RDS\Hydrogen\Query;
18
19
/**
20
 * Class Processor
21
 */
22
abstract class Processor implements ProcessorInterface
23
{
24
    /**
25
     * @var string[]|BuilderInterface[]
26
     */
27
    protected const CRITERIA_MAPPINGS = [];
28
29
    /**
30
     * @var ObjectRepository|EntityRepository
31
     */
32
    protected $repository;
33
34
    /**
35
     * @var EntityManagerInterface
36
     */
37
    protected $em;
38
39
    /**
40
     * @var array|BuilderInterface[]
41
     */
42
    private $builderInstances = [];
43
44
    /**
45
     * DatabaseProcessor constructor.
46
     * @param ObjectRepository $repository
47
     * @param EntityManagerInterface $em
48
     */
49
    public function __construct(ObjectRepository $repository, EntityManagerInterface $em)
50
    {
51
        $this->em         = $em;
52
        $this->repository = $repository;
53
54
        \assert(\count(static::CRITERIA_MAPPINGS));
55
    }
56
57
    /**
58
     * @param CriterionInterface $criterion
59
     * @return BuilderInterface
60
     */
61
    protected function getBuilder(CriterionInterface $criterion): BuilderInterface
62
    {
63
        $key = \get_class($criterion);
64
65
        if (isset($this->builderInstances[$key])) {
66
            return $this->builderInstances[$key];
67
        }
68
69
        $processor = static::CRITERIA_MAPPINGS[\get_class($criterion)] ?? null;
70
71
        if ($processor === null) {
72
            $error = \vsprintf('%s processor does not support the "%s" criterion', [
73
                \str_replace_last('Processor', '', \class_basename($this)),
74
                \class_basename($criterion),
75
            ]);
76
77
            throw new \InvalidArgumentException($error);
78
        }
79
80
        return $this->builderInstances[$key] = new $processor($this);
81
    }
82
83
    /**
84
     * @param mixed $context
85
     * @param Query $query
86
     * @return \Generator
87
     */
88
    protected function forEach($context, Query $query): \Generator
89
    {
90
        foreach ($query->getCriteria() as $criterion) {
91
            $builder = $this->getBuilder($criterion);
92
93
            yield from $builder->apply($context, $criterion);
94
        }
95
    }
96
97
    /**
98
     * @param \Generator $generator
99
     * @param Query $query
100
     * @param \Closure $each
101
     * @return \Generator
102
     */
103
    protected function bypass(\Generator $generator, Query $query, \Closure $each): \Generator
104
    {
105
        $this->builderInstances = [];
106
107
        while ($generator->valid()) {
108
            [$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...
109
110
            yield from $result = $this->yieldThrough($key, $value, $query, $each);
111
112
            $response = $result->getReturn();
113
114
            \assert($response !== null);
115
116
            $generator->send($response);
117
        }
118
    }
119
120
    /**
121
     * @param mixed $key
122
     * @param mixed $value
123
     * @param Query $query
124
     * @param \Closure $each
125
     * @return \Generator
126
     */
127
    private function yieldThrough($key, $value, Query $query, \Closure $each): \Generator
128
    {
129
        switch (true) {
130
            case $value instanceof Field:
131
                return $this->applyField($query, $value);
132
                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...
133
134
            case $key instanceof Field:
135
                yield from $co = $this->applyFieldWithValue($query, $key, $value);
136
                return $co->getReturn();
137
                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...
138
139
            case $value instanceof \Closure:
140
                yield $value;
141
                return $value;
142
143
            case $value instanceof Query:
144
                $query->merge($value);
145
                return $query;
146
147
            default:
148
                return $each($value, $key);
149
        }
150
    }
151
152
    /**
153
     * @param Query $query
154
     * @param Field $field
155
     * @return string
156
     */
157
    private function applyField(Query $query, Field $field): string
158
    {
159
        return $field->withQuery($query)->toString();
160
    }
161
162
    /**
163
     * @param Query $query
164
     * @param Field $field
165
     * @param $value
166
     * @return \Generator
167
     * @throws \Exception
168
     */
169
    private function applyFieldWithValue(Query $query, Field $field, $value): \Generator
170
    {
171
        $placeholder = $query->placeholder($field->getName());
172
173
        yield $placeholder => $value;
174
175
        return $placeholder;
176
    }
177
}
178