Passed
Push — main ( 073c01...b49c3d )
by Dimitri
03:21
created

View::setValidationErrors()   A

Complexity

Conditions 5
Paths 9

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 5
eloc 14
c 2
b 1
f 0
nc 9
nop 0
dl 0
loc 25
rs 9.4888
1
<?php
2
3
/**
4
 * This file is part of Blitz PHP framework.
5
 *
6
 * (c) 2022 Dimitri Sitchet Tomkeu <[email protected]>
7
 *
8
 * For the full copyright and license information, please view
9
 * the LICENSE file that was distributed with this source code.
10
 */
11
12
namespace BlitzPHP\View;
13
14
use BlitzPHP\Container\Services;
15
use BlitzPHP\Exceptions\ConfigException;
16
use BlitzPHP\Validation\ErrorBag;
17
use BlitzPHP\View\Adapters\BladeAdapter;
18
use BlitzPHP\View\Adapters\LatteAdapter;
19
use BlitzPHP\View\Adapters\NativeAdapter;
20
use BlitzPHP\View\Adapters\PlatesAdapter;
21
use BlitzPHP\View\Adapters\SmartyAdapter;
22
use BlitzPHP\View\Adapters\TwigAdapter;
23
24
class View
25
{
26
    /**
27
     * Views configuration
28
     *
29
     * @var array
30
     */
31
    protected $config;
32
33
    /**
34
     * @var RendererInterface
35
     */
36
    private $adapter;
37
38
    /**
39
     * Liste des adapters pris en comptes
40
     *
41
     * @var array
42
     */
43
    public static $validAdapters = [
44
        'native' => NativeAdapter::class,
45
        'blade'  => BladeAdapter::class,
46
        'latte'  => LatteAdapter::class,
47
        'plates' => PlatesAdapter::class,
48
        'smarty' => SmartyAdapter::class,
49
        'twig'   => TwigAdapter::class,
50
    ];
51
52
    /**
53
     * Options de la vue
54
     *
55
     * @var array
56
     */
57
    private $options = [];
58
59
    /**
60
     * La vue à rendre
61
     *
62
     * @var string
63
     */
64
    private $view;
65
66
    /**
67
     * Données partagées à toutes les vues
68
     *
69
     * @var array
70
     */
71
    private static $shared = [];
72
73
    /**
74
     * Constructeur
75
     */
76
    public function __construct()
77
    {
78
        $this->config = config('view');
0 ignored issues
show
Documentation Bug introduced by
It seems like config('view') can also be of type BlitzPHP\Config\Config. However, the property $config is declared as type array. 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...
79
80
        $this->setAdapter($this->config['active_adapter'] ?? 'native');
81
    }
82
83
    public function __toString()
84
    {
85
        return $this->get();
86
    }
87
88
    /**
89
     * Defini les données partagées entre plusieurs vues
90
     */
91
    public static function share(array|string $key, mixed $value = null): void
92
    {
93
        if (is_string($key)) {
0 ignored issues
show
introduced by
The condition is_string($key) is always false.
Loading history...
94
            $key = [$key => $value];
95
        }
96
97
        static::$shared = array_merge(static::$shared, $key);
0 ignored issues
show
Bug introduced by
Since $shared is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $shared to at least protected.
Loading history...
98
    }
99
100
    /**
101
     * Recupere et retourne le code html de la vue créée
102
     *
103
     * @param bool|string $compress
104
     */
105
    public function get($compress = 'auto'): string
106
    {
107
        $output = $this->adapter->render($this->view, $this->options);
108
109
        return $this->compressView($output, $compress);
110
    }
111
112
    /**
113
     * Affiche la vue generee au navigateur
114
     */
115
    public function render(): void
116
    {
117
        $compress = $this->config['compress_output'] ?? 'auto';
118
119
        echo $this->get($compress);
120
    }
121
122
    /**
123
     * Modifier les options d'affichage
124
     */
125
    public function setOptions(?array $options = []): self
126
    {
127
        $this->options = (array) $options;
128
129
        return $this;
130
    }
131
132
    /**
133
     * Définir la vue à afficher
134
     */
135
    public function display(string $view): self
136
    {
137
        $this->view = $view;
138
139
        return $this;
140
    }
141
142
    /**
143
     * Définit plusieurs éléments de données de vue à la fois.
144
     */
145
    public function addData(array $data = [], ?string $context = null): self
146
    {
147
        unset($data['errors']);
148
149
        $data = array_merge(static::$shared, $data);
0 ignored issues
show
Bug introduced by
Since $shared is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $shared to at least protected.
Loading history...
150
        
151
        $this->adapter->addData($data, $context);
152
153
        if (! array_key_exists('errors', $this->getData())) {
154
            $this->setValidationErrors();
155
        }
156
157
        return $this;
158
    }
159
160
    /**
161
     * Définit plusieurs éléments de données de vue à la fois.
162
     */
163
    public function with(array|string $key, mixed $value = null, ?string $context = null): self
164
    {
165
        if (is_array($key)) {
0 ignored issues
show
introduced by
The condition is_array($key) is always true.
Loading history...
166
            $context = $value;
167
        } else {
168
            $key = [$key => $value];
169
        }
170
171
        return $this->addData($key, $context);
172
    }
173
174
    /**
175
     * Définit une seule donnée de vue.
176
     *
177
     * @param mixed|null $value
178
     */
179
    public function setVar(string $name, $value = null, ?string $context = null): self
180
    {
181
        $this->adapter->setVar($name, $value, $context);
182
183
        return $this;
184
    }
185
186
    /**
187
     * Remplacer toutes les données de vue par de nouvelles données
188
     */
189
    public function setData(array $data, ?string $context = null): self
190
    {
191
        unset($data['errors']);
192
193
        $data = array_merge(static::$shared, $data);
0 ignored issues
show
Bug introduced by
Since $shared is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $shared to at least protected.
Loading history...
194
195
        $this->adapter->setData($data, $context);
196
197
        if (! array_key_exists('errors', $this->getData())) {
198
            $this->setValidationErrors();
199
        }
200
201
        return $this;
202
    }
203
204
    /**
205
     * Remplacer toutes les données de vue par de nouvelles données
206
     */
207
    public function getData(): array
208
    {
209
        return $this->adapter->getData();
210
    }
211
212
    /**
213
     * Supprime toutes les données de vue du système.
214
     */
215
    public function resetData(): self
216
    {
217
        $this->adapter->resetData();
218
219
        return $this;
220
    }
221
222
    /**
223
     * Definit le layout a utiliser par les vues
224
     */
225
    public function setLayout(string $layout): self
226
    {
227
        $this->adapter->setLayout($layout);
228
229
        return $this;
230
    }
231
232
    /**
233
     * Defini l'adapteur à utiliser
234
     */
235
    public function setAdapter(string $adapter, array $config = []): self
236
    {
237
        if (! array_key_exists($adapter, self::$validAdapters)) {
238
            $adapter = 'native';
239
        }
240
        if (empty($this->config['adapters']) || ! is_array($this->config['adapters'])) {
241
            $this->config['adapters'] = [];
242
        }
243
244
        $config = array_merge($this->config['adapters'][$adapter] ?? [], $config);
245
        if (empty($config)) {
246
            throw ConfigException::viewAdapterConfigNotFound($adapter);
247
        }
248
249
        $debug = $this->config['debug'] ?? 'auto';
250
        if ($debug === 'auto') {
251
            $debug = on_dev();
252
        }
253
254
        $this->adapter = new self::$validAdapters[$adapter](
255
            $config,
256
            Services::locator(),
257
            $debug
258
        );
259
260
        return $this;
261
    }
262
263
    /**
264
     * Renvoie les données de performances qui ont pu être collectées
265
     * lors de l'exécution. Utilisé principalement dans la barre d'outils de débogage.
266
     */
267
    public function getPerformanceData(): array
268
    {
269
        return $this->adapter->getPerformanceData();
270
    }
271
272
    /**
273
     * Compresse le code html d'une vue
274
     *
275
     * @param bool|string $compress
276
     */
277
    protected function compressView(string $output, $compress = 'auto'): string
278
    {
279
        if ($compress === 'auto') {
280
            $compress = is_online();
281
        }
282
283
        return true === $compress ? trim(preg_replace('/\s+/', ' ', $output)) : $output;
284
    }
285
286
    /**
287
     * Defini les erreurs de validation pour la vue
288
     */
289
    private function setValidationErrors()
290
    {
291
        $errors = [];
292
293
        if (null !== $e = session()->getFlashdata('errors')) {
294
            if (is_array($e)) {
0 ignored issues
show
introduced by
The condition is_array($e) is always true.
Loading history...
295
                $errors = array_merge($errors, $e);
296
            } else {
297
                $errors['error'] = $e;
298
            }
299
300
            session()->unmarkFlashdata('errors');
301
        }
302
        
303
        if (null !== $e = session()->getFlashdata('error')) {
304
            if (is_array($e)) {
0 ignored issues
show
introduced by
The condition is_array($e) is always true.
Loading history...
305
                $errors = array_merge($errors, $e);
306
            } else {
307
                $errors['error'] = $e;
308
            }
309
310
            session()->unmarkFlashdata('error');
311
        }
312
313
        $this->adapter->addData(['errors' => new ErrorBag($errors)]);
314
    }
315
}
316