Completed
Push — master ( 907aac...ea4501 )
by Iman
02:05
created

Normalizer::normalizePresenterName()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 8.6737
c 0
b 0
f 0
cc 5
eloc 14
nc 6
nop 0
1
<?php
2
3
namespace Imanghafoori\Widgets\Utils;
4
5
6
use Imanghafoori\Widgets\BaseWidget;
7
8
class Normalizer
9
{
10
    private $widget;
11
12
    public function normalizeWidgetConfig(BaseWidget $widget)
13
    {
14
        // to avoid normalizing a widget multiple times unnecessarily :
15
        if (isset($widget->isNormalized)) {
16
            return null;
17
        }
18
19
        $this->widget = $widget;
20
        $this->normalizeControllerMethod();
21
        $this->normalizePresenterName();
22
        $this->normalizeTemplateName();
23
        $this->normalizeContextAs();
24
        $this->normalizeCacheLifeTime();
25
        $this->normalizeCacheTags();
26
        $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...
27
    }
28
29
    /**
30
     * Figures out which method should be called as the controller.
31
     * @return null
32
     */
33
    private function normalizeControllerMethod()
34
    {
35
        // We decide to call data method on widget object by default.
36
        $controllerMethod = [$this->widget, 'data'];
37
        $ctrlClass = get_class($this->widget);
38
39
        // If the user has explicitly declared controller class path on widget
40
        // then we decide to call data method on that instead.
41
        if ($this->widget->controller) {
42
            $ctrlClass = $this->widget->controller;
43
            $controllerMethod = ($this->widget->controller) . '@data';
44
        }
45
46
        if (!method_exists($ctrlClass, 'data')) {
47
            throw new \BadMethodCallException("'data' method not found on " . class_basename($this->widget));
48
        }
49
50
        if (!class_exists($ctrlClass)) {
51
            throw new \InvalidArgumentException("Controller class: [{$ctrlClass}] not found.");
52
        }
53
54
        $this->widget->controller = $controllerMethod;
55
    }
56
57
    /**
58
     * Figures out which method should be called as the presenter
59
     * @return null
60
     */
61
    private function normalizePresenterName()
62
    {
63
        if ($this->widget->presenter !== 'default') {
64
            if (!class_exists($this->widget->presenter)) {
65
                throw new \InvalidArgumentException("Presenter Class [{$this->widget->presenter}] not found.");
66
            }
67
            $presenter = $this->widget->presenter;
68
        } else {
69
            $presenter = get_class($this->widget) . 'Presenter';
70
            $method = null;
0 ignored issues
show
Unused Code introduced by
$method is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
71
            if (!class_exists($presenter)) {
72
                $this->widget->presenter =  null;
73
                return ;
74
            }
75
        }
76
77
        if (!method_exists($presenter, 'present')) {
78
            throw new \InvalidArgumentException("'present' method not found on : " . get_class($this->widget));
79
        }
80
81
        $this->widget->presenter = $presenter . '@present';
82
    }
83
84
    /**
85
     * Figures out which template to render.
86
     * @return null
87
     */
88
    private function normalizeTemplateName()
89
    {
90
        // class name without namespace.
91
        $className = str_replace('App\\Widgets\\', '', class_basename($this->widget));
92
        // replace slashes with dots
93
        $className = str_replace(['\\', '/'], '.', $className);
94
95
        if ($this->widget->template === null) {
96
            $this->widget->template = 'Widgets::' . $className . 'View';
97
        }
98
99
        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...
100
            throw new \InvalidArgumentException("View file [{$className}View] not found by: '" . class_basename($this->widget) . " '");
101
        }
102
    }
103
104
    /**
105
     * Figures out what the variable name should be in view file.
106
     * @return null
107
     */
108
    private function normalizeContextAs()
109
    {
110
        // removes the $ sign.
111
        $this->widget->contextAs = str_replace('$', '', (string)$this->widget->contextAs);
112
    }
113
114
    /**
115
     * ّFigures out how long the cache life time should be.
116
     * @return null
117
     */
118
    private function normalizeCacheLifeTime()
119
    {
120
        if ($this->widget->cacheLifeTime === 'env_default') {
121
            $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...
122
        }
123
124
        if ($this->widget->cacheLifeTime === 'forever') {
125
            $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...
126
        }
127
128
    }
129
130
    /**
131
     * ّFigures out what the cache tags should be.
132
     * @return null
133
     */
134
    private function normalizeCacheTags()
135
    {
136
        if (!$this->cacheCanUseTags() || !$this->widget->cacheTags) {
137
            $this->widget->cacheTags = null;
138
            return null;
139
        }
140
141
        if (is_string($this->widget->cacheTags)) {
142
            $this->widget->cacheTags = [$this->widget->cacheTags];
143
        }
144
145
        if (!is_array($this->widget->cacheTags)) {
146
            throw new \InvalidArgumentException('Cache Tags should be of type String or Array.');
147
        }
148
    }
149
150
    /**
151
     * Determine whether cache tags should be applied or not
152
     * @return bool
153
     */
154
    private function cacheCanUseTags()
155
    {
156
        return !in_array(env('CACHE_DRIVER', 'file'), ['file', 'database']);
157
    }
158
159
}