Passed
Push — master ( 07f27f...cc2af6 )
by Anton
04:06 queued 10s
created

Factory::source()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 31
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 5
nop 3
dl 0
loc 31
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Cycle DataMapper ORM
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\ORM;
13
14
use Cycle\ORM\Config\RelationConfig;
15
use Cycle\ORM\Exception\TypecastException;
16
use Cycle\ORM\Mapper\Mapper;
17
use Cycle\ORM\Relation\RelationInterface;
18
use Cycle\ORM\Select\ConstrainInterface;
19
use Cycle\ORM\Select\LoaderInterface;
20
use Cycle\ORM\Select\Repository;
21
use Cycle\ORM\Select\Source;
22
use Cycle\ORM\Select\SourceInterface;
23
use Psr\Container\ContainerInterface;
24
use Spiral\Core\Container;
25
use Spiral\Core\FactoryInterface as CoreFactory;
26
use Spiral\Database\DatabaseInterface;
27
use Spiral\Database\DatabaseProviderInterface;
28
29
final class Factory implements FactoryInterface
30
{
31
    /** @var RelationConfig */
32
    private $config;
33
34
    /** @var CoreFactory */
35
    private $factory;
36
37
    /** @var ContainerInterface */
38
    private $container;
39
40
    /** @var DatabaseProviderInterface */
41
    private $dbal;
42
43
    /** @var array<string, string> */
44
    private $defaults = [];
45
46
    /**
47
     * @param DatabaseProviderInterface $dbal
48
     * @param RelationConfig $config
49
     * @param CoreFactory|null $factory
50
     * @param ContainerInterface|null $container
51
     */
52
    public function __construct(
53
        DatabaseProviderInterface $dbal,
54
        RelationConfig $config = null,
55
        CoreFactory $factory = null,
56
        ContainerInterface $container = null
57
    ) {
58
        $this->dbal = $dbal;
59
        $this->config = $config ?? RelationConfig::getDefault();
60
        $this->factory = $factory ?? new Container();
61
        $this->container = $container ?? new Container();
62
        $this->defaults = [
63
            Schema::REPOSITORY => Repository::class,
64
            Schema::SOURCE => Source::class,
65
            Schema::MAPPER => Mapper::class,
66
            Schema::CONSTRAIN => null,
67
        ];
68
    }
69
70
    /**
71
     * @inheritdoc
72
     */
73
    public function make(
74
        string $alias,
75
        array $parameters = []
76
    ) {
77
        return $this->factory->make($alias, $parameters);
78
    }
79
80
    /**
81
     * @inheritdoc
82
     */
83
    public function mapper(
84
        ORMInterface $orm,
85
        SchemaInterface $schema,
86
        string $role
87
    ): MapperInterface {
88
        $class = $schema->define($role, Schema::MAPPER) ?? $this->defaults[Schema::MAPPER];
89
90
        if (!is_subclass_of($class, MapperInterface::class)) {
91
            throw new TypecastException($class . ' not implement MapperInterface');
92
        }
93
94
        return $this->factory->make($class, [
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->factory->m...e\ORM\Schema::SCHEMA))) could return the type null which is incompatible with the type-hinted return Cycle\ORM\MapperInterface. Consider adding an additional type-check to rule them out.
Loading history...
95
            'orm' => $orm,
96
            'role' => $role,
97
            'schema' => $schema->define($role, Schema::SCHEMA)
98
        ]);
99
    }
100
101
    /**
102
     * @inheritdoc
103
     */
104
    public function loader(
105
        ORMInterface $orm,
106
        SchemaInterface $schema,
107
        string $role,
108
        string $relation
109
    ): LoaderInterface {
110
        $schema = $schema->defineRelation($role, $relation);
111
112
        return $this->config->getLoader($schema[Relation::TYPE])->resolve($this->factory, [
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->config->ge...ORM\Relation::SCHEMA])) could return the type null which is incompatible with the type-hinted return Cycle\ORM\Select\LoaderInterface. Consider adding an additional type-check to rule them out.
Loading history...
113
            'orm' => $orm,
114
            'name' => $relation,
115
            'target' => $schema[Relation::TARGET],
116
            'schema' => $schema[Relation::SCHEMA]
117
        ]);
118
    }
119
120
    /**
121
     * @inheritdoc
122
     */
123
    public function relation(
124
        ORMInterface $orm,
125
        SchemaInterface $schema,
126
        string $role,
127
        string $relation
128
    ): RelationInterface {
129
        $relSchema = $schema->defineRelation($role, $relation);
130
        $type = $relSchema[Relation::TYPE];
131
132
        return $this->config->getRelation($type)->resolve($this->factory, [
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->config->ge...ation::LOAD] ?? null))) could return the type null which is incompatible with the type-hinted return Cycle\ORM\Relation\RelationInterface. Consider adding an additional type-check to rule them out.
Loading history...
133
            'orm' => $orm,
134
            'name' => $relation,
135
            'target' => $relSchema[Relation::TARGET],
136
            'schema' => $relSchema[Relation::SCHEMA] + [Relation::LOAD => $relSchema[Relation::LOAD] ?? null],
137
        ]);
138
    }
139
140
    /**
141
     * @inheritdoc
142
     */
143
    public function database(string $database = null): DatabaseInterface
144
    {
145
        return $this->dbal->database($database);
146
    }
147
148
    /**
149
     * @inheritDoc
150
     */
151
    public function repository(
152
        ORMInterface $orm,
153
        SchemaInterface $schema,
154
        string $role,
155
        ?Select $select
156
    ): RepositoryInterface {
157
        $class = $schema->define($role, Schema::REPOSITORY) ?? $this->defaults[Schema::REPOSITORY];
158
159
        if (!is_subclass_of($class, RepositoryInterface::class)) {
160
            throw new TypecastException($class . ' not implement RepositoryInterface');
161
        }
162
163
        return $this->factory->make($class, ['select' => $select, 'orm' => $orm]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->factory->m...select, 'orm' => $orm)) could return the type null which is incompatible with the type-hinted return Cycle\ORM\RepositoryInterface. Consider adding an additional type-check to rule them out.
Loading history...
164
    }
165
166
    /**
167
     * @inheritDoc
168
     */
169
    public function source(
170
        ORMInterface $orm,
171
        SchemaInterface $schema,
172
        string $role
173
    ): SourceInterface {
174
        $source = $schema->define($role, Schema::SOURCE) ?? $this->defaults[Schema::SOURCE];
175
176
        if (!is_subclass_of($source, SourceInterface::class)) {
177
            throw new TypecastException($source . ' not implement SourceInterface');
178
        }
179
180
        if ($source !== Source::class) {
181
            return $this->factory->make($source, ['orm' => $orm, 'role' => $role]);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->factory->m...$orm, 'role' => $role)) could return the type null which is incompatible with the type-hinted return Cycle\ORM\Select\SourceInterface. Consider adding an additional type-check to rule them out.
Loading history...
182
        }
183
184
        $source = new Source(
185
            $this->database($schema->define($role, Schema::DATABASE)),
186
            $schema->define($role, Schema::TABLE)
187
        );
188
189
        $constrain = $schema->define($role, Schema::CONSTRAIN) ?? $this->defaults[Schema::CONSTRAIN];
190
191
        if ($constrain === null) {
192
            return $source;
193
        }
194
195
        if (!is_subclass_of($constrain, ConstrainInterface::class)) {
196
            throw new TypecastException($constrain . ' not implement ConstrainInterface');
197
        }
198
199
        return $source->withConstrain(is_object($constrain) ? $constrain : $this->factory->make($constrain));
200
    }
201
202
    /**
203
     * Add default classes for resolve
204
     * @param array $defaults
205
     * @return FactoryInterface
206
     */
207
    public function withDefaultSchemaClasses(array $defaults): FactoryInterface
208
    {
209
        $clone = clone $this;
210
211
        $clone->defaults = $defaults + $this->defaults;
212
213
        return $clone;
214
    }
215
}
216