Advertisement
  1. Code
  2. PHP
  3. Laravel

Desconstruindo Laravel: Session, Auth e Cache

Scroll to top
Read Time: 21 min

() translation by (you can also view the original English article)

Nos últimos anos, Laravel tornou-se uma das frameworks mais importantes e utilizadas por engenheiros de software na hora de construir suas aplicações web. Com popularidade semelhante à do CodeIgniter em seus dias de glória, Laravel tem sido louvado pela sua simplicidade, facilidade de uso por parte dos iniciantes e aderência aos padrões da indústria.

Introdução

Algo que muitos programadores deixam de aproveitar do Laravel é a sua componentização. Desde sua conversão à utilização de componentes que lançam utilizam o Composer, Laravel 4 tornou-se um sistema bastante modular, semelhante às frameworks mais maduras, como a Symfony. Ela usa o grupo de componentes chamado de Illuminate, que, na minha opinião, não é a framework em si, mas uma compilação de bibliotecas que uma framework pode chegar a usar. A framework Laravel, de verdade, é representada pela aplicação base do Laravel (encontrada no repositório do GitHub chamado laravel/laravel), que faz uso desses componente para construir uma aplicação web.

Nesse tutorial, nós nos aprofundaremos em alguns dos componentes desse grupo, aprendendo como eles funcionam, como eles são utilizados pela framework e como estender a funcionalidade deles.

O Componente Session

O componente Session do Laravel lida com as sessões das aplicações web. Ele faz uso de um sistema de drivers chamado Laravel Manager, que age tanto como uma fábrica (do padrão de programação Factory) quanto um envólucro para qualquer driver atribuído no arquivo de configuração. Até o momento da escrita desse post, o componente Session tem os seguintes drivers:

  • file - driver baseado em arquivo, onde os dados da sessão são salvos em um arquivo criptografado.
  • cookie - driver baseados em cookies, onde os dados da sessão são salvos de forma criptografada nos cookies (do navegador) do usuário.
  • database - os dados da sessão são salvos na base de dados configurada para a aplicação.
  • apc - os dados da sessão são salvos no APC (Alternative PHP Cache).
  • memcached - os dados da sessão são salvas no Memcached.
  • redis - os dados da sessão são salvo no Redis.
  • array - os dados da sessão são salvos em uma array do PHP. Atente que o driver de sessão baseado em array não dá suporte a persistência de dados e, geralmente, é usado somente em linha de comando.

Provedores de Serviço

A maioria dos usuários de Laravel não percebem mas, grande parte de como o Laravel funciona se deve aos seus provedores de serviço. Os provedores de serviços são, em essência, arquivos inicializadores de cada componente e eles são tão abstraídos que os usuários podem utilizá-los para inicializar qualquer componente, de qualquer forma.

Uma explicação grosseira de como isso funciona segue abaixo:

  1. O componente Application do Laravel é inicializado. Esse é o driver principal de toda a framework, responsável por lidar com as Requisições HTTP, executar os provedores de serviços, e agir como recipiente de dependências para a framework.
  2. Uma vez que um provedor de serviço é executado, o método register dele é chamado. Isso permite instanciar qualquer componente que quisermos.
    • Tenha em mente que todos os provedores de serviço tem acesso à aplicação principal do Laravel (via $this->app), o que permite que os provedores de serviços tenham acesso a instâncias de classes criadas de dentro do recipiente de depedência.
  3. Uma vez que essas dependências são carregadas, nós estamos livres para chamar o recipiente, por exemplo, pelo sistema Facade do Laravel, através do App::make.

Voltando ao componente Sessions, daremos uma rápida olhada no SessionServiceProivider:

1
 /**

2
   * Register the session manager instance.

3
*

4
* @return void

5
*/
6
  protected function registerSessionManager()
7
	{
8
$this->app->bindShared('session', function($app)
9
{
10
	return new SessionManager($app);
11
});
12
	}
13
14
	/**

15
* Register the session driver instance.

16
*

17
* @return void

18
*/
19
	protected function registerSessionDriver()
20
	{
21
$this->app->bindShared('session.store', function($app)
22
{
23
	// First, we will create the session manager which is responsible for the

24
	// creation of the various session drivers when they are needed by the

25
	// application instance, and will resolve them on a lazy load basis.

26
	$manager = $app['session'];
27
28
	return $manager->driver();
29
});
30
	}

Esses dois métodos são chamados pela função register(). O primeiro, registerSessionManager(), é chamado para registrar inicialmente o SessionManager. Essa classe estende a classe Manager que mencionei mais acima. O segundo, registerSessionDriver(), registrar um manipulador de registros para o manager, baseado nas configurações que instituimos no início. Isso, eventualmente, invoca esse método da classe Illuminate\Support\Manager:

1
/**

2
   * Create a new driver instance.

3
*

4
* @param  string  $driver

5
* @return mixed

6
*

7
* @throws \InvalidArgumentException

8
*/
9
	protected function createDriver($driver)
10
	{
11
$method = 'create'.ucfirst($driver).'Driver';
12
13
// We'll check to see if a creator method exists for the given driver. If not we

14
// will check for a custom driver creator, which allows developers to create

15
// drivers using their own customized driver creator Closure to create it.

16
if (isset($this->customCreators[$driver]))
17
{
18
	return $this->callCustomCreator($driver);
19
}
20
elseif (method_exists($this, $method))
21
{
22
	return $this->$method();
23
}
24
25
throw new \InvalidArgumentException("Driver [$driver] not supported.");
26
	}

Aqui, podemos ver que, baseado no nome do driver, escolhido no arquivo de configuração, um método específico é chamado. Então, se tivermos configurados o sistema para usar o manipulador de sessão do tipo file, ele invocará esse método na classe SessionManager:

1
/**

2
   * Create an instance of the file session driver.

3
*

4
* @return \Illuminate\Session\Store

5
*/
6
	protected function createFileDriver()
7
	{
8
return $this->createNativeDriver();
9
	}
10
11
	/**

12
* Create an instance of the file session driver.

13
*

14
* @return \Illuminate\Session\Store

15
*/
16
	protected function createNativeDriver()
17
	{
18
$path = $this->app['config']['session.files'];
19
20
return $this->buildSession(new FileSessionHandler($this->app['files'], $path));
21
	}

A classe correta do driver é, então, injetada na classe Store, que é responsável por invocar os métodos verdadeiros para manipulação da sessão. Isso permite que separemos a implementação da classe SessionHandlerInterface da SPL (Standard PHP Library), a classe Store facilita isso.

Criando Nossa Própria Manipuladora de Sessão

Vamos criar nossa própria classe manipuladora de sessão, usando MongoDB. Primeiro, precisaremos criar a classe MongoSessionHandler em uma instalação recém criada do Laravel (Nós pegaremos muitos códigos emprestados da classe Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler):

1
<?php namespace Illuminate\Session;
2
3
  use Mongo;
4
  use MongoDate;
5
  use MongoBinData;
6
7
  class MongoSessionHandler implements \SessionHandlerInterface
8
  {
9
      /**

10
       * Configuração do Mongo DB

11
       *

12
       * @var array

13
       */
14
      protected $config;
15
16
      /**

17
       * Conexão do Mongo DB

18
       * 

19
       * @var \Mongo

20
       */
21
      protected $connection;
22
23
      /**

24
       * Coleção do Mongo DB

25
       * 

26
       * @var \MongoCollection

27
       */
28
      protected $collection;
29
      /**

30
       * Cria uma nova instância do Manipulador do driver do Mongo DB.

31
       *

32
       * @param  array $config

33
       *  - $config['host']       Mongodb host

34
       *  - $config['username']   Mongodb username

35
       *  - $config['password']   Mongodb password

36
       *  - $config['database']     Mongodb database

37
       *  - $config['collection'] Mongodb collection

38
       * @return void

39
       */
40
      public function __construct(array $config)
41
      {
42
          $this->config = $config;
43
44
          $connection_string = 'mongodb://';
45
46
          if (!empty($this->config['username']) && !empty($this->config['password'])) {
47
              $connection_string .= "{$this->config['user']}:{$this->config['password']}@";
48
          }
49
50
          $connection_string .= "{$this->config['host']}";
51
52
          $this->connection = new Mongo($connection_string);
53
54
          $this->collection = $this->connection->selectCollection($this->config['database'], $this->config['collection']);
55
      }
56
57
      /**

58
       * {@inheritDoc}

59
       */
60
      public function open($savePath, $sessionName)
61
      {
62
          return true;
63
      }
64
65
      /**

66
       * {@inheritDoc}

67
       */
68
      public function close()
69
      {
70
          return true;
71
      }
72
73
      /**

74
       * {@inheritDoc}

75
       */
76
      public function read($sessionId)
77
      {
78
          $session_data = $this->collection->findOne(array(
79
              '_id' => $sessionId,
80
          ));
81
82
          if (is_null($session_data)) {
83
              return '';
84
          } else {
85
              return $session_data['session_data']->bin;
86
          }
87
      }
88
89
      /**

90
       * {@inheritDoc}

91
       */
92
      public function write($sessionId, $data)
93
      {
94
          $this->collection->update(
95
              array(
96
                  '_id' => $sessionId
97
              ),
98
              array(
99
                  '$set' => array(
100
                      'session_data' => new MongoBinData($data, MongoBinData::BYTE_ARRAY),
101
                      'timestamp' => new MongoDate(),
102
                  )
103
              ),
104
              array(
105
                  'upsert' => true,
106
                  'multiple' => false
107
              )
108
          );
109
      }
110
111
      /**

112
       * {@inheritDoc}

113
       */
114
      public function destroy($sessionId)
115
      {
116
          $this->collection->remove(array(
117
              '_id' => $sessionId
118
          ));
119
120
          return true;
121
      }
122
123
      /**

124
       * {@inheritDoc}

125
       */
126
      public function gc($lifetime)
127
      {
128
          $time = new MongoDate(time() - $lifetime);
129
130
          $this->collection->remove(array(
131
              'timestamp' => array('$lt' => $time),
132
          ));
133
134
          return true;
135
      }
136
  }

Você deve salvar esse arquivo no diretório vendor/laravel/framework/src/Illuminate/Session. Para os propósitos desse projeto, nós colocaremos nesse diretório, porém, idealmente, ele deve ficar localizado dentro de um diretório usando seu próprio namespace.

Feito isso, precisamos garantir que a classe Manager pode invocar o driver. Nós podemos fazer isso utilizando o método Manager::extend. Abra o arquivo vendor/laravel/framework/src/Illuminate/Session/SessionServiceProvider.php e adicione o código a seguir. Idealmente, deveríamos estender o provedor de serviços, porém, essa parte está além do escopo desse tutorial.

1
/**

2
   * Prepara a callback do Mongo Driver

3
*

4
* @return  void

5
*/
6
	public function setupMongoDriver()
7
	{
8
$manager = $this->app['session'];
9
10
$manager->extend('mongo', function($app) {
11
    return new MongoSessionHandler(array(
12
        'host'       => $app['config']->get('session.mongo.host'),
13
        'username'   => $app['config']->get('session.mongo.username'),
14
        'password'   => $app['config']->get('session.mongo.password'),
15
        'database'   => $app['config']->get('session.mongo.database'),
16
        'collection' => $app['config']->get('session.mongo.collection')
17
    ));
18
});
19
	}

Atualize o método register() para que ele invoce esse método:

1
/**

2
   * Register the service provider.

3
*

4
* @return void

5
*/
6
	public function register()
7
	{
8
$this->setupDefaultDriver();
9
10
$this->registerSessionManager();
11
12
$this->setupMongoDriver();
13
14
$this->registerSessionDriver();
15
	}

Depois disso, precisamos definir a configuração do Mongo DB. Abra o arquivo app/config/session.php e defina as seguintes configurações:

1
/**

2
   * Configurações do Mongo DB

3
*/
4
	'mongo' => array(
5
'host' => '127.0.0.1',
6
'username' => '',
7
'password' => '',
8
'database' => 'laravel',
9
'collection' => 'laravel_session_collection'
10
	)

Já que estamos nesse arquivo, também devemos atualizar a configuração do driver na parte superior driver :

1
'driver' => 'mongo'

Agora, tente acessar a página inicial (geralmente, localhost/diretorio_instalacao_laravel/public). Se a página carregar sem mostrar a página WHOOPS (página de erros), então, parabéns, nós fomos bem sucedidos em criar um driver de sessão novinho em folha! Teste-o, adicionando alguns dados fictícios na sessão, através do método Session::set() e, então, recupere-o através do Session::get() para mostrá-lo na página.

O Componente Auth

O componente Auth do Laravel é responsável por manipular a autenticação dos usuários na framework e, também, é responsável por administrar as senhas. O que o componente do Laravel fez, foi criar uma abstração de um típico sistema de administração de usuários, usavél na maioria das aplicações web, o que ajuda aos programadores a, facilmente, implementar um sistemade login. Da mesma forma que o componente Session, ele também faz uso do Laravel Manager. Atualmente, o componente Auth tem drivers para:

  • eloquent - esse driver faz uso do ORM embutido no Laravel, o Eloquent. Ele também lança mão de uma classe User.php pré-existente, que fica no diretório models.
  • database - Essa daqui usa qualquer conexão de base de dados que estiver configurada por padrão. Ela faz uso da classe GenericUser para acessar os dados dos usuários.

Já que aqui também seguiremos a mesma implementação do componente Session, o provedor de serviços é bem semelhante ao que vimos mais acima:

1
/**

2
   * Register the service provider.

3
*

4
* @return void

5
*/
6
	public function register()
7
	{
8
$this->app->bindShared('auth', function($app)
9
{
10
	// Once the authentication service has actually been requested by the developer

11
	// we will set a variable in the application indicating such. This helps us

12
	// know that we need to set any queued cookies in the after event later.

13
	$app['auth.loaded'] = true;
14
15
	return new AuthManager($app);
16
});
17
	}

Nós podemos ver que, basicamente, ele cria uma classe AuthManager que envolve qualquer driver que estamos usando, além de agir como uma fábrica para esse driver. Dentro da classe AuthManager, ela, novamente, cria o driver apropriado, envolta na classe Guard, que age da mesma forma que a classe Store para a Session.

Criando Nosso Próprio Manipulador de Autenticação

Da mesma forma que antes, vamos criar uma classe MongoUserProvider:

1
<?php namespace Illuminate\Auth;
2
3
  use Mongo;
4
  use Illuminate\Hashing\HasherInterface;
5
6
  class MongoUserProvider implements UserProviderInterface {
7
8
      /**

9
       * Uma instância do MongoDB

10
       *

11
       * @param  \Mongo

12
       */
13
      protected $connection;
14
15
      /**

16
       * A instância da conexão com o MongoDB

17
       *

18
       * @param  \MongoConnection

19
       */
20
      protected $collection;
21
22
      /**

23
       * A array de configuração do Mongo

24
       *

25
       * @var array

26
       */
27
      protected $config;
28
29
      /**

30
       * Create a new Mongo user provider.

31
       *

32
       * @param  array $config

33
       *     - $config['host']       Mongodb host

34
       *     - $config['username']   Mongodb username

35
       *     - $config['password']   Mongodb password

36
       *     - $config['database']   Mongodb database

37
       *     - $config['collection'] Mongodb collection

38
       * @return void

39
       */
40
      public function __construct(array $config)
41
      {
42
          $this->config = $config;
43
44
          $connection_string = 'mongodb://';
45
46
          if (!empty($this->config['username']) && !empty($this->config['password'])) {
47
              $connection_string .= "{$this->config['user']}:{$this->config['password']}@";
48
          }
49
50
          $connection_string .= "{$this->config['host']}";
51
52
          $this->connection = new Mongo($connection_string);
53
54
          $this->collection = $this->connection->selectCollection($this->config['database'], $this->config['collection']);
55
      }
56
57
      /**

58
       * Retorna um usuário a partir do seu identificador único.

59
       *

60
       * @param  mixed  $identifier

61
       * @return \Illuminate\Auth\UserInterface|null

62
       */
63
      public function retrieveById($identifier)
64
      {
65
          $user_data = $this->collection->findOne(array(
66
              '_id' => $identifier,
67
          ));
68
69
          if (!is_null($user_data)) {
70
              return new GenericUser((array) $user_data);
71
          }
72
      }
73
74
      /**

75
       * Retorna um usuário a partir de credenciais apresentadas.

76
       *

77
       * @param  array  $credentials

78
       * @return \Illuminate\Auth\UserInterface|null

79
       */
80
      public function retrieveByCredentials(array $credentials)
81
      {
82
          // Attempt to look for the user first regardless of password

83
          // We'll do that in the validateCredentials method

84
          if (isset($credentials['password'])) {
85
              unset($credentials['password']);
86
          }
87
88
          $user_data = $this->collection->findOne($credentials);
89
90
          if (!is_null($user_data)) {
91
              return new GenericUser((array) $user_data);
92
          }
93
      }
94
95
      /**

96
       * Valida um usuário em relação credenciais apresentadas.

97
       *

98
       * @param  \Illuminate\Auth\UserInterface  $user

99
       * @param  array  $credentials

100
       * @return bool

101
       */
102
      public function validateCredentials(UserInterface $user, array $credentials)
103
      {
104
          if (!isset($credentials['password'])) {
105
              return false;
106
          }
107
          
108
          return ($credentials['password'] === $user->getAuthPassword());
109
      }
110
  }

É importante atentar que não estamos temos métodos de comparação com senhas criptografadas, uma vez que esse código foi criado para facilitar a criação de dados fictícios e poder testá-la depois. No código de produção, você precisará criptgrafar as senhas. Verifique a classe Illuminate\Auth\DatabaseUserProvider para um ótimo exemplo de como fazer isso.

Depois, precisamos registrar a callback do nosso driver customizado junto ao AuthManager. Para fazer isso, precisamos atualizar o método register do provedor de serviços:

1
/**

2
   * Register the service provider.

3
*

4
* @return void

5
*/
6
	public function register()
7
	{
8
$this->app->bindShared('auth', function($app)
9
{
10
	// Once the authentication service has actually been requested by the developer

11
	// we will set a variable in the application indicating such. This helps us

12
	// know that we need to set any queued cookies in the after event later.

13
	$app['auth.loaded'] = true;
14
15
	$auth_manager = new AuthManager($app);
16
17
	$auth_manager->extend('mongo', function($app) {
18
		return new MongoUserProvider(
19
			array(
20
				'host'       => $app['config']->get('auth.mongo.host'),
21
		        'username'   => $app['config']->get('auth.mongo.username'),
22
		        'password'   => $app['config']->get('auth.mongo.password'),
23
		        'database'   => $app['config']->get('auth.mongo.database'),
24
		        'collection' => $app['config']->get('auth.mongo.collection')
25
			)
26
		);
27
	});
28
29
	return $auth_manager;
30
});
31
	}

Por último, também precisamos atualizar o arquivo de configuração auth.php para usar o driver do Mongo, assim como prover os valores de configuração do Mongo:

1
'driver' => 'mongo',
2
  ...
3
  ...
4
  ...
5
  /**

6
   * Configurações do Mongo DB

7
*/
8
	'mongo' => array(
9
'host' => '127.0.0.1',
10
'username' => '',
11
'password' => '',
12
'database' => 'laravel',
13
'collection' => 'laravel_auth_collection'
14
	)

Testar isso é um pouco complicado, mas, para fazê-lo, lançaremos mão da linha de comando do Mongo DB para inserir um novo usuário na coleção:

1
mongo
2
3
  > use laravel_auth
4
  switched to db laravel_auth
5
  > db.laravel_auth_collection.insert({id: 1, email:"nikko@nikkobautista.com", password:"test_password"})
6
  > db.laravel_auth_collection.find()
7
  > { "_id" : ObjectId("530c609f2caac8c3a8e4814f"), "id" 1, "email" : "nikko@emailtest.com", "password" : "test_password" }

Agora, testaremos o método Auth::validate:

1
var_dump(Auth::validate(array('email' => 'nikko@emailtest.com', 'password' => 'test_password')));

Isso deveria retornar um bool(true). Se ele retornar, então acabamos de criar nosso próprio driver de auntenticação!

O Componente Cache

O componente de Cache do Laravel manipula o mecanismo de cache para usarmos na framework. Da mesma forma que discutimos para os outros componentes, ele também faz uso do Laravel Manager (você percebeu algum padrão?). O componente Cache tem drivers para:

  • apc
  • memcached
  • redis
  • file - cache baseado em arquivos. Os dados são salvos no diretórios app/storage/cache.
  • database - cache salvos na base de dados. Os dados são salvos em registros na base de dados. O schema da base de dados para isso é descrito na Documentação do Laravel.
  • array - dados são "guardados" em um array. Lembre-se que o cache baseado em array não persiste os dados e é apagado a cada carregamento.

Como, novamente, segue a mesma implementação dos componente anteriores, você pode assumir que o processo de criar o provedor de serviços é bem semelhante:

1
/**

2
   * Register the service provider.

3
*

4
* @return void

5
*/
6
	public function register()
7
	{
8
$this->app->bindShared('cache', function($app)
9
{
10
	return new CacheManager($app);
11
});
12
13
$this->app->bindShared('cache.store', function($app)
14
{
15
	return $app['cache']->driver();
16
});
17
18
$this->app->bindShared('memcached.connector', function()
19
{
20
	return new MemcachedConnector;
21
});
22
23
$this->registerCommands();
24
	}

O método register() cria um CacheManager, que serve como envólucro e fábrica para os drivers. Dentro do manager, ele envolve o driver em relação à classe Repository, de forma semelhante às classes Store e Guard.

Criando Nosso Próprio Manipulador de Cache

Crie a classe MongoStore, que estenderá a classe Illuminate\Cache\StoreInterface:

1
<?php namespace Illuminate\Cache;
2
3
  use Mongo;
4
5
  class MongoStore implements StoreInterface
6
  {
7
      /**

8
       * A instância do Mongo DB

9
       *

10
       * @param  \Mongo

11
       */
12
      protected $connection;
13
14
      /**

15
       * A instância da conexão com o MongoDB

16
       *

17
       * @param  \MongoConnection

18
       */
19
      protected $collection;
20
21
      /**

22
       * A array de configuração do Mongo DB

23
       *

24
       * @var array

25
       */
26
      protected $config;
27
28
      /**

29
       * Criar a nova "loja" de cache com Mongo.

30
       *

31
       * @param  array $config

32
       *     - $config['host']       Mongodb host

33
       *     - $config['username']   Mongodb username

34
       *     - $config['password']   Mongodb password

35
       *     - $config['database']   Mongodb database

36
       *     - $config['collection'] Mongodb collection

37
       * @return void

38
       */
39
      public function __construct(array $config)
40
      {
41
          $this->config = $config;
42
43
          $connection_string = 'mongodb://';
44
45
          if (!empty($this->config['username']) && !empty($this->config['password'])) {
46
              $connection_string .= "{$this->config['user']}:{$this->config['password']}@";
47
          }
48
49
          $connection_string .= "{$this->config['host']}";
50
51
          $this->connection = new Mongo($connection_string);
52
53
          $this->collection = $this->connection->selectCollection($this->config['database'], $this->config['collection']);
54
      }
55
56
      /**

57
       * Retorna um item do cache usando uma chave.

58
       *

59
       * @param  string  $key

60
       * @return mixed

61
       */
62
      public function get($key)
63
      {
64
          $cache_data = $this->getObject($key);
65
66
          if (!$cache_data) {
67
              return null;
68
          }
69
70
          return unserialize($cache_data['cache_data']);
71
      }
72
73
      /**

74
       * Retorna todo o objeto, ao invés de retorna somente os dados

75
       * 

76
       * @param  string  $key

77
       * @return array|null

78
       */
79
      protected function getObject($key)
80
      {
81
          $cache_data = $this->collection->findOne(array(
82
              'key' => $key,
83
          ));
84
85
          if (is_null($cache_data)) {
86
              return null;
87
          }
88
89
          if (isset($cache_data['expire']) && time() >= $cache_data['expire']) {
90
              $this->forget($key);
91
              return null;
92
          }
93
94
          return $cache_data;
95
      }
96
97
      /**

98
       * Salva um item na loja por um dado número de minutos.

99
       *

100
       * @param  string  $key

101
       * @param  mixed   $value

102
       * @param  int     $minutes

103
       * @return void

104
       */
105
      public function put($key, $value, $minutes)
106
      {
107
          $expiry = $this->expiration($minutes);
108
109
          $this->collection->update(
110
              array(
111
                  'key' => $key
112
              ),
113
              array(
114
                  '$set' => array(
115
                      'cache_data' => serialize($value),
116
                      'expiry' => $expiry,
117
                      'ttl' => ($minutes * 60)
118
                  )
119
              ),
120
              array(
121
                  'upsert' => true,
122
                  'multiple' => false
123
              )
124
          );
125
      }
126
127
      /**

128
       * Incrementa o valor de um item no cache.

129
       *

130
       * @param  string  $key

131
       * @param  mixed   $value

132
       * @return void

133
       *

134
       * @throws \LogicException

135
       */
136
      public function increment($key, $value = 1)
137
      {
138
          $cache_data = $this->getObject($key);
139
140
          if (!$cache_data) {
141
              $new_data = array(
142
                  'cache_data' => serialize($value),
143
                  'expiry' => $this->expiration(0),
144
                  'ttl' => $this->expiration(0)
145
              );
146
          } else {
147
              $new_data = array(
148
                  'cache_data' => serialize(unserialize($cache_data['cache_data']) + $value),
149
                  'expiry' => $this->expiration((int) ($cache_data['ttl']/60)),
150
                  'ttl' => $cache_data['ttl']
151
              );
152
          }
153
154
          $this->collection->update(
155
              array(
156
                  'key' => $key
157
              ),
158
              array(
159
                  '$set' => $new_data
160
              ),
161
              array(
162
                  'upsert' => true,
163
                  'multiple' => false
164
              )
165
          );
166
      }
167
168
      /**

169
       * Decrementa o valor de um item no cache.

170
       *

171
       * @param  string  $key

172
       * @param  mixed   $value

173
       * @return void

174
       *

175
       * @throws \LogicException

176
       */
177
      public function decrement($key, $value = 1)
178
      {
179
          $cache_data = $this->getObject($key);
180
181
          if (!$cache_data) {
182
              $new_data = array(
183
                  'cache_data' => serialize((0 - $value)),
184
                  'expiry' => $this->expiration(0),
185
                  'ttl' => $this->expiration(0)
186
              );
187
          } else {
188
              $new_data = array(
189
                  'cache_data' => serialize(unserialize($cache_data['cache_data']) - $value),
190
                  'expiry' => $this->expiration((int) ($cache_data['ttl']/60)),
191
                  'ttl' => $cache_data['ttl']
192
              );
193
          }
194
195
          $this->collection->update(
196
              array(
197
                  'key' => $key
198
              ),
199
              array(
200
                  '$set' => $new_data
201
              ),
202
              array(
203
                  'upsert' => true,
204
                  'multiple' => false
205
              )
206
          );
207
      }
208
209
      /**

210
       * Salva um item no cache, indefinidamente.

211
       *

212
       * @param  string  $key

213
       * @param  mixed   $value

214
       * @return void

215
       */
216
      public function forever($key, $value)
217
      {
218
          return $this->put($key, $value, 0);
219
      }
220
221
      /**

222
       * Apaga um item do cache.

223
       *

224
       * @param  string  $key

225
       * @return void

226
       */
227
      public function forget($key)
228
      {
229
          $this->collection->remove(array(
230
              'key' => $key
231
          ));
232
      }
233
234
      /**

235
       * Apaga todos os itens do cache.

236
       *

237
       * @return void

238
       */
239
      public function flush()
240
      {
241
          $this->collection->remove();
242
      }
243
244
      /**

245
       * Retorna o tempo de expiração de um item.

246
       *

247
       * @param  int  $minutes

248
       * @return int

249
       */
250
      protected function expiration($minutes)
251
      {
252
          if ($minutes === 0) return 9999999999;
253
254
          return time() + ($minutes * 60);
255
      }
256
257
      /**

258
       * Get the cache key prefix.

259
       *

260
       * @return string

261
       */
262
      public function getPrefix()
263
      {
264
          return '';
265
      }
266
  }

Nós também adicionaremos a callback do Mongo, novamente, no manager:

1
/**

2
   * Register the service provider.

3
*

4
* @return void

5
*/
6
	public function register()
7
	{
8
$this->app->bindShared('cache', function($app)
9
{
10
	$cache_manager = new CacheManager($app);
11
12
	$cache_manager->extend('mongo', function($app) {
13
		return new MongoStore(
14
			array(
15
				'host'       => $app['config']->get('cache.mongo.host'),
16
		        'username'   => $app['config']->get('cache.mongo.username'),
17
		        'password'   => $app['config']->get('cache.mongo.password'),
18
		        'database'   => $app['config']->get('cache.mongo.database'),
19
		        'collection' => $app['config']->get('cache.mongo.collection')
20
			)
21
		);
22
	});
23
24
	return $cache_manager;
25
});
26
27
$this->app->bindShared('cache.store', function($app)
28
{
29
	return $app['cache']->driver();
30
});
31
32
$this->app->bindShared('memcached.connector', function()
33
{
34
	return new MemcachedConnector;
35
});
36
37
$this->registerCommands();
38
	}

Por último, precisamos atualizar o arquivo de configuração cache.php:

1
'driver' => 'mongo',
2
  ...
3
  ...
4
  ...
5
  /**

6
* Configuração do MongoDB

7
*/
8
	'mongo' => array(
9
'host' => '127.0.0.1',
10
'username' => '',
11
'password' => '',
12
'database' => 'laravel',
13
'collection' => 'laravel_cache_collection'
14
	)

Agora, tente usar os métodos Cache::put() e Cache::get(). Se tiver feito tudo certo, você foi capaz de guardar e recuperar dados de um sistema de cache que usa MongoDB!

Conclusão

Nesse tutorial aprendemos:

  • Sobre o sistema de componentes do Laravel, chamado Illuminate, que é usado pela framework Laravel.
  • Sobre os provedores de serviços do Laravel e um pouco sobre como eles funcionam.
  • Sobre o sistema Manager do Laravel, que age tanto como envólucro quanto uma fábrica para os drivers.
  • Sobre os componentes Session, Auth e Cache e como criar novos drivers para cada um deles.
  • As bibliotecas Store, Guard e Repository que utilizam esses drivers.

Espero que esse artigo possa ajudar os programadores a criarem seus próprios drivers para que possam estender as funcionalidades do Laravel.

Seja o primeiro a saber sobre novas traduções–siga @tutsplus_pt no Twitter!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.