BelongsTo::getLoader()   B
last analyzed

Complexity

Conditions 8
Paths 48

Size

Total Lines 49
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 27
c 1
b 0
f 0
nc 48
nop 3
dl 0
loc 49
rs 8.4444
1
<?php
2
3
/**
4
 * Platine ORM
5
 *
6
 * Platine ORM provides a flexible and powerful ORM implementing a data-mapper pattern.
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine ORM
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a copy
13
 * of this software and associated documentation files (the "Software"), to deal
14
 * in the Software without restriction, including without limitation the rights
15
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
 * copies of the Software, and to permit persons to whom the Software is
17
 * furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in all
20
 * copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
 * SOFTWARE.
29
 */
30
31
/**
32
 *  @file Relation.php
33
 *
34
 *  The BelongsTo class
35
 *
36
 *  @package    Platine\Orm\Relation
37
 *  @author Platine Developers Team
38
 *  @copyright  Copyright (c) 2020
39
 *  @license    http://opensource.org/licenses/MIT  MIT License
40
 *  @link   https://www.platine-php.com
41
 *  @version 1.0.0
42
 *  @filesource
43
 */
44
45
declare(strict_types=1);
46
47
namespace Platine\Orm\Relation;
48
49
50
use Platine\Database\Query\QueryStatement;
51
use Platine\Orm\Entity;
52
use Platine\Orm\EntityManager;
53
use Platine\Orm\Mapper\DataMapper;
54
use Platine\Orm\Mapper\EntityMapper;
55
use Platine\Orm\Mapper\Proxy;
56
use Platine\Orm\Query\EntityQuery;
57
use Platine\Orm\Query\Query;
58
use Platine\Orm\Relation\Relation;
59
use Platine\Orm\Relation\RelationLoader;
60
61
/**
62
 * @class BelongsTo
63
 * @package Platine\Orm\Relation
64
 * @template TEntity as Entity
65
 * @extends Relation<TEntity>
66
 */
67
class BelongsTo extends Relation
68
{
69
    /**
70
     *
71
     * @param DataMapper<TEntity> $owner
72
     * @param TEntity|null $entity
0 ignored issues
show
Bug introduced by
The type Platine\Orm\Relation\TEntity was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
73
     *
74
     * @return void
75
     */
76
    public function addRelatedEntity(DataMapper $owner, ?Entity $entity = null): void
77
    {
78
        if ($entity === null) {
79
            $columns = [];
80
            $mapper = $owner->getEntityManager()->getEntityMapper($this->entityClass);
81
        } else {
82
            $related = Proxy::instance()->getEntityDataMapper($entity);
83
            $mapper = $related->getEntityMapper();
84
            $columns = $related->getRawColumns();
85
        }
86
87
        if ($this->foreignKey === null) {
88
            $this->foreignKey = $mapper->getForeignKey();
89
        }
90
91
        $foreignKeys = $this->foreignKey->getValue($columns, true);
0 ignored issues
show
Bug introduced by
The method getValue() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

91
        /** @scrutinizer ignore-call */ 
92
        $foreignKeys = $this->foreignKey->getValue($columns, true);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
92
        if (is_array($foreignKeys)) {
93
            foreach ($foreignKeys as $fkColumn => $fkValue) {
94
                $owner->setColumn($fkColumn, $fkValue);
95
            }
96
        }
97
    }
98
99
    /**
100
     * {@inheritedoc}
101
     * @param EntityManager<TEntity> $manager
102
     * @param EntityMapper<TEntity> $owner
103
     * @param array<string, mixed> $options
104
     *
105
     * @return RelationLoader<TEntity>
106
     */
107
    public function getLoader(
108
        EntityManager $manager,
109
        EntityMapper $owner,
110
        array $options
111
    ): RelationLoader {
112
113
        $related = $manager->getEntityMapper($this->entityClass);
114
115
        if ($this->foreignKey === null) {
116
            $this->foreignKey = $related->getForeignKey();
117
        }
118
119
        /** @var array<string, array<int, mixed>> $ids */
120
        $ids = [];
121
122
        foreach ($options['results'] as $result) {
123
            $primaryKeys = $this->foreignKey->getInverseValue($result, true);
124
            if (is_array($primaryKeys)) {
125
                foreach ($primaryKeys as $pkColumn => $pkValue) {
126
                    $ids[$pkColumn][] = $pkValue;
127
                }
128
            }
129
        }
130
131
        $queryStatement = new QueryStatement();
132
        $select = new EntityQuery($manager, $related, $queryStatement);
133
134
        foreach ($ids as $col => $value) {
135
            $value = array_unique($value);
136
            if (count($value) > 1) {
137
                $select->where($col)->in($value);
138
            } else {
139
                $select->where($col)->is(reset($value));
140
            }
141
        }
142
143
        if ($options['callback'] !== null) {
144
            $callback = $options['callback'];
145
            $callback(new Query($queryStatement));
146
        }
147
148
        $select->with($options['with'], $options['immediate']);
149
150
        return new RelationLoader(
151
            $select,
152
            $this->foreignKey,
0 ignored issues
show
Bug introduced by
It seems like $this->foreignKey can also be of type null; however, parameter $foreignKey of Platine\Orm\Relation\RelationLoader::__construct() does only seem to accept Platine\Orm\Relation\ForeignKey, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

152
            /** @scrutinizer ignore-type */ $this->foreignKey,
Loading history...
153
            true,
154
            false,
155
            $options['immediate']
156
        );
157
    }
158
159
    /**
160
     * {@inheritedoc}
161
     * @param DataMapper<TEntity> $mapper
162
     * @return TEntity|null
163
     */
164
    public function getResult(DataMapper $mapper, ?callable $callback = null): ?Entity
165
    {
166
        $manager = $mapper->getEntityManager();
167
        $related = $manager->getEntityMapper($this->entityClass);
168
169
        if ($this->foreignKey === null) {
170
            $this->foreignKey = $related->getForeignKey();
171
        }
172
173
        $queryStatement = new QueryStatement();
174
        $select = new EntityQuery($manager, $related, $queryStatement);
175
176
        $primaryKeys = $this->foreignKey->getInverseValue($mapper->getRawColumns(), true);
177
        if (is_array($primaryKeys)) {
178
            foreach ($primaryKeys as $pkColumn => $pkValue) {
179
                $select->where($pkColumn)->is($pkValue);
180
            }
181
        }
182
183
        if ($this->queryCallback !== null || $callback !== null) {
184
            $query = $select;
185
186
            if ($this->queryCallback !== null) {
187
                ($this->queryCallback)($query);
188
            }
189
190
            if ($callback !== null) {
191
                $callback($query);
192
            }
193
        }
194
195
        return $select->get();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $select->get() also could return the type Platine\Orm\Entity which is incompatible with the documented return type Platine\Orm\Relation\TEntity|null.
Loading history...
196
    }
197
}
198