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 as FactoryNotInstantiableException; |
||
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 bool $initialized = false; |
||
25 | private static ?Factory $factory = null; |
||
26 | |||
27 | /** |
||
28 | * @psalm-var array<string, array<string, array>> |
||
29 | */ |
||
30 | private static array $themes = []; |
||
31 | |||
32 | private static ?string $defaultTheme = null; |
||
33 | |||
34 | /** |
||
35 | * @psalm-var array<string, string> |
||
36 | */ |
||
37 | private static array $widgetDefaultThemes = []; |
||
38 | |||
39 | /** |
||
40 | * @codeCoverageIgnore |
||
41 | */ |
||
42 | private function __construct() |
||
43 | { |
||
44 | } |
||
45 | |||
46 | /** |
||
47 | * @psalm-param array<string, mixed> $definitions |
||
48 | * @psalm-param array<string, array<string, array>> $themes |
||
49 | * @psalm-param array<string, string> $widgetDefaultThemes |
||
50 | * |
||
51 | * @throws InvalidConfigException |
||
52 | * |
||
53 | * @see Factory::__construct() |
||
54 | */ |
||
55 | 42 | public static function initialize( |
|
56 | ?ContainerInterface $container = null, |
||
57 | array $definitions = [], |
||
58 | bool $validate = true, |
||
59 | array $themes = [], |
||
60 | ?string $defaultTheme = null, |
||
61 | array $widgetDefaultThemes = [], |
||
62 | ): void { |
||
63 | 42 | self::$factory = new Factory($container, $definitions, $validate); |
|
64 | |||
65 | 42 | if ($validate) { |
|
66 | 42 | self::assertThemesStructure($themes); |
|
67 | 37 | self::assertWidgetDefaultThemesStructure($widgetDefaultThemes); |
|
68 | } |
||
69 | |||
70 | 35 | self::$themes = $themes; |
|
71 | 35 | self::$defaultTheme = $defaultTheme; |
|
72 | 35 | self::$widgetDefaultThemes = $widgetDefaultThemes; |
|
73 | |||
74 | 35 | self::$initialized = true; |
|
75 | } |
||
76 | |||
77 | 1 | public static function setDefaultTheme(?string $theme): void |
|
78 | { |
||
79 | 1 | self::$defaultTheme = $theme; |
|
80 | } |
||
81 | |||
82 | /** |
||
83 | * Creates a widget defined by config passed. |
||
84 | * |
||
85 | * @param array $config The parameters for creating a widget. |
||
86 | * @param string|null $theme The widget theme. |
||
87 | * |
||
88 | * @throws CircularReferenceException |
||
89 | * @throws InvalidConfigException |
||
90 | * @throws NotFoundException |
||
91 | * @throws FactoryNotInstantiableException |
||
92 | * |
||
93 | * @see Factory::create() |
||
94 | * |
||
95 | * @psalm-suppress MixedInferredReturnType |
||
96 | * @psalm-suppress MixedReturnStatement |
||
97 | */ |
||
98 | 33 | public static function createWidget(array $config, ?string $theme = null): Widget |
|
99 | { |
||
100 | 33 | if (self::$factory === null) { |
|
101 | 2 | self::$factory = new Factory(); |
|
102 | } |
||
103 | |||
104 | 33 | $className = $config[ArrayDefinition::CLASS_NAME] ?? null; |
|
105 | 33 | if (is_string($className)) { |
|
106 | 33 | $theme ??= self::$widgetDefaultThemes[$className] ?? self::$defaultTheme; |
|
107 | 33 | if ($theme !== null && isset(self::$themes[$theme][$className])) { |
|
108 | 9 | $config = ArrayDefinitionHelper::merge( |
|
109 | 9 | self::$themes[$theme][$className], |
|
110 | 9 | $config |
|
111 | 9 | ); |
|
112 | } |
||
113 | } |
||
114 | |||
115 | try { |
||
116 | 33 | return self::$factory->create($config); |
|
0 ignored issues
–
show
|
|||
117 | 2 | } catch (FactoryNotInstantiableException $exception) { |
|
118 | /** |
||
119 | * @var string $className When `$className` is not string, `$factory->create()` does not throw |
||
120 | * {@see FactoryNotInstantiableException} exception. |
||
121 | */ |
||
122 | 2 | throw new NotInstantiableException($className, self::$initialized, $exception); |
|
123 | } |
||
124 | } |
||
125 | |||
126 | /** |
||
127 | * @throws InvalidConfigException |
||
128 | */ |
||
129 | 42 | private static function assertThemesStructure(array $themes): void |
|
130 | { |
||
131 | 42 | foreach ($themes as $theme => $definitions) { |
|
132 | 18 | if (!is_string($theme)) { |
|
133 | 1 | throw new InvalidConfigException( |
|
134 | 1 | sprintf('Theme name must be a string. Integer value "%s" given.', $theme) |
|
135 | 1 | ); |
|
136 | } |
||
137 | 17 | if (!is_array($definitions)) { |
|
138 | 1 | throw new InvalidConfigException( |
|
139 | 1 | sprintf( |
|
140 | 1 | 'Theme configuration must be an array. "%s" given for theme "%s".', |
|
141 | 1 | get_debug_type($definitions), |
|
142 | 1 | $theme, |
|
143 | 1 | ) |
|
144 | 1 | ); |
|
145 | } |
||
146 | 16 | foreach ($definitions as $id => $definition) { |
|
147 | 16 | if (!is_string($id)) { |
|
148 | 1 | throw new InvalidConfigException( |
|
149 | 1 | sprintf('Widget name must be a string. Integer value "%s" given in theme "%s".', $id, $theme) |
|
150 | 1 | ); |
|
151 | } |
||
152 | 15 | if (!is_array($definition)) { |
|
153 | 1 | throw new InvalidConfigException( |
|
154 | 1 | sprintf( |
|
155 | 1 | 'Widget themes supports array definitions only. "%s" given for "%s" definition in "%s" theme.', |
|
156 | 1 | get_debug_type($definition), |
|
157 | 1 | $id, |
|
158 | 1 | $theme, |
|
159 | 1 | ) |
|
160 | 1 | ); |
|
161 | } |
||
162 | 14 | DefinitionValidator::validateArrayDefinition($definition, $id); |
|
163 | } |
||
164 | } |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * @throws InvalidConfigException |
||
169 | */ |
||
170 | 37 | private static function assertWidgetDefaultThemesStructure(array $value): void |
|
171 | { |
||
172 | 37 | foreach ($value as $widget => $theme) { |
|
173 | 5 | if (!is_string($widget)) { |
|
174 | 1 | throw new InvalidConfigException( |
|
175 | 1 | sprintf('Widget class must be a string. Integer value "%s" given.', $widget) |
|
176 | 1 | ); |
|
177 | } |
||
178 | 4 | if (!is_string($theme)) { |
|
179 | 1 | throw new InvalidConfigException( |
|
180 | 1 | sprintf( |
|
181 | 1 | 'Theme name must be a string. "%s" given for widget "%s".', |
|
182 | 1 | get_debug_type($theme), |
|
183 | 1 | $widget, |
|
184 | 1 | ) |
|
185 | 1 | ); |
|
186 | } |
||
187 | } |
||
188 | } |
||
189 | } |
||
190 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.