Completed
Push — master ( df4490...fbc7c8 )
by Iman
02:04
created

Normalizer::normalizeWidgetConfig()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 11
nc 2
nop 1
1
<?php
2
3
namespace Imanghafoori\Widgets\Utils;
4
5
use Imanghafoori\Widgets\BaseWidget;
6
7
class Normalizer
8
{
9
    private $widget;
10
11
    public function normalizeWidgetConfig(BaseWidget $widget)
12
    {
13
        // to avoid normalizing a widget multiple times unnecessarily :
14
        if (isset($widget->isNormalized)) {
15
            return null;
16
        }
17
18
        $this->widget = $widget;
19
        $this->normalizeControllerMethod();
20
        $this->normalizePresenterName();
21
        $this->normalizeTemplateName();
22
        $this->normalizeContextAs();
23
        $this->normalizeCacheLifeTime();
24
        $this->normalizeCacheTags();
25
        $widget->isNormalized = true;
0 ignored issues
show
Bug introduced by
The property isNormalized does not seem to exist in Imanghafoori\Widgets\BaseWidget.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
26
    }
27
28
    /**
29
     * Figures out which method should be called as the controller.
30
     * @return null
31
     */
32
    private function normalizeControllerMethod()
33
    {
34
        // We decide to call data method on widget object by default.
35
        $controllerMethod = [$this->widget, 'data'];
36
        $ctrlClass = get_class($this->widget);
37
38
        // If the user has explicitly declared controller class path on widget
39
        // then we decide to call data method on that instead.
40
        if ($this->widget->controller) {
41
            $ctrlClass = $this->widget->controller;
42
            $controllerMethod = ($ctrlClass) . '@data';
43
        }
44
45
        $this->checkControllerExists($ctrlClass);
46
        $this->checkDataMethodExists($ctrlClass);
47
48
        $this->widget->controller = $controllerMethod;
49
    }
50
51
    /**
52
     * Figures out which method should be called as the presenter
53
     * @return null
54
     */
55
    private function normalizePresenterName()
56
    {
57
        if ($this->widget->presenter !== 'default') {
58
            $presenter = $this->widget->presenter;
59
            $this->checkPresenterExists($presenter);
60
        } else {
61
            $presenter = get_class($this->widget) . 'Presenter';
62
            if (!class_exists($presenter)) {
63
                return $this->widget->presenter = null;
64
            }
65
        }
66
67
        $this->checkPresentMethodExists($presenter);
68
69
        $this->widget->presenter = $presenter . '@present';
70
    }
71
72
    /**
73
     * Figures out which template to render.
74
     * @return null
75
     */
76
    private function normalizeTemplateName()
77
    {
78
        // class name without namespace.
79
        $className = str_replace('App\\Widgets\\', '', class_basename($this->widget));
80
81
        // replace slashes with dots
82
        $className = str_replace(['\\', '/'], '.', $className);
83
84
        if ($this->widget->template === null) {
85
            $this->widget->template = 'Widgets::' . $className . 'View';
86
        }
87
88
        if (!view()->exists($this->widget->template)) {
0 ignored issues
show
Bug introduced by
The method exists does only exist in Illuminate\Contracts\View\Factory, but not in Illuminate\View\View.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
89
            throw new \InvalidArgumentException("View file [{$className}View] not found by: '" . class_basename($this->widget) . " '");
90
        }
91
    }
92
93
    /**
94
     * Figures out what the variable name should be in view file.
95
     * @return null
96
     */
97
    private function normalizeContextAs()
98
    {
99
        // removes the $ sign.
100
        $this->widget->contextAs = str_replace('$', '', (string)$this->widget->contextAs);
101
    }
102
103
    /**
104
     * ّFigures out how long the cache life time should be.
105
     * @return null
106
     */
107
    private function normalizeCacheLifeTime()
108
    {
109
        if ($this->widget->cacheLifeTime === 'env_default') {
110
            $this->widget->cacheLifeTime = (int)(env('WIDGET_DEFAULT_CACHE_LIFETIME', 0));
0 ignored issues
show
Documentation Bug introduced by
The property $cacheLifeTime was declared of type string, but (int) env('WIDGET_DEFAULT_CACHE_LIFETIME', 0) is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
111
        }
112
113
        if ($this->widget->cacheLifeTime === 'forever') {
114
            $this->widget->cacheLifeTime = -1;
0 ignored issues
show
Documentation Bug introduced by
The property $cacheLifeTime was declared of type string, but -1 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
115
        }
116
    }
117
118
    /**
119
     * ّFigures out what the cache tags should be.
120
     * @return null
121
     */
122
    private function normalizeCacheTags()
123
    {
124
        if (!$this->cacheCanUseTags() || !$this->widget->cacheTags) {
125
            return $this->widget->cacheTags = null;
126
        }
127
128
        if (is_array($this->widget->cacheTags)) {
129
            return $this->widget->cacheTags;
130
        }
131
132
        if (is_string($this->widget->cacheTags)) {
133
            return $this->widget->cacheTags = [$this->widget->cacheTags];
134
        }
135
136
        throw new \InvalidArgumentException('Cache Tags should be of type String or Array.');
137
    }
138
139
    /**
140
     * Determine whether cache tags should be applied or not
141
     * @return bool
142
     */
143
    private function cacheCanUseTags()
144
    {
145
        return !in_array(env('CACHE_DRIVER', 'file'), ['file', 'database']);
146
    }
147
148
    /**
149
     * @param $ctrlClass
150
     */
151
    private function checkControllerExists($ctrlClass)
152
    {
153
        if (!class_exists($ctrlClass)) {
154
            throw new \InvalidArgumentException("Controller class: [{$ctrlClass}] not found.");
155
        }
156
    }
157
158
    /**
159
     * @param $ctrlClass
160
     */
161
    private function checkDataMethodExists($ctrlClass)
162
    {
163
        if (!method_exists($ctrlClass, 'data')) {
164
            throw new \InvalidArgumentException("'data' method not found on " . $ctrlClass);
165
        }
166
    }
167
168
    /**
169
     * @param $presenter
170
     */
171
    private function checkPresentMethodExists($presenter)
172
    {
173
        if (!method_exists($presenter, 'present')) {
174
            throw new \InvalidArgumentException("'present' method not found on : " . $presenter);
175
        }
176
    }
177
178
    /**
179
     * @param $presenter
180
     */
181
    private function checkPresenterExists($presenter)
182
    {
183
        if (!class_exists($presenter)) {
184
            throw new \InvalidArgumentException("Presenter Class [{$presenter}] not found.");
185
        }
186
    }
187
}
188