I'm coming from the Symfony framework where interface autowiring is build-in. It is tiresome that you need to use app binding in a ServiceProvider.
So I wrote a function that can be added to a ServiceProvider boot method.
private function bindContracts(): void {
$contractsPath = __DIR__ . '/../Contracts';
$Directory = new RecursiveDirectoryIterator($contractsPath);
$Iterator = new RecursiveIteratorIterator($Directory);
$Regex = new RegexIterator($Iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH);
$interfaces = new \CallbackFilterIterator($Regex, fn($i) => is_array($i));
foreach ($interfaces as $val) {
$interfaceName = str_replace([$contractsPath, '.php', '/'], ['', '', '\\'], $val[0]);
$interface = "App\Contracts$interfaceName";
$class = "App$interfaceName" ;
if(class_exists($class)) {
$this->app->bind($interface, $class);
}
}
}
This works by mirroring the Contracts directory structure with the App directory structure.
To do this with facades, simply change the directory and the $interface
value.
The next problem is that there is no artisan command that creates classes with interfaces.
<?php
namespace {{ namespace }};
use {{ interfaceNamespace }}\{{ interface }} as {{ interface }}Interface;
class {{ class }} implements {{ interface }}Interface
{
public function __constuct()
{
}
}
<?php
namespace {{ namespace }};
interface {{ interface }}
{
}
These are the stub files for a class and an interface.
<?php
namespace App\Console\Commands;
use Illuminate\Console\GeneratorCommand;
use Symfony\Component\Console\Attribute\AsCommand;
#[AsCommand('make:class')]
class MakeClass extends GeneratorCommand
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $name = 'make:class';
protected $type = 'Console command';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create all sorts of classes with their interface.';
/**
* Execute the console command.
*/
public function handle()
{
if ($this->isReservedName($this->getNameInput())) {
$this->components->error('The name "'.$this->getNameInput().'" is reserved by PHP.');
return false;
}
$name = $this->getNameInput();
$classNamespace = $this->rootNamespace();
$interFaceNamespace = $classNamespace . "Contracts\\";
if(strpos($name, '\\') > 1) {
[$partialNamespace, $name] = str_split($name, strrpos($name, '\\'));
$name = substr($name, 1);
$classNamespace .= $partialNamespace;
$interFaceNamespace .= $partialNamespace;
}
$classFile = $this->getPath("$classNamespace\\$name");
$interfaceFile = $this->getPath("$interFaceNamespace\\$name");
$this->makeDirectory($classNamespace);
$this->makeDirectory($interFaceNamespace);
[$classStub, $interfaceStub] = $this->getStub();
$interfaceStubFile = $this->files->get($interfaceStub);
$interfaceContent = $this->replaceNamespaceService($interfaceStubFile, $interFaceNamespace);
$interfaceContent = $this->replaceInterface($interfaceContent, $name);
$this->files->put($interfaceFile, $interfaceContent);
$classStubFile = $this->files->get($classStub);
$classContent = $this->replaceNamespaceService($classStubFile, $classNamespace);
$classContent = $this->replaceInterface($classContent, $name, $interFaceNamespace);
$classContent = $this->replaceClass($classContent, $name);
$this->files->put($classFile, $classContent);
$this->components->info(sprintf('%s [%s] created successfully.', $name, $classFile));
$this->components->info(sprintf('%s [%s] created successfully.', $name, $interfaceFile));
}
protected function getStub()
{
return [
__DIR__ . '/stubs/class.stub',
__DIR__ . '/stubs/interface.stub'
];
}
protected function replaceNamespaceService($stub, $name)
{
$stub = str_replace(['{{ namespace }}', '{{namespace}}'], $name, $stub);
return $stub;
}
protected function replaceInterface($stub, $name, $namespace = '')
{
$stub = str_replace(['DummyInterface', '{{ interface }}', '{{interface}}'], $name, $stub);
if(strlen($namespace)) {
$stub = str_replace(['{{ interfaceNamespace }}', '{{interfaceNamespace}}'], $namespace, $stub);
}
return $stub;
}
}
I have overridden the make:class
command to make all sorts of classes.
This makes working with Laravel easier for me.
Top comments (0)