Test Failed
Push — main ( 6ea9a3...5960f6 )
by Rafael
04:57
created

ViewTrait   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 230
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 19
eloc 65
dl 0
loc 230
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A addError() 0 3 1
A _() 0 3 1
A addAdvice() 0 3 1
A addMessage() 0 3 1
A setTemplatesPath() 0 7 2
A getViewPaths() 0 16 2
A __destruct() 0 21 4
A getContainer() 0 43 4
A getMessages() 0 13 3
1
<?php
2
3
/* Copyright (C) 2024      Rafael San José      <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
namespace Alxarafe\Base\Controller\Trait;
20
21
use Alxarafe\Lib\Trans;
22
use Illuminate\Container\Container;
23
use Illuminate\Events\Dispatcher;
24
use Illuminate\Filesystem\Filesystem;
25
use Illuminate\View\Engines\CompilerEngine;
26
use Illuminate\View\Engines\EngineResolver;
27
use Illuminate\View\FileViewFinder;
28
use Illuminate\View\Factory;
29
use Illuminate\View\Compilers\BladeCompiler;
30
31
trait ViewTrait
32
{
33
    /**
34
     * Contains messages, advices and errors pending to be shown.
35
     *
36
     * @var array
37
     */
38
    public static array $messages = [];
39
40
    /**
41
     * Theme name.
42
     *
43
     * @var string
44
     */
45
    public static string $theme = '';
46
47
    /**
48
     * Template routes added by modules.
49
     *
50
     * @var array
51
     */
52
    public static array $templatesPath = [];
53
54
    /**
55
     * Contains the name of the blade template to print
56
     *
57
     * @var string
58
     */
59
    public string $template;
60
61
    /**
62
     * Contains the title of the view.
63
     *
64
     * @var string
65
     */
66
    public string $title;
67
68
    /**
69
     * Contains an array with the messages to be displayed, indicating the
70
     * type (message, advice or error) and the text to be displayed.
71
     *
72
     * @var array
73
     */
74
    public array $alerts;
75
76
    /**
77
     * Shows a translated text
78
     *
79
     * @param $message
80
     * @param array $parameters
81
     * @param $locale
82
     * @return string
83
     */
84
    public static function _($message, array $parameters = [], $locale = null): string
85
    {
86
        return Trans::_($message, $parameters, $locale);
87
    }
88
89
    /**
90
     * Add a new message (success) to show the user
91
     *
92
     * @param $message
93
     * @return void
94
     */
95
    public static function addMessage($message): void
96
    {
97
        self::$messages[]['success'] = $message;
98
    }
99
100
    /**
101
     * Add a new advice (warning) to show the user
102
     *
103
     * @param $message
104
     * @return void
105
     */
106
    public static function addAdvice($message): void
107
    {
108
        self::$messages[]['warning'] = $message;
109
    }
110
111
    /**
112
     * Add a new error (danger) to show the user
113
     *
114
     * @param $message
115
     * @return void
116
     */
117
    public static function addError($message): void
118
    {
119
        self::$messages[]['danger'] = $message;
120
    }
121
122
    /**
123
     * Upon completion of the controller execution, the template is displayed.
124
     */
125
    public function __destruct()
126
    {
127
        if (!isset($this->template)) {
128
            return;
129
        }
130
131
        if (!isset(self::$theme)) {
132
            self::$theme = 'alxarafe';
133
        }
134
135
        if (!isset($this->title)) {
136
            $this->title = 'Alxarafe';
137
        }
138
139
        $this->alerts = self::getMessages();
140
141
        $container = self::getContainer();
0 ignored issues
show
Bug Best Practice introduced by
The method Alxarafe\Base\Controller...ewTrait::getContainer() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

141
        /** @scrutinizer ignore-call */ 
142
        $container = self::getContainer();
Loading history...
142
143
        $viewFactory = $container['view'];
144
145
        echo $viewFactory->make($this->template, ['me' => $this])->render();
146
    }
147
148
    /**
149
     * Generates an array with the messages to be displayed, indicating the
150
     * type (message, advice or error) and the text to be displayed.
151
     *
152
     * @return array
153
     */
154
    private static function getMessages(): array
155
    {
156
        $alerts = [];
157
        foreach (self::$messages as $message) {
158
            foreach ($message as $type => $text) {
159
                $alerts[] = [
160
                    'type' => $type,
161
                    'text' => $text
162
                ];
163
            }
164
        }
165
        self::$messages = [];
166
        return $alerts;
167
    }
168
169
    /**
170
     * Set up and return a service container configured for Blade template rendering.
171
     *
172
     * This function initializes and configures an Illuminate\Container\Container instance
173
     * with the necessary services and dependencies required for Blade templating.
174
     * It sets up the file system, view finder, Blade compiler, view engine resolver,
175
     * and view factory services. It ensures that the cache directory for compiled
176
     * Blade templates exists and is writable.
177
     *
178
     * @return \Illuminate\Container\Container Configured service container for Blade rendering.
179
     */
180
    private function getContainer(): Container
181
    {
182
        $viewPaths = self::getViewPaths();
183
184
        $cachePaths = realpath(constant('BASE_PATH') . '/..') . '/tmp/blade';
185
        if (!is_dir($cachePaths) && !mkdir($cachePaths, 0777, true) && !is_dir($cachePaths)) {
186
            die('Could not create cache directory for templates: ' . $cachePaths);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return Illuminate\Container\Container. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
187
        }
188
189
        $container = new Container();
190
191
        $container->singleton('files', function () {
192
            return new Filesystem();
193
        });
194
195
        $container->singleton('view.finder', function ($app) use ($viewPaths) {
196
            return new FileViewFinder($app['files'], $viewPaths);
197
        });
198
199
        $container->singleton('blade.compiler', function ($app) use ($cachePaths) {
200
            return new BladeCompiler($app['files'], $cachePaths);
201
        });
202
203
        $container->singleton('view.engine.resolver', function ($app) {
204
            $resolver = new EngineResolver();
205
206
            // Register Blade engine
207
            $resolver->register('blade', function () use ($app) {
208
                return new CompilerEngine($app['blade.compiler']);
209
            });
210
211
            return $resolver;
212
        });
213
214
        $container->singleton('view', function ($app) {
215
            $resolver = $app['view.engine.resolver'];
216
            $finder = $app['view.finder'];
217
            $dispatcher = new Dispatcher($app);
218
219
            return new Factory($resolver, $finder, $dispatcher);
220
        });
221
222
        return $container;
223
    }
224
225
    /**
226
     * Returns the routes to the application templates.
227
     *
228
     * @return string[]
229
     */
230
    private static function getViewPaths(): array
231
    {
232
        $viewPaths = [
233
            constant('APP_PATH') . '/Templates',
234
            constant('APP_PATH') . '/Templates/theme/' . self::$theme,
235
            constant('APP_PATH') . '/Templates/common',
236
            constant('ALX_PATH') . '/Templates',
237
            constant('ALX_PATH') . '/Templates/theme/' . self::$theme,
238
            constant('ALX_PATH') . '/Templates/common',
239
        ];
240
241
        if (!empty(self::$templatesPath)) {
242
            $viewPaths = array_merge(self::$templatesPath, $viewPaths);
243
        }
244
245
        return $viewPaths;
246
    }
247
248
    /**
249
     * Sets a new path for the templates, prepending the current selection.
250
     *
251
     * @param array|string $path
252
     * @return void
253
     */
254
    public function setTemplatesPath(array|string $path): void
255
    {
256
        if (is_array($path)) {
0 ignored issues
show
introduced by
The condition is_array($path) is always true.
Loading history...
257
            self::$templatesPath = array_merge($path, self::$templatesPath);
258
            return;
259
        }
260
        array_unshift(self::$templatesPath, $path);
261
    }
262
}
263