Completed
Push — master ( e2de7a...156090 )
by Philip
04:48
created

DoctrineCrudService   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 235
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 26.12%

Importance

Changes 0
Metric Value
wmc 24
lcom 1
cbo 8
dl 0
loc 235
ccs 29
cts 111
cp 0.2612
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 2
A findAllPaginated() 0 8 1
A createFindAllQueryBuilder() 0 6 1
A create() 0 7 1
A update() 0 6 1
A remove() 0 5 1
B findAssociationPaginated() 0 27 3
A createAssociation() 0 12 1
B addAssociation() 0 33 4
B removeAssociation() 0 34 4
A getInverseFieldName() 0 9 2
A setLogger() 0 4 1
A getLogger() 0 8 2
1
<?php
2
3
namespace Dontdrinkandroot\Service;
4
5
use Doctrine\Common\Collections\Collection;
6
use Doctrine\ORM\EntityManager;
7
use Doctrine\ORM\EntityRepository;
8
use Doctrine\ORM\Mapping\ClassMetadata;
9
use Doctrine\ORM\QueryBuilder;
10
use Doctrine\ORM\Tools\Pagination\Paginator;
11
use Dontdrinkandroot\Repository\TransactionManager;
12
use Psr\Log\LoggerInterface;
13
use Psr\Log\NullLogger;
14
use Symfony\Component\PropertyAccess\PropertyAccess;
15
16
class DoctrineCrudService extends EntityRepository implements CrudServiceInterface
17
{
18
    /**
19
     * @var  LoggerInterface
20
     */
21
    private $logger;
22
23
    /**
24
     * @var TransactionManager
25
     */
26
    private $transactionManager;
27
28
    /**
29
     * DoctrineCrudService constructor.
30
     *
31
     * @param EntityManager        $em
32
     * @param ClassMetadata|string $class
33
     */
34 6
    public function __construct(EntityManager $em, $class)
35
    {
36 6
        $classMetaData = $class;
37 6
        if (is_string($classMetaData)) {
38
            $classMetaData = $em->getClassMetadata($classMetaData);
39
        }
40 6
        parent::__construct($em, $classMetaData);
41 6
        $this->transactionManager = new TransactionManager($em);
42 6
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47
    public function findAllPaginated(int $page = 1, int $perPage = 50): Paginator
48
    {
49
        $queryBuilder = $this->createFindAllQueryBuilder();
50
        $queryBuilder->setFirstResult(($page - 1) * $perPage);
51
        $queryBuilder->setMaxResults($perPage);
52
53
        return new Paginator($queryBuilder);
54
    }
55
56
    protected function createFindAllQueryBuilder(): QueryBuilder
57
    {
58
        $queryBuilder = $this->createQueryBuilder('entity');
59
60
        return $queryBuilder;
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function create($entity)
67
    {
68
        $this->getEntityManager()->persist($entity);
69
        $this->getEntityManager()->flush($entity);
70
71
        return $entity;
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77
    public function update($entity)
78
    {
79
        $this->getEntityManager()->flush($entity);
80
81
        return $entity;
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87
    public function remove($entity)
88
    {
89
        $this->getEntityManager()->remove($entity);
90
        $this->getEntityManager()->flush($entity);
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96 4
    public function findAssociationPaginated($entity, string $fieldName, int $page = 1, $perPage = 50)
97
    {
98 4
        $classMetadata = $this->getEntityManager()->getClassMetadata(get_class($entity));
99 4
        $association = $classMetadata->associationMappings[$fieldName];
100 4
        $targetClass = $classMetadata->getAssociationTargetClass($fieldName);
101 4
        $inverseFieldName = $this->getInverseFieldName($fieldName, $classMetadata);
102
103 4
        $queryBuilder = $this->getEntityManager()->createQueryBuilder();
104 4
        $queryBuilder->select('association');
105 4
        $queryBuilder->from($targetClass, 'association');
106 4
        $queryBuilder->join('association.' . $inverseFieldName, 'entity');
107 4
        $queryBuilder->where('entity = :entity');
108
109 4
        if (array_key_exists('orderBy', $association)) {
110 2
            $orderBy = $association['orderBy'];
111 2
            foreach ($orderBy as $fieldName => $order) {
112 2
                $queryBuilder->addOrderBy('association.' . $fieldName, $order);
113
            }
114
        }
115
116 4
        $queryBuilder->setParameter('entity', $entity);
117
118 4
        $queryBuilder->setFirstResult(($page - 1) * $perPage);
119 4
        $queryBuilder->setMaxResults($perPage);
120
121 4
        return new Paginator($queryBuilder);
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127
    public function createAssociation($entity, string $fieldName)
128
    {
129
        $classMetadata = $this->getEntityManager()->getClassMetadata(get_class($entity));
130
        $targetClass = $classMetadata->getAssociationTargetClass($fieldName);
131
        $child = new $targetClass;
132
133
        $inverseFieldName = $this->getInverseFieldName($fieldName, $classMetadata);
134
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
135
        $propertyAccessor->setValue($child, $inverseFieldName, $entity);
136
137
        return $child;
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143
    public function addAssociation($entity, string $fieldName, $id)
144
    {
145
        $classMetadata = $this->getEntityManager()->getClassMetadata(get_class($entity));
146
        $collection = $classMetadata->isCollectionValuedAssociation($fieldName);
147
        $targetClass = $classMetadata->getAssociationTargetClass($fieldName);
148
        $inverse = $classMetadata->isAssociationInverseSide($fieldName);
149
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
150
        $reference = $this->getEntityManager()->getReference($targetClass, $id);
151
152
        if (!$inverse) {
153
            if ($collection) {
154
                /** @var Collection $collection */
155
                $collection = $propertyAccessor->getValue($entity, $fieldName);
156
                $collection->add($reference);
157
            } else {
158
                $propertyAccessor->setValue($entity, $fieldName, $reference);
159
            }
160
            $this->getEntityManager()->flush($entity);
161
        } else {
162
            $inverseClassMetadata = $this->getEntityManager()->getClassMetadata($targetClass);
163
            $association = $classMetadata->getAssociationMapping($fieldName);
164
            $inverseFieldName = $association['mappedBy'];
165
            $inverseCollection = $inverseClassMetadata->isCollectionValuedAssociation($inverseFieldName);
166
            if ($inverseCollection) {
167
                /** @var Collection $collection */
168
                $collection = $propertyAccessor->getValue($reference, $inverseFieldName);
169
                $collection->add($entity);
170
            } else {
171
                $propertyAccessor->setValue($reference, $inverseFieldName, $entity);
172
            }
173
            $this->getEntityManager()->flush($reference);
174
        }
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     */
180
    public function removeAssociation($entity, string $fieldName, $id = null)
181
    {
182
        $classMetadata = $this->getEntityManager()->getClassMetadata(get_class($entity));
183
        $collection = $classMetadata->isCollectionValuedAssociation($fieldName);
184
        $targetClass = $classMetadata->getAssociationTargetClass($fieldName);
185
        $inverse = $classMetadata->isAssociationInverseSide($fieldName);
186
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
187
188
        if ($inverse) {
189
            $reference = $this->getEntityManager()->getReference($targetClass, $id);
190
            $inverseClassMetadata = $this->getEntityManager()->getClassMetadata($targetClass);
191
            $association = $classMetadata->getAssociationMapping($fieldName);
192
            $inverseFieldName = $association['mappedBy'];
193
            $inverseCollection = $inverseClassMetadata->isCollectionValuedAssociation($inverseFieldName);
194
            if ($inverseCollection) {
195
                /** @var Collection $collection */
196
                $collection = $propertyAccessor->getValue($reference, $inverseFieldName);
197
                $collection->removeElement($entity);
198
            } else {
199
                $propertyAccessor->setValue($reference, $inverseFieldName, null);
200
            }
201
            $this->getEntityManager()->flush($reference);
202
        } else {
203
            if ($collection) {
204
                $reference = $this->getEntityManager()->getReference($targetClass, $id);
205
                /** @var Collection $collection */
206
                $collection = $propertyAccessor->getValue($entity, $fieldName);
207
                $collection->removeElement($reference);
208
            } else {
209
                $propertyAccessor->setValue($entity, $fieldName, null);
210
            }
211
            $this->getEntityManager()->flush($entity);
212
        }
213
    }
214
215
    /**
216
     * @param string        $fieldName
217
     * @param ClassMetadata $classMetadata
218
     *
219
     * @return string
220
     */
221 4
    protected function getInverseFieldName(string $fieldName, ClassMetadata $classMetadata)
222
    {
223 4
        $association = $classMetadata->getAssociationMapping($fieldName);
224 4
        if ($classMetadata->isAssociationInverseSide($fieldName)) {
225 2
            return $association['mappedBy'];
226
        } else {
227 2
            return $association['inversedBy'];
228
        }
229
    }
230
231
    /**
232
     * @param LoggerInterface $logger
233
     */
234
    public function setLogger(LoggerInterface $logger): void
235
    {
236
        $this->logger = $logger;
237
    }
238
239
    /**
240
     * @return LoggerInterface
241
     */
242
    public function getLogger(): LoggerInterface
243
    {
244
        if (null === $this->logger) {
245
            $this->logger = new NullLogger();
246
        }
247
248
        return $this->logger;
249
    }
250
}
251