1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Happyr\DoctrineSpecification; |
4
|
|
|
|
5
|
|
|
use Doctrine\ORM\NonUniqueResultException; |
6
|
|
|
use Doctrine\ORM\NoResultException; |
7
|
|
|
use Doctrine\ORM\Query; |
8
|
|
|
use Doctrine\ORM\QueryBuilder; |
9
|
|
|
use Happyr\DoctrineSpecification\Filter\Filter; |
10
|
|
|
use Happyr\DoctrineSpecification\Query\QueryModifier; |
11
|
|
|
use Happyr\DoctrineSpecification\Result\ResultModifier; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* This trait should be used by a class extending \Doctrine\ORM\EntityRepository. |
15
|
|
|
*/ |
16
|
|
|
trait EntitySpecificationRepositoryTrait |
17
|
|
|
{ |
18
|
|
|
/** |
19
|
|
|
* @var string alias |
20
|
|
|
*/ |
21
|
|
|
private $alias = 'e'; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Get results when you match with a Specification. |
25
|
|
|
* |
26
|
|
|
* @param Filter|QueryModifier $specification |
27
|
|
|
* @param ResultModifier|null $modifier |
28
|
|
|
* |
29
|
|
|
* @return mixed[] |
30
|
|
|
*/ |
31
|
|
|
public function match($specification, ResultModifier $modifier = null) |
32
|
|
|
{ |
33
|
|
|
$query = $this->getQuery($specification, $modifier); |
34
|
|
|
|
35
|
|
|
return $query->execute(); |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Get single result when you match with a Specification. |
40
|
|
|
* |
41
|
|
|
* @param Filter|QueryModifier $specification |
42
|
|
|
* @param ResultModifier|null $modifier |
43
|
|
|
* |
44
|
|
|
* @throw Exception\NonUniqueException If more than one result is found |
45
|
|
|
* @throw Exception\NoResultException If no results found |
46
|
|
|
* |
47
|
|
|
* @return mixed |
48
|
|
|
*/ |
49
|
|
View Code Duplication |
public function matchSingleResult($specification, ResultModifier $modifier = null) |
|
|
|
|
50
|
|
|
{ |
51
|
|
|
$query = $this->getQuery($specification, $modifier); |
52
|
|
|
|
53
|
|
|
try { |
54
|
|
|
return $query->getSingleResult(); |
55
|
|
|
} catch (NonUniqueResultException $e) { |
56
|
|
|
throw new Exception\NonUniqueResultException($e->getMessage(), $e->getCode(), $e); |
57
|
|
|
} catch (NoResultException $e) { |
58
|
|
|
throw new Exception\NoResultException($e->getMessage(), $e->getCode(), $e); |
59
|
|
|
} |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Get single result or null when you match with a Specification. |
64
|
|
|
* |
65
|
|
|
* @param Filter|QueryModifier $specification |
66
|
|
|
* @param ResultModifier|null $modifier |
67
|
|
|
* |
68
|
|
|
* @throw Exception\NonUniqueException If more than one result is found |
69
|
|
|
* |
70
|
|
|
* @return mixed|null |
71
|
|
|
*/ |
72
|
|
|
public function matchOneOrNullResult($specification, ResultModifier $modifier = null) |
73
|
|
|
{ |
74
|
|
|
try { |
75
|
|
|
return $this->matchSingleResult($specification, $modifier); |
76
|
|
|
} catch (Exception\NoResultException $e) { |
77
|
|
|
return; |
78
|
|
|
} |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Get single scalar result when you match with a Specification. |
83
|
|
|
* |
84
|
|
|
* @param Filter|QueryModifier $specification |
85
|
|
|
* @param ResultModifier|null $modifier |
86
|
|
|
* |
87
|
|
|
* @throw Exception\NonUniqueException If more than one result is found |
88
|
|
|
* @throw Exception\NoResultException If no results found |
89
|
|
|
* |
90
|
|
|
* @return mixed |
91
|
|
|
*/ |
92
|
|
View Code Duplication |
public function matchSingleScalarResult($specification, ResultModifier $modifier = null) |
|
|
|
|
93
|
|
|
{ |
94
|
|
|
$query = $this->getQuery($specification, $modifier); |
95
|
|
|
|
96
|
|
|
try { |
97
|
|
|
return $query->getSingleScalarResult(); |
98
|
|
|
} catch (NonUniqueResultException $e) { |
99
|
|
|
throw new Exception\NonUniqueResultException($e->getMessage(), $e->getCode(), $e); |
100
|
|
|
} catch (NoResultException $e) { |
101
|
|
|
throw new Exception\NoResultException($e->getMessage(), $e->getCode(), $e); |
102
|
|
|
} |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* Get scalar result when you match with a Specification. |
107
|
|
|
* |
108
|
|
|
* @param Filter|QueryModifier $specification |
109
|
|
|
* @param ResultModifier|null $modifier |
110
|
|
|
* |
111
|
|
|
* @throw Exception\NonUniqueException If more than one result is found |
112
|
|
|
* @throw Exception\NoResultException If no results found |
113
|
|
|
* |
114
|
|
|
* @return mixed |
115
|
|
|
*/ |
116
|
|
View Code Duplication |
public function matchScalarResult($specification, ResultModifier $modifier = null) |
|
|
|
|
117
|
|
|
{ |
118
|
|
|
$query = $this->getQuery($specification, $modifier); |
119
|
|
|
|
120
|
|
|
try { |
121
|
|
|
return $query->getScalarResult(); |
122
|
|
|
} catch (NonUniqueResultException $e) { |
123
|
|
|
throw new Exception\NonUniqueResultException($e->getMessage(), $e->getCode(), $e); |
124
|
|
|
} catch (NoResultException $e) { |
125
|
|
|
throw new Exception\NoResultException($e->getMessage(), $e->getCode(), $e); |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* Prepare a Query with a Specification. |
131
|
|
|
* |
132
|
|
|
* @param Filter|QueryModifier $specification |
133
|
|
|
* @param ResultModifier|null $modifier |
134
|
|
|
* |
135
|
|
|
* @return Query |
136
|
|
|
*/ |
137
|
|
|
public function getQuery($specification, ResultModifier $modifier = null) |
138
|
|
|
{ |
139
|
|
|
$qb = $this->createQueryBuilder($this->alias); |
|
|
|
|
140
|
|
|
$this->applySpecification($qb, $specification); |
141
|
|
|
$query = $qb->getQuery(); |
142
|
|
|
|
143
|
|
|
if (null !== $modifier) { |
144
|
|
|
$modifier->modify($query); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
return $query; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @param Filter|QueryModifier $specification |
152
|
|
|
* @param string|null $alias |
153
|
|
|
* |
154
|
|
|
* @return QueryBuilder |
155
|
|
|
*/ |
156
|
|
|
public function getQueryBuilder($specification, $alias = null) |
157
|
|
|
{ |
158
|
|
|
$qb = $this->createQueryBuilder($alias ?: $this->getAlias()); |
|
|
|
|
159
|
|
|
$this->applySpecification($qb, $specification, $alias); |
160
|
|
|
|
161
|
|
|
return $qb; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* @param string $alias |
166
|
|
|
* |
167
|
|
|
* @return $this |
168
|
|
|
*/ |
169
|
|
|
public function setAlias($alias) |
170
|
|
|
{ |
171
|
|
|
$this->alias = $alias; |
172
|
|
|
|
173
|
|
|
return $this; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* @return string |
178
|
|
|
*/ |
179
|
|
|
public function getAlias() |
180
|
|
|
{ |
181
|
|
|
return $this->alias; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* @param QueryBuilder $queryBuilder |
186
|
|
|
* @param Filter|QueryModifier $specification |
187
|
|
|
* @param string $alias |
188
|
|
|
* |
189
|
|
|
* @throws \InvalidArgumentException |
190
|
|
|
*/ |
191
|
|
|
protected function applySpecification(QueryBuilder $queryBuilder, $specification = null, $alias = null) |
192
|
|
|
{ |
193
|
|
|
if (null === $specification) { |
194
|
|
|
return; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
if (!$specification instanceof QueryModifier && !$specification instanceof Filter) { |
198
|
|
|
throw new \InvalidArgumentException(sprintf( |
199
|
|
|
'Expected argument of type "%s" or "%s", "%s" given.', |
200
|
|
|
'Happyr\DoctrineSpecification\Query\QueryModifier', |
201
|
|
|
'Happyr\DoctrineSpecification\Filter\Filter', |
202
|
|
|
is_object($specification) ? get_class($specification) : gettype($specification) |
203
|
|
|
)); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
if ($specification instanceof QueryModifier) { |
207
|
|
|
$specification->modify($queryBuilder, $alias ?: $this->getAlias()); |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
if ($specification instanceof Filter |
211
|
|
|
&& $filter = (string) $specification->getFilter($queryBuilder, $alias ?: $this->getAlias()) |
212
|
|
|
) { |
213
|
|
|
$queryBuilder->andWhere($filter); |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
} |
217
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.