1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Majora\Framework\Loader\Bridge\Doctrine; |
4
|
|
|
|
5
|
|
|
use Doctrine\Common\Collections\Collection; |
6
|
|
|
use Doctrine\ORM\EntityRepository; |
7
|
|
|
use Majora\Framework\Loader\LoaderTrait; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Trait to use into Doctrine loaders to get a simple implementation of LoaderInterface. |
11
|
|
|
* |
12
|
|
|
* @property $entityRepository |
13
|
|
|
* @property $entityClass |
14
|
|
|
* @property $collectionClass |
15
|
|
|
* @property $filterResolver |
16
|
|
|
*/ |
17
|
|
|
trait DoctrineLoaderTrait |
18
|
|
|
{ |
19
|
|
|
use LoaderTrait; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Construct. |
23
|
|
|
* |
24
|
|
|
* @param EntityRepository $entityRepository (optionnal) |
25
|
|
|
*/ |
26
|
|
|
public function __construct(EntityRepository $entityRepository = null) |
27
|
|
|
{ |
28
|
|
|
$this->entityRepository = $entityRepository; |
|
|
|
|
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Checks if loader is properly configured. |
33
|
|
|
* |
34
|
|
|
* @throws \RuntimeException if not configured |
35
|
|
|
*/ |
36
|
|
|
private function assertIsConfigured() |
37
|
|
|
{ |
38
|
|
|
if (!$this->entityClass || !$this->collectionClass || !$this->filterResolver) { |
39
|
|
|
throw new \RuntimeException(sprintf( |
40
|
|
|
'%s methods cannot be used while it has not been initialize through %s::configureMetadata().', |
41
|
|
|
static::class, |
42
|
|
|
static::class |
43
|
|
|
)); |
44
|
|
|
} |
45
|
|
|
if (!$this->entityRepository) { |
46
|
|
|
throw new \RuntimeException(sprintf( |
47
|
|
|
'You must provide %s entity Doctrine repository throught %s::__construct() method to use this loader.', |
48
|
|
|
$this->entityClass, |
49
|
|
|
static::class |
50
|
|
|
)); |
51
|
|
|
} |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* Hook called with every entity or collection loaded through this loader. |
56
|
|
|
* |
57
|
|
|
* @param CollectionnableInterface|EntityCollection $entity |
58
|
|
|
* |
59
|
|
|
* @return $object same entity or collection |
|
|
|
|
60
|
|
|
*/ |
61
|
|
|
protected function onLoad($entity) |
62
|
|
|
{ |
63
|
|
|
@trigger_error(__METHOD__.' is deprecated and will be removed in 2.0. Use full class delegate instead, see Majora\Framework\Loader\LazyLoaderInterface.', E_USER_DEPRECATED); |
|
|
|
|
64
|
|
|
|
65
|
|
|
return $entity; |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Convert given array or Collection result set to managed entity collection class. |
70
|
|
|
* |
71
|
|
|
* @param array|Collection $result |
72
|
|
|
* |
73
|
|
|
* @return EntityCollection |
74
|
|
|
*/ |
75
|
|
|
protected function toEntityCollection($result) |
76
|
|
|
{ |
77
|
|
|
switch (true) { |
78
|
|
|
|
79
|
|
|
// already a collection ? |
80
|
|
|
case is_object($result) && is_subclass_of($result, $this->collectionClass) : |
|
|
|
|
81
|
|
|
$collection = $result; |
82
|
|
|
break; |
83
|
|
|
|
84
|
|
|
// already a collection ? |
85
|
|
|
case $result instanceof Collection : |
|
|
|
|
86
|
|
|
$collection = new $this->collectionClass($result->toArray()); |
87
|
|
|
break; |
88
|
|
|
|
89
|
|
|
// simple related entity ? |
90
|
|
|
case is_object($result) && is_subclass_of($result, $this->entityClass) : |
|
|
|
|
91
|
|
|
$collection = new $this->collectionClass(array($result)); |
92
|
|
|
break; |
93
|
|
|
|
94
|
|
|
// simple array ? |
95
|
|
|
case is_array($result) : |
|
|
|
|
96
|
|
|
$collection = new $this->collectionClass($result); |
97
|
|
|
break; |
98
|
|
|
|
99
|
|
|
default: |
100
|
|
|
$collection = new $this->collectionClass(); |
101
|
|
|
break; |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
return $this->onLoad($collection); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Create entity query. |
109
|
|
|
* Proxy to base query builder method to use to custom all queries from this loader. |
110
|
|
|
* |
111
|
|
|
* @param string $alias |
112
|
|
|
* |
113
|
|
|
* @return QueryBuilder |
114
|
|
|
*/ |
115
|
|
|
protected function createQuery($alias = 'entity') |
116
|
|
|
{ |
117
|
|
|
return $this->entityRepository->createQueryBuilder($alias); |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* create query an filter it with given data. |
122
|
|
|
* |
123
|
|
|
* @param array $filters |
124
|
|
|
* |
125
|
|
|
* @return Query |
126
|
|
|
*/ |
127
|
|
|
private function createFilteredQuery(array $filters) |
128
|
|
|
{ |
129
|
|
|
$qb = $this->createQuery('entity'); |
130
|
|
|
|
131
|
|
|
foreach ($filters as $field => $filter) { |
132
|
|
|
$qb->andWhere(is_array($filter) |
133
|
|
|
? sprintf('entity.%s in (:%s)', $field, $field) |
134
|
|
|
: sprintf('entity.%s = :%s', $field, $field) |
135
|
|
|
) |
136
|
|
|
->setParameter(sprintf(':%s', $field), $filter) |
137
|
|
|
; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
return $qb->getQuery(); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* @see LoaderInterface::retrieveAll() |
145
|
|
|
*/ |
146
|
|
|
public function retrieveAll(array $filters = array(), $limit = null, $offset = null) |
147
|
|
|
{ |
148
|
|
|
$this->assertIsConfigured(); |
149
|
|
|
|
150
|
|
|
$query = $this->createFilteredQuery( |
151
|
|
|
$this->filterResolver->resolve($filters) |
152
|
|
|
); |
153
|
|
|
|
154
|
|
|
if ($limit) { |
155
|
|
|
$query->setMaxResults($limit); |
156
|
|
|
} |
157
|
|
|
if ($offset) { |
158
|
|
|
$query->setFirstResult($offset); |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
return $this->toEntityCollection( |
162
|
|
|
$query->getResult() |
163
|
|
|
); |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* @see LoaderInterface::retrieveOne() |
168
|
|
|
*/ |
169
|
|
|
public function retrieveOne(array $filters = array()) |
170
|
|
|
{ |
171
|
|
|
$this->assertIsConfigured(); |
172
|
|
|
|
173
|
|
|
return $this->onLoad($this->createFilteredQuery($filters) |
174
|
|
|
->setMaxResults(1) |
175
|
|
|
->getOneOrNullResult() |
176
|
|
|
); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* @see LoaderInterface::retrieve() |
181
|
|
|
*/ |
182
|
|
|
public function retrieve($id) |
183
|
|
|
{ |
184
|
|
|
return $this->onLoad($this->retrieveOne(array('id' => $id))); |
185
|
|
|
} |
186
|
|
|
} |
187
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.