Passed
Push — master ( 323966...c1edad )
by Alexander
26:08 queued 23:42
created

assertWidgetDefaultThemesStructure()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 10
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 14
ccs 12
cts 12
cp 1
crap 4
rs 9.9332
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
    /**
34
     * @psalm-var array<string, string>
35
     */
36
    private static array $widgetDefaultThemes = [];
37
38
    private function __construct()
39
    {
40
    }
41
42
    /**
43
     * @psalm-param array<string, mixed> $definitions
44
     * @psalm-param array<string, array<string, array>> $themes
45
     * @psalm-param array<string, string> $widgetDefaultThemes
46
     *
47
     * @throws InvalidConfigException
48
     *
49
     * @see Factory::__construct()
50
     */
51 40
    public static function initialize(
52
        ContainerInterface $container,
53
        array $definitions = [],
54
        bool $validate = true,
55
        array $themes = [],
56
        ?string $defaultTheme = null,
57
        array $widgetDefaultThemes = [],
58
    ): void {
59 40
        self::$factory = new Factory($container, $definitions, $validate);
60
61 40
        if ($validate) {
62 40
            self::assertThemesStructure($themes);
63 35
            self::assertWidgetDefaultThemesStructure($widgetDefaultThemes);
64
        }
65
66 33
        self::$themes = $themes;
67 33
        self::$defaultTheme = $defaultTheme;
68 33
        self::$widgetDefaultThemes = $widgetDefaultThemes;
69
    }
70
71 1
    public static function setDefaultTheme(?string $theme): void
72
    {
73 1
        self::$defaultTheme = $theme;
74
    }
75
76
    /**
77
     * Creates a widget defined by config passed.
78
     *
79
     * @param array $config The parameters for creating a widget.
80
     * @param string|null $theme The widget theme.
81
     *
82
     * @throws WidgetFactoryInitializationException If factory was not initialized.
83
     * @throws CircularReferenceException
84
     * @throws InvalidConfigException
85
     * @throws NotFoundException
86
     * @throws NotInstantiableException
87
     *
88
     * @see Factory::create()
89
     *
90
     * @psalm-suppress MixedInferredReturnType
91
     * @psalm-suppress MixedReturnStatement
92
     */
93 31
    public static function createWidget(array $config, ?string $theme = null): Widget
94
    {
95 31
        if (self::$factory === null) {
96 1
            throw new WidgetFactoryInitializationException(
97 1
                'Widget factory should be initialized with WidgetFactory::initialize() call.',
98 1
            );
99
        }
100
101 30
        $className = $config[ArrayDefinition::CLASS_NAME] ?? null;
102 30
        if (is_string($className)) {
103 30
            $theme ??= self::$widgetDefaultThemes[$className] ?? self::$defaultTheme;
104 30
            if ($theme !== null && isset(self::$themes[$theme][$className])) {
105 9
                $config = ArrayDefinitionHelper::merge(
106 9
                    self::$themes[$theme][$className],
107 9
                    $config
108 9
                );
109
            }
110
        }
111
112 30
        return self::$factory->create($config);
113
    }
114
115
    /**
116
     * @throws InvalidConfigException
117
     */
118 40
    private static function assertThemesStructure(array $themes): void
119
    {
120 40
        foreach ($themes as $theme => $definitions) {
121 18
            if (!is_string($theme)) {
122 1
                throw new InvalidConfigException(
123 1
                    sprintf('Theme name must be a string. Integer value "%s" given.', $theme)
124 1
                );
125
            }
126 17
            if (!is_array($definitions)) {
127 1
                throw new InvalidConfigException(
128 1
                    sprintf(
129 1
                        'Theme configuration must be an array. "%s" given for theme "%s".',
130 1
                        get_debug_type($definitions),
131 1
                        $theme,
132 1
                    )
133 1
                );
134
            }
135 16
            foreach ($definitions as $id => $definition) {
136 16
                if (!is_string($id)) {
137 1
                    throw new InvalidConfigException(
138 1
                        sprintf('Widget name must be a string. Integer value "%s" given in theme "%s".', $id, $theme)
139 1
                    );
140
                }
141 15
                if (!is_array($definition)) {
142 1
                    throw new InvalidConfigException(
143 1
                        sprintf(
144 1
                            'Widget themes supports array definitions only. "%s" given for "%s" definition in "%s" theme.',
145 1
                            get_debug_type($definition),
146 1
                            $id,
147 1
                            $theme,
148 1
                        )
149 1
                    );
150
                }
151 14
                DefinitionValidator::validateArrayDefinition($definition, $id);
152
            }
153
        }
154
    }
155
156
    /**
157
     * @throws InvalidConfigException
158
     */
159 35
    private static function assertWidgetDefaultThemesStructure(array $value): void
160
    {
161 35
        foreach ($value as $widget => $theme) {
162 5
            if (!is_string($widget)) {
163 1
                throw new InvalidConfigException(
164 1
                    sprintf('Widget class must be a string. Integer value "%s" given.', $widget)
165 1
                );
166
            }
167 4
            if (!is_string($theme)) {
168 1
                throw new InvalidConfigException(
169 1
                    sprintf(
170 1
                        'Theme name must be a string. "%s" given for widget "%s".',
171 1
                        get_debug_type($theme),
172 1
                        $widget,
173 1
                    )
174 1
                );
175
            }
176
        }
177
    }
178
}
179