Passed
Push — master ( 37af9c...efcfea )
by Sergei
03:49 queued 57s
created

WidgetFactory::setDefaultTheme()   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
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Widget;
6
7
use Psr\Container\ContainerInterface;
8
use Yiisoft\Definitions\ArrayDefinition;
9
use Yiisoft\Definitions\Exception\CircularReferenceException;
10
use Yiisoft\Definitions\Exception\InvalidConfigException;
11
use Yiisoft\Definitions\Exception\NotInstantiableException;
12
use Yiisoft\Definitions\Helpers\ArrayDefinitionHelper;
13
use Yiisoft\Definitions\Helpers\DefinitionValidator;
14
use Yiisoft\Factory\NotFoundException;
15
use Yiisoft\Factory\Factory;
16
17
/**
18
 * WidgetFactory creates an instance of the widget based on the specified configuration
19
 * {@see WidgetFactory::createWidget()}. Before creating a widget, you need to initialize
20
 * the WidgetFactory with {@see WidgetFactory::initialize()}.
21
 */
22
final class WidgetFactory
23
{
24
    private static ?Factory $factory = null;
25
26
    /**
27
     * @psalm-var array<string, array<string, array>>
28
     */
29
    private static array $themes = [];
30
31
    private static ?string $defaultTheme = null;
32
33
    private function __construct()
34
    {
35
    }
36
37
    /**
38
     * @psalm-param array<string, mixed> $definitions
39
     * @psalm-param array<string, array<string, array>> $themes
40
     *
41
     * @throws InvalidConfigException
42
     *
43
     * @see Factory::__construct()
44
     */
45 35
    public static function initialize(
46
        ContainerInterface $container,
47
        array $definitions = [],
48
        bool $validate = true,
49
        array $themes = [],
50
        ?string $defaultTheme = null,
51
    ): void {
52 35
        self::$factory = new Factory($container, $definitions, $validate);
53
54 35
        if ($validate) {
55 35
            self::assertThemesStructure($themes);
56
        }
57 30
        self::$themes = $themes;
58 30
        self::$defaultTheme = $defaultTheme;
59
    }
60
61 1
    public static function setDefaultTheme(?string $theme): void
62
    {
63 1
        self::$defaultTheme = $theme;
64
    }
65
66
    /**
67
     * Creates a widget defined by config passed.
68
     *
69
     * @param array $config The parameters for creating a widget.
70
     * @param string|null $theme The widget theme.
71
     *
72
     * @throws WidgetFactoryInitializationException If factory was not initialized.
73
     * @throws CircularReferenceException
74
     * @throws InvalidConfigException
75
     * @throws NotFoundException
76
     * @throws NotInstantiableException
77
     *
78
     * @see Factory::create()
79
     *
80
     * @psalm-suppress MixedInferredReturnType
81
     * @psalm-suppress MixedReturnStatement
82
     */
83 28
    public static function createWidget(array $config, ?string $theme = null): Widget
84
    {
85 28
        if (self::$factory === null) {
86 1
            throw new WidgetFactoryInitializationException(
87 1
                'Widget factory should be initialized with WidgetFactory::initialize() call.',
88 1
            );
89
        }
90
91 27
        $theme ??= self::$defaultTheme;
92
93 27
        if ($theme !== null && isset(self::$themes[$theme])) {
94
            /** @var mixed $className */
95 6
            $className = $config[ArrayDefinition::CLASS_NAME] ?? null;
96 6
            if (is_string($className) && isset(self::$themes[$theme][$className])) {
97 6
                $config = ArrayDefinitionHelper::merge(
98 6
                    self::$themes[$theme][$className],
99 6
                    $config
100 6
                );
101
            }
102
        }
103
104 27
        return self::$factory->create($config);
105
    }
106
107
    /**
108
     * @throws InvalidConfigException
109
     */
110 35
    private static function assertThemesStructure(array $themes): void
111
    {
112
        /** @var mixed $definitions */
113 35
        foreach ($themes as $theme => $definitions) {
114 15
            if (!is_string($theme)) {
115 1
                throw new InvalidConfigException(
116 1
                    sprintf('Theme name must be a string. Integer value "%s" given.', $theme)
117 1
                );
118
            }
119 14
            if (!is_array($definitions)) {
120 1
                throw new InvalidConfigException(
121 1
                    sprintf(
122 1
                        'Theme configuration must be an array. "%s" given for theme "%s".',
123 1
                        get_debug_type($definitions),
124 1
                        $theme,
125 1
                    )
126 1
                );
127
            }
128
            /** @var mixed $definition */
129 13
            foreach ($definitions as $id => $definition) {
130 13
                if (!is_string($id)) {
131 1
                    throw new InvalidConfigException(
132 1
                        sprintf('Widget name must be a string. Integer value "%s" given in theme "%s".', $id, $theme)
133 1
                    );
134
                }
135 12
                if (!is_array($definition)) {
136 1
                    throw new InvalidConfigException(
137 1
                        sprintf(
138 1
                            'Widget themes supports array definitions only. "%s" given for "%s" definition in "%s" theme.',
139 1
                            get_debug_type($definition),
140 1
                            $id,
141 1
                            $theme,
142 1
                        )
143 1
                    );
144
                }
145 11
                DefinitionValidator::validateArrayDefinition($definition, $id);
146
            }
147
        }
148
    }
149
}
150