Contracts
Introdução
Os contratos Laravel são um conjunto de interfaces que definem o núcleo de serviços que são fornecidos pelo framework. Por exemplo, o contrato Queue
defini o os métodos necessários para queueing jobs(enfileirar trabalhos), enquanto o contrato Mailer
defini os métodos necessários para o envio e-mails.
Cada contratos tem uma implementação correspondente fornecidade pelo o frameork. Por exemplo, Laravel fornece a implementação de Queue
com a variedade de drivers, e a implementação de Mailer
é alimentada pelo SwiftMailer.
Todo os contratos de Laravel vivem nos seus proprios repositórios GitHub. Isto fornece um rápido ponto de referência para todos os contratos disponíveis, bem como um pacote único, desacoplado que pode ser utilizado por outros desenvolvedores de pacotes.
Porque Contratos ?
Você pode ter várias questões sobre contratos. Porque usar interfaces como um todo? Não usar interfaces é mais complicado?
Vamos destrinchar as razões para usar inteface para os seguintes tópicos: baixo acoplamento e simplicidade.
Baixo Acoplamento
Primeiro, vamos revisar algum código que estreitamente ligado a implementação de cache. Considere o seguinte:
<?php namespace App\Orders;
class Repository {
/**
* The cache.
*/
protected $cache;
/**
* Create a new repository instance.
*
* @param \SomePackage\Cache\Memcached $cache
* @return void
*/
public function __construct(\SomePackage\Cache\Memcached $cache)
{
$this->cache = $cache;
}
/**
* Retrieve an Order by ID.
*
* @param int $id
* @return Order
*/
public function find($id)
{
if ($this->cache->has($id))
{
//
}
}
}
Nesta classe, o código é estreitamente acoplado para uma dada implementação de cache. Isto é estreitamente acoplado porque nos dependemos de uma classe Cache concreta, de um pacote vendor. Se a API do pacote muda nosso código também deve mudar.
Da mesma forma, se nos substituirmos nossa tecnologia cache subjacente (Memcached) com outra tecnologia (Redis), que novamente iremos ter que modificar nosso repositório. Nosso repositório deve não ter muito conhecimento a respeito a quem está fornecendo-lhe dados ou como eles estão fornecedo-os.
Aos invés desta abordagem, nos podemos melhorar nosso código pela dependência de uma simples interface agnóstica do vendor:
<?php namespace App\Orders;
use Illuminate\Contracts\Cache\Repository as Cache;
class Repository {
/**
* Create a new repository instance.
*
* @param Cache $cache
* @return void
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
}
Agora o código é não acoplado para qualquer vendor específico, ou até mesmo Laravel. Uma vez que os pacotes de contratos contenham nenhuma implementação e dependência, você pode facilmente escrever uma implementação alternativa de qualquer contrato dado, permitindo você possa substituir sua implementação cache sem modificar qualquer dos seus códigos consumidores de cache.
Simplicidade
Quando todos os serviços do Laravel são bem definidos dentro interfaces simples, isto é muito fácil de determinar a funcionalidade oferecida por um determinado serviço. Os contratos servem como uma documentação sucinta às funcionalidades do framework Laravel.
Além disso, quando você depende de interfaces simples, seu código é mais fácil de entender e manter. Ao invés de inspecionar dentro dos métodos que estão disponívels para você dentro de grande e complicada classe, você pode se referir a uma simples e limpa interface.
Referência do Contrato
Isto é a referencia para a maioria dos contratos do Laravel, bem como as "fachadas" Laravel contrapartidas:
Como Usar Contratos
Então, como você pode começar a implementação de contrato? Na verdade é muito simples. Muitos tipos de classes em Laravel são resolvidas pro meio do container de serviços, incluíndo controladores, listeners(ouvidores) de eventos, queue jobs(trabalhos em fila), e até mesmo Closures de rota. Então, para começar a implementação de um contrato, você pode apenas "tipar" a interface no contrutor da classe que está sendo resolvida. Por exemplo, de uma olhada neste manipulador de evento.
<?php namespace App\Handlers\Events;
use App\User;
use App\Events\NewUserRegistered;
use Illuminate\Contracts\Redis\Database;
class CacheUserInformation {
/**
* The Redis database implementation.
*/
protected $redis;
/**
* Create a new event handler instance.
*
* @param Database $redis
* @return void
*/
public function __construct(Database $redis)
{
$this->redis = $redis;
}
/**
* Handle the event.
*
* @param NewUserRegistered $event
* @return void
*/
public function handle(NewUserRegistered $event)
{
//
}
}
Quando os listener de evento é resolvido, o container de serviço irá ler a tipagem no construtor da classse, e irá injetar o valor apropriado. Para aprender mais sobre como registrar as coisas no container de serviços, dê uma olhada na documentação.