Completed
Push — master ( 3214c9...a8a248 )
by Quentin
10:44 queued 01:22
created

DoctrineLoaderTrait::onLoad()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
ccs 0
cts 5
cp 0
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Majora\Framework\Loader\Bridge\Doctrine;
4
5
use Doctrine\Common\Collections\Collection;
6
use Doctrine\ORM\EntityRepository;
7
use Majora\Framework\Loader\LoaderTrait;
8
9
/**
10
 * Trait to use into Doctrine loaders to get a simple implementation of LoaderInterface.
11
 *
12
 * @method getEntityRepository : EntityRepository
13
 * @method setEntityRepository(EntityRepository)
14
 *
15
 * @property $entityClass
16
 * @property $collectionClass
17
 * @property $filterResolver
18
 */
19
trait DoctrineLoaderTrait
20
{
21
    use LoaderTrait;
22
23
    /**
24
     * Construct.
25
     *
26
     * @param EntityRepository $entityRepository (optionnal)
27
     */
28
    public function __construct(EntityRepository $entityRepository = null)
29
    {
30
        if ($entityRepository) {
31
            @trigger_error('Repository constructor injection is deprecated for ORM implementation due to circular references with Doctrine events and will be removed in 2.0. Use setEntityRepository() instead.', E_USER_DEPRECATED);
32
            $this->setEntityRepository($entityRepository);
33
        }
34
    }
35
36
    /**
37
     * Checks if loader is properly configured.
38
     *
39
     * @throws \RuntimeException if not configured
40
     */
41
    private function assertIsConfigured()
42
    {
43
        if (!$this->entityClass || !$this->collectionClass || !$this->filterResolver) {
44
            throw new \RuntimeException(sprintf(
45
                '%s methods cannot be used while it has not been initialize through %s::configureMetadata().',
46
                static::class,
47
                static::class
48
            ));
49
        }
50
    }
51
52
    /**
53
     * Convert given array or Collection result set to managed entity collection class.
54
     *
55
     * @param array|Collection $result
56
     *
57
     * @return EntityCollection
58
     */
59
    protected function toEntityCollection($result)
60
    {
61
        switch (true) {
62
63
            // already a collection ?
64
            case is_object($result) && is_subclass_of($result, $this->collectionClass) :
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $this->collectionClass can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
65
                $collection = $result;
66
                break;
67
68
            // already a collection ?
69
            case $result instanceof Collection :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
70
                $collection = new $this->collectionClass($result->toArray());
71
                break;
72
73
            // simple related entity ?
74
            case is_object($result) && is_subclass_of($result, $this->entityClass) :
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $this->entityClass can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
75
                $collection = new $this->collectionClass(array($result));
76
                break;
77
78
            // simple array ?
79
            case is_array($result) :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
80
                $collection = new $this->collectionClass($result);
81
                break;
82
83
            default:
84
                $collection = new $this->collectionClass();
85
                break;
86
        }
87
88 View Code Duplication
        if (is_callable(array($this, 'onLoad'))) {
0 ignored issues
show
Duplication introduced by
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...
89
            @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
90
                sprintf('%s::onLoad() call is deprecated and will be removed in 2.0. Make "%s" invokable instead if you require to custom every "%s" loaded by ORM.',
91
                    static::class,
92
                    static::class,
93
                    $this->entityClass
94
                ),
95
                E_USER_DEPRECATED
96
            );
97
98
            return $this->onLoad($collection);
0 ignored issues
show
Bug introduced by
It seems like onLoad() 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...
99
        }
100
101
        return $collection;
102
    }
103
104
    /**
105
     * Create entity query.
106
     * Proxy to base query builder method to use to custom all queries from this loader.
107
     *
108
     * @param string $alias
109
     *
110
     * @return QueryBuilder
111
     */
112
    protected function createQuery($alias = 'entity')
113
    {
114
        return $this->getEntityRepository()
0 ignored issues
show
Bug introduced by
It seems like getEntityRepository() 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...
115
            ->createQueryBuilder($alias)
116
        ;
117
    }
118
119
    /**
120
     * create query an filter it with given data.
121
     *
122
     * @param array $filters
123
     *
124
     * @return Query
125
     */
126
    private function createFilteredQuery(array $filters)
127
    {
128
        $qb = $this->createQuery('entity');
129
130
        foreach ($filters as $field => $filter) {
131
            $qb->andWhere(is_array($filter)
132
                    ? sprintf('entity.%s in (:%s)', $field, $field)
133
                    : sprintf('entity.%s = :%s', $field, $field)
134
                )
135
                ->setParameter(sprintf(':%s', $field), $filter)
136
            ;
137
        }
138
139
        return $qb->getQuery();
140
    }
141
142
    /**
143
     * @see LoaderInterface::retrieveAll()
144
     */
145
    public function retrieveAll(array $filters = array(), $limit = null, $offset = null)
146
    {
147
        $this->assertIsConfigured();
148
149
        $query = $this->createFilteredQuery(
150
            $this->filterResolver->resolve($filters)
151
        );
152
153
        if ($limit) {
154
            $query->setMaxResults($limit);
155
        }
156
        if ($offset) {
157
            $query->setFirstResult($offset);
158
        }
159
160
        return $this->toEntityCollection(
161
            $query->getResult()
162
        );
163
    }
164
165
    /**
166
     * @see LoaderInterface::retrieveOne()
167
     */
168
    public function retrieveOne(array $filters = array())
169
    {
170
        $this->assertIsConfigured();
171
172
        $entity = $this->createFilteredQuery($filters)
173
            ->setMaxResults(1)
174
            ->getOneOrNullResult()
175
        ;
176
177 View Code Duplication
        if (is_callable(array($this, 'onLoad'))) {
0 ignored issues
show
Duplication introduced by
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...
178
            @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
179
                sprintf('%s::onLoad() call is deprecated and will be removed in 2.0. Make "%s" invokable instead if you require to custom every "%s" loaded by ORM.',
180
                    static::class,
181
                    static::class,
182
                    $this->entityClass
183
                ),
184
                E_USER_DEPRECATED
185
            );
186
187
            return $this->onLoad($entity);
0 ignored issues
show
Bug introduced by
It seems like onLoad() 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...
188
        }
189
190
        return $entity;
191
    }
192
193
    /**
194
     * @see LoaderInterface::retrieve()
195
     */
196
    public function retrieve($id)
197
    {
198
        return $this->retrieveOne(array('id' => $id));
199
    }
200
}
201