david duymelinck
Posted on April 28, 2024
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.
Posted on April 28, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 27, 2024
November 21, 2024