Laravel: autowire contracts or facades

RMAG news

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 = “AppContracts$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 AppConsoleCommands;

use IlluminateConsoleGeneratorCommand;
use SymfonyComponentConsoleAttributeAsCommand;

#[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.

Leave a Reply

Your email address will not be published. Required fields are marked *