AbstractORMRepository::getPropertyName()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
cc 3
eloc 4
nc 2
nop 2
1
<?php
2
3
declare (strict_types = 1);
4
5
namespace HMLB\DDDBundle\Doctrine\ORM;
6
7
use Doctrine\ORM\EntityManager;
8
use Doctrine\ORM\EntityRepository;
9
use Doctrine\ORM\QueryBuilder;
10
use HMLB\DDD\Entity\AggregateRoot;
11
use HMLB\DDD\Entity\Identity;
12
use HMLB\DDD\Entity\Repository;
13
14
/**
15
 * Aggregate root repository implementation for ORM.
16
 *
17
 * @author Hugues Maignol <[email protected]>
18
 */
19
abstract class AbstractORMRepository implements Repository
20
{
21
    /**
22
     * @var EntityManager
23
     */
24
    protected $em;
25
    /**
26
     * @var EntityRepository
27
     */
28
    protected $entityRepository;
29
30
    public function __construct(EntityManager $em)
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $em. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
31
    {
32
        $this->em = $em;
33
        $this->entityRepository = $em->getRepository($this->getClassName());
34
    }
35
36
    /**
37
     * @return AggregateRoot[]
38
     */
39
    public function getAll(): array
40
    {
41
        return $this->entityRepository->findAll();
42
    }
43
44
    /**
45
     * @param Identity $identity
46
     *
47
     * @return AggregateRoot
48
     */
49
    public function get(Identity $identity)
50
    {
51
        return $this->entityRepository->find($identity);
52
    }
53
54
    /**
55
     * @param AggregateRoot $document
56
     */
57
    public function add(AggregateRoot $document)
58
    {
59
        $this->em->persist($document);
60
    }
61
62
    /**
63
     * Finds Entities by a set of criteria.
64
     *
65
     * @param array    $criteria Query criteria
66
     * @param array    $sort     Sort array for Cursor::sort()
67
     * @param int|null $limit    Limit for Cursor::limit()
68
     * @param int|null $skip     Skip for Cursor::skip()
69
     *
70
     * @return AggregateRoot[]
71
     */
72
    protected function getBy(array $criteria, array $sort = null, int $limit = null, int $skip = null)
73
    {
74
        return $this->entityRepository->findBy($criteria, $sort, $limit, $skip);
75
    }
76
77
    /**
78
     * Finds a single AggregateRoot by a set of criteria.
79
     *
80
     * @param array $criteria
81
     *
82
     * @return AggregateRoot
83
     */
84
    protected function getOneBy(array $criteria)
85
    {
86
        return $this->entityRepository->findOneBy($criteria);
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92
    protected function applyCriteria(QueryBuilder $queryBuilder, array $criteria = [], array $rootProperties = [])
93
    {
94
        if (null === $criteria) {
95
            return;
96
        }
97
98
        foreach ($criteria as $property => $value) {
99
            if (null === $value) {
100
                $queryBuilder
101
                    ->andWhere($queryBuilder->expr()->isNull($this->getPropertyName($property, $rootProperties)));
102
            } elseif (is_array($value)) {
103
                $queryBuilder->andWhere(
104
                    $queryBuilder->expr()->in($this->getPropertyName($property, $rootProperties), $value)
105
                );
106
            } elseif ('' !== $value) {
107
                $sanitizedProperty = $this->sanitizeParameterName($property);
108
                $queryBuilder
109
                    ->andWhere(
110
                        $queryBuilder->expr()->eq(
111
                            $this->getPropertyName($property, $rootProperties),
112
                            ':'.$sanitizedProperty
113
                        )
114
                    )
115
                    ->setParameter($sanitizedProperty, $value);
116
            }
117
        }
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123
    protected function applySorting(QueryBuilder $queryBuilder, array $sorting = null, array $rootProperties = [])
124
    {
125
        if (null === $sorting) {
126
            return;
127
        }
128
        foreach ($sorting as $property => $order) {
129
            if (!empty($order)) {
130
                $queryBuilder->addOrderBy($this->getPropertyName($property, $rootProperties), $order);
131
            }
132
        }
133
    }
134
135
    /**
136
     * @param string $name
137
     * @param array  $rootProperties Properties that will not be bound to the object alias
138
     *
139
     * @return string
140
     */
141
    protected function getPropertyName(string $name, array $rootProperties = []): string
142
    {
143
        if (!in_array($name, $rootProperties) && false === mb_strpos($name, '.')) {
144
            return $this->getAlias().'.'.$name;
145
        }
146
147
        return $name;
148
    }
149
150
    /**
151
     * If properties have complex path, it cannot be used as parameter key in
152
     * requests.
153
     * This sanitize property path for proper requests.
154
     *
155
     * @param string $property
156
     *
157
     * @return string
158
     */
159
    protected function sanitizeParameterName(string $property): string
160
    {
161
        return str_replace('.', '_', $property);
162
    }
163
164
    /**
165
     * @return string The main alias used for this repository's entity in queries.
166
     */
167
    protected function getAlias(): string
168
    {
169
        $className = $this->getClassName();
170
        $classPieces = explode('\\', $className);
171
        $last = array_pop($classPieces);
172
173
        return strtolower($last);
174
    }
175
}
176