Passed
Push — main ( e73dd9...4c351e )
by Michael
01:01 queued 13s
created

BindsToContainer::providesCache()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 9
ccs 5
cts 5
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MichaelRubel\AutoBinder\Traits;
6
7
use Illuminate\Support\Facades\File;
8
use Illuminate\Support\LazyCollection;
9
use Illuminate\Support\Str;
10
use Psr\Container\ContainerExceptionInterface;
11
use Psr\Container\NotFoundExceptionInterface;
12
use Symfony\Component\Finder\SplFileInfo;
13
14
trait BindsToContainer
15
{
16
    /**
17
     * @var bool|null
18
     */
19
    private ?bool $providesCache = null;
20
21
    /**
22
     * Run the directory scanning & bind the results.
23
     *
24
     * @return void
25
     * @throws ContainerExceptionInterface
26
     * @throws NotFoundExceptionInterface
27
     */
28 23
    protected function scan(): void
29
    {
30 23
        $this->getFolderFiles()->each(
31 22
            fn (array $files, string $actualFolder) => LazyCollection::make($files)->each(
0 ignored issues
show
Bug introduced by
$files of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Illuminate\Support\LazyCollection::make(). ( Ignorable by Annotation )

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

31
            fn (array $files, string $actualFolder) => LazyCollection::make(/** @scrutinizer ignore-type */ $files)->each(
Loading history...
32 22
                function (SplFileInfo $file) use ($actualFolder) {
33 22
                    $relativePath = $file->getRelativePathname();
34 22
                    $filenameWithoutExtension = $file->getFilenameWithoutExtension();
35 22
                    $filenameWithRelativePath = $this->prepareFilename($relativePath);
36
37 22
                    $interface = $this->interfaceFrom($filenameWithoutExtension);
38 22
                    $concrete = $this->concreteFrom($actualFolder, $filenameWithRelativePath);
39
40 22
                    if (! interface_exists($interface) || ! class_exists($concrete)) {
41 21
                        return;
42
                    }
43
44 21
                    $dependencies = collect($this->dependencies);
45
46 21
                    $concrete = match (true) {
47 21
                        $dependencies->has($interface) => $dependencies->get($interface),
48 21
                        $dependencies->has($concrete) => $dependencies->get($concrete),
49 21
                        default => $concrete,
50
                    };
51
52 21
                    if ($this->providesCache() && $this->cacheEnabled()) {
0 ignored issues
show
Bug introduced by
It seems like cacheEnabled() 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

52
                    if ($this->providesCache() && $this->/** @scrutinizer ignore-call */ cacheEnabled()) {
Loading history...
53 19
                        $this->cacheBindingFor($interface, $concrete);
0 ignored issues
show
Bug introduced by
It seems like cacheBindingFor() 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

53
                        $this->/** @scrutinizer ignore-call */ 
54
                               cacheBindingFor($interface, $concrete);
Loading history...
54
                    }
55
56 21
                    app()->{$this->bindingType}($interface, $concrete);
57
                }
58
            )
59
        );
60
    }
61
62
    /**
63
     * Get the folder files except for ignored ones.
64
     *
65
     * @return LazyCollection<string, array<SplFileInfo>>
66
     */
67 23
    protected function getFolderFiles(): LazyCollection
68
    {
69 23
        return LazyCollection::make(File::directories(base_path($this->basePath . DIRECTORY_SEPARATOR . $this->classFolder)))
0 ignored issues
show
Bug introduced by
Illuminate\Support\Facad... . $this->classFolder)) of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Illuminate\Support\LazyCollection::make(). ( Ignorable by Annotation )

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

69
        return LazyCollection::make(/** @scrutinizer ignore-type */ File::directories(base_path($this->basePath . DIRECTORY_SEPARATOR . $this->classFolder)))
Loading history...
70 22
            ->reject(fn (string $folder) => in_array(basename($folder), $this->excludesFolders))
71 22
            ->mapWithKeys(fn (string $folder) => [basename($folder) => File::allFiles($folder)]);
72
    }
73
74
    /**
75
     * Prepare the filename.
76
     *
77
     * @param  string  $filename
78
     *
79
     * @return string
80
     */
81 22
    protected function prepareFilename(string $filename): string
82
    {
83 22
        return str($filename)
84 22
            ->replace('/', '\\')
85 22
            ->substr(0, strrpos($filename, '.'))
86 22
            ->value();
87
    }
88
89
    /**
90
     * Get the namespace from a given path.
91
     *
92
     * @param  string  $path
93
     *
94
     * @return string
95
     */
96 22
    protected function namespaceFrom(string $path): string
97
    {
98 22
        return str($path)
99 22
            ->replace('/', '\\')
100 22
            ->ucfirst()
101 22
            ->value();
102
    }
103
104
    /**
105
     * Get the concrete from filename.
106
     *
107
     * @param  string  $folder
108
     * @param  string  $filenameWithRelativePath
109
     *
110
     * @return string
111
     */
112 22
    protected function concreteFrom(string $folder, string $filenameWithRelativePath): string
113
    {
114 22
        return $this->classNamespace . '\\'
115 22
            . $this->classFolder . '\\'
116 22
            . $this->prepareActual($folder . '\\')
117 22
            . $this->prepareNamingFor($filenameWithRelativePath);
118
    }
119
120
    /**
121
     * Get the interface from filename.
122
     *
123
     * @param  string  $filenameWithoutExtension
124
     *
125
     * @return string
126
     */
127 22
    protected function interfaceFrom(string $filenameWithoutExtension): string
128
    {
129 22
        $guessedInterface = $this->guessInterfaceBy($filenameWithoutExtension);
130
131 22
        return ! is_null($guessedInterface)
132 15
            ? $guessedInterface
133 22
            : $this->buildInterfaceBy($filenameWithoutExtension);
134
    }
135
136
    /**
137
     * Guess the interface with a given filename.
138
     *
139
     * @param  string  $filenameWithoutExtension
140
     *
141
     * @return string|null
142
     */
143 22
    protected function guessInterfaceBy(string $filenameWithoutExtension): ?string
144
    {
145 22
        return ! Str::contains($this->interfaceNamespace, '\\')
146 14
            ? $this->buildInterfaceFromClassBy($filenameWithoutExtension)
147 22
            : null;
148
    }
149
150
    /**
151
     * Build the interface class-string.
152
     *
153
     * @param  string  $filename
154
     *
155
     * @return string
156
     */
157 8
    protected function buildInterfaceBy(string $filename): string
158
    {
159 8
        return $this->interfaceNamespace . '\\'
160 8
            . $this->prepareNamingFor($filename)
161 8
            . $this->interfaceNaming;
162
    }
163
164
    /**
165
     * Build the interface class-string based on the class folder.
166
     *
167
     * @param  string  $filename
168
     *
169
     * @return string
170
     */
171 15
    protected function buildInterfaceFromClassBy(string $filename): string
172
    {
173 15
        return $this->classNamespace . '\\'
174 15
            . $this->classFolder . '\\'
175 15
            . $this->interfaceNamespace . '\\'
176 15
            . $this->prepareNamingFor($filename)
177 15
            . $this->interfaceNaming;
178
    }
179
180
    /**
181
     * Cleans up filename to append the desired interface name.
182
     *
183
     * @param  string  $filename
184
     *
185
     * @return string
186
     */
187 22
    protected function prepareNamingFor(string $filename): string
188
    {
189 22
        return Str::replace($this->interfaceNaming, '', $filename);
190
    }
191
192
    /**
193
     * prepares an actual folder.
194
     *
195
     * @param  string  $folder
196
     *
197
     * @return string
198
     */
199 22
    protected function prepareActual(string $folder): string
200
    {
201 22
        return Str::replace(Str::plural($this->interfaceNaming) . '\\', '', $folder);
202
    }
203
204
    /**
205
     * Check if the class use `CachesBindings` trait.
206
     *
207
     * @return bool
208
     */
209 22
    protected function providesCache(): bool
210
    {
211 22
        if ($this->providesCache) {
212 20
            return true;
213
        }
214
215 22
        $uses = class_uses_recursive(static::class);
216
217 22
        return $this->providesCache = in_array(CachesBindings::class, $uses);
218
    }
219
}
220