Extending The Framework
- Gerenciadores & Factories(Fábricas)
- Cache
- Sessões
- Autenticação
- Conteiner de Serviço Baseado em Extensão
Gerenciadores & Factories(Fábricas)
Laravel tem várias classes gerenciadoras
que gerenciam a criação de drivers baseados-em-componentes. Estes incluem o cache, seção, autenticação, e componentes de queue(fila). A classe gerenciadora é responsável pela criação de uma implementação de driver específico baseado na configuração da aplicação. Por exemplo, a classe CacheManager
pode criar APC, Mencached, Arquivos, e várias outras implementações de drivers de cache.
Cada um dos gerenciadores incluem um método extend
que pode ser usado para facilmente a injetar de novas funcionalidades de resolução de drivers no gerenciador. Nos iremos cobrir cada desses gerenciadores abaixo, com exemplos de como injetar um driver de suporte customizado em cada um deles.
Nota: Pegue um momento para explorar várias classes
gerenciadoras
que vem com o Laravel, como oCacheManager
e aSessionManager
. Lendo por essas classes dará um entendimento completo a mais de como Laravel trabalha por baixo dos panos. Todas as classes gerenciadoras extendem da classe base `Illuminate\Support\Manager, que fornece algumas coisas úteis, funcionalidade comum para cada gerenciador.
Cache
Para extender da instalações do cache do laravel, nos iremos usar o método extend
no CacheManager
, que é usado para vincular um driver resolvedor customizado a um gerenciador, e é comum a todas as classes gerenciadoras. Por exemplo, para o registrar um novo driver cache chamado "mongo", nos podemos fazer o seguinte:
Cache::extend('mongo', function($app)
{
return Cache::repository(new MongoStore);
});
O primeiro argumento passado para o método extend
é o nome do driver. Isto irá corresponder a sua opção driver
no seu arquivo de configuração config/cache.php
. O segundo argumento é um Closure que deve retornar uma instância de Illuminate\Cache\Repository
. A Closure será passada à uma instância de $app
, que é uma instância de Illuminate\Foundation\Application
e um container de serviços.
A chamada para Cache::extend
pode ser realizada no método boot
do padrão App\Providers\AppServiceProvider
que vem em instalações nativas de aplicações Larave, ou você pode criar seu próprio fornecedor de serviço para alojar a extenção - apenas não se esqueça de registrar o fornecedor, no array provider no arquivo config/app.php
.
Para criar nosso driver cache customizado, nos primeiro precisamos implementar o contrato Illuminate\Contracts\Cache\Store
. Então, nossa implementação de cache MongoDB deve parecer com isto:
class MongoStore implements Illuminate\Contracts\Cache\Store {
public function get($key) {}
public function put($key, $value, $minutes) {}
public function increment($key, $value = 1) {}
public function decrement($key, $value = 1) {}
public function forever($key, $value) {}
public function forget($key) {}
public function flush() {}
}
Nos apenas precisamos implementar cada um destes métodos usando uma conexão MongoDB. Uma vez que nossa implementação é completa, nos podemos finalizar o registro do nosso driver customizado.
Cache::extend('mongo', function($app)
{
return Cache::repository(new MongoStore);
});
Se você estiver pensativo sobre aonde alocar o código do seu driver de cache customizado, considere fazer com que o mesmo esteja disponível no Packagist! OU, você pode criar o namespace Extensions
(Extenções) dentro do seu diretório app
. No entanto, tenha em mente que o Laravel não tem uma estrutura de aplicação rígida e você é livre para organizar a sua aplicação de acordo com suas preferências.
Sessões
Extender do Laravel com um driver de sessão customizado é tão fácil quando extender do sistema de cache. Novamente, nos iremos usar o método extend
para registrar nosso código customizado.
Session::extend('mongo', function($app)
{
// Return implementation of SessionHandlerInterface
});
Onde Extender A Sessão
Você deve alocar seu código de extenção da sessão no método boot
do seu AppServiceProvider
.
Escrevendo A extensão Session (Sessão)
Note que o nosso driver se sessão customizado deve implementar a SessionHandlerInterface
. Esta interface contém apenas alguns simples métodos que nos precisamos implementar. Uma implementação MongoDB encurtada deve parece com algo assim:
class MongoHandler implements SessionHandlerInterface {
public function open($savePath, $sessionName) {}
public function close() {}
public function read($sessionId) {}
public function write($sessionId, $data) {}
public function destroy($sessionId) {}
public function gc($lifetime) {}
}
Desde que estes métodos não são tão compreensíveis a leitura quanto os da cache StoreInterface
, vamos rapidamenta explicar o que cada um destes métodos faz:
- O método
open
deve tipicamente ser usado em um arquivo baseado nos sistemas de armazenamento de sessão. Desde que o Laravel entrega o driver da sessão com umarquivo
, você quase nunca precisará colocar qualquer coisa neste método. Você pode deixar isto em um stub vazio. Isto é pelo simples fato de um design de interface pobre (que nos iremos discutir posteriormente) que o PHP requere que nos façamos a implementação deste método. - O método
close
, como o métodoopen
, pode também ser usualmente desconsiderado. Para a maioria dos drivers, isto não é necessário. - O método
read
deve retornar a versão string dos dados da sessão associados com o$sessionId
dado. Não há necessidado para qualquer serealizaççao ou outra codificação quando se esta recuperando ou armazenando dados de sessão no seu driver, já que o Laravel fará a serialização para você. - O método
write
deve escrever a string$data
dada associada com o$sessionId
para algum sistema de armazenamento de persistênte, tais como MongoDB, Dynamo, etc. - O método
destroy
deve remover os dados associados com o$sessionId
do armazenamento persistente. - O método
gc
deve destroir todos os dados da sessão que é mais velho do que$lifetime
(tempo-de-vida) dado, que é um timestamp UNIX. Para sistemas auto-expiração como Memcached e Redis, este método pode ser deixado vazio.
Uma vez que a SessionHandlerInterface
tiver sido implementada, nos estaremos prontos para registrar isto com o gerenciador de Sessão:
Session::extend('mongo', function($app)
{
return new MongoHandler;
});
Uma vez que o driver de sessão tiver sido registrado, nos podemos usar o driver mongo
nos seu arquivo de configuração config/session.php
.
Nota: Lembre-se, se você escrever um manipulador de sessão customizado, compartilhe isso no Packagist!
Autenticação
Autenticação pode ser extendida do mesma forma que as instalações de cache e sessão. Novamente, no iremos usar o método extend
que nós nos tornamos familiarizados com:
Auth::extend('riak', function($app)
{
// Return implementation of Illuminate\Contracts\Auth\UserProvider
});
As implementações de UserProvider
são apenas responsáveis por buscar a implementação Illuminate\Contracts\Auth\Authenticatable
fora de um sistema de armazenamento persistente, como MySQL, Riak, etc. Estas duas interfaces permitem o mecanismo de autenticação do Laravel continuar funcionando independentemente da como os dados do usuário é armazenado ou que tipo de classe é usado para reprensentar isto.
Vamos dar uma olhada no contrato UserProvider
:
interface UserProvider {
public function retrieveById($identifier);
public function retrieveByToken($identifier, $token);
public function updateRememberToken(Authenticatable $user, $token);
public function retrieveByCredentials(array $credentials);
public function validateCredentials(Authenticatable $user, array $credentials);
}
A função retrieveById
típicamente recebe uma chave númerica representando o usuário, tanto como um ID auto-incrementing de um banco de dados MySQL. A implementação Authenticatable
combinando o ID deve ser recuperado e retornado pelo método.
A função retrieveByToken
recupera um usuário pelo seu único $identifier
e pelo $token
"Lembre-me", armazenado em um campo remember_token
. Como o método prévido, a implemtanção de Authenticatable
deve ser retornado.
O método updateRememberToken
atualiza o campo remember_token
do (usuário) $user
com um novo $token
. O novo token pode ser tanto um token recém gerado, atribuído em uma tentativa de login "Lembre-me" de sucesso, ou um usuário nulo é deslogado.
O método retrieveByCredentials
recebe um arrya de credenciais passados para o método Auth::attempt
quando se tenta entrar na aplicação. O método deve então "consultado(query)" o armazenamento persistente subjacente para verificar as credenciais. Tipicamente, este método irá executar uma query com a condição "where"(onde) no $credentials['username']
. O método deve então retornar a implementação do UserInterface
. Este método não deve tentar fazer qualquer avaliação de senha ou atenticação.
O método validateCredentials
deve comparar o dado $user
(usuário) com as $credentials
(credenciais) para autenticar o usuário. Por exemplo, este método pode compara a string $user->getAuthPassword()
ao Hash::make
do $credentials['password']
. Este método deve apenas validar as credenciais do usuário e retornar um boolean.
Agora que nos temos explorado cada um dos méotodos no UserProvider
, vamos dar uma olhada na Authenticatable
. Lembre-se, o fornecedor deve retornar implementações desta interface a partir dos métodos retrieveById
e retrieveByCredentials
:
interface Authenticatable {
public function getAuthIdentifier();
public function getAuthPassword();
public function getRememberToken();
public function setRememberToken($value);
public function getRememberTokenName();
}
This interface is simple. The getAuthIdentifier
method should return the "primary key" of the user. In a MySQL back-end, again, this would be the auto-incrementing primary key. The getAuthPassword
should return the user's hashed password. This interface allows the authentication system to work with any User class, regardless of what ORM or storage abstraction layer you are using. By default, Laravel includes a User
class in the app
directory which implements this interface, so you may consult this class for an implementation example.
Finally, once we have implemented the UserProvider
, we are ready to register our extension with the Auth
facade:
Auth::extend('riak', function($app)
{
return new RiakUserProvider($app['riak.connection']);
});
After you have registered the driver with the extend
method, you switch to the new driver in your config/auth.php
configuration file.
Conteiner de Serviço Baseado em Extensão
Quase todos os fornecedores de serviços incluídos com o famework Laravel combinam objetos em um container de serviços. Você pode achar a lista dos fornecedores de serviço da sua aplicação no seu arquivo de configuração config/app.php
. Como você tem tempo, você deve percorrer pelo código fonte de cada um desses fornecedores de serviço. Ao fazer isto, você irá ganhar um melhor entendimento do que cada fornecedor adiciona ao framework, bem como quais chaves são usadas para combinar vários serviços em um container de serviço.
Por exemplo, o HashServiceProvider
combina uma chave hash
em um container de serviço, que resolve na instância de Illuminate\Hashing\BcryptHasher
. Você pode facilmente extender e sobrescrever esta classe dentro da sua aplicação sobrescrevendo esta combinação. Por exemplo:
<?php namespace App\Providers;
class SnappyHashProvider extends \Illuminate\Hashing\HashServiceProvider {
public function boot()
{
parent::boot();
$this->app->bindShared('hash', function()
{
return new \Snappy\Hashing\ScryptHasher;
});
}
}
Note que esta classe extende a HashServiceProvider
, e não a classe base padrãoServiceProvider
. Uma vez que você tenha extendido o fornecedo de serviço, troque o
HashServiceProvider
no seu arquivo de configuração config/app.php
com o nome do seu fornecedor de serviço extendido.
Isto é o método geral de extensão de qualquer classe do core(núcleo) que está ligada ao container. Essencialmente toda classe de core(núcleo) é ligada ao container desta forma, e pode ser sobrescrita. Novamente, a leitura através dos fornecedores de serviços incluídos no framework irão famialirizar você com onde várias classe são ligadas ao container, e quais chaves por quais eles estão ligados. Este é um grande método para aprender mais sobre como os componentes do Laravel são unidos.