Passed
Push — master ( 362089...a7fd52 )
by Iman
03:08
created

WidgetRenderer   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Test Coverage

Coverage 86.54%

Importance

Changes 14
Bugs 5 Features 0
Metric Value
eloc 50
c 14
b 5
f 0
dl 0
loc 152
ccs 45
cts 52
cp 0.8654
rs 10
wmc 20

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A makeWidgetObj() 0 9 2
A renderWidget() 0 19 4
A generateHtml() 0 15 2
A renderTemplate() 0 23 4
A callController() 0 12 4
A makeDataForView() 0 17 3
1
<?php
2
3
namespace Imanghafoori\Widgets\Utils;
4
5
class WidgetRenderer
6
{
7
    public $html;
8
9
    private $_viewData;
10
11
    private $_policies;
12
13
    /**
14
     * BaseWidget constructor.
15
     */
16 20
    public function __construct()
17
    {
18 20
        $this->_policies = app(Policies::class);
19 20
    }
20
21
    /**
22
     * @param $widget object|string
23
     * @param array $args
24
     * @return string
25
     */
26 20
    public function renderWidget($widget, ...$args)
27
    {
28 20
        if (is_string($widget)) {
29 1
            $widget = $this->makeWidgetObj($widget);
30
        }
31
32 20
        if (is_array($widget)) {
33
            $widget = (object) $widget;
34
        }
35
36 20
        event('widgetize.rendering_widget', [$widget]);
37
38 20
        app(Normalizer::class)->normalizeWidgetConfig($widget);
39
40 20
        if (app()->offsetExists('debugbar')) {
41
            app('widgetize.debugger')->addMessage(['widget class:' => $widget, 'args:' => $args]);
42
        }
43
44 20
        return $this->generateHtml($widget, ...$args);
45
    }
46
47
    /**
48
     * @param $widget object
49
     * @return \Illuminate\Foundation\Application|mixed
50
     */
51 1
    private function makeWidgetObj($widget)
52
    {
53 1
        if (starts_with($widget, ['\\'])) {
54
            return app($widget);
55
        }
56
57 1
        $widget = app()->getNamespace().'Widgets\\'.$widget;
0 ignored issues
show
introduced by
The method getNamespace() does not exist on Illuminate\Container\Container. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

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

57
        $widget = app()->/** @scrutinizer ignore-call */ getNamespace().'Widgets\\'.$widget;
Loading history...
58
59 1
        return app($widget);
60
    }
61
62
    /**
63
     * It tries to get the html from cache if possible, otherwise generates it.
64
     *
65
     * @param $widget object
66
     * @param array ...$args
67
     *
68
     * @return string
69
     */
70
    private function generateHtml($widget, ...$args)
71
    {
72
        // Everything inside this function is executed only when the cache is not available.
73 20
        $expensivePhpCode = function () use ($widget, $args) {
74 18
            $this->makeDataForView($widget, $args);
75
76 18
            return $this->renderTemplate($widget, ...$args);
0 ignored issues
show
Bug introduced by
$args is expanded, but the parameter $args of Imanghafoori\Widgets\Uti...derer::renderTemplate() does not expect variable arguments. ( Ignorable by Annotation )

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

76
            return $this->renderTemplate($widget, /** @scrutinizer ignore-type */ ...$args);
Loading history...
77 20
        };
78
79 20
        if (! $widget->cacheView) {
80 2
            return $expensivePhpCode();
81
        }
82
83
        // We first try to get the output from the cache before trying to run the expensive $expensivePhpCode...
84 19
        return app(Cache::class)->cacheResult($args, $expensivePhpCode, $widget);
0 ignored issues
show
Bug introduced by
Are you sure the usage of app(Imanghafoori\Widgets...ensivePhpCode, $widget) targeting Imanghafoori\Widgets\Utils\Cache::cacheResult() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
85
    }
86
87
    /**
88
     * @param $widget object
89
     * @param $args array
90
     *
91
     * @return null
92
     */
93
    private function makeDataForView($widget, array $args)
94
    {
95 18
        $expensiveCode = function () use ($widget, $args) {
96 18
            $viewData = $this->callController($widget, $args);
97
98 18
            if ($widget->presenter) {
99
                // Pipe the data through the presenter before sending it to view.
100 1
                $viewData = \App::call($widget->presenter, [$viewData]);
101
            }
102
103 18
            return $viewData;
104 18
        };
105
106 18
        if ($widget->cacheView) {
107 17
            $this->_viewData = $expensiveCode();
108
        } else {
109 2
            $this->_viewData = app(Cache::class)->cacheResult($args, $expensiveCode, $widget, 'dataProvider');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $this->_viewData is correct as app(Imanghafoori\Widgets...widget, 'dataProvider') targeting Imanghafoori\Widgets\Utils\Cache::cacheResult() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
110
        }
111 18
    }
112
113
    /**
114
     * @param      $widget object
115
     * @param null $args
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $args is correct as it would always require null to be passed?
Loading history...
116
     *
117
     * @throws \Throwable
118
     * @return string HTML output
119
     */
120 18
    private function renderTemplate($widget, $args = null)
121
    {
122
        // Here we render the view file to raw html.
123 18
        $data = [$widget->contextAs => $this->_viewData, 'params' => $args];
124
125
        try {
126 18
            $this->html = view($widget->template, $data)->render();
127
        } catch (\Throwable $t) {
128
            throw new \ErrorException('There was some error rendering '.get_class($widget).', template file: \''.$widget->template.'\' Error: '.$t->getMessage());
129
        }
130
131
        // We try to minify the html before storing it in cache to save space.
132 18
        if ($this->_policies->widgetShouldBeMinified($widget)) {
133 9
            $this->html = app(HtmlMinifier::class)->minify($this->html);
134
        }
135
136
        // We add some HTML comments before and after the widget output
137
        // So then, we will be able to easily identify the widget in browser's developer tool.
138 18
        if ($this->_policies->widgetShouldHaveDebugInfo()) {
139 8
            $this->html = app(DebugInfo::class)->addIdentifierToHtml($widget, $this->html);
140
        }
141
142 18
        return $this->html;
143
    }
144
145 18
    private function callController($widget, array $args)
146
    {
147 18
        if (! isset($widget->controller)) {
148
            $viewData = [];
149 18
        } elseif (is_array($widget->controller) && is_string($widget->controller[0])) {
150
            $viewData = call_user_func_array($widget->controller, $args);
151
        } else {
152
            // Here we call the data method on the widget class.
153 18
            $viewData = \App::call($widget->controller, ...$args);
0 ignored issues
show
Bug introduced by
$args is expanded, but the parameter $parameters of Illuminate\Foundation\Application::call() does not expect variable arguments. ( Ignorable by Annotation )

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

153
            $viewData = \App::call($widget->controller, /** @scrutinizer ignore-type */ ...$args);
Loading history...
154
        }
155
156 18
        return $viewData;
157
    }
158
}
159