Passed
Pull Request — main (#1)
by Michael
03:07
created

BindsToContainer::run()   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\Collection;
8
use Illuminate\Support\Facades\File;
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 run(): 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 Collection
49
     */
50 12
    protected function getFolderFiles(): Collection
51
    {
52 12
        return collect(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 $value of collect(). ( 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 collect(/** @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::of($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::of($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
        if (is_null($guessedInterface)) {
112 4
            return $this->buildInterfaceBy($filenameWithoutExtension);
113
        }
114
115 7
        return $guessedInterface;
116
    }
117
118
    /**
119
     * Guess the interface with a given filename.
120
     *
121
     * @param string $filenameWithoutExtension
122
     *
123
     * @return string|null
124
     */
125 11
    protected function guessInterfaceBy(string $filenameWithoutExtension): ?string
126
    {
127 11
        if (! Str::contains($this->interfaceNamespace, '\\')) {
128 7
            return $this->buildInterfaceFromClassBy($filenameWithoutExtension);
129
        }
130
131 4
        return null;
132
    }
133
134
    /**
135
     * Build the interface class-string.
136
     *
137
     * @param string $filename
138
     *
139
     * @return string
140
     */
141 4
    protected function buildInterfaceBy(string $filename): string
142
    {
143 4
        return $this->interfaceNamespace . '\\'
144 4
            . $this->prepareNamingFor($filename)
145 4
            . ($this->interfaceNaming);
146
    }
147
148
    /**
149
     * Build the interface class-string based on the class folder.
150
     *
151
     * @param string $filename
152
     *
153
     * @return string
154
     */
155 7
    protected function buildInterfaceFromClassBy(string $filename): string
156
    {
157 7
        return $this->classNamespace . '\\'
158 7
            . $this->classFolder . '\\'
159 7
            . $this->interfaceNamespace . '\\'
160 7
            . $this->prepareNamingFor($filename)
161 7
            . ($this->interfaceNaming);
162
    }
163
164
    /**
165
     * Cleans up filename to append the desired interface name.
166
     *
167
     * @param string $filename
168
     *
169
     * @return string
170
     */
171 11
    protected function prepareNamingFor(string $filename): string
172
    {
173 11
        return Str::replace($this->interfaceNaming, '', $filename);
174
    }
175
}
176