Completed
Push — 1.0 ( e070af...78562a )
by Peter
28:01 queued 17:58
created

EntitySpecificationRepositoryTrait::match()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
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
    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
    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
        }
101
    }
102
103
    /**
104
     * Get scalar result when you match with a Specification.
105
     *
106
     * @param Filter|QueryModifier $specification
107
     * @param ResultModifier|null  $modifier
108
     *
109
     * @throw Exception\NonUniqueException  If more than one result is found
110
     * @throw Exception\NoResultException   If no results found
111
     *
112
     * @return mixed
113
     */
114
    public function matchScalarResult($specification, ResultModifier $modifier = null)
115
    {
116
        $query = $this->getQuery($specification, $modifier);
117
118
        return $query->getScalarResult();
119
    }
120
121
    /**
122
     * Prepare a Query with a Specification.
123
     *
124
     * @param Filter|QueryModifier $specification
125
     * @param ResultModifier|null  $modifier
126
     *
127
     * @return Query
128
     */
129
    public function getQuery($specification, ResultModifier $modifier = null)
130
    {
131
        $query = $this->getQueryBuilder($specification)->getQuery();
132
133
        if (null !== $modifier) {
134
            $modifier->modify($query);
135
        }
136
137
        return $query;
138
    }
139
140
    /**
141
     * @param Filter|QueryModifier $specification
142
     * @param string|null          $alias
143
     *
144
     * @return QueryBuilder
145
     */
146
    public function getQueryBuilder($specification, $alias = null)
147
    {
148
        $qb = $this->createQueryBuilder($alias ?: $this->getAlias());
0 ignored issues
show
Bug introduced by
It seems like createQueryBuilder() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
149
        $this->applySpecification($qb, $specification, $alias);
150
151
        return $qb;
152
    }
153
154
    /**
155
     * Iterate results when you match with a Specification.
156
     *
157
     * @param Filter|QueryModifier $specification
158
     * @param ResultModifier|null  $modifier
159
     *
160
     * @return mixed[]|\Generator
161
     */
162
    public function iterate($specification, ResultModifier $modifier = null)
163
    {
164
        foreach ($this->getQuery($specification, $modifier)->iterate() as $row) {
165
            yield current($row);
166
        }
167
    }
168
169
    /**
170
     * @param string $alias
171
     *
172
     * @return $this
173
     */
174
    public function setAlias($alias)
175
    {
176
        $this->alias = $alias;
177
178
        return $this;
179
    }
180
181
    /**
182
     * @return string
183
     */
184
    public function getAlias()
185
    {
186
        return $this->alias;
187
    }
188
189
    /**
190
     * @param QueryBuilder         $queryBuilder
191
     * @param Filter|QueryModifier $specification
192
     * @param string               $alias
193
     *
194
     * @throws \InvalidArgumentException
195
     */
196
    protected function applySpecification(QueryBuilder $queryBuilder, $specification = null, $alias = null)
197
    {
198
        if (null === $specification) {
199
            return;
200
        }
201
202
        if (!$specification instanceof QueryModifier && !$specification instanceof Filter) {
203
            throw new \InvalidArgumentException(sprintf(
204
                'Expected argument of type "%s" or "%s", "%s" given.',
205
                'Happyr\DoctrineSpecification\Query\QueryModifier',
206
                'Happyr\DoctrineSpecification\Filter\Filter',
207
                is_object($specification) ? get_class($specification) : gettype($specification)
208
            ));
209
        }
210
211
        if ($specification instanceof QueryModifier) {
212
            $specification->modify($queryBuilder, $alias ?: $this->getAlias());
213
        }
214
215
        if ($specification instanceof Filter
216
            && $filter = (string) $specification->getFilter($queryBuilder, $alias ?: $this->getAlias())
217
        ) {
218
            $queryBuilder->andWhere($filter);
219
        }
220
    }
221
}
222