Completed
Push — master ( b7ef6a...58a002 )
by Kirill
03:12
created

Processor::getBuilder()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.5

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 4
cts 8
cp 0.5
rs 9.7666
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2.5
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\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 ClassMetadata
41
     */
42
    protected $meta;
43
44
    /**
45
     * DatabaseProcessor constructor.
46
     * @param ObjectRepository $repository
47
     * @param EntityManagerInterface $em
48
     */
49 30
    public function __construct(ObjectRepository $repository, EntityManagerInterface $em)
50
    {
51 30
        $this->em = $em;
52 30
        $this->meta = $em->getClassMetadata($repository->getClassName());
53 30
        $this->repository = $repository;
54
55 30
        \assert(\count(static::CRITERIA_MAPPINGS));
56 30
    }
57
58
    /**
59
     * @return EntityManagerInterface
60
     */
61
    public function getEntityManager(): EntityManagerInterface
62
    {
63
        return $this->em;
64
    }
65
66
    /**
67
     * @return EntityRepository|ObjectRepository
68
     */
69
    public function getRepository(): ObjectRepository
70
    {
71
        return $this->repository;
72
    }
73
74
    /**
75
     * @return ClassMetadata
76
     */
77 2
    public function getMetadata(): ClassMetadata
78
    {
79 2
        return $this->meta;
80
    }
81
82
    /**
83
     * @param mixed $context
84
     * @param Query $query
85
     * @return \Generator
86
     */
87 30
    protected function bypass($context, Query $query): \Generator
88
    {
89 30
        foreach ($this->builders($query) as $criterion => $builder) {
90 30
            $result = $builder->apply($context, $criterion);
91
92 30
            if (\is_iterable($result)) {
93 30
                yield $criterion => $result;
94
            }
95
        }
96 30
    }
97
98
    /**
99
     * @param \Generator $generator
100
     * @return array
101
     */
102 30
    protected function await(\Generator $generator): array
103
    {
104 30
        $queue = new Queue();
105
106 30
        while ($generator->valid()) {
107
            $value = $generator->current();
108
109
            if ($value instanceof \Closure) {
110
                $queue->push($value);
111
            }
112
113
            $generator->next();
114
        }
115
116 30
        return [$queue, $generator->getReturn()];
117
    }
118
119
    /**
120
     * @param Query $query
121
     * @return \Generator|BuilderInterface[]
122
     */
123 30
    private function builders(Query $query): \Generator
124
    {
125 30
        $context = [];
126
127 30
        foreach ($query->getCriteria() as $criterion) {
128 30
            $key = \get_class($criterion);
129
130 30
            yield $criterion => $context[$key] ?? $context[$key] = $this->getBuilder($query, $criterion);
131
        }
132
133 30
        unset($context);
134 30
    }
135
136
    /**
137
     * @param Query $query
138
     * @param CriterionInterface $criterion
139
     * @return BuilderInterface
140
     */
141 30
    protected function getBuilder(Query $query, CriterionInterface $criterion): BuilderInterface
142
    {
143 30
        $processor = static::CRITERIA_MAPPINGS[\get_class($criterion)] ?? null;
144
145 30
        if ($processor === null) {
146
            $error = \vsprintf('%s processor does not support the "%s" criterion', [
147
                \str_replace_last('Processor', '', \class_basename($this)),
148
                \class_basename($criterion),
149
            ]);
150
151
            throw new \InvalidArgumentException($error);
152
        }
153
154 30
        return new $processor($query, $this);
155
    }
156
157
    /**
158
     * @param string $entity
159
     * @return ProcessorInterface
160
     */
161 2
    public function getProcessor(string $entity): ProcessorInterface
162
    {
163 2
        $repository = $this->em->getRepository($entity);
164
165 2
        if (\method_exists($repository, 'getProcessor')) {
166 2
            return $repository->getProcessor();
167
        }
168
169
        return new static($repository, $this->em);
170
    }
171
}
172