Test Failed
Branch main (345e92)
by Rafael
08:42
created

ViewTrait::getDefaultTemplateName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
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\Messages;
22
use Alxarafe\Lib\Trans;
23
use Illuminate\Container\Container;
24
use Illuminate\Events\Dispatcher;
25
use Illuminate\Filesystem\Filesystem;
26
use Illuminate\Support\Str;
27
use Illuminate\View\Compilers\BladeCompiler;
28
use Illuminate\View\Engines\CompilerEngine;
29
use Illuminate\View\Engines\EngineResolver;
30
use Illuminate\View\Factory;
31
use Illuminate\View\FileViewFinder;
32
33
/**
34
 * Trait for controllers using Blade templates.
35
 */
36
trait ViewTrait
37
{
38
    /**
39
     * Theme name.
40
     *
41
     * @var string
42
     */
43
    public static string $theme = '';
44
45
    /**
46
     * Template routes added by modules.
47
     *
48
     * @var array
49
     */
50
    public static array $templatesPath = [];
51
52
    /**
53
     * Contains the name of the blade template to print
54
     *
55
     * @var null|string
56
     */
57
    public null|string $template;
58
59
    /**
60
     * Contains the title of the view.
61
     *
62
     * @var string
63
     */
64
    public string $title;
65
66
    /**
67
     * Contains an array with the messages to be displayed, indicating the
68
     * type (message, advice or error) and the text to be displayed.
69
     *
70
     * @var array
71
     */
72
    public array $alerts;
73
74
    /**
75
     * Shows a translated text
76
     *
77
     * @param $message
78
     * @param array $parameters
79
     * @param $locale
80
     * @return string
81
     */
82
    public static function _($message, array $parameters = [], $locale = null): string
83
    {
84
        return Trans::_($message, $parameters, $locale);
85
    }
86
87
    /**
88
     * Returns the generic url of the controller;
89
     *
90
     * @param $full
91
     *
92
     * @return string
93
     */
94
    public static function url($full = true)
95
    {
96
        $url = '';
97
        if ($full) {
98
            $url .= constant('BASE_URL') . '/index.php';
99
        }
100
101
        $url .=
102
            '?' . \Alxarafe\Tools\Dispatcher::MODULE . '=' . static::getModuleName() .
103
            '&' . \Alxarafe\Tools\Dispatcher::CONTROLLER . '=' . static::getControllerName();
104
105
        $action = filter_input(INPUT_GET, 'action');
106
        if ($action) {
107
            $url .= '&action=' . $action;
108
        }
109
110
        return $url;
111
    }
112
113
    /**
114
     * Returns the module name for use in url function
115
     *
116
     * @return string
117
     */
118
    abstract public static function getModuleName(): string;
119
120
    /**
121
     * Returns the controller name for use in url function
122
     *
123
     * @return string
124
     */
125
    abstract public static function getControllerName(): string;
126
127
    /**
128
     * Upon completion of the controller execution, the template is displayed.
129
     */
130
    public function __destruct()
131
    {
132
        if (!isset($this->template)) {
133
            return;
134
        }
135
136
        if (!isset(self::$theme)) {
137
            self::$theme = 'alxarafe';
138
        }
139
140
        if (!isset($this->title)) {
141
            $this->title = 'Alxarafe';
142
        }
143
144
        $this->alerts = Messages::getMessages();
145
146
        $container = self::getContainer();
147
148
        $viewFactory = $container['view'];
149
150
        echo $viewFactory->make($this->template, ['me' => $this])->render();
151
    }
152
153
    /**
154
     * Set up and return a service container configured for Blade template rendering.
155
     *
156
     * This function initializes and configures an Illuminate\Container\Container instance
157
     * with the necessary services and dependencies required for Blade templating.
158
     * It sets up the file system, view finder, Blade compiler, view engine resolver,
159
     * and view factory services. It ensures that the cache directory for compiled
160
     * Blade templates exists and is writable.
161
     *
162
     * @return Container|null Configured service container for Blade rendering.
163
     */
164
    private static function getContainer(): ?Container
165
    {
166
        $viewPaths = self::getViewPaths();
167
168
        $cachePaths = realpath(constant('BASE_PATH') . '/..') . '/tmp/blade';
169
        if (!is_dir($cachePaths) && !mkdir($cachePaths, 0777, true) && !is_dir($cachePaths)) {
170
            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...
171
        }
172
173
        $container = new Container();
174
175
        $container->singleton('files', function () {
176
            return new Filesystem();
177
        });
178
179
        $container->singleton('view.finder', function ($app) use ($viewPaths) {
180
            return new FileViewFinder($app['files'], $viewPaths);
181
        });
182
183
        $container->singleton('blade.compiler', function ($app) use ($cachePaths) {
184
            return new BladeCompiler($app['files'], $cachePaths);
185
        });
186
187
        $container->singleton('view.engine.resolver', function ($app) {
188
            $resolver = new EngineResolver();
189
190
            // Register Blade engine
191
            $resolver->register('blade', function () use ($app) {
192
                return new CompilerEngine($app['blade.compiler']);
193
            });
194
195
            return $resolver;
196
        });
197
198
        $container->singleton('view', function ($app) {
199
            $resolver = $app['view.engine.resolver'];
200
            $finder = $app['view.finder'];
201
            $dispatcher = new Dispatcher($app);
202
203
            return new Factory($resolver, $finder, $dispatcher);
204
        });
205
206
        return $container;
207
    }
208
209
    /**
210
     * Returns the routes to the application templates.
211
     *
212
     * @return string[]
213
     */
214
    private static function getViewPaths(): array
215
    {
216
        $viewPaths = [
217
            constant('APP_PATH') . '/Templates',
218
            constant('APP_PATH') . '/Templates/theme/' . self::$theme,
219
            constant('APP_PATH') . '/Templates/common',
220
            constant('ALX_PATH') . '/Templates',
221
            constant('ALX_PATH') . '/Templates/theme/' . self::$theme,
222
            constant('ALX_PATH') . '/Templates/common',
223
        ];
224
225
        if (!empty(self::$templatesPath)) {
226
            $viewPaths = array_merge(self::$templatesPath, $viewPaths);
227
        }
228
229
        return $viewPaths;
230
    }
231
232
    /**
233
     * Sets a new path for the templates, prepending the current selection.
234
     *
235
     * @param array|string $path
236
     * @return void
237
     */
238
    public function setTemplatesPath(array|string $path): void
239
    {
240
        if (is_array($path)) {
0 ignored issues
show
introduced by
The condition is_array($path) is always true.
Loading history...
241
            self::$templatesPath = array_merge($path, self::$templatesPath);
242
            return;
243
        }
244
        array_unshift(self::$templatesPath, $path);
245
    }
246
247
    /**
248
     * Assign the default template for the class.
249
     *
250
     * @return void
251
     */
252
    private function setDefaultTemplate(): void
253
    {
254
        if (empty($this->template)) {
255
            $this->template = 'page/' . $this->getDefaultTemplateName();
256
        }
257
    }
258
259
    /**
260
     * Returns the name of the template, given the class name.
261
     * The default template name is the class name with the "Controller"
262
     * removed from the end and converted to 'snake_case'.
263
     *
264
     * For example, for the UserTestController class, it will return user_test.
265
     *
266
     * @return string
267
     */
268
    private function getDefaultTemplateName(): string
269
    {
270
        $array_object = explode('\\', get_class($this));
271
        if (empty($array_object)) {
272
            return '';
273
        }
274
        return Str::snake(substr(end($array_object), 0, -10));
275
    }
276
}
277