Completed
Push — master ( 5a3b29...e6885e )
by Joachim
20:02 queued 05:12
created

AbstractRepository::generator()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 16
nc 8
nop 2
dl 0
loc 25
ccs 0
cts 6
cp 0
crap 30
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
namespace Loevgaard\DandomainFoundation\Repository;
4
5
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
6
use Doctrine\Common\Persistence\ManagerRegistry;
7
use Doctrine\ORM\QueryBuilder;
8
use Loevgaard\DandomainDateTime\DateTimeImmutable;
9
use Loevgaard\DandomainFoundation\Repository\Generated\AbstractRepositoryTrait;
10
use Symfony\Component\OptionsResolver\OptionsResolver;
11
12
abstract class AbstractRepository extends ServiceEntityRepository implements RepositoryInterface
13
{
14
    use AbstractRepositoryTrait;
15
16
    /**
17
     * @var array
18
     */
19
    protected $options;
20
21
    public function __construct(ManagerRegistry $registry, string $entityClass)
22
    {
23
        $this->options = [];
24
25
        parent::__construct($registry, $entityClass);
26
    }
27
28
    /**
29
     * @param object $entity
30
     * @throws \Doctrine\ORM\ORMException
31
     * @throws \Doctrine\ORM\OptimisticLockException
32
     */
33
    public function save($entity)
34
    {
35
        $this->getEntityManager()->persist($entity);
36
        $this->getEntityManager()->flush();
37
    }
38
39
    /**
40
     * @param array $options
41
     * @return \Generator
42
     * @throws \Doctrine\Common\Persistence\Mapping\MappingException
43
     * @throws \Doctrine\ORM\ORMException
44
     * @throws \Doctrine\ORM\OptimisticLockException
45
     */
46
    public function iterate(array $options = []): \Generator
47
    {
48
        $options['iterate'] = true;
49
        $this->setOptions($options);
50
51
        return $this->result($this->createQueryBuilder('c'));
52
    }
53
54
    /**
55
     * Will remove entities based on the ids you input.
56
     *
57
     * @param int[] $in
58
     * @param int[] $notIn
59
     */
60
    public function removeByIds(array $in = [], array $notIn = [])
61
    {
62
        if (!count($in) && !count($notIn)) {
63
            return;
64
        }
65
66
        $qb = $this->createQueryBuilder('e');
67
68
        if ($this->getClassMetadata()->hasField('deletedAt')) {
69
            $qb->update()
70
                ->set('e.deletedAt', ':date')
71
                ->setParameter('date', new DateTimeImmutable())
72
            ;
73
        } else {
74
            $qb->delete();
75
        }
76
77
        if (count($in)) {
78
            $qb->andWhere($qb->expr()->in('e.id', ':inIds'));
79
            $qb->setParameter('inIds', $in);
80
        }
81
82
        if (count($notIn)) {
83
            $qb->andWhere($qb->expr()->notIn('e.id', ':notInIds'));
84
            $qb->setParameter('notInIds', $notIn);
85
        }
86
87
        $qb->getQuery()->execute();
88
    }
89
90
    /**
91
     * @param QueryBuilder $qb
92
     * @return \Generator|mixed
93
     * @throws \Doctrine\Common\Persistence\Mapping\MappingException
94
     * @throws \Doctrine\ORM\ORMException
95
     * @throws \Doctrine\ORM\OptimisticLockException
96
     */
97
    protected function result(QueryBuilder $qb)
98
    {
99
        $resolver = new OptionsResolver();
100
        $this->configureOptions($resolver);
101
        $options = $resolver->resolve($this->options);
102
103
        // reset options
104
        $this->options = [];
105
106
        if($options['iterate']) {
107
            return $this->generator($qb, $options);
108
        } else {
109
            return $qb->getQuery()->getResult();
110
        }
111
    }
112
113
    /**
114
     * @param QueryBuilder $qb
115
     * @param array $options
116
     * @return \Generator
117
     * @throws \Doctrine\Common\Persistence\Mapping\MappingException
118
     * @throws \Doctrine\ORM\ORMException
119
     * @throws \Doctrine\ORM\OptimisticLockException
120
     */
121
    protected function generator(QueryBuilder $qb, array $options) : \Generator
122
    {
123
        $em = $this->getEntityManager();
124
125
        $result = $qb->getQuery()->iterate();
126
        $i = 1;
127
        foreach ($result as $item) {
128
            $obj = $item[0];
129
            yield $obj;
130
131
            if ($options['update']) {
132
                if (0 == $i % $options['bulkSize']) {
133
                    $em->flush();
134
                    $em->clear();
135
                }
136
            } else {
137
                $em->detach($obj);
138
            }
139
140
            ++$i;
141
        }
142
143
        if ($options['update']) {
144
            $em->flush();
145
            $em->clear();
146
        }
147
    }
148
149
    /**
150
     * @throws \Doctrine\Common\Persistence\Mapping\MappingException
151
     */
152
    public function clearAll()
153
    {
154
        $this->getEntityManager()->clear();
155
    }
156
157
    /**
158
     * @param $id
159
     *
160
     * @return bool|\Doctrine\Common\Proxy\Proxy|null|object
161
     *
162
     * @throws \Doctrine\ORM\ORMException
163
     */
164
    public function getReference($id)
165
    {
166
        return $this->getEntityManager()->getReference($this->getClassName(), $id);
167
    }
168
169
    /**
170
     * @param array $options
171
     * @return AbstractRepository
172
     */
173
    public function setOptions(array $options)
174
    {
175
        $this->options = $options;
176
        return $this;
177
    }
178
179
    /**
180
     * On 90% of the entities there is an external id so we put this helper method here
181
     * so that all these repository doesn't have to implement the same method, instead they
182
     * can call this method and just create the type hint and validation of input.
183
     *
184
     * @param $externalId
185
     *
186
     * @return null|object
187
     */
188
    protected function _findOneByExternalId($externalId)
189
    {
190
        $obj = $this->findOneBy([
191
            'externalId' => $externalId,
192
        ]);
193
194
        return $obj;
195
    }
196
197
    protected function configureOptions(OptionsResolver $resolver)
198
    {
199
        $resolver->setDefaults([
200
            'iterate' => false,
201
            'update' => false,
202
            'bulkSize' => 50,
203
        ]);
204
    }
205
}
206