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
![]() |
|||||||
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
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
![]() |
|||||||
49 | 19 | $this->cacheBindingFor($interface, $concrete); |
|||||
0 ignored issues
–
show
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
![]() |
|||||||
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
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
![]() |
|||||||
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 |