Passed
Push — main ( c1689c...c69b94 )
by Michael
03:36
created

BindsToContainer::prepareActual()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 1
c 1
b 1
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
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 Symfony\Component\Finder\SplFileInfo;
11
12
trait BindsToContainer
13
{
14
    /**
15
     * Run the directory scanning & bind the results.
16
     *
17
     * @return void
18
     */
19 13
    protected function scan(): void
20
    {
21 13
        $this->getFolderFiles()->each(
22 12
            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

22
            fn (array $files, string $actualFolder) => LazyCollection::make(/** @scrutinizer ignore-type */ $files)->each(
Loading history...
23 12
                function (SplFileInfo $file) use ($actualFolder) {
24 12
                    $relativePath             = $file->getRelativePathname();
25 12
                    $filenameWithoutExtension = $file->getFilenameWithoutExtension();
26 12
                    $filenameWithRelativePath = $this->prepareFilename($relativePath);
27
28 12
                    $interface = $this->interfaceFrom($filenameWithoutExtension);
29 12
                    $concrete  = $this->concreteFrom($actualFolder, $filenameWithRelativePath);
30
31 12
                    if (! interface_exists($interface) || ! class_exists($concrete)) {
32 10
                        return;
33
                    }
34
35 12
                    $dependencies = collect($this->dependencies);
36
37 12
                    $concrete = match (true) {
38 12
                        $dependencies->has($interface) => $dependencies->get($interface),
39 11
                        $dependencies->has($concrete)  => $dependencies->get($concrete),
40 10
                        default                        => $concrete,
41
                    };
42
43 12
                    app()->{$this->bindingType}($interface, $concrete);
44
                }
45
            )
46
        );
47
    }
48
49
    /**
50
     * Get the folder files except for ignored ones.
51
     *
52
     * @return LazyCollection
53
     */
54 13
    protected function getFolderFiles(): LazyCollection
55
    {
56 13
        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

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