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

Widget::getDefaultConfig()   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 0
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 RuntimeException;
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\Factory\NotFoundException;
14
use Yiisoft\Html\NoEncodeStringableInterface;
15
16
use function array_pop;
17
use function sprintf;
18
19
/**
20
 * Widget generates a string content based on some logic and input data.
21
 * These are typically used in templates to conceal complex HTML rendering logic.
22
 *
23
 * This is the base class that is meant to be inherited when implementing your own widgets.
24
 */
25
abstract class Widget implements NoEncodeStringableInterface
26
{
27
    /**
28
     * The widgets that are currently opened and not yet closed.
29
     * This property is maintained by {@see begin()} and {@see end()} methods.
30
     *
31
     * @var static[]
32
     */
33
    private static array $stack = [];
34
35
    /**
36
     * Used to open a wrapping widget (the one with begin/end).
37
     *
38
     * When implementing this method, don't forget to call `parent::begin()`.
39
     *
40
     * @return string|null Opening part of widget markup.
41
     */
42 4
    public function begin(): ?string
43
    {
44 4
        self::$stack[] = $this;
45 4
        return null;
46
    }
47
48
    /**
49
     * Checks that the widget was opened with {@see begin()}. If so, runs it and returns content generated.
50
     *
51
     * @throws RuntimeException
52
     */
53 7
    final public static function end(): string
54
    {
55 7
        if (self::$stack === []) {
56 3
            throw new RuntimeException(sprintf(
57 3
                'Unexpected "%s::end()" call. A matching "%s::begin()" is not found.',
58 3
                static::class,
59 3
                static::class,
60 3
            ));
61
        }
62
63 4
        $widget = array_pop(self::$stack);
64 4
        $widgetClass = $widget::class;
65
66 4
        if ($widgetClass !== static::class) {
67 1
            throw new RuntimeException(sprintf(
68 1
                'Expecting "%s::end()" call, found "%s::end()".',
69 1
                $widgetClass,
70 1
                static::class,
71 1
            ));
72
        }
73
74 3
        return $widget->render();
75
    }
76
77
    /**
78
     * Creates a widget instance.
79
     *
80
     * @param array $constructorArguments The constructor arguments.
81
     * @param array $config The configuration for creating a widget. For a description of the configuration syntax, see
82
     * array definitions documentation in the Yii Definitions by link
83
     * {@link https://github.com/yiisoft/definitions#arraydefinition).
84
     * @param string|null $theme The widget theme.
85
     *
86
     * @throws InvalidConfigException
87
     * @throws CircularReferenceException
88
     * @throws NotInstantiableException
89
     * @throws NotFoundException
90
     *
91
     * @return static The widget instance.
92
     */
93 29
    final public static function widget(
94
        array $constructorArguments = [],
95
        array $config = [],
96
        ?string $theme = null
97
    ): static {
98 29
        $config = ArrayDefinitionHelper::merge(
99 29
            static::getThemeConfig($theme),
100 29
            $config,
101 29
            empty($constructorArguments) ? [] : [ArrayDefinition::CONSTRUCTOR => $constructorArguments],
102 29
        );
103
104 28
        $config[ArrayDefinition::CLASS_NAME] = static::class;
105
106 28
        return WidgetFactory::createWidget($config, $theme);
107
    }
108
109
    /**
110
     * Returns configuration that will be merged with configuration passed to {@see widget()} method.
111
     *
112
     * @param string|null $theme The widget theme.
113
     *
114
     * @return array Configuration in the form of array definition (see syntax description in the Yii Definitions
115
     * documentation by link {@link https://github.com/yiisoft/definitions#arraydefinition}).
116
     *
117
     * @infection-ignore-all
118
     */
119 28
    protected static function getThemeConfig(?string $theme): array
120
    {
121 28
        return [];
122
    }
123
124
    /**
125
     * Allows not to call `->render()` explicitly:
126
     *
127
     * ```php
128
     * <?= MyWidget::widget(); ?>
129
     * ```
130
     */
131 1
    final public function __toString(): string
132
    {
133 1
        return $this->render();
134
    }
135
136
    /**
137
     * Renders widget content.
138
     *
139
     * This method must be overridden when implementing concrete widget.
140
     *
141
     * @return string The result of widget execution to be outputted.
142
     */
143
    abstract public function render(): string;
144
}
145