Passed
Branch main (9144f9)
by Michael
11:35
created

BindsToContainer::scan()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 14
nc 1
nop 0
dl 0
loc 23
ccs 15
cts 15
cp 1
crap 3
rs 9.7998
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 Symfony\Component\Finder\SplFileInfo;
11
12
trait BindsToContainer
13
{
14
    /**
15
     * Run the directory scanning & bind the results.
16
     *
17
     * @return void
18
     */
19 12
    protected function scan(): void
20
    {
21 12
        $this->getFolderFiles()->each(function (SplFileInfo $file) {
22 11
            $relativePath             = $file->getRelativePathname();
23 11
            $filenameWithoutExtension = $file->getFilenameWithoutExtension();
24 11
            $filenameWithRelativePath = $this->prepareFilename($relativePath);
25
26 11
            $interface = $this->interfaceFrom($filenameWithoutExtension);
27 11
            $concrete  = $this->concreteFrom($filenameWithRelativePath);
28
29 11
            if (! interface_exists($interface) || ! class_exists($concrete)) {
30 9
                return;
31
            }
32
33 11
            $dependencies = collect($this->dependencies);
34
35 11
            $concrete = match (true) {
36 11
                $dependencies->has($interface) => $dependencies->get($interface),
37 10
                $dependencies->has($concrete)  => $dependencies->get($concrete),
38 9
                default                        => $concrete,
39
            };
40
41 11
            app()->{$this->bindingType}($interface, $concrete);
42
        });
43
    }
44
45
    /**
46
     * Get the folder files except for ignored ones.
47
     *
48
     * @return LazyCollection
49
     */
50 12
    protected function getFolderFiles(): LazyCollection
51
    {
52 12
        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

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