DEV Community

david duymelinck
david duymelinck

Posted on

Laravel: autowire contracts or facades

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); } } } 
Enter fullscreen mode Exit fullscreen mode

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() { } } 
Enter fullscreen mode Exit fullscreen mode
<?php namespace {{ namespace }}; interface {{ interface }} { } 
Enter fullscreen mode Exit fullscreen mode

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; } } 
Enter fullscreen mode Exit fullscreen mode

I have overridden the make:class command to make all sorts of classes.

This makes working with Laravel easier for me.

Top comments (0)