Issues (56)

src/Relation/HasRelation.php (5 issues)

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 HasRelation.php
33
 *
34
 *  The HasRelation 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
use Platine\Database\Query\QueryStatement;
50
use Platine\Orm\Entity;
51
use Platine\Orm\EntityManager;
52
use Platine\Orm\Mapper\DataMapper;
53
use Platine\Orm\Mapper\EntityMapper;
54
use Platine\Orm\Mapper\Proxy;
55
use Platine\Orm\Query\EntityQuery;
56
use Platine\Orm\Query\Query;
57
58
/**
59
 * @class HasRelation
60
 * @package Platine\Orm\Relation
61
 * @template TEntity as Entity
62
 * @extends Relation<TEntity>
63
 */
64
abstract class HasRelation extends Relation
65
{
66
    /**
67
     * Whether is many or not
68
     * @var bool
69
     */
70
    protected bool $hasMany = false;
71
72
    /**
73
     * Create new instance
74
     * @param class-string<TEntity> $entityClass
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<TEntity> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<TEntity>.
Loading history...
75
     * @param ForeignKey|null $foreignKey
76
     */
77
    public function __construct(
78
        string $entityClass,
79
        ?ForeignKey $foreignKey = null
80
    ) {
81
        parent::__construct($entityClass, $foreignKey);
82
    }
83
84
    /**
85
     *
86
     * @param DataMapper<TEntity> $owner
87
     * @param TEntity $entity
0 ignored issues
show
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...
88
     *
89
     * @return void
90
     */
91
    public function addRelatedEntity(DataMapper $owner, Entity $entity): void
92
    {
93
        $mapper = $owner->getEntityMapper();
94
        if ($this->foreignKey === null) {
95
            $this->foreignKey = $mapper->getForeignKey();
96
        }
97
        $related = Proxy::instance()->getEntityDataMapper($entity);
98
99
        $foreignKeys = $this->foreignKey->getValue($owner->getRawColumns(), true);
0 ignored issues
show
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

99
        /** @scrutinizer ignore-call */ 
100
        $foreignKeys = $this->foreignKey->getValue($owner->getRawColumns(), 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...
100
        if (is_array($foreignKeys)) {
101
            foreach ($foreignKeys as $fkColumn => $fkValue) {
102
                $related->setColumn($fkColumn, $fkValue);
103
            }
104
        }
105
    }
106
107
    /**
108
     * {@inheritedoc}
109
     * @param EntityManager<TEntity> $manager
110
     * @param EntityMapper<TEntity> $owner
111
     * @param array<string, mixed> $options
112
     *
113
     * @return RelationLoader<TEntity>
114
     */
115
    public function getLoader(
116
        EntityManager $manager,
117
        EntityMapper $owner,
118
        array $options
119
    ): RelationLoader {
120
        $related = $manager->getEntityMapper($this->entityClass);
121
122
        if ($this->foreignKey === null) {
123
            $this->foreignKey = $owner->getForeignKey();
124
        }
125
126
        /** @var array<string, array<mixed>> $ids */
127
        $ids = [];
128
129
        $primaryKey = $owner->getPrimaryKey();
130
        foreach ($options['results'] as $result) {
131
            $primaryKeys = $primaryKey->getValue($result, true);
132
            if (is_array($primaryKeys)) {
133
                foreach ($primaryKeys as $pkColumn => $pkValue) {
134
                    $ids[$pkColumn][] = $pkValue;
135
                }
136
            }
137
        }
138
139
        $queryStatement = new QueryStatement();
140
        $select = new EntityQuery($manager, $related, $queryStatement);
141
142
        $foreignKeys = $this->foreignKey->getValue($ids, true);
143
        if (is_array($foreignKeys)) {
144
            foreach ($foreignKeys as $fkColumn => $fkValue) {
145
                $select->where($fkColumn)->in([$fkValue]);
146
            }
147
        }
148
149
        if ($options['callback'] !== null) {
150
            $callback = $options['callback'];
151
            $callback(new Query($queryStatement));
152
        }
153
154
        $select->with($options['with'], $options['immediate']);
155
156
        return new RelationLoader(
157
            $select,
158
            $this->foreignKey,
0 ignored issues
show
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

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