Completed
Push — master ( 3976a1...2ed0ed )
by Basil
03:11
created

Element::hasElement()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace luya\web;
4
5
use Yii;
6
use Exception;
7
use luya\helpers\FileHelper;
8
use Twig_Loader_Filesystem;
9
10
/**
11
 * Ability to register small html elements via closure function and run those
12
 * parts an every part of the page.
13
 * 
14
 * ```php
15
 * Yii::$app->element->addElement('foo', function($param) {
16
 *     return '<button>' . $param . '</button>';
17
 * });
18
 * ```
19
 * 
20
 * The above example can be execute like this:
21
 * 
22
 * ```php
23
 * echo Yii::$app->element->foo('Hello World');
24
 * ```
25
 * 
26
 * or in Twig
27
 * 
28
 * ```twig
29
 * {{ element('foo', 'Hello World') }}
30
 * ```
31
 * 
32
 * By default the Element-Component will lookup for an `elements.php` file returning an array
33
 * where the key is the element name and value the closure to be execute.
34
 * 
35
 * Example elements.php
36
 * 
37
 * ```php
38
 * <?php
39
 * return [
40
 *    'button' => function($value, $link) {
41
 *        return '<a class="btn btn-primary" href="'.$link.'">'.$value.'</a>';  
42
 *    },
43
 *    'teaserbox' => function($title, $text, $buttonValue, $buttonLink) {
44
 *        return '<div class="teaser-box" style="padding:10px; border:1px solid red;"><h1>'.$title.'</h1><p>'.$text.'</p>'.$this->button($buttonValue, $buttonLink).'</div>';
45
 *    },
46
 * ];
47
 * ```
48
 * 
49
 * @author nadar
50
 */
51
class Element extends \yii\base\Component
52
{
53
    /**
54
     * @var string The path to the default element file. Alias names will be parsed by Yii::getAlias.
55
     */
56
    public $configFile = '@app/elements.php';
57
58
    /**
59
     * @var string The path to the folder where the view files to render can be found.
60
     */
61
    public $viewsFolder = '@app/views/elements/';
62
63
    /**
64
     * @var array Contains all registered elements.
65
     */
66
    private $_elements = [];
67
68
    /**
69
     * @var string Parsed path of the folder where the view files are stored.
70
     */
71
    private $_folder = null;
72
73
    /**
74
     * Yii intializer, is loading the default elements.php if existing.
75
     */
76
    public function init()
77
    {
78
        $path = Yii::getAlias($this->configFile);
79
        if (file_exists($path)) {
80
            $config = (include($path));
81
            foreach ($config as $name => $closure) {
82
                $this->addElement($name, $closure);
83
            }
84
        }
85
    }
86
87
    /**
88
     * Magic method to run an closre directly from the Element-Object, for convincience. Example use.
89
     * 
90
     * ```php
91
     * $element = new Element();
92
     * $element->name($param1);
93
     * ```
94
     * 
95
     * @param string $name   access method name
96
     * @param array  $params access method params
97
     */
98
    public function __call($name, $params)
99
    {
100
        return $this->run($name, $params);
101
    }
102
103
    /**
104
     * Add an element with a closure to the elements array.
105
     * 
106
     * @param string   $name    The identifier of the element where the close is binde to.
107
     * @param callable $closure The closure function to registered, for instance:
108
     * 
109
     * ```php
110
     * function() {
111
     *     return 'foobar';
112
     * }
113
     * ```
114
     */
115
    public function addElement($name, $closure)
116
    {
117
        $this->_elements[$name] = $closure;
118
    }
119
120
    /**
121
     * Checks whether an elemnt exists in the elements list or not
122
     * 
123
     * @param string $name The name of the element
124
     * @return boolean 
125
     */
126
    public function hasElement($name)
127
    {
128
        return array_key_exists($name, $this->_elements);
129
    }
130
    
131
    /**
132
     * Returns an array with all registered Element-Names.
133
     *
134
     * @return array Value is the name of the element
135
     */
136
    public function getNames()
137
    {
138
        return array_keys($this->_elements);
139
    }
140
141
    /**
142
     * Return all elements as an array where the key is the name and the value the closure.
143
     * 
144
     * @return array Key is the Name of the Element, value the Closure.
145
     */
146
    public function getElements()
147
    {
148
        return $this->_elements;
149
    }
150
151
    /**
152
     * Run an element and return the closures return value.
153
     * 
154
     * @param string $name   The name of the elemente to execute.
155
     * @param array  $params The params to pass to the closure methode.
156
     *
157
     * @return mixed The return value of the executed closure function.
158
     *
159
     * @throws Exception
160
     */
161
    public function run($name, array $params = [])
162
    {
163
        if (!array_key_exists($name, $this->_elements)) {
164
            throw new Exception("The requested element '$name' does not exist in the list. You may register the element first with `addElement(name, closure)`.");
165
        }
166
167
        return call_user_func_array($this->_elements[$name], $params);
168
    }
169
170
    /**
171
     * Returns the path to the view files used for the render() method. Singleton method the return 
172
     * the evaluated viewFolder path once.
173
     * 
174
     * @return string Evaluated view foler path
175
     */
176
    public function getFolder()
177
    {
178
        if ($this->_folder === null) {
179
            $this->_folder = Yii::getAlias($this->viewsFolder);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Yii::getAlias($this->viewsFolder) can also be of type boolean. However, the property $_folder is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
180
        }
181
182
        return $this->_folder;
183
    }
184
185
    /**
186
     * Method to render twig files with theyr specific arguments, can be used inside the element closure depending
187
     * on where the closure was registered. Otherwhise the use of the element variable must be provided.
188
     * 
189
     * @param string $file The name of the file to render.
190
     * @param array  $args The parameters to pass in the render file.
191
     *
192
     * @return string The render value of the view file.
193
     */
194
    public function render($file, array $args = [])
195
    {
196
        $twig = Yii::$app->twig->env(new Twig_Loader_Filesystem($this->getFolder()));
0 ignored issues
show
Bug introduced by
It seems like $this->getFolder() targeting luya\web\Element::getFolder() can also be of type boolean; however, Twig_Loader_Filesystem::__construct() does only seem to accept string|array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
197
198
        return $twig->render(FileHelper::appendExtensionToString($file, 'twig'), $args);
199
    }
200
}
201