Completed
Push — 1.0 ( 4c0b42...75b22b )
by Peter
07:06
created

matchScalarResult()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 12
Ratio 100 %

Importance

Changes 0
Metric Value
dl 12
loc 12
c 0
b 0
f 0
rs 9.8666
cc 3
nc 3
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 View Code Duplication
    public function matchSingleResult($specification, ResultModifier $modifier = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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);
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...
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());
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...
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