Issues (56)

src/Entity.php (2 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 Entity.php
33
 *
34
 *  The Entity class
35
 *
36
 *  @package    Platine\Orm
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;
48
49
use JsonSerializable;
50
use Platine\Orm\Exception\PropertyNotFoundException;
51
use Platine\Orm\Mapper\DataMapper;
52
use Platine\Orm\Mapper\DataMapperInterface;
53
use Platine\Orm\Mapper\EntityMapper;
54
use Platine\Orm\Mapper\EntityMapperInterface;
55
use Stringable;
56
57
/**
58
 * @class Entity
59
 * @package Platine\Orm
60
 * @template TEntity as Entity
61
 */
62
abstract class Entity implements JsonSerializable, Stringable
63
{
64
    /**
65
     * The instance of data mapper
66
     * @var DataMapper<TEntity>|null
67
     */
68
    private ?DataMapper $dataMapper = null;
69
70
    /**
71
     * The data mapper constructor arguments
72
     * @var array<int, mixed>
73
     */
74
    private array $dataMapperArgs = [];
75
76
    /**
77
     *
78
     * @param EntityManager<TEntity> $manager
79
     * @param EntityMapper<TEntity>  $mapper
80
     * @param array<string, mixed> $columns
81
     * @param array<string, \Platine\Orm\Relation\RelationLoader<TEntity>> $loaders
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string, \Platine\O...elationLoader<TEntity>> at position 4 could not be parsed: Expected '>' at position 4, but found '\Platine\Orm\Relation\RelationLoader'.
Loading history...
82
     * @param bool $isReadOnly
83
     * @param bool $isNew
84
     */
85
    final public function __construct(
86
        EntityManager $manager,
87
        EntityMapper $mapper,
88
        array $columns = [],
89
        array $loaders = [],
90
        bool $isReadOnly = false,
91
        bool $isNew = false
92
    ) {
93
        $this->dataMapperArgs = [
94
            $manager,
95
            $mapper,
96
            $columns,
97
            $loaders,
98
            $isReadOnly,
99
            $isNew
100
        ];
101
    }
102
103
    /**
104
     * Convert entity to JSON array
105
     * @return array<string, mixed>
106
     */
107
    public function jsonSerialize(): mixed
108
    {
109
        $rawColumns = $this->mapper()->getRawColumns();
110
        $data = [];
111
        foreach ($rawColumns as $name => $value) {
112
            if ($this->mapper()->hasRelation($name)) {
113
                $relation = $this->mapper()->getRelated($name);
114
                if ($relation instanceof self) {
115
                    $data[$name] = $relation->jsonSerialize();
116
                } else {
117
                    $data[$name] = $relation;
118
                }
119
            } elseif ($this->mapper()->hasColumn($name)) {
120
                $data[$name] = $this->mapper()->getColumn($name);
121
            } else {
122
                $data[$name] = $value;
123
            }
124
        }
125
126
        return $data;
127
    }
128
129
    /**
130
     * Shortcut to DataMapper getColumn and getRelated
131
     * @param string $name
132
     * @return mixed
133
     */
134
    public function __get(string $name): mixed
135
    {
136
        if ($this->mapper()->hasRelation($name)) {
137
            return $this->mapper()->getRelated($name);
138
        }
139
140
        if ($this->mapper()->hasColumn($name)) {
141
            return $this->mapper()->getColumn($name);
142
        }
143
144
        throw new PropertyNotFoundException(sprintf(
145
            'Unknown column or relation [%s]',
146
            $name
147
        ));
148
    }
149
150
    /**
151
     * Shortcut to DataMapper setColumn and setRelated
152
     * @param string $name
153
     * @param mixed $value
154
     * @return void
155
     */
156
    public function __set(string $name, mixed $value): void
157
    {
158
        if ($this->mapper()->hasRelation($name)) {
159
            if (is_array($value)) {
160
                foreach ($value as $entity) {
161
                    $this->mapper()->link($name, $entity);
162
                }
163
            } else {
164
                $this->mapper()->setRelated($name, $value);
165
            }
166
        } else {
167
            $this->mapper()->setColumn($name, $value);
168
        }
169
    }
170
171
    /**
172
     * Shortcut to DataMapper hasColumn and hasRelated
173
     * @param string $name
174
     * @return bool
175
     */
176
    public function __isset(string $name): bool
177
    {
178
        return $this->mapper()->hasRelation($name)
179
                || $this->mapper()->hasColumn($name);
180
    }
181
182
    /**
183
     * Shortcut to DataMapper clearColumn
184
     * @param string $name
185
     * @return void
186
     */
187
    public function __unset(string $name): void
188
    {
189
        $this->mapper()->clearColumn($name, true);
190
    }
191
192
    /**
193
     * Return the string representation of this entity
194
     * @return string
195
     */
196
    public function __toString(): string
197
    {
198
        $columns = $this->mapper()->getRawColumns();
199
        $columnsStr = '';
200
        foreach ($columns as $name => $value) {
201
            $columnsStr .= sprintf('%s=%s, ', $name, (string) $value);
202
        }
203
204
        return sprintf('[%s(%s)]', __CLASS__, rtrim($columnsStr, ', '));
205
    }
206
207
        /**
208
     * Map the entity information
209
     * @param EntityMapperInterface<TEntity> $mapper
210
     */
211
    abstract public static function mapEntity(EntityMapperInterface $mapper): void;
212
213
    /**
214
     * Return the instance of data mapper
215
     * @return DataMapperInterface<TEntity>
216
     */
217
    final protected function mapper(): DataMapperInterface
218
    {
219
        if ($this->dataMapper === null) {
220
            /** @var DataMapper<TEntity> $dataMapper */
221
            $dataMapper = new DataMapper(...$this->dataMapperArgs);
222
223
            $this->dataMapper = $dataMapper;
224
        }
225
226
        return $this->dataMapper;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->dataMapper could return the type null which is incompatible with the type-hinted return Platine\Orm\Mapper\DataMapperInterface. Consider adding an additional type-check to rule them out.
Loading history...
227
    }
228
}
229