Статьи

Laravel Unwrapped: сессия, аутентификация и кэш

В последние годы Laravel стала одной из самых выдающихся платформ, которые инженеры-программисты используют для создания своих веб-приложений. По аналогии с популярностью, которой CodeIgniter пользовался в период своего расцвета, Laravel похвалили за простоту использования, дружелюбие к новичкам и приверженность отраслевым стандартам.

Одна вещь, которой пользуются немногие программисты, — это система Laravel, основанная на компонентах. С момента своего преобразования в компоненты на основе композиторов Laravel 4 стал очень модульной системой, похожей на многословность более зрелых фреймворков, таких как Symfony. Это называется группа компонентов Illuminate , которая, на мой взгляд, не является реальной платформой, а представляет собой компиляцию библиотек, которые потенциально может использовать фреймворк. Фактическая структура Laravel представлена ​​скелетным приложением Laravel (находится в laravel/laravel ), которое использует эти компоненты для создания веб-приложения.

В этом уроке мы рассмотрим группу этих компонентов, узнаем, как они работают, как они используются фреймворком и как мы можем расширить их функциональность.

Компонент Laravel Session обрабатывает сеансы для веб-приложения. Он использует систему на основе драйверов, называемую Laravel Manager, которая действует как фабрика и как оболочка для любого драйвера, установленного в файле конфигурации. На момент написания статьи компонент Session имеет драйверы для:

  • file — драйвер сеанса на основе файла, в котором данные сеанса сохраняются в зашифрованном файле.
  • cookie — драйвер сеанса на основе cookie, в котором данные сеанса зашифрованы в файлах cookie пользователя.
  • database — данные сеанса сохраняются в любой базе данных, настроенной для приложения.
  • apc — данные сессии сохраняются в APC.
  • memcached — данные сессии сохраняются в Memcached.
  • redis — данные сеанса сохраняются в Redis.
  • array — данные сеанса сохраняются в массиве PHP. Обратите внимание, что драйвер сеанса массива не поддерживает постоянство и обычно используется только в консольных командах.

Большинство пользователей Laravel не осознают, но большая часть того, как работает Laravel, находится в пределах его поставщиков услуг. По сути, это файлы начальной загрузки для каждого компонента, и они достаточно абстрагированы, чтобы пользователи могли загружать любые компоненты любым способом.

Грубое объяснение того, как это работает, приведено ниже:

  1. Компонент Laravel Application запущен. Это основной драйвер всей платформы, отвечающий за обработку HTTP-запроса, запуск поставщиков услуг, а также за выполнение функции контейнера зависимости.
  2. После запуска поставщика услуг вызывается его метод register . Это позволяет нам создавать экземпляр любого компонента, который мы хотим.
    • Имейте в виду, что все поставщики услуг имеют доступ к основному приложению Laravel (через $this->app ), что позволяет поставщикам услуг помещать экземпляры разрешенных классов в контейнер зависимостей.
  3. Как только эти зависимости загружены, мы можем свободно использовать их, вызывая контейнер, например, через систему Facade Laravel, App::make .

Возвращаясь к сеансам, давайте SessionServiceProivider рассмотрим SessionServiceProivider :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
    * Register the session manager instance.
    *
    * @return void
    */
   protected function registerSessionManager()
   {
       $this->app->bindShared(‘session’, function($app)
       {
           return new SessionManager($app);
       });
   }
 
   /**
    * Register the session driver instance.
    *
    * @return void
    */
   protected function registerSessionDriver()
   {
       $this->app->bindShared(‘session.store’, function($app)
       {
           // First, we will create the session manager which is responsible for the
           // creation of the various session drivers when they are needed by the
           // application instance, and will resolve them on a lazy load basis.
           $manager = $app[‘session’];
 
           return $manager->driver();
       });
   }

Эти два метода вызываются функцией register() . Первый, registerSessionManager() , вызывается для первоначальной регистрации SessionManager . Этот класс расширяет Manager о котором я упоминал сверху. Второй, registerSessionDriver() регистрирует обработчик сеанса для менеджера, основываясь на том, что мы настроили. В конечном итоге это вызывает этот метод в классе Illuminate\Support\Manager :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
    * Create a new driver instance.
    *
    * @param string $driver
    * @return mixed
    *
    * @throws \InvalidArgumentException
    */
   protected function createDriver($driver)
   {
       $method = ‘create’.ucfirst($driver).’Driver’;
 
       // We’ll check to see if a creator method exists for the given driver.
       // will check for a custom driver creator, which allows developers to create
       // drivers using their own customized driver creator Closure to create it.
       if (isset($this->customCreators[$driver]))
       {
           return $this->callCustomCreator($driver);
       }
       elseif (method_exists($this, $method))
       {
           return $this->$method();
       }
 
       throw new \InvalidArgumentException(«Driver [$driver] not supported.»);
   }

Отсюда видно, что в зависимости от имени драйвера из файла конфигурации вызывается определенный метод. Итак, если мы настроили использование обработчика file сеанса, он вызовет этот метод в классе SessionManager :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
/**
    * Create an instance of the file session driver.
    *
    * @return \Illuminate\Session\Store
    */
   protected function createFileDriver()
   {
       return $this->createNativeDriver();
   }
 
   /**
    * Create an instance of the file session driver.
    *
    * @return \Illuminate\Session\Store
    */
   protected function createNativeDriver()
   {
       $path = $this->app[‘config’][‘session.files’];
 
       return $this->buildSession(new FileSessionHandler($this->app[‘files’], $path));
   }

Затем класс драйвера внедряется в класс Store , который отвечает за вызов реальных методов сеанса. Это позволяет нам фактически отделить реализацию SessionHandlerInterface от SPL на драйверы, класс Store облегчает это.

Давайте создадим наш собственный обработчик сеансов, обработчик сеансов MongoDB. Прежде всего, нам нужно создать MongoSessionHandler внутри недавно установленного экземпляра проекта Laravel. (Мы будем активно заимствовать у Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler ) .:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<?php namespace Illuminate\Session;
 
   use Mongo;
   use MongoDate;
   use MongoBinData;
 
   class MongoSessionHandler implements \SessionHandlerInterface
   {
       /**
        * Mongo db config
        *
        * @var array
        */
       protected $config;
 
       /**
        * Mongo db connection
        *
        * @var \Mongo
        */
       protected $connection;
 
       /**
        * Mongodb collection
        *
        * @var \MongoCollection
        */
       protected $collection;
       /**
        * Create a new Mongo driven handler instance.
        *
        * @param array $config
        * — $config[‘host’] Mongodb host
        * — $config[‘username’] Mongodb username
        * — $config[‘password’] Mongodb password
        * — $config[‘database’] Mongodb database
        * — $config[‘collection’] Mongodb collection
        * @return void
        */
       public function __construct(array $config)
       {
           $this->config = $config;
 
           $connection_string = ‘mongodb://’;
 
           if (!empty($this->config[‘username’]) && !empty($this->config[‘password’])) {
               $connection_string .= «{$this->config[‘user’]}:{$this->config[‘password’]}@»;
           }
 
           $connection_string .= «{$this->config[‘host’]}»;
 
           $this->connection = new Mongo($connection_string);
 
           $this->collection = $this->connection->selectCollection($this->config[‘database’], $this->config[‘collection’]);
       }
 
       /**
        * {@inheritDoc}
        */
       public function open($savePath, $sessionName)
       {
           return true;
       }
 
       /**
        * {@inheritDoc}
        */
       public function close()
       {
           return true;
       }
 
       /**
        * {@inheritDoc}
        */
       public function read($sessionId)
       {
           $session_data = $this->collection->findOne(array(
               ‘_id’ => $sessionId,
           ));
 
           if (is_null($session_data)) {
               return »;
           } else {
               return $session_data[‘session_data’]->bin;
           }
       }
 
       /**
        * {@inheritDoc}
        */
       public function write($sessionId, $data)
       {
           $this->collection->update(
               array(
                   ‘_id’ => $sessionId
               ),
               array(
                   ‘$set’ => array(
                       ‘session_data’ => new MongoBinData($data, MongoBinData::BYTE_ARRAY),
                       ‘timestamp’ => new MongoDate(),
                   )
               ),
               array(
                   ‘upsert’ => true,
                   ‘multiple’ => false
               )
           );
       }
 
       /**
        * {@inheritDoc}
        */
       public function destroy($sessionId)
       {
           $this->collection->remove(array(
               ‘_id’ => $sessionId
           ));
 
           return true;
       }
 
       /**
        * {@inheritDoc}
        */
       public function gc($lifetime)
       {
           $time = new MongoDate(time() — $lifetime);
 
           $this->collection->remove(array(
               ‘timestamp’ => array(‘$lt’ => $time),
           ));
 
           return true;
       }
   }

Вы должны сохранить это в vendor/laravel/framework/src/Illuminate/Session . Для целей этого проекта мы разместим его здесь, но в идеале этот файл должен находиться в пределах собственного пространства имен библиотеки.

Далее нам нужно убедиться, что класс Manager может вызывать этот драйвер. Мы можем сделать это, используя метод Manager::extend . Откройте vendor/laravel/framework/src/Illuminate/Session/SessionServiceProvider.php и добавьте следующий код. В идеале мы должны расширять поставщика услуг, но это выходит за рамки этого руководства.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
/**
    * Setup the Mongo Driver callback
    *
    * @return void
    */
   public function setupMongoDriver()
   {
       $manager = $this->app[‘session’];
 
       $manager->extend(‘mongo’, function($app) {
           return new MongoSessionHandler(array(
               ‘host’ => $app[‘config’]->get(‘session.mongo.host’),
               ‘username’ => $app[‘config’]->get(‘session.mongo.username’),
               ‘password’ => $app[‘config’]->get(‘session.mongo.password’),
               ‘database’ => $app[‘config’]->get(‘session.mongo.database’),
               ‘collection’ => $app[‘config’]->get(‘session.mongo.collection’)
           ));
       });
   }

Обязательно обновите метод register() для вызова этого метода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
/**
    * Register the service provider.
    *
    * @return void
    */
   public function register()
   {
       $this->setupDefaultDriver();
 
       $this->registerSessionManager();
 
       $this->setupMongoDriver();
 
       $this->registerSessionDriver();
   }

Далее нам нужно определить конфигурацию Mongo DB. Откройте app/config/session.php и определите следующие параметры конфигурации:

01
02
03
04
05
06
07
08
09
10
/**
    * Mongo DB settings
    */
   ‘mongo’ => array(
       ‘host’ => ‘127.0.0.1’,
       ‘username’ => »,
       ‘password’ => »,
       ‘database’ => ‘laravel’,
       ‘collection’ => ‘laravel_session_collection’
   )

Пока мы находимся в этом файле, мы также должны обновить конфигурацию driver :

1
‘driver’ => ‘mongo’

Теперь попробуйте получить доступ к главной странице (обычно localhost/somefolder/public ). Если эта страница загружается без отображения страницы WHOOPS , то поздравляем, мы успешно создали совершенно новый драйвер сеанса! Проверьте это, установив некоторые фиктивные данные в сеансе через Session::set() а затем вернув их обратно через Session::get() .

Компонент Laravel Auth обрабатывает аутентификацию пользователя для инфраструктуры, а также управление паролями. Компонент Laravel сделал здесь, чтобы создать абстрактную интерпретацию типичной системы управления пользователями, которая может использоваться в большинстве веб-приложений, что, в свою очередь, помогает программисту легко реализовать систему входа в систему. Как и компонент Session, он также использует Laravel Manager. В настоящее время компонент Auth имеет драйверы для:

  • eloquent — в нем используется встроенный в Laravel ORM под названием Eloquent . Он также использует User.php класс User.php внутри папки models .
  • database — это использует любое соединение с базой данных, настроенное по умолчанию. Он использует класс GenericUser для доступа к пользовательским данным.

Поскольку это соответствует той же реализации, что и компонент Session , поставщик услуг очень похож на то, что мы видели сверху:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
/**
    * Register the service provider.
    *
    * @return void
    */
   public function register()
   {
       $this->app->bindShared(‘auth’, function($app)
       {
           // Once the authentication service has actually been requested by the developer
           // we will set a variable in the application indicating such.
           // know that we need to set any queued cookies in the after event later.
           $app[‘auth.loaded’] = true;
 
           return new AuthManager($app);
       });
   }

Здесь мы видим, что он в основном создает класс AuthManager который оборачивается вокруг того драйвера, который мы используем, а также действует как фабрика для него. Внутри AuthManager он снова создает соответствующий драйвер, обернутый вокруг класса Guard , который действует так же, как класс Store из Session .

Как и прежде, давайте начнем с создания MongoUserProvider :

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
<?php namespace Illuminate\Auth;
 
   use Mongo;
   use Illuminate\Hashing\HasherInterface;
 
   class MongoUserProvider implements UserProviderInterface {
 
       /**
        * The mongo instance
        *
        * @param \Mongo
        */
       protected $connection;
 
       /**
        * The mongo connection instance
        *
        * @param \MongoConnection
        */
       protected $collection;
 
       /**
        * The Mongo config array
        *
        * @var array
        */
       protected $config;
 
       /**
        * Create a new Mongo user provider.
        *
        * @param array $config
        * — $config[‘host’] Mongodb host
        * — $config[‘username’] Mongodb username
        * — $config[‘password’] Mongodb password
        * — $config[‘database’] Mongodb database
        * — $config[‘collection’] Mongodb collection
        * @return void
        */
       public function __construct(array $config)
       {
           $this->config = $config;
 
           $connection_string = ‘mongodb://’;
 
           if (!empty($this->config[‘username’]) && !empty($this->config[‘password’])) {
               $connection_string .= «{$this->config[‘user’]}:{$this->config[‘password’]}@»;
           }
 
           $connection_string .= «{$this->config[‘host’]}»;
 
           $this->connection = new Mongo($connection_string);
 
           $this->collection = $this->connection->selectCollection($this->config[‘database’], $this->config[‘collection’]);
       }
 
       /**
        * Retrieve a user by their unique identifier.
        *
        * @param mixed $identifier
        * @return \Illuminate\Auth\UserInterface|null
        */
       public function retrieveById($identifier)
       {
           $user_data = $this->collection->findOne(array(
               ‘_id’ => $identifier,
           ));
 
           if (!is_null($user_data)) {
               return new GenericUser((array) $user_data);
           }
       }
 
       /**
        * Retrieve a user by the given credentials.
        *
        * @param array $credentials
        * @return \Illuminate\Auth\UserInterface|null
        */
       public function retrieveByCredentials(array $credentials)
       {
           // Attempt to look for the user first regardless of password
           // We’ll do that in the validateCredentials method
           if (isset($credentials[‘password’])) {
               unset($credentials[‘password’]);
           }
 
           $user_data = $this->collection->findOne($credentials);
 
           if (!is_null($user_data)) {
               return new GenericUser((array) $user_data);
           }
       }
 
       /**
        * Validate a user against the given credentials.
        *
        * @param \Illuminate\Auth\UserInterface $user
        * @param array $credentials
        * @return bool
        */
       public function validateCredentials(UserInterface $user, array $credentials)
       {
           if (!isset($credentials[‘password’])) {
               return false;
           }
            
           return ($credentials[‘password’] === $user->getAuthPassword());
       }
   }

Здесь важно отметить, что я не проверяю по хешированному паролю, это было сделано для простоты, чтобы было проще с нашей стороны создавать фиктивные данные и проверять это позже. В рабочем коде вам нужно обязательно хешировать пароль. Посмотрите класс Illuminate\Auth\DatabaseUserProvider для отличного примера того, как это сделать.

После этого нам нужно зарегистрировать наш пользовательский обратный вызов драйвера в AuthManager . Для этого нам нужно обновить метод register поставщика услуг:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
    * Register the service provider.
    *
    * @return void
    */
   public function register()
   {
       $this->app->bindShared(‘auth’, function($app)
       {
           // Once the authentication service has actually been requested by the developer
           // we will set a variable in the application indicating such.
           // know that we need to set any queued cookies in the after event later.
           $app[‘auth.loaded’] = true;
 
           $auth_manager = new AuthManager($app);
 
           $auth_manager->extend(‘mongo’, function($app) {
               return new MongoUserProvider(
                   array(
                       ‘host’ => $app[‘config’]->get(‘auth.mongo.host’),
                       ‘username’ => $app[‘config’]->get(‘auth.mongo.username’),
                       ‘password’ => $app[‘config’]->get(‘auth.mongo.password’),
                       ‘database’ => $app[‘config’]->get(‘auth.mongo.database’),
                       ‘collection’ => $app[‘config’]->get(‘auth.mongo.collection’)
                   )
               );
           });
 
           return $auth_manager;
       });
   }

Наконец, нам также необходимо обновить auth.php конфигурации auth.php чтобы использовать драйвер Mongo, и предоставить ему правильные значения конфигурации Mongo:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
‘driver’ => ‘mongo’,
   …
   …
   …
   /**
    * Mongo DB settings
    */
   ‘mongo’ => array(
       ‘host’ => ‘127.0.0.1’,
       ‘username’ => »,
       ‘password’ => »,
       ‘database’ => ‘laravel’,
       ‘collection’ => ‘laravel_auth_collection’
   )

Проверить это немного сложнее, для этого используйте CLI Mongo DB, чтобы вставить нового пользователя в коллекцию:

1
2
3
4
5
6
7
mongo
 
   > use laravel_auth
   switched to db laravel_auth
   > db.laravel_auth_collection.insert({id: 1, email:»[email protected]», password:»test_password»})
   > db.laravel_auth_collection.find()
   > { «_id» : ObjectId(«530c609f2caac8c3a8e4814f»), «id» 1, «email» : «[email protected]», «password» : «test_password» }

Теперь проверьте это, попробовав вызов метода Auth::validate :

1
var_dump(Auth::validate(array(’email’ => ‘[email protected]’, ‘password’ => ‘test_password’)));

Это должно сбрасывать bool(true) . Если это так, то мы успешно создали наш собственный драйвер Auth!

Компонент Laravel Cache обрабатывает механизмы кэширования для использования в среде. Как и оба компонента, которые мы обсуждали, он также использует Laravel Manager (замечаете ли вы шаблон?). Компонент Cache имеет драйверы для:

  • apc
  • memcached
  • redis
  • file — файловый кеш. Данные сохраняются в app/storage/cache .
  • database данных — кэш на основе database данных. Данные сохраняются в строках в базу данных. Схема базы данных описана в документации Laravel .
  • array — данные «кэшируются» в массиве. Имейте в виду, что кэш array не является постоянным и очищается при каждой загрузке страницы.

Поскольку это соответствует той же реализации, что и оба компонента, которые мы обсуждали, можно смело предположить, что поставщик услуг довольно похож:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
    * Register the service provider.
    *
    * @return void
    */
   public function register()
   {
       $this->app->bindShared(‘cache’, function($app)
       {
           return new CacheManager($app);
       });
 
       $this->app->bindShared(‘cache.store’, function($app)
       {
           return $app[‘cache’]->driver();
       });
 
       $this->app->bindShared(‘memcached.connector’, function()
       {
           return new MemcachedConnector;
       });
 
       $this->registerCommands();
   }

Метод register() здесь создает CacheManager , который снова действует как оболочка и фабрика для драйверов. Внутри менеджера он оборачивает драйвер вокруг класса Repository , аналогично классам Store и Guard .

Создайте MongoStore , который должен расширить Illuminate\Cache\StoreInterface :

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
<?php namespace Illuminate\Cache;
 
   use Mongo;
 
   class MongoStore implements StoreInterface
   {
       /**
        * The mongo instance
        *
        * @param \Mongo
        */
       protected $connection;
 
       /**
        * The mongo connection instance
        *
        * @param \MongoConnection
        */
       protected $collection;
 
       /**
        * The Mongo config array
        *
        * @var array
        */
       protected $config;
 
       /**
        * Create a new Mongo cache store.
        *
        * @param array $config
        * — $config[‘host’] Mongodb host
        * — $config[‘username’] Mongodb username
        * — $config[‘password’] Mongodb password
        * — $config[‘database’] Mongodb database
        * — $config[‘collection’] Mongodb collection
        * @return void
        */
       public function __construct(array $config)
       {
           $this->config = $config;
 
           $connection_string = ‘mongodb://’;
 
           if (!empty($this->config[‘username’]) && !empty($this->config[‘password’])) {
               $connection_string .= «{$this->config[‘user’]}:{$this->config[‘password’]}@»;
           }
 
           $connection_string .= «{$this->config[‘host’]}»;
 
           $this->connection = new Mongo($connection_string);
 
           $this->collection = $this->connection->selectCollection($this->config[‘database’], $this->config[‘collection’]);
       }
 
       /**
        * Retrieve an item from the cache by key.
        *
        * @param string $key
        * @return mixed
        */
       public function get($key)
       {
           $cache_data = $this->getObject($key);
 
           if (!$cache_data) {
               return null;
           }
 
           return unserialize($cache_data[‘cache_data’]);
       }
 
       /**
        * Return the whole object instead of just the cache_data
        *
        * @param string $key
        * @return array|null
        */
       protected function getObject($key)
       {
           $cache_data = $this->collection->findOne(array(
               ‘key’ => $key,
           ));
 
           if (is_null($cache_data)) {
               return null;
           }
 
           if (isset($cache_data[‘expire’]) && time() >= $cache_data[‘expire’]) {
               $this->forget($key);
               return null;
           }
 
           return $cache_data;
       }
 
       /**
        * Store an item in the cache for a given number of minutes.
        *
        * @param string $key
        * @param mixed $value
        * @param int $minutes
        * @return void
        */
       public function put($key, $value, $minutes)
       {
           $expiry = $this->expiration($minutes);
 
           $this->collection->update(
               array(
                   ‘key’ => $key
               ),
               array(
                   ‘$set’ => array(
                       ‘cache_data’ => serialize($value),
                       ‘expiry’ => $expiry,
                       ‘ttl’ => ($minutes * 60)
                   )
               ),
               array(
                   ‘upsert’ => true,
                   ‘multiple’ => false
               )
           );
       }
 
       /**
        * Increment the value of an item in the cache.
        *
        * @param string $key
        * @param mixed $value
        * @return void
        *
        * @throws \LogicException
        */
       public function increment($key, $value = 1)
       {
           $cache_data = $this->getObject($key);
 
           if (!$cache_data) {
               $new_data = array(
                   ‘cache_data’ => serialize($value),
                   ‘expiry’ => $this->expiration(0),
                   ‘ttl’ => $this->expiration(0)
               );
           } else {
               $new_data = array(
                   ‘cache_data’ => serialize(unserialize($cache_data[‘cache_data’]) + $value),
                   ‘expiry’ => $this->expiration((int) ($cache_data[‘ttl’]/60)),
                   ‘ttl’ => $cache_data[‘ttl’]
               );
           }
 
           $this->collection->update(
               array(
                   ‘key’ => $key
               ),
               array(
                   ‘$set’ => $new_data
               ),
               array(
                   ‘upsert’ => true,
                   ‘multiple’ => false
               )
           );
       }
 
       /**
        * Decrement the value of an item in the cache.
        *
        * @param string $key
        * @param mixed $value
        * @return void
        *
        * @throws \LogicException
        */
       public function decrement($key, $value = 1)
       {
           $cache_data = $this->getObject($key);
 
           if (!$cache_data) {
               $new_data = array(
                   ‘cache_data’ => serialize((0 — $value)),
                   ‘expiry’ => $this->expiration(0),
                   ‘ttl’ => $this->expiration(0)
               );
           } else {
               $new_data = array(
                   ‘cache_data’ => serialize(unserialize($cache_data[‘cache_data’]) — $value),
                   ‘expiry’ => $this->expiration((int) ($cache_data[‘ttl’]/60)),
                   ‘ttl’ => $cache_data[‘ttl’]
               );
           }
 
           $this->collection->update(
               array(
                   ‘key’ => $key
               ),
               array(
                   ‘$set’ => $new_data
               ),
               array(
                   ‘upsert’ => true,
                   ‘multiple’ => false
               )
           );
       }
 
       /**
        * Store an item in the cache indefinitely.
        *
        * @param string $key
        * @param mixed $value
        * @return void
        */
       public function forever($key, $value)
       {
           return $this->put($key, $value, 0);
       }
 
       /**
        * Remove an item from the cache.
        *
        * @param string $key
        * @return void
        */
       public function forget($key)
       {
           $this->collection->remove(array(
               ‘key’ => $key
           ));
       }
 
       /**
        * Remove all items from the cache.
        *
        * @return void
        */
       public function flush()
       {
           $this->collection->remove();
       }
 
       /**
        * Get the expiration time based on the given minutes.
        *
        * @param int $minutes
        * @return int
        */
       protected function expiration($minutes)
       {
           if ($minutes === 0) return 9999999999;
 
           return time() + ($minutes * 60);
       }
 
       /**
        * Get the cache key prefix.
        *
        * @return string
        */
       public function getPrefix()
       {
           return »;
       }
   }

Мы также должны снова добавить обратный вызов Mongo к менеджеру:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
    * Register the service provider.
    *
    * @return void
    */
   public function register()
   {
       $this->app->bindShared(‘cache’, function($app)
       {
           $cache_manager = new CacheManager($app);
 
           $cache_manager->extend(‘mongo’, function($app) {
               return new MongoStore(
                   array(
                       ‘host’ => $app[‘config’]->get(‘cache.mongo.host’),
                       ‘username’ => $app[‘config’]->get(‘cache.mongo.username’),
                       ‘password’ => $app[‘config’]->get(‘cache.mongo.password’),
                       ‘database’ => $app[‘config’]->get(‘cache.mongo.database’),
                       ‘collection’ => $app[‘config’]->get(‘cache.mongo.collection’)
                   )
               );
           });
 
           return $cache_manager;
       });
 
       $this->app->bindShared(‘cache.store’, function($app)
       {
           return $app[‘cache’]->driver();
       });
 
       $this->app->bindShared(‘memcached.connector’, function()
       {
           return new MemcachedConnector;
       });
 
       $this->registerCommands();
   }

Наконец, нам нужно обновить конфигурационный файл cache.php :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
‘driver’ => ‘mongo’,
   …
   …
   …
   /**
    * Mongo DB settings
    */
   ‘mongo’ => array(
       ‘host’ => ‘127.0.0.1’,
       ‘username’ => »,
       ‘password’ => »,
       ‘database’ => ‘laravel’,
       ‘collection’ => ‘laravel_cache_collection’
   )

Теперь попробуйте использовать методы Cache::put() и Cache::get() . Если все сделано правильно, мы сможем использовать MongoDB для кэширования данных!

В этом уроке мы узнали о следующем:

  • Компонентная система Laravel под названием Illuminate , которая используется в фреймворке Laravel.
  • Поставщики услуг Laravel и немного о том, как они работают.
  • Система Laravel’s Manager, которая служит как оберткой, так и фабрикой для водителей.
  • Компоненты Session, Auth и Cache и как создавать новые драйверы для каждого.
  • Библиотеки Store, Guard и Repository, которые используют эти драйверы.

Надеюсь, это поможет программистам создавать свои собственные драйверы и расширять текущие функциональные возможности платформы Laravel.