Completed
Pull Request — master (#39)
by Eric
13:12 queued 25s
created

RepositoryTrait::findOneBy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 2
crap 1
1
<?php
2
3
/*
4
 * This file is part of the Lug package.
5
 *
6
 * (c) Eric GELOEN <[email protected]>
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Lug\Component\Resource\Repository\Doctrine\ORM;
13
14
use Doctrine\ORM\EntityManager;
15
use Doctrine\ORM\Mapping\ClassMetadata;
16
use Doctrine\ORM\QueryBuilder;
17
use Lug\Component\Grid\DataSource\Doctrine\ORM\DataSourceBuilder;
18
use Lug\Component\Resource\Model\ResourceInterface;
19
use Pagerfanta\Adapter\DoctrineORMAdapter;
20
use Pagerfanta\Pagerfanta;
21
22
/**
23
 * WARNING - This trait should only be used with a class extending an EntityRepository.
24
 *
25
 * @author GeLo <[email protected]>
26
 */
27
trait RepositoryTrait
28
{
29
    /**
30
     * @var ResourceInterface
31
     */
32
    private $resource;
33
34
    /**
35
     * @param EntityManager     $em
36
     * @param ClassMetadata     $class
37
     * @param ResourceInterface $resource
38
     */
39 22
    public function __construct($em, ClassMetadata $class, ResourceInterface $resource)
40
    {
41 22
        parent::__construct($em, $class);
42
43 22
        $this->resource = $resource;
44 22
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49 1
    public function findForIndex(array $criteria, array $orderBy = [])
50
    {
51 1
        return new Pagerfanta(new DoctrineORMAdapter(
52 1
            $this->buildQueryBuilder($criteria, $orderBy, true),
53 1
            false,
54
            false
55 1
        ));
56
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61 1
    public function findForShow(array $criteria, array $orderBy = [])
62
    {
63 1
        return $this->findOneBy($criteria, $orderBy);
64
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69 1
    public function findForUpdate(array $criteria, array $orderBy = [])
70
    {
71 1
        return $this->findOneBy($criteria, $orderBy);
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77 1
    public function findForDelete(array $criteria, array $orderBy = [])
78
    {
79 1
        return $this->findOneBy($criteria, $orderBy);
80
    }
81
82
    /**
83
     * {@inheritdoc}
84
     */
85 7
    public function findOneBy(array $criteria, array $orderBy = [])
86
    {
87 7
        return $this->buildQueryBuilder($criteria, $orderBy)->getQuery()->getOneOrNullResult();
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93 1 View Code Duplication
    public function findBy(array $criteria, array $orderBy = [], $limit = null, $offset = 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...
94
    {
95 1
        $queryBuilder = $this->buildQueryBuilder($criteria, $orderBy);
96
97 1
        if ($limit !== null) {
98 1
            $queryBuilder->setMaxResults($limit);
99 1
        }
100
101 1
        if ($offset !== null) {
102 1
            $queryBuilder->setFirstResult($offset);
103 1
        }
104
105 1
        return $queryBuilder->getQuery()->getResult();
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111 18
    public function createQueryBuilder($alias = null, $indexBy = null)
112
    {
113 18
        return parent::createQueryBuilder($alias ?: $this->getAlias(), $indexBy);
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119 5
    public function createQueryBuilderForCollection($alias = null, $indexBy = null)
120
    {
121 5
        return $this->createQueryBuilder($alias, $indexBy);
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127 1
    public function createDataSourceBuilder(array $options = [])
128
    {
129 1
        return new DataSourceBuilder($this, $options);
130
    }
131
132
    /**
133
     * @param string                   $property
134
     * @param QueryBuilder|string|null $root
135
     *
136
     * @return string
137
     */
138 11
    public function getProperty($property, $root = null)
139
    {
140 11
        return $this->getRootAlias($root).'.'.$property;
141
    }
142
143
    /**
144
     * @param mixed[]  $criteria
145
     * @param string[] $orderBy
146
     * @param bool     $collection
147
     *
148
     * @return QueryBuilder
149
     */
150 9 View Code Duplication
    protected function buildQueryBuilder(array $criteria, array $orderBy, $collection = false)
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...
151
    {
152 9
        $queryBuilder = $collection ? $this->createQueryBuilderForCollection() : $this->createQueryBuilder();
153
154 9
        $this->applyCriteria($queryBuilder, $criteria);
155 9
        $this->applySorting($queryBuilder, $orderBy);
156
157 9
        return $queryBuilder;
158
    }
159
160
    /**
161
     * @param QueryBuilder $queryBuilder
162
     * @param mixed[]      $criteria
163
     */
164 9
    private function applyCriteria(QueryBuilder $queryBuilder, array $criteria = null)
165
    {
166 9
        foreach ($criteria as $property => $value) {
0 ignored issues
show
Bug introduced by
The expression $criteria of type null|array<integer,*> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
167 9
            if ($value === null) {
168 1
                $queryBuilder->andWhere($queryBuilder->expr()->isNull(
169 1
                    $this->getProperty($property, $queryBuilder)
170 1
                ));
171 9
            } elseif (is_array($value)) {
172
                $queryBuilder
173 1
                    ->andWhere($queryBuilder->expr()->in(
174 1
                        $property = $this->getProperty($property, $queryBuilder),
175 1
                        $this->createPlaceholder($parameter = $this->createParameter($property))
176 1
                    ))
177 1
                    ->setParameter($parameter, $value);
178 8
            } elseif ($value !== null) {
179
                $queryBuilder
180 7
                    ->andWhere($queryBuilder->expr()->eq(
181 7
                        $property = $this->getProperty($property, $queryBuilder),
182 7
                        $this->createPlaceholder($parameter = $this->createParameter($property))
183 7
                    ))
184 7
                    ->setParameter($parameter, $value);
185 7
            }
186 9
        }
187 9
    }
188
189
    /**
190
     * @param QueryBuilder $queryBuilder
191
     * @param string[]     $orderBy
192
     */
193 9 View Code Duplication
    private function applySorting(QueryBuilder $queryBuilder, array $orderBy = [])
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...
194
    {
195 9
        foreach ($orderBy as $property => $order) {
196 8
            if (!empty($order)) {
197 8
                $queryBuilder->addOrderBy($this->getProperty($property, $queryBuilder), $order);
198 8
            }
199 9
        }
200 9
    }
201
202
    /**
203
     * @param string $property
204
     *
205
     * @return string
206
     */
207 8
    private function createParameter($property)
208
    {
209 8
        return str_replace('.', '_', $property).'_'.str_replace('.', '', uniqid(null, true));
210
    }
211
212
    /**
213
     * @param string $parameter
214
     *
215
     * @return string
216
     */
217 8
    private function createPlaceholder($parameter)
218
    {
219 8
        return ':'.$parameter;
220
    }
221
222
    /**
223
     * @param QueryBuilder|string|null $root
224
     *
225
     * @return string
226
     */
227 11
    private function getRootAlias($root)
228
    {
229 11
        if ($root instanceof QueryBuilder) {
230 11
            $root = $root->getRootAliases()[0];
231 11
        }
232
233 11
        return $root;
234
    }
235
236
    /**
237
     * @return string
238
     */
239 16
    private function getAlias()
240
    {
241 16
        return $this->resource->getName();
242
    }
243
}
244