Passed
Push — main ( ebfbeb...970435 )
by Dimitri
04:29
created

FileLocator::getBasename()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 8
rs 10
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\Loader;
13
14
use BlitzPHP\Container\Services;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, BlitzPHP\Loader\Services. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
15
use BlitzPHP\Contracts\Database\ConnectionInterface;
16
use BlitzPHP\Exceptions\LoadException;
17
use BlitzPHP\Utilities\Helpers;
18
use BlitzPHP\Utilities\String\Text;
19
use Nette\Schema\Expect;
20
use Nette\Schema\Schema;
21
22
class FileLocator
23
{
24
    /**
25
     * Charge un fichier d'aide en mémoire.
26
     * Prend en charge les helpers d'espace de noms, à la fois dans et hors du répertoire 'helpers' d'un répertoire d'espace de noms.
27
     *
28
     * Chargera TOUS les helpers du nom correspondant, dans l'ordre suivant :
29
     *   1. app/Helpers
30
     *   2. {namespace}/Helpers
31
     *   3. system/Helpers
32
     *
33
     * @throws FileNotFoundException
34
     */
35
    public static function helper(array|string $filenames)
36
    {
37
        static $loaded = [];
38
39
        $loader = Services::locator();
40
41
        if (! is_array($filenames)) {
0 ignored issues
show
introduced by
The condition is_array($filenames) is always true.
Loading history...
42
            $filenames = [$filenames];
43
        }
44
45
        // Enregistrez une liste de tous les fichiers à inclure...
46
        $includes = [];
47
48
        foreach ($filenames as $filename) {
49
            // Stockez nos versions d'helpers système et d'application afin que nous puissions contrôler l'ordre de chargement.
50
            $systemHelper  = null;
51
            $appHelper     = null;
52
            $localIncludes = [];
53
54
            // Vérifiez si ce helper a déjà été chargé
55
            if (in_array($filename, $loaded, true)) {
56
                continue;
57
            }
58
59
            // Si le fichier est dans un espace de noms, nous allons simplement saisir ce fichier et ne pas en rechercher d'autres
60
            if (strpos($filename, '\\') !== false) {
61
                $path = $loader->locateFile($filename, 'Helpers');
62
63
                if (empty($path)) {
64
                    throw LoadException::helperNotFound($filename);
65
                }
66
67
                $includes[] = $path;
68
                $loaded[]   = $filename;
69
            } else {
70
                // Pas d'espaces de noms, donc recherchez dans tous les emplacements disponibles
71
                $paths = $loader->search('Helpers/' . $filename);
72
73
                foreach ($paths as $path) {
74
                    if (strpos($path, APP_PATH . 'Helpers' . DS) === 0) {
75
                        $appHelper = $path;
76
                    } elseif (strpos($path, SYST_PATH . 'Helpers' . DS) === 0) {
77
                        $systemHelper = $path;
78
                    } else {
79
                        $localIncludes[] = $path;
80
                        $loaded[]        = $filename;
81
                    }
82
                }
83
84
                // Les helpers au niveau de l'application doivent remplacer tous les autres
85
                if (! empty($appHelper)) {
86
                    $includes[] = $appHelper;
87
                    $loaded[]   = $filename;
88
                }
89
90
                // Tous les fichiers avec espace de noms sont ajoutés ensuite
91
                $includes = [...$includes, ...$localIncludes];
92
93
                // Et celui par défaut du système doit être ajouté en dernier.
94
                if (! empty($systemHelper)) {
95
                    $includes[] = $systemHelper;
96
                    $loaded[]   = $filename;
97
                }
98
            }
99
        }
100
101
        // Incluez maintenant tous les fichiers
102
        foreach ($includes as $path) {
103
            include_once $path;
104
        }
105
    }
106
107
	/**
108
     * Charge un fichier d'aide en mémoire.
109
     * Prend en charge les helpers d'espace de noms, à la fois dans et hors du répertoire 'helpers' d'un répertoire d'espace de noms.
110
     */
111
    public static function schema(string $name): Schema
112
    {
113
        static $loadedSchema = [];
114
115
        $loader = Services::locator();
116
117
		// Stockez nos versions de schame système et d'application afin que nous puissions contrôler l'ordre de chargement.
118
		$systemSchema  = null;
119
		$appSchema     = null;
120
		$vendorSchema  = null;
121
		
122
		// Le fichier de schema qui sera finalement utiliser
123
		$file = null;
124
		
125
		// Vérifiez si ce schama a déjà été chargé
126
		if (in_array($name, $loadedSchema, true)) {
127
            return $loadedSchema[$name];
128
		}
129
130
		// Si le fichier est dans un espace de noms, nous allons simplement saisir ce fichier et ne pas en rechercher d'autres
131
		if (strpos($name, '\\') !== false) {
132
			if (!empty($path = $loader->locateFile($name, 'schemas'))) {
133
				$file = $path;
134
			}
135
		} else {
136
			// Pas d'espaces de noms, donc recherchez dans tous les emplacements disponibles
137
			$paths = $loader->search('schemas/' . $name);
138
139
			foreach ($paths as $path) {
140
				if (strpos($path, CONFIG_PATH . 'schemas' . DS) === 0) {
141
					$appSchema = $path;
142
				} elseif (strpos($path, SYST_PATH . 'Constants' . DS . 'schemas' . DS) === 0) {
143
					$systemSchema = $path;
144
				} else {
145
					$vendorSchema = $path;
146
				}
147
			}
148
149
			// Les schema des vendor sont prioritaire, ensuite vienne ceux de l'application
150
			if (!empty($vendorSchema)) {
0 ignored issues
show
introduced by
The condition empty($vendorSchema) is always false.
Loading history...
151
				$file = $vendorSchema;
152
			} else if (!empty($appSchema)) {
153
				$file = $appSchema;
154
			} else if (!empty($systemSchema)) {
155
				$file = $systemSchema;
156
			}
157
        }
158
159
		if (!empty($file)) {
160
			$schema = require($file);
161
		} else {
162
			$schema = null;
163
		}
164
165
        if (empty($schema) || ! ($schema instanceof Schema)) {
166
            $schema = Expect::mixed();
167
        }
168
169
        return $loadedSchema[$name] = $schema;
170
    }
171
172
    /**
173
     * Cree et renvoi un model donné
174
     *
175
     * @template T of \BlitzPHP\Models\BaseModel
176
     *
177
     * @param class-string<T> $model
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<T> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<T>.
Loading history...
178
     *
179
     * @return T
180
     */
181
    public static function model(string $model, ?ConnectionInterface $connection = null)
182
    {
183
        if (! class_exists($model) && ! Text::endsWith($model, 'Model')) {
0 ignored issues
show
Bug introduced by
'Model' of type string is incompatible with the type iterable expected by parameter $needles of BlitzPHP\Utilities\String\Text::endsWith(). ( Ignorable by Annotation )

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

183
        if (! class_exists($model) && ! Text::endsWith($model, /** @scrutinizer ignore-type */ 'Model')) {
Loading history...
184
            $model .= 'Model';
185
        }
186
187
        if (! class_exists($model)) {
188
            $model = str_replace(APP_NAMESPACE . '\\Models\\', '', $model);
189
            $model = APP_NAMESPACE . '\\Models\\' . $model;
190
        }
191
192
        if (! class_exists($model)) {
193
            throw LoadException::modelNotFound($model);
194
        }
195
196
        return Services::container()->make($model, ['db' => $connection]);
197
    }
198
199
    /**
200
     * Recupere le nom de base a partir du nom de la classe, namespacé ou non.
201
     */
202
    public static function getBasename(string $name): string
203
    {
204
        // Determine le basename
205
        if ($basename = strrchr($name, '\\')) {
206
            return substr($basename, 1);
207
        }
208
209
        return $name;
210
    }
211
212
    /**
213
     * Verifie si la classe satisfait l'option "preferApp"
214
     *
215
     * @param array  $options directives specifier pqr le composant
216
     * @param string $name    Nom de la classe, namespace optionel
217
     */
218
    protected static function verifyPreferApp(array $options, string $name): bool
219
    {
220
        // Tout element sans restriction passe
221
        if (! $options['preferApp']) {
222
            return true;
223
        }
224
225
        return strpos($name, APP_NAMESPACE) === 0;
226
    }
227
}
228