Completed
Pull Request — master (#57)
by Wilmer
02:10
created

Widget::run()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2
1
<?php
2
declare(strict_types = 1);
3
4
namespace Yiisoft\Widget;
5
6
use ReflectionClass;
7
use Psr\EventDispatcher\EventDispatcherInterface;
8
use Yiisoft\View\ViewContextInterface;
9
use Yiisoft\View\WebView;
10
use Yiisoft\Widget\Event\AfterRun;
11
use Yiisoft\Widget\Event\BeforeRun;
12
use Yiisoft\Widget\Exception\InvalidConfigException;
13
14
/**
15
 * Widget is the base class for widgets.
16
 *
17
 * For more details and usage information on Widget, see the [guide article on widgets](guide:structure-widgets).
18
 */
19
class Widget
20
{
21
    /**
22
     * @var EventDispatcherInterface $eventDispatcher
23
     */
24
    private $eventDispatcher;
25
26
    /**
27
     * The widgets that are currently being rendered (not ended). This property is maintained by {@see begin()} and
28
     * {@see end} methods.
29
     *
30
     * @var Widget[] $stack
31
     */
32
    private $stack;
33
34 27
    public function __construct(WebView $webView)
35
    {
36 27
        $this->eventDispatcher = $webView->getEventDispatcher();
37
    }
38
39
    /**
40
     * Begin the rendering of content.
41
     *
42
     * @return Widget
43
     */
44 9
    public function begin(): Widget
45
    {
46 9
        $this->stack[] = $this;
47 9
        $this->init();
0 ignored issues
show
Bug introduced by
The method init() does not exist on Yiisoft\Widget\Widget. It seems like you code against a sub-type of said class. However, the method does not exist in Yiisoft\Widget\Tests\Stubs\TestWidget or Yiisoft\Widget\Menu or Yiisoft\Widget\Breadcrumbs. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

47
        $this->/** @scrutinizer ignore-call */ 
48
               init();
Loading history...
48
49 9
        return $this;
50
    }
51
52
    /**
53
     * Ends the rendering of content.
54
     *
55
     * @param string $class
56
     *
57
     * @return Widget
58
     */
59 10
    public function end(): Widget
60
    {
61 10
        if (!empty($this->stack)) {
62 8
            $widget = array_pop($this->stack);
63
64 8
            if (get_class($widget) === get_called_class()) {
65
                /* @var $widget Widget */
66 8
                if ($widget->beforeRun()) {
67 8
                    $result = $widget->run();
68 8
                    $result = $widget->afterRun($result);
69 8
                    echo $result;
70
                }
71 8
                return $widget;
72
            }
73
            throw new InvalidConfigException(
74
                'Expecting end() of ' . get_class($widget) . ', found ' . get_called_class()
75
            );
76
        }
77 2
        throw new InvalidConfigException(
78 2
            'Unexpected ' . get_called_class() . '::end() call. A matching begin() is not found.'
79
        );
80
    }
81
82
    /**
83
     * Executes the widget.
84
     *
85
     * @return string the result of widget execution to be outputted.
86
     */
87 16
    public function run(): string
88
    {
89 16
        $out = '';
90
91 16
        if ($this->beforeRun()) {
92 16
            $result = $this->getContent();
0 ignored issues
show
Bug introduced by
The method getContent() does not exist on Yiisoft\Widget\Widget. It seems like you code against a sub-type of Yiisoft\Widget\Widget such as Yiisoft\Widget\Tests\Stubs\TestWidget or Yiisoft\Widget\Menu or Yiisoft\Widget\Breadcrumbs. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

92
            /** @scrutinizer ignore-call */ 
93
            $result = $this->getContent();
Loading history...
93 16
            $out = $this->afterRun($result);
94
        }
95
96 16
        return $out;
97
    }
98
99
    /**
100
     * This method is invoked right before the widget is executed.
101
     *
102
     * The method will trigger the {@see BeforeRun()} event. The return value of the method will determine whether the
103
     * widget should continue to run.
104
     *
105
     * When overriding this method, make sure you call the parent implementation like the following:
106
     *
107
     * ```php
108
     * public function beforeRun()
109
     * {
110
     *     if (!parent::beforeRun()) {
111
     *         return false;
112
     *     }
113
     *
114
     *     // your custom code here
115
     *
116
     *     return true; // or false to not run the widget
117
     * }
118
     * ```
119
     *
120
     * @return bool whether the widget should continue to be executed.
121
     */
122 24
    public function beforeRun(): bool
123
    {
124 24
        $event = new BeforeRun();
125 24
        $event = $this->eventDispatcher->dispatch($event);
126
127 24
        return !$event->isPropagationStopped();
128
    }
129
130
    /**
131
     * This method is invoked right after a widget is executed.
132
     *
133
     * The method will trigger the {@see AfterRun()} event. The return value of the method will be used as the widget
134
     * return value.
135
     *
136
     * If you override this method, your code should look like the following:
137
     *
138
     * ```php
139
     * public function afterRun($result)
140
     * {
141
     *     $result = parent::afterRun($result);
142
     *     // your custom code here
143
     *     return $result;
144
     * }
145
     * ```
146
     *
147
     * @param mixed $result the widget return result.
148
     *
149
     * @return mixed the processed widget result.
150
     */
151 24
    public function afterRun($result)
152
    {
153 24
        $event = new AfterRun($result);
154 24
        $event = $this->eventDispatcher->dispatch($event);
155
156 24
        return $event->getResult();
157
    }
158
}
159