BindsToContainer::providesCache()   A
last analyzed

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
    private ?bool $providesCache = null;
17
18
    /**
19
     * Run the directory scanning & bind the results.
20
     *
21
     * @throws ContainerExceptionInterface
22
     * @throws NotFoundExceptionInterface
23
     */
24 23
    protected function scan(): void
25
    {
26 23
        $this->getFolderFiles()->each(
27 23
            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

27
            fn (array $files, string $actualFolder) => LazyCollection::make(/** @scrutinizer ignore-type */ $files)->each(
Loading history...
28 23
                function (SplFileInfo $file) use ($actualFolder) {
29 22
                    $relativePath = $file->getRelativePathname();
30 22
                    $filenameWithoutExtension = $file->getFilenameWithoutExtension();
31 22
                    $filenameWithRelativePath = $this->prepareFilename($relativePath);
32
33 22
                    $interface = $this->interfaceFrom($filenameWithoutExtension);
34 22
                    $concrete = $this->concreteFrom($actualFolder, $filenameWithRelativePath);
35
36 22
                    if (! interface_exists($interface) || ! class_exists($concrete)) {
37 21
                        return;
38
                    }
39
40 21
                    $dependencies = collect($this->dependencies);
41
42 21
                    $concrete = match (true) {
43 21
                        $dependencies->has($interface) => $dependencies->get($interface),
44 21
                        $dependencies->has($concrete) => $dependencies->get($concrete),
45 21
                        default => $concrete,
46 21
                    };
47
48 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

48
                    if ($this->providesCache() && $this->/** @scrutinizer ignore-call */ cacheEnabled()) {
Loading history...
49 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

49
                        $this->/** @scrutinizer ignore-call */ 
50
                               cacheBindingFor($interface, $concrete);
Loading history...
50
                    }
51
52 21
                    app()->{$this->bindingType}($interface, $concrete);
53 23
                }
54 23
            )
55 23
        );
56
    }
57
58
    /**
59
     * Get the folder files except for ignored ones.
60
     *
61
     * @return LazyCollection<string, array<SplFileInfo>>
62
     */
63 23
    protected function getFolderFiles(): LazyCollection
64
    {
65 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

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