Passed
Push — master ( a99469...d0154e )
by Sergei
02:23
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
     *
85
     * @throws InvalidConfigException
86
     * @throws CircularReferenceException
87
     * @throws NotInstantiableException
88
     * @throws NotFoundException
89
     *
90
     * @return static The widget instance.
91
     */
92 17
    final public static function widget(array $constructorArguments = [], array $config = []): static
93
    {
94 17
        $config = ArrayDefinitionHelper::merge(
95 17
            static::getDefaultConfig(),
96 17
            $config,
97 17
            empty($constructorArguments) ? [] : [ArrayDefinition::CONSTRUCTOR => $constructorArguments],
98 17
        );
99
100 16
        $config[ArrayDefinition::CLASS_NAME] = static::class;
101
102 16
        return WidgetFactory::createWidget($config);
103
    }
104
105 17
    protected static function getDefaultConfig(): array
106
    {
107 17
        return [];
108
    }
109
110
    /**
111
     * Allows not to call `->render()` explicitly:
112
     *
113
     * ```php
114
     * <?= MyWidget::widget(); ?>
115
     * ```
116
     */
117 1
    final public function __toString(): string
118
    {
119 1
        return $this->render();
120
    }
121
122
    /**
123
     * Renders widget content.
124
     *
125
     * This method must be overridden when implementing concrete widget.
126
     *
127
     * @return string The result of widget execution to be outputted.
128
     */
129
    abstract public function render(): string;
130
}
131