Passed
Push — master ( ae0c00...465be9 )
by Sergei
02:21
created

Widget::render()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10

1 Method

Rating   Name   Duplication   Size   Complexity  
A Widget::__toString() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Widget;
6
7
use RuntimeException;
8
use Stringable;
9
use Yiisoft\Definitions\Exception\CircularReferenceException;
10
use Yiisoft\Definitions\Exception\InvalidConfigException;
11
use Yiisoft\Definitions\Exception\NotInstantiableException;
12
use Yiisoft\Factory\NotFoundException;
13
use Yiisoft\Html\NoEncodeStringableInterface;
14
15
use function array_key_exists;
16
use function array_pop;
17
use function is_array;
18
use function sprintf;
19
20
/**
21
 * Widget generates a string content based on some logic and input data.
22
 * These are typically used in templates to conceal complex HTML rendering logic.
23
 *
24
 * This is the base class that is meant to be inherited when implementing your own widgets.
25
 */
26
abstract class Widget implements NoEncodeStringableInterface, Stringable
27
{
28
    /**
29
     * The widgets that are currently opened and not yet closed.
30
     * This property is maintained by {@see begin()} and {@see end()} methods.
31
     *
32
     * @var static[]
33
     */
34
    private static array $stack = [];
35
36
    /**
37
     * Used to open a wrapping widget (the one with begin/end).
38
     *
39
     * When implementing this method, don't forget to call `parent::begin()`.
40
     *
41
     * @return string|null Opening part of widget markup.
42
     */
43 4
    public function begin(): ?string
44
    {
45 4
        self::$stack[] = $this;
46 4
        return null;
47
    }
48
49
    /**
50
     * Checks that the widget was opened with {@see begin()}. If so, runs it and returns content generated.
51
     *
52
     * @throws RuntimeException
53
     */
54 7
    final public static function end(): string
55
    {
56 7
        if (self::$stack === []) {
57 3
            throw new RuntimeException(sprintf(
58 3
                'Unexpected "%s::end()" call. A matching "%s::begin()" is not found.',
59 3
                static::class,
60 3
                static::class,
61 3
            ));
62
        }
63
64 4
        $widget = array_pop(self::$stack);
65 4
        $widgetClass = $widget::class;
66
67 4
        if ($widgetClass !== static::class) {
68 1
            throw new RuntimeException(sprintf(
69 1
                'Expecting "%s::end()" call, found "%s::end()".',
70 1
                $widgetClass,
71 1
                static::class,
72 1
            ));
73
        }
74
75 3
        return (string) $widget->render();
76
    }
77
78
    /**
79
     * Creates a widget instance.
80
     *
81
     * @param array|callable|string $config The parameters for creating a widget.
82
     *
83
     * @throws InvalidConfigException
84
     * @throws CircularReferenceException
85
     * @throws NotInstantiableException
86
     * @throws NotFoundException
87
     *
88
     * @return static The widget instance.
89
     */
90 14
    final public static function widget(array|callable|string $config = []): self
91
    {
92 14
        if (is_array($config) && !array_key_exists('class', $config)) {
93 14
            $config['class'] = static::class;
94
        }
95
96 14
        return WidgetFactory::createWidget($config);
97
    }
98
99
    /**
100
     * Allows not to call `->render()` explicitly:
101
     *
102
     * ```php
103
     * <?= MyWidget::widget(); ?>
104
     * ```
105
     */
106 1
    final public function __toString(): string
107
    {
108 1
        return (string) $this->render();
109
    }
110
111
    /**
112
     * Renders widget content.
113
     *
114
     * This method must be overridden when implementing concrete widget.
115
     *
116
     * @return string|Stringable The result of widget execution to be outputted.
117
     */
118
    abstract public function render(): string|Stringable;
119
}
120