Passed
Push — master ( 8d4d73...ee2cd0 )
by Alexander
13:53
created

Factory::setDefaultDefinitions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Factory;
6
7
use Psr\Container\ContainerInterface;
8
use Yiisoft\Definitions\Infrastructure\DefinitionValidator;
9
use Yiisoft\Definitions\Exception\CircularReferenceException;
10
use Yiisoft\Definitions\Exception\InvalidConfigException;
11
use Yiisoft\Definitions\Exception\NotFoundException;
12
use Yiisoft\Definitions\Exception\NotInstantiableException;
13
14
/**
15
 * Factory allows creating objects passing arguments runtime.
16
 * A factory will try to use a PSR-11 compliant container to get dependencies,
17
 * but will fall back to manual instantiation
18
 * if the container cannot provide a required dependency.
19
 */
20
final class Factory
21
{
22
    private DependencyResolver $dependencyResolver;
23
24
    /**
25
     * @var bool $validate Validate definitions when set
26
     */
27
    private bool $validate;
28
29
    /**
30
     * Factory constructor.
31
     *
32
     * @psalm-param array<string, mixed> $definitions
33
     *
34
     * @throws InvalidConfigException
35
     */
36 84
    public function __construct(
37
        ContainerInterface $container = null,
38
        array $definitions = [],
39
        bool $validate = true
40
    ) {
41 84
        $this->dependencyResolver = new DependencyResolver($container);
42 84
        $this->validate = $validate;
43 84
        $this->setMultiple($definitions);
44 82
    }
45
46
    /**
47
     * Creates a new object using the given configuration.
48
     *
49
     * You may view this method as an enhanced version of the `new` operator.
50
     * The method supports creating an object based on a class name, a configuration array or
51
     * an anonymous function.
52
     *
53
     * Below are some usage examples:
54
     *
55
     * ```php
56
     * // create an object using a class name
57
     * $object = $factory->create(\Yiisoft\Db\Connection::class);
58
     *
59
     * // create an object using a configuration array
60
     * $object = $factory->create([
61
     *     'class' => \Yiisoft\Db\Connection\Connection::class,
62
     *     '__construct()' => [
63
     *         'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
64
     *     ],
65
     *     'setUsername()' => ['root'],
66
     *     'setPassword()' => [''],
67
     *     'setCharset()' => ['utf8'],
68
     * ]);
69
     * ```
70
     *
71
     * Using [[Container|dependency injection container]], this method can also identify
72
     * dependent objects, instantiate them and inject them into the newly created object.
73
     *
74
     * @param mixed $config The object configuration. This can be specified in one of the following forms:
75
     *
76
     * - A string: representing the class name of the object to be created.
77
     *
78
     * - A configuration array: the array must contain a `class` element which is treated as the object class,
79
     *   and the rest of the name-value pairs will be used to initialize the corresponding object properties.
80
     *
81
     * - A PHP callable: either an anonymous function or an array representing a class method
82
     *   (`[$class or $object, $method]`). The callable should return a new instance of the object being created.
83
     *
84
     * @throws InvalidConfigException If the configuration is invalid.
85
     * @throws CircularReferenceException
86
     * @throws NotFoundException
87
     * @throws NotInstantiableException
88
     *
89
     * @return mixed|object The created object.
90
     *
91
     * @psalm-template T
92
     * @psalm-param mixed|class-string<T> $config
93
     * @psalm-return ($config is class-string ? T : mixed)
94
     */
95 81
    public function create($config)
96
    {
97 81
        if ($this->validate) {
98 77
            DefinitionValidator::validate($config);
99
        }
100
101
        /** @psalm-suppress MixedReturnStatement */
102 77
        return $this->dependencyResolver->create($config);
103
    }
104
105
    /**
106
     * Sets a definition to the factory.
107
     *
108
     * @param mixed $definition
109
     *
110
     * @throws InvalidConfigException
111
     */
112 52
    public function set(string $id, $definition): void
113
    {
114 52
        if ($this->validate) {
115 49
            DefinitionValidator::validate($definition, $id);
116
        }
117
118 49
        $this->dependencyResolver->setFactoryDefinition($id, $definition);
119 49
    }
120
121
    /**
122
     * Sets multiple definitions at once.
123
     *
124
     * @param array $definitions definitions indexed by their ids
125
     *
126
     * @psalm-param array<string, mixed> $definitions
127
     *
128
     * @throws InvalidConfigException
129
     */
130 84
    public function setMultiple(array $definitions): void
131
    {
132
        /** @var mixed $definition */
133 84
        foreach ($definitions as $id => $definition) {
134 50
            $this->set($id, $definition);
135
        }
136 82
    }
137
}
138