Completed
Push — master ( ff6c8c...e2de7a )
by Philip
03:35
created

DoctrineCrudService::update()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 3
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
crap 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 2
    public function __construct(EntityManager $em, $class)
35
    {
36 2
        $classMetaData = $class;
37 2
        if (is_string($classMetaData)) {
38
            $classMetaData = $em->getClassMetadata($classMetaData);
39
        }
40 2
        parent::__construct($em, $classMetaData);
41 2
        $this->transactionManager = new TransactionManager($em);
42 2
    }
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
    public function findAssociationPaginated($entity, string $fieldName, int $page = 1, $perPage = 50)
97
    {
98
        $classMetadata = $this->getEntityManager()->getClassMetadata(get_class($entity));
99
        $targetClass = $classMetadata->getAssociationTargetClass($fieldName);
100
101
        $inverseFieldName = $this->getInverseFieldName($fieldName, $classMetadata);
102
103
        $queryBuilder = $this->getEntityManager()->createQueryBuilder();
104
        $queryBuilder->select('association');
105
        $queryBuilder->from($targetClass, 'association');
106
        $queryBuilder->join('association.' . $inverseFieldName, 'entity');
107
        $queryBuilder->where('entity = :entity');
108
        $queryBuilder->setParameter('entity', $entity);
109
110
        $queryBuilder->setFirstResult(($page - 1) * $perPage);
111
        $queryBuilder->setMaxResults($perPage);
112
113
        return new Paginator($queryBuilder);
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119
    public function createAssociation($entity, string $fieldName)
120
    {
121
        $classMetadata = $this->getEntityManager()->getClassMetadata(get_class($entity));
122
        $targetClass = $classMetadata->getAssociationTargetClass($fieldName);
123
        $child = new $targetClass;
124
125
        $inverseFieldName = $this->getInverseFieldName($fieldName, $classMetadata);
126
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
127
        $propertyAccessor->setValue($child, $inverseFieldName, $entity);
128
129
        return $child;
130
    }
131
132
    /**
133
     * {@inheritdoc}
134
     */
135
    public function addAssociation($entity, string $fieldName, $id)
136
    {
137
        $classMetadata = $this->getEntityManager()->getClassMetadata(get_class($entity));
138
        $collection = $classMetadata->isCollectionValuedAssociation($fieldName);
139
        $targetClass = $classMetadata->getAssociationTargetClass($fieldName);
140
        $inverse = $classMetadata->isAssociationInverseSide($fieldName);
141
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
142
        $reference = $this->getEntityManager()->getReference($targetClass, $id);
143
144
        if (!$inverse) {
145
            if ($collection) {
146
                /** @var Collection $collection */
147
                $collection = $propertyAccessor->getValue($entity, $fieldName);
148
                $collection->add($reference);
149
            } else {
150
                $propertyAccessor->setValue($entity, $fieldName, $reference);
151
            }
152
            $this->getEntityManager()->flush($entity);
153
        } else {
154
            $inverseClassMetadata = $this->getEntityManager()->getClassMetadata($targetClass);
155
            $association = $classMetadata->getAssociationMapping($fieldName);
156
            $inverseFieldName = $association['mappedBy'];
157
            $inverseCollection = $inverseClassMetadata->isCollectionValuedAssociation($inverseFieldName);
158
            if ($inverseCollection) {
159
                /** @var Collection $collection */
160
                $collection = $propertyAccessor->getValue($reference, $inverseFieldName);
161
                $collection->add($entity);
162
            } else {
163
                $propertyAccessor->setValue($reference, $inverseFieldName, $entity);
164
            }
165
            $this->getEntityManager()->flush($reference);
166
        }
167
    }
168
169
    /**
170
     * {@inheritdoc}
171
     */
172
    public function removeAssociation($entity, string $fieldName, $id = null)
173
    {
174
        $classMetadata = $this->getEntityManager()->getClassMetadata(get_class($entity));
175
        $collection = $classMetadata->isCollectionValuedAssociation($fieldName);
176
        $targetClass = $classMetadata->getAssociationTargetClass($fieldName);
177
        $inverse = $classMetadata->isAssociationInverseSide($fieldName);
178
        $propertyAccessor = PropertyAccess::createPropertyAccessor();
179
180
        if ($inverse) {
181
            $reference = $this->getEntityManager()->getReference($targetClass, $id);
182
            $inverseClassMetadata = $this->getEntityManager()->getClassMetadata($targetClass);
183
            $association = $classMetadata->getAssociationMapping($fieldName);
184
            $inverseFieldName = $association['mappedBy'];
185
            $inverseCollection = $inverseClassMetadata->isCollectionValuedAssociation($inverseFieldName);
186
            if ($inverseCollection) {
187
                /** @var Collection $collection */
188
                $collection = $propertyAccessor->getValue($reference, $inverseFieldName);
189
                $collection->removeElement($entity);
190
            } else {
191
                $propertyAccessor->setValue($reference, $inverseFieldName, null);
192
            }
193
            $this->getEntityManager()->flush($reference);
194
        } else {
195
            if ($collection) {
196
                $reference = $this->getEntityManager()->getReference($targetClass, $id);
197
                /** @var Collection $collection */
198
                $collection = $propertyAccessor->getValue($entity, $fieldName);
199
                $collection->removeElement($reference);
200
            } else {
201
                $propertyAccessor->setValue($entity, $fieldName, null);
202
            }
203
            $this->getEntityManager()->flush($entity);
204
        }
205
    }
206
207
    /**
208
     * @param string        $fieldName
209
     * @param ClassMetadata $classMetadata
210
     *
211
     * @return string
212
     */
213
    protected function getInverseFieldName(string $fieldName, ClassMetadata $classMetadata)
214
    {
215
        $association = $classMetadata->getAssociationMapping($fieldName);
216
        if ($classMetadata->isAssociationInverseSide($fieldName)) {
217
            return $association['mappedBy'];
218
        } else {
219
            return $association['inversedBy'];
220
        }
221
    }
222
223
    /**
224
     * @param LoggerInterface $logger
225
     */
226
    public function setLogger(LoggerInterface $logger): void
227
    {
228
        $this->logger = $logger;
229
    }
230
231
    /**
232
     * @return LoggerInterface
233
     */
234
    public function getLogger(): LoggerInterface
235
    {
236
        if (null === $this->logger) {
237
            $this->logger = new NullLogger();
238
        }
239
240
        return $this->logger;
241
    }
242
}
243