Passed
Push — master ( d51216...708e0d )
by Iman
02:30
created

WidgetRenderer::printError()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 6
ccs 0
cts 4
cp 0
crap 6
rs 10
1
<?php
2
3
namespace Imanghafoori\Widgets\Utils;
4
5
use Illuminate\Contracts\Debug\ExceptionHandler;
6
use Illuminate\Support\Str;
7
8
class WidgetRenderer
9
{
10
    public $html;
11
12
    private $_viewData;
13
14
    private $_policies;
15
16
    /**
17
     * BaseWidget constructor.
18
     */
19 20
    public function __construct()
20
    {
21 20
        $this->_policies = app(Policies::class);
22 20
    }
23
24
    /**
25
     * @param $widget object|string
26
     * @param array $args
27
     * @return string
28
     */
29 20
    public function renderWidget($widget, ...$args)
30
    {
31 20
        if (is_string($widget)) {
32 1
            $widget = $this->makeWidgetObj($widget);
33
        }
34 20
        event('widgetize.rendering_widget', [$widget]);
35
36 20
        app(Normalizer::class)->normalizeWidgetConfig($widget);
37
38 20
        if (app()->offsetExists('debugbar')) {
39
            app('widgetize.debugger')->addMessage(['widget class:' => $widget, 'args:' => $args]);
40
        }
41
42
        try {
43 20
            $html = $this->generateHtml($widget, ...$args);
44
        } catch (\Exception $e) {
45
46
            return app()->make(ExceptionHandler::class)->render(app('request'), $e)->send();
47
        }
48
49 20
        return $html;
50
    }
51
52
    /**
53
     * @param $widget object
54
     * @return \Illuminate\Foundation\Application|mixed
55
     */
56 1
    private function makeWidgetObj($widget)
57
    {
58 1
        if (starts_with($widget, ['\\'])) {
59
            return app($widget);
60
        }
61
62 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

62
        $widget = app()->/** @scrutinizer ignore-call */ getNamespace().'Widgets\\'.$widget;
Loading history...
63
64 1
        return app($widget);
65
    }
66
67
    /**
68
     * It tries to get the html from cache if possible, otherwise generates it.
69
     *
70
     * @param $widget object
71
     * @param array ...$args
72
     *
73
     * @return string
74
     */
75
    private function generateHtml($widget, ...$args)
76
    {
77
        // Everything inside this function is executed only when the cache is not available.
78 20
        $expensivePhpCode = function () use ($widget, $args) {
79 18
            $this->makeDataForView($widget, $args);
80
81 18
            return $this->renderTemplate($widget);
82 20
        };
83
84 20
        if (! $widget->cacheView) {
85 2
            return $expensivePhpCode();
86
        }
87
88
        // We first try to get the output from the cache before trying to run the expensive $expensivePhpCode...
89 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...
90
    }
91
92
    /**
93
     * @param $widget object
94
     * @param $args array
95
     *
96
     * @return null
97
     */
98
    private function makeDataForView($widget, array $args)
99
    {
100 18
        $expensiveCode = function () use ($widget, $args) {
101
102
            // Here we call the data method on the widget class.
103 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

103
            $viewData = \App::call($widget->controller, /** @scrutinizer ignore-type */ ...$args);
Loading history...
104
105 18
            if (($widget->presenter)) {
106
                // We make an object and call the `present` method on it.
107
                // Piping the data through the presenter before sending it to view.
108 1
                $viewData = \App::call($widget->presenter, [$viewData]);
109
            }
110
111 18
            return $viewData;
112 18
        };
113
114 18
        if ($widget->cacheView) {
115 17
            $this->_viewData = $expensiveCode();
116
        } else {
117 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...
118
        }
119 18
    }
120
121
    /**
122
     * @param $widget object
123
     * @return string HTML output
124
     * @throws \Throwable
125
     */
126 18
    private function renderTemplate($widget)
127
    {
128
        // Here we render the view file to raw html.
129
        try {
130 18
            $this->html = view($widget->template, [$widget->contextAs => $this->_viewData])->render();
131
        } catch (\Exception $e) {
132
            $this->printError($widget, $e);
133
        }
134
135
        // We try to minify the html before storing it in cache to save space.
136 18
        if ($this->_policies->widgetShouldBeMinified($widget)) {
137 9
            $this->html = app(HtmlMinifier::class)->minify($this->html);
138
        }
139
140
        // We add some HTML comments before and after the widget output
141
        // So then, we will be able to easily identify the widget in browser's developer tool.
142 18
        if ($this->_policies->widgetShouldHaveDebugInfo()) {
143 8
            $this->html = app(DebugInfo::class)->addIdentifierToHtml($widget, $this->html);
144
        }
145
146 18
        return $this->html;
147
    }
148
149
    /**
150
     * @param            $widget
151
     * @param \Exception $e
152
     */
153
    private function printError($widget, \Exception $e): void
154
    {
155
        if (Str::contains($e->getMessage(), 'Undefined variable:')) {
156
            dump('You should use the "$'.$widget->contextAs.'" variable in your widget view to access controller data');
157
        }
158
        dd($e);
159
    }
160
}
161