Completed
Push — 2.0 ( 5877a9...9fa07d )
by Peter
07:07 queued 10s
created

matchScalarResult()   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
declare(strict_types=1);
3
4
/**
5
 * This file is part of the Happyr Doctrine Specification package.
6
 *
7
 * (c) Tobias Nyholm <[email protected]>
8
 *     Kacper Gunia <[email protected]>
9
 *     Peter Gribanov <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Happyr\DoctrineSpecification\Repository;
16
17
use Doctrine\ORM\AbstractQuery;
18
use Doctrine\ORM\NonUniqueResultException as DoctrineNonUniqueResultException;
19
use Doctrine\ORM\NoResultException as DoctrineNoResultException;
20
use Doctrine\ORM\Query;
21
use Doctrine\ORM\QueryBuilder;
22
use Happyr\DoctrineSpecification\Exception\NonUniqueResultException;
23
use Happyr\DoctrineSpecification\Exception\NoResultException;
24
use Happyr\DoctrineSpecification\Filter\Filter;
25
use Happyr\DoctrineSpecification\Query\QueryModifier;
26
use Happyr\DoctrineSpecification\Result\ResultModifier;
27
28
/**
29
 * This trait should be used by a class extending \Doctrine\ORM\EntityRepository.
30
 */
31
trait EntitySpecificationRepositoryTrait
32
{
33
    /**
34
     * @var string
35
     */
36
    private $alias = 'root';
37
38
    /**
39
     * Get results when you match with a Specification.
40
     *
41
     * @param Filter|QueryModifier $specification
42
     * @param ResultModifier|null  $modifier
43
     *
44
     * @return mixed
45
     */
46
    public function match($specification, ?ResultModifier $modifier = null)
47
    {
48
        $query = $this->getQuery($specification, $modifier);
49
50
        return $query->execute();
51
    }
52
53
    /**
54
     * Get single result when you match with a Specification.
55
     *
56
     * @param Filter|QueryModifier $specification
57
     * @param ResultModifier|null  $modifier
58
     *
59
     * @throw Exception\NonUniqueException  If more than one result is found
60
     * @throw Exception\NoResultException   If no results found
61
     *
62
     * @return mixed
63
     */
64
    public function matchSingleResult($specification, ?ResultModifier $modifier = null)
65
    {
66
        $query = $this->getQuery($specification, $modifier);
67
68
        try {
69
            return $query->getSingleResult();
70
        } catch (DoctrineNonUniqueResultException $e) {
71
            throw new NonUniqueResultException($e->getMessage(), $e->getCode(), $e);
72
        } catch (DoctrineNoResultException $e) {
73
            throw new NoResultException($e->getMessage(), $e->getCode(), $e);
74
        }
75
    }
76
77
    /**
78
     * Get single result or null when you match with a Specification.
79
     *
80
     * @param Filter|QueryModifier $specification
81
     * @param ResultModifier|null  $modifier
82
     *
83
     * @throw Exception\NonUniqueException  If more than one result is found
84
     *
85
     * @return mixed|null
86
     */
87
    public function matchOneOrNullResult($specification, ?ResultModifier $modifier = null)
88
    {
89
        try {
90
            return $this->matchSingleResult($specification, $modifier);
91
        } catch (NoResultException $e) {
92
            return null;
93
        }
94
    }
95
96
    /**
97
     * Get single scalar result when you match with a Specification.
98
     *
99
     * @param Filter|QueryModifier $specification
100
     * @param ResultModifier|null  $modifier
101
     *
102
     * @throw Exception\NonUniqueException  If more than one result is found
103
     * @throw Exception\NoResultException   If no results found
104
     *
105
     * @return mixed
106
     */
107
    public function matchSingleScalarResult($specification, ?ResultModifier $modifier = null)
108
    {
109
        $query = $this->getQuery($specification, $modifier);
110
111
        try {
112
            return $query->getSingleScalarResult();
113
        } catch (DoctrineNonUniqueResultException $e) {
114
            throw new NonUniqueResultException($e->getMessage(), $e->getCode(), $e);
115
        }
116
    }
117
118
    /**
119
     * Get scalar result when you match with a Specification.
120
     *
121
     * @param Filter|QueryModifier $specification
122
     * @param ResultModifier|null  $modifier
123
     *
124
     * @throw Exception\NonUniqueException  If more than one result is found
125
     * @throw Exception\NoResultException   If no results found
126
     *
127
     * @return mixed
128
     */
129
    public function matchScalarResult($specification, ?ResultModifier $modifier = null)
130
    {
131
        $query = $this->getQuery($specification, $modifier);
132
133
        return $query->getScalarResult();
134
    }
135
136
    /**
137
     * Prepare a Query with a Specification.
138
     *
139
     * @param Filter|QueryModifier $specification
140
     * @param ResultModifier|null  $modifier
141
     *
142
     * @return Query
143
     */
144
    public function getQuery($specification, ?ResultModifier $modifier = null): AbstractQuery
145
    {
146
        $query = $this->getQueryBuilder($specification)->getQuery();
147
148
        if (null !== $modifier) {
149
            $modifier->modify($query);
150
        }
151
152
        return $query;
153
    }
154
155
    /**
156
     * @param Filter|QueryModifier $specification
157
     * @param string|null          $alias
158
     *
159
     * @return QueryBuilder
160
     */
161
    public function getQueryBuilder($specification, ?string $alias = null): QueryBuilder
162
    {
163
        $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...
164
        $this->applySpecification($qb, $specification, $alias);
165
166
        return $qb;
167
    }
168
169
    /**
170
     * Iterate results when you match with a Specification.
171
     *
172
     * @param Filter|QueryModifier $specification
173
     * @param ResultModifier|null  $modifier
174
     *
175
     * @return \Traversable<mixed>
0 ignored issues
show
Documentation introduced by
The doc-type \Traversable<mixed> could not be parsed: Expected "|" or "end of type", but got "<" at position 12. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
176
     */
177
    public function iterate($specification, ?ResultModifier $modifier = null): \Traversable
178
    {
179
        foreach ($this->getQuery($specification, $modifier)->iterate() as $row) {
180
            yield current($row);
181
        }
182
    }
183
184
    /**
185
     * @param string $alias
186
     */
187
    public function setAlias(string $alias): void
188
    {
189
        $this->alias = $alias;
190
    }
191
192
    /**
193
     * @return string
194
     */
195
    public function getAlias(): string
196
    {
197
        return $this->alias;
198
    }
199
200
    /**
201
     * @param QueryBuilder         $queryBuilder
202
     * @param Filter|QueryModifier $specification
203
     * @param string|null          $alias
204
     *
205
     * @throws \InvalidArgumentException
206
     */
207
    protected function applySpecification(
208
        QueryBuilder $queryBuilder,
209
        $specification = null,
210
        ?string $alias = null
211
    ): void {
212
        if ($specification instanceof QueryModifier) {
213
            $specification->modify($queryBuilder, $alias ?: $this->getAlias());
214
        }
215
216
        if ($specification instanceof Filter) {
217
            $filter = $specification->getFilter($queryBuilder, $alias ?: $this->getAlias());
218
            $filter = trim($filter);
219
220
            if ('' !== $filter) {
221
                $queryBuilder->andWhere($filter);
222
            }
223
        }
224
    }
225
}
226