ModelBuilder::createSource()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 10
nc 6
nop 2
dl 0
loc 18
rs 9.9332
c 1
b 0
f 0
1
<?php
2
3
namespace Charcoal\Model\Service;
4
5
use UnexpectedValueException;
6
7
// From 'charcoal-factory'
8
use Charcoal\Factory\FactoryInterface;
9
10
// From 'charcoal-core'
11
use Charcoal\Model\ModelMetadata;
12
use Charcoal\Model\Service\MetadataLoader;
13
14
/**
15
 *
16
 */
17
final class ModelBuilder
18
{
19
    const DEFAULT_SOURCE_TYPE = 'database';
20
21
    /**
22
     * @var FactoryInterface
23
     */
24
    private $factory;
25
26
    /**
27
     * @var MetadataLoader
28
     */
29
    private $metadataLoader;
30
31
    /**
32
     * @var FactoryInterface
33
     */
34
    private $sourceFactory;
35
36
    /**
37
     * @param array $data Constructor dependencies.
38
     */
39
    public function __construct(array $data)
40
    {
41
        $this->setFactory($data['factory']);
42
        $this->setMetadataLoader($data['metadata_loader']);
43
        $this->setSourceFactory($data['source_factory']);
44
    }
45
46
    /**
47
     * Build a model, pre-initializing its metadata and its source.
48
     *
49
     * By default, the name of the "obj type" (the model class name) is used to determine the metadata ident to load.
50
     * To load a custom metadata for the object, use the `$metadataIdent` argument.
51
     *
52
     * By default, the object's _default_ source (from its metadata) is used as source.
53
     * To load a custom source for the object, use the `$sourceIdent` argument.
54
     *
55
     * @param string      $objType       The object type of the Model.
56
     * @param string|null $metadataIdent Optional. The metadata ident of the object.
57
     * @param string|null $sourceIdent   Optional. The custom source ident to load as source.
58
     * @return \Charcoal\Model\ModelInterface
59
     */
60
    public function build($objType, $metadataIdent = null, $sourceIdent = null)
61
    {
62
        $metadata = $this->createMetadata($objType, $metadataIdent);
63
        $source = $this->createSource($metadata, $sourceIdent);
64
        $args = array_merge($this->factory->arguments(), [
65
            'metadata'  => $metadata,
66
            'source'    => $source
67
        ]);
68
        $model = $this->factory->create($objType, $args);
69
        $model->source()->setModel($model);
70
        return $model;
71
    }
72
73
    /**
74
     * The builder can be invoked (used as function).
75
     *
76
     * @param string      $objType       The object type of the Model.
77
     * @param string|null $metadataIdent Optional. The metadata ident of the object.
78
     * @param string|null $sourceIdent   Optional. The custom source ident to load as source.
79
     * @return \Charcoal\Model\ModelInterface
80
     */
81
    public function __invoke($objType, $metadataIdent = null, $sourceIdent = null)
82
    {
83
        return $this->build($objType, $metadataIdent, $sourceIdent);
84
    }
85
86
87
    /**
88
     * @param FactoryInterface $factory The factory to use to create models.
89
     * @return void
90
     */
91
    private function setFactory(FactoryInterface $factory)
92
    {
93
        $this->factory = $factory;
94
    }
95
96
    /**
97
     * @param MetadataLoader $loader The loader instance, used to load metadata.
98
     * @return void
99
     */
100
    private function setMetadataLoader(MetadataLoader $loader)
101
    {
102
        $this->metadataLoader = $loader;
103
    }
104
105
    /**
106
     * @param FactoryInterface $factory The factory to use to create models.
107
     * @return void
108
     */
109
    private function setSourceFactory(FactoryInterface $factory)
110
    {
111
        $this->sourceFactory = $factory;
112
    }
113
114
    /**
115
     * @param string      $objType       The type of object to load.
116
     *     (A class name or object identifier).
117
     * @param string|null $metadataIdent Optional. The metadata identifier to load.
118
     *     If NULL, it will be implied from objType.
119
     * @return \Charcoal\Model\MetadataInterface
120
     */
121
    private function createMetadata($objType, $metadataIdent = null)
122
    {
123
        $metadataIdent = ($metadataIdent !== null) ? $metadataIdent : $objType;
124
        return $this->metadataLoader->load($metadataIdent, ModelMetadata::class);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->metadataLo...l\ModelMetadata::class) also could return the type array which is incompatible with the documented return type Charcoal\Model\MetadataInterface.
Loading history...
125
    }
126
127
    /**
128
     * @param ModelMetadata $metadata    The object metadata, where to find the object's
129
     *     source configuration.
130
     * @param string|null   $sourceIdent Optional. Custom source ident to load.
131
     *     If NULL, the default (from metadata) will be used.
132
     * @throws UnexpectedValueException If the source is not defined in the model's metadata.
133
     * @return \Charcoal\Source\SourceInterface
134
     */
135
    private function createSource(ModelMetadata $metadata, $sourceIdent = null)
136
    {
137
        if ($sourceIdent === null) {
138
            $sourceIdent = $metadata->defaultSource();
139
        }
140
        $sourceConfig = $metadata->source($sourceIdent);
141
142
        if (!$sourceConfig) {
143
            throw new UnexpectedValueException(
144
                sprintf('Can not create %s source: "%s" is not defined in metadata.', get_class($this), $sourceIdent)
145
            );
146
        }
147
148
        $sourceType = isset($sourceConfig['type']) ? $sourceConfig['type'] : self::DEFAULT_SOURCE_TYPE;
149
        $source = $this->sourceFactory->create($sourceType);
150
        $source->setData($sourceConfig);
151
152
        return $source;
153
    }
154
}
155