Test Failed
Push — master ( a25a4c...498f08 )
by Divine Niiquaye
13:17
created

HelperTrait   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 189
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 54
c 1
b 0
f 0
dl 0
loc 189
rs 10
wmc 29

9 Methods

Rating   Name   Duplication   Size   Complexity  
A mount() 0 3 1
A load() 0 15 4
A escape() 0 3 1
A loadExtensions() 0 3 1
A getConfigLoader() 0 20 4
A isRunningInConsole() 0 3 1
C getLocation() 0 55 13
A isDebug() 0 3 1
A inVagrantEnvironment() 0 3 3
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of DivineNii opensource projects.
7
 *
8
 * PHP version 7.4 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 DivineNii (https://divinenii.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Rade\Traits;
19
20
use Composer\InstalledVersions;
21
use Laminas\Escaper\Escaper;
22
use Nette\Utils\FileSystem;
23
use Rade\DI\Exceptions\ContainerResolutionException;
24
use Rade\DI\Extensions\ExtensionBuilder;
25
use Rade\Provider\ConfigServiceProvider;
0 ignored issues
show
Bug introduced by
The type Rade\Provider\ConfigServiceProvider was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
use Symfony\Component\Config\Exception\LoaderLoadException;
27
use Symfony\Component\Config\Loader\LoaderResolverInterface;
28
29
trait HelperTrait
30
{
31
    /** @var array<string,string> */
32
    private array $loadedExtensionPaths = [];
33
34
    public function isDebug(): bool
35
    {
36
        return $this->parameters['debug'];
37
    }
38
39
    /**
40
     * Determine if the application is running in the console.
41
     */
42
    public function isRunningInConsole(): bool
43
    {
44
        return \in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true);
45
    }
46
47
    /**
48
     * Determine if the application is in vagrant environment.
49
     */
50
    public function inVagrantEnvironment(): bool
51
    {
52
        return ('/home/vagrant' === \getenv('HOME') || 'VAGRANT' === \getenv('VAGRANT')) && \is_dir('/dev/shm');
53
    }
54
55
    /**
56
     * The the delegated config loaders instance.
57
     */
58
    public function getConfigLoader(): LoaderResolverInterface
59
    {
60
        $configLoader = $this->services['config.loader_resolver'] ?? $this->privates['builder.loader_resolver'] ?? null;
61
62
        if (null === $configLoader) {
63
            if ($this->has('config.loader_resolver')) {
0 ignored issues
show
Bug introduced by
It seems like has() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

63
            if ($this->/** @scrutinizer ignore-call */ has('config.loader_resolver')) {
Loading history...
64
                return $this->get('config.loader_resolver');
0 ignored issues
show
Bug introduced by
It seems like get() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

64
                return $this->/** @scrutinizer ignore-call */ get('config.loader_resolver');
Loading history...
65
             }
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 12 spaces, found 13
Loading history...
66
67
             if (isset($this->definitions['builder.loader_resolver'])) {
68
                $configLoader = $this->definitions['builder.loader_resolver'];
69
                unset($this->definitions['builder.loader_resolver']);
70
71
                return $this->privates['builder.loader_resolver'] = $configLoader;
0 ignored issues
show
Bug Best Practice introduced by
The property privates does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
72
            }
0 ignored issues
show
Coding Style introduced by
Closing brace indented incorrectly; expected 13 spaces, found 12
Loading history...
73
74
            throw new ContainerResolutionException(\sprintf('Did you forgot to register the "%s" class?', ConfigServiceProvider::class));
75
        }
76
77
        return $configLoader;
78
    }
79
80
    /**
81
     * Context specific methods for use in secure output escaping.
82
     *
83
     * @param string $encoding
84
     */
85
    public function escape(string $encoding = null): Escaper
86
    {
87
        return new Escaper($encoding);
88
    }
89
90
    /**
91
     * Mounts a service provider like controller taking in a parameter of application.
92
     *
93
     * @param callable(\Rade\DI\AbstractContainer) $controllers
94
     */
95
    public function mount(callable $controllers): void
96
    {
97
        $controllers($this);
98
    }
99
100
    /**
101
     * Loads a set of container extensions.
102
     *
103
     * Example for extensions:
104
     * [
105
     *    PhpExtension::class,
106
     *    CoreExtension::class => -1,
107
     *    [ProjectExtension::class, ['%project.dir%']],
108
     * ]
109
     *
110
     * @param array<int,mixed> $extensions
111
     * @param array<string,mixed> $config the default configuration for all extensions
112
     */
113
    public function loadExtensions(array $extensions, array $configs = []): void
114
    {
115
        (new ExtensionBuilder($this, $configs))->load($extensions);
0 ignored issues
show
Bug introduced by
$this of type Rade\Traits\HelperTrait is incompatible with the type Rade\DI\AbstractContainer expected by parameter $container of Rade\DI\Extensions\ExtensionBuilder::__construct(). ( Ignorable by Annotation )

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

115
        (new ExtensionBuilder(/** @scrutinizer ignore-type */ $this, $configs))->load($extensions);
Loading history...
116
    }
117
118
    /**
119
     * Loads a resource.
120
     *
121
     * @param mixed $resource the resource can be anything supported by a config loader
122
     *
123
     * @throws \Exception If something went wrong
124
     *
125
     * @return mixed
126
     */
127
    public function load($resource, string $type = null)
128
    {
129
        if (\is_string($resource)) {
130
            $resource = $this->parameter($resource);
0 ignored issues
show
Bug introduced by
It seems like parameter() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

130
            /** @scrutinizer ignore-call */ 
131
            $resource = $this->parameter($resource);
Loading history...
131
132
            if ('@' === $resource[0]) {
133
                $resource = $this->getLocation($resource);
134
            }
135
        }
136
137
        if (false === $loader = $this->getConfigLoader()->resolve($resource, $type)) {
138
            throw new LoaderLoadException($resource, null, 0, null, $type);
139
        }
140
141
        return $loader->load($resource, $type);
142
    }
143
144
    /**
145
     * Returns the file path for a given service extension or class name resource.
146
     *
147
     * A Resource can be a file or a directory. The resource name must follow the following pattern:
148
     * "@CoreExtension/path/to/a/file.something"
149
     *
150
     * where CoreExtension is the name of the service extension or class,
151
     * and the remaining part is the relative path to a file or directory.
152
     *
153
     * We recommend using composer v2, as this method depends on it or use $baseDir parameter.
154
     *
155
     * @param string $name
156
     *
157
     * @throws \InvalidArgumentException    if the file cannot be found or the name is not valid
158
     * @throws \RuntimeException            if the name contains invalid/unsafe characters
159
     * @throws ContainerResolutionException if the service provider is not included in path
160
     *
161
     * @return string The absolute path of the resource
162
     */
163
    public function getLocation(string $path, string $baseDir = 'src')
164
    {
165
        if (false !== \strpos($path, '..')) {
166
            throw new \RuntimeException(\sprintf('File name "%s" contains invalid characters (..).', $path));
167
        }
168
169
        if ('@' === $path[0]) {
170
            [$bundleName, $path] = \explode('/', \substr($path, 1), 2);
171
172
            if (isset($this->loadedExtensionPaths[$bundleName])) {
173
                return $this->loadedExtensionPaths[$bundleName] . '/' . $path;
174
            }
175
176
            if (null !== $extension = $this->getExtension($bundleName)) {
0 ignored issues
show
Bug introduced by
It seems like getExtension() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

176
            if (null !== $extension = $this->/** @scrutinizer ignore-call */ getExtension($bundleName)) {
Loading history...
177
                $bundleName = \get_class($extension);
178
            }
179
180
            try {
181
                $ref = new \ReflectionClass($bundleName);
182
                $directory = \str_replace('\\', '/', \dirname($ref->getFileName()));
183
            } catch (\ReflectionException $e) {
184
                throw new ContainerResolutionException(\sprintf('Resource path is not supported for %s', $bundleName), 0, $e);
185
            }
186
187
            if ($pos = \strpos($directory, $baseDir)) {
188
                $directory = \substr($directory, 0, $pos + \strlen($baseDir));
189
190
                if (!\file_exists($directory)) {
191
                    $directory = \substr_replace($directory, '', $pos, 3);
192
                }
193
194
                return ($this->loadedExtensionPaths[$bundleName] = \substr($directory, 0, $pos + \strlen($baseDir))) . '/' . $path;
0 ignored issues
show
Bug introduced by
It seems like $directory can also be of type array; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

194
                return ($this->loadedExtensionPaths[$bundleName] = \substr(/** @scrutinizer ignore-type */ $directory, 0, $pos + \strlen($baseDir))) . '/' . $path;
Loading history...
195
            }
196
197
            if (\class_exists(InstalledVersions::class)) {
198
                $rootPath = InstalledVersions::getRootPackage()['install_path'] ?? false;
199
200
                if ($rootPath && $rPos = \strpos($rootPath, 'composer')) {
201
                    $rootPath = \substr($rootPath, 0, $rPos);
202
203
                    if (!$pos = \strpos($directory, $rootPath)) {
204
                        throw new \UnexpectedValueException(sprintf('Looks like package "%s" does not live in composer\'s directory "%s".', InstalledVersions::getRootPackage()['name'], $rootPath));
205
                    }
206
207
                    $parts = \explode('/', \substr($directory, $pos));
208
                    $directory = InstalledVersions::getInstallPath($parts[1] . '/' . $parts[2]);
209
210
                    if (null !== $directory) {
211
                        return ($this->loadedExtensionPaths[$bundleName] = FileSystem::normalizePath($directory)) . '/' . $path;
212
                    }
213
                }
214
            }
215
        }
216
217
        throw new \InvalidArgumentException(\sprintf('Unable to find file "%s".', $path));
218
    }
219
}
220