Failed Conditions
Push — master ( 2ade86...13f838 )
by Jonathan
18s
created

lib/Doctrine/ORM/EntityRepository.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM;
21
22
use Doctrine\Common\Util\Inflector;
23
use Doctrine\ORM\Query\ResultSetMappingBuilder;
24
use Doctrine\Common\Persistence\ObjectRepository;
25
use Doctrine\Common\Collections\Selectable;
26
use Doctrine\Common\Collections\Criteria;
27
28
/**
29
 * An EntityRepository serves as a repository for entities with generic as well as
30
 * business specific methods for retrieving entities.
31
 *
32
 * This class is designed for inheritance and users can subclass this class to
33
 * write their own repositories with business-specific methods to locate entities.
34
 *
35
 * @since   2.0
36
 * @author  Benjamin Eberlei <[email protected]>
37
 * @author  Guilherme Blanco <[email protected]>
38
 * @author  Jonathan Wage <[email protected]>
39
 * @author  Roman Borschel <[email protected]>
40
 */
41
class EntityRepository implements ObjectRepository, Selectable
42
{
43
    /**
44
     * @var string
45
     */
46
    protected $_entityName;
47
48
    /**
49
     * @var EntityManager
50
     */
51
    protected $_em;
52
53
    /**
54
     * @var \Doctrine\ORM\Mapping\ClassMetadata
55
     */
56
    protected $_class;
57
58
    /**
59
     * Initializes a new <tt>EntityRepository</tt>.
60
     *
61
     * @param EntityManager         $em    The EntityManager to use.
62
     * @param Mapping\ClassMetadata $class The class descriptor.
63
     */
64 158
    public function __construct(EntityManagerInterface $em, Mapping\ClassMetadata $class)
65
    {
66 158
        $this->_entityName = $class->name;
67 158
        $this->_em         = $em;
68 158
        $this->_class      = $class;
69 158
    }
70
71
    /**
72
     * Creates a new QueryBuilder instance that is prepopulated for this entity name.
73
     *
74
     * @param string $alias
75
     * @param string $indexBy The index for the from.
76
     *
77
     * @return QueryBuilder
78
     */
79 9
    public function createQueryBuilder($alias, $indexBy = null)
80
    {
81 9
        return $this->_em->createQueryBuilder()
82 9
            ->select($alias)
83 9
            ->from($this->_entityName, $alias, $indexBy);
84
    }
85
86
    /**
87
     * Creates a new result set mapping builder for this entity.
88
     *
89
     * The column naming strategy is "INCREMENT".
90
     *
91
     * @param string $alias
92
     *
93
     * @return ResultSetMappingBuilder
94
     */
95 1
    public function createResultSetMappingBuilder($alias)
96
    {
97 1
        $rsm = new ResultSetMappingBuilder($this->_em, ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT);
98 1
        $rsm->addRootEntityFromClassMetadata($this->_entityName, $alias);
99
100 1
        return $rsm;
101
    }
102
103
    /**
104
     * Creates a new Query instance based on a predefined metadata named query.
105
     *
106
     * @param string $queryName
107
     *
108
     * @return Query
109
     */
110 3
    public function createNamedQuery($queryName)
111
    {
112 3
        return $this->_em->createQuery($this->_class->getNamedQuery($queryName));
113
    }
114
115
    /**
116
     * Creates a native SQL query.
117
     *
118
     * @param string $queryName
119
     *
120
     * @return NativeQuery
121
     */
122 7
    public function createNativeNamedQuery($queryName)
123
    {
124 7
        $queryMapping   = $this->_class->getNamedNativeQuery($queryName);
125 7
        $rsm            = new Query\ResultSetMappingBuilder($this->_em);
126 7
        $rsm->addNamedNativeQueryMapping($this->_class, $queryMapping);
127
128 7
        return $this->_em->createNativeQuery($queryMapping['query'], $rsm);
129
    }
130
131
    /**
132
     * Clears the repository, causing all managed entities to become detached.
133
     *
134
     * @return void
135
     */
136
    public function clear()
137
    {
138
        $this->_em->clear($this->_class->rootEntityName);
139
    }
140
141
    /**
142
     * Finds an entity by its primary key / identifier.
143
     *
144
     * @param mixed    $id          The identifier.
145
     * @param int|null $lockMode    One of the \Doctrine\DBAL\LockMode::* constants
146
     *                              or NULL if no specific lock mode should be used
147
     *                              during the search.
148
     * @param int|null $lockVersion The lock version.
149
     *
150
     * @return object|null The entity instance or NULL if the entity can not be found.
151
     */
152 15
    public function find($id, $lockMode = null, $lockVersion = null)
153
    {
154 15
        return $this->_em->find($this->_entityName, $id, $lockMode, $lockVersion);
155
    }
156
157
    /**
158
     * Finds all entities in the repository.
159
     *
160
     * @return array The entities.
161
     */
162 34
    public function findAll()
163
    {
164 34
        return $this->findBy([]);
165
    }
166
167
    /**
168
     * Finds entities by a set of criteria.
169
     *
170
     * @param array      $criteria
171
     * @param array|null $orderBy
172
     * @param int|null   $limit
173
     * @param int|null   $offset
174
     *
175
     * @return array The objects.
176
     */
177 65
    public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
178
    {
179 65
        $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
180
181 65
        return $persister->loadAll($criteria, $orderBy, $limit, $offset);
182
    }
183
184
    /**
185
     * Finds a single entity by a set of criteria.
186
     *
187
     * @param array      $criteria
188
     * @param array|null $orderBy
189
     *
190
     * @return object|null The entity instance or NULL if the entity can not be found.
191
     */
192 22
    public function findOneBy(array $criteria, array $orderBy = null)
193
    {
194 22
        $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
195
196 22
        return $persister->load($criteria, null, null, [], null, 1, $orderBy);
197
    }
198
199
    /**
200
     * Counts entities by a set of criteria.
201
     *
202
     * @todo Add this method to `ObjectRepository` interface in the next major release
203
     *
204
     * @param array $criteria
205
     *
206
     * @return int The cardinality of the objects that match the given criteria.
207
     */
208 2
    public function count(array $criteria)
209
    {
210 2
        return $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName)->count($criteria);
211
    }
212
213
    /**
214
     * Adds support for magic method calls.
215
     *
216
     * @param string $method
217
     * @param array  $arguments
218
     *
219
     * @return mixed The returned value from the resolved method.
220
     *
221
     * @throws ORMException
222
     * @throws \BadMethodCallException If the method called is invalid
223
     */
224 14
    public function __call($method, $arguments)
225
    {
226 14 View Code Duplication
        if (0 === strpos($method, 'findBy')) {
0 ignored issues
show
This code seems to be duplicated across 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...
227 8
            return $this->resolveMagicCall('findBy', substr($method, 6), $arguments);
228
        }
229
230 6 View Code Duplication
        if (0 === strpos($method, 'findOneBy')) {
0 ignored issues
show
This code seems to be duplicated across 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...
231 4
            return $this->resolveMagicCall('findOneBy', substr($method, 9), $arguments);
232
        }
233
234 2 View Code Duplication
        if (0 === strpos($method, 'countBy')) {
0 ignored issues
show
This code seems to be duplicated across 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...
235 1
            return $this->resolveMagicCall('count', substr($method, 7), $arguments);
236
        }
237
238 1
        throw new \BadMethodCallException(
239 1
            "Undefined method '$method'. The method name must start with ".
240 1
            "either findBy, findOneBy or countBy!"
241
        );
242
    }
243
244
    /**
245
     * @return string
246
     */
247
    protected function getEntityName()
248
    {
249
        return $this->_entityName;
250
    }
251
252
    /**
253
     * @return string
254
     */
255
    public function getClassName()
256
    {
257
        return $this->getEntityName();
258
    }
259
260
    /**
261
     * @return EntityManager
262
     */
263
    protected function getEntityManager()
264
    {
265
        return $this->_em;
266
    }
267
268
    /**
269
     * @return Mapping\ClassMetadata
270
     */
271
    protected function getClassMetadata()
272
    {
273
        return $this->_class;
274
    }
275
276
    /**
277
     * Select all elements from a selectable that match the expression and
278
     * return a new collection containing these elements.
279
     *
280
     * @param \Doctrine\Common\Collections\Criteria $criteria
281
     *
282
     * @return \Doctrine\Common\Collections\Collection
283
     */
284 26
    public function matching(Criteria $criteria)
285
    {
286 26
        $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
287
288 26
        return new LazyCriteriaCollection($persister, $criteria);
289
    }
290
291
    /**
292
     * Resolves a magic method call to the proper existent method at `EntityRepository`.
293
     *
294
     * @param string $method    The method to call
295
     * @param string $by        The property name used as condition
296
     * @param array  $arguments The arguments to pass at method call
297
     *
298
     * @throws ORMException If the method called is invalid or the requested field/association does not exist
299
     *
300
     * @return mixed
301
     */
302 13
    private function resolveMagicCall($method, $by, array $arguments)
303
    {
304 13
        if (! $arguments) {
305 1
            throw ORMException::findByRequiresParameter($method . $by);
306
        }
307
308 12
        $fieldName = lcfirst(Inflector::classify($by));
309
310 12
        if (! ($this->_class->hasField($fieldName) || $this->_class->hasAssociation($fieldName))) {
311 1
            throw ORMException::invalidMagicCall($this->_entityName, $fieldName, $method . $by);
312
        }
313
314 11
        return $this->$method([$fieldName => $arguments[0]], ...array_slice($arguments, 1));
315
    }
316
}
317