Может войдёшь?
Черновики Написать статью Профиль

Расширение фреймворка

перевод документация 5.х

  1. 1. Управляющие и фабрики
  2. 2. Кэш
  3. 3. Сессии
    1. 3.1. Где расширять сессии
    2. 3.2. Написание расширения сессий
  4. 4. Авторизация
  5. 5. Расширения на основе сервис-контейнера
Этот перевод актуален для англоязычной документации на (ветка 5.0). Опечатка? Выдели и нажми Ctrl+Enter.

Данная статья документации актуальна только для версии 5.0 и была удалена в версии 5.1.

Управляющие и фабрики

Laravel содержит несколько классов PHPManager, которые управляют созданием компонентов, основанных на драйверах. Эти компоненты включают в себя кэш, сессии, авторизацию и очереди. Класс-управляющий ответственен за создание конкретной реализации драйвера в зависимости от настроек приложения. Например, класс PHPCacheManager может создавать объекты-реализации APC, Memcached, File и различных других драйверов кэша.

Каждый из этих управляющих классов имеет метод PHPextend(), который может использоваться для простого добавления новой реализации драйвера. Мы поговорим об этих управляющих классах ниже, с примерами того, как добавить собственный драйвер в каждый из них.

Внимание: Уделите несколько минут изучению различных классов PHPManager, которые поставляются с Laravel, таких как PHPCacheManager и PHPSessionManager. Знакомство с их кодом поможет вам лучше понять внутреннюю работу Laravel. Все классы-управляющие наследуют базовый класс PHPIlluminate\Support\Manager, который реализует общую полезную функциональность для каждого из них.

Кэш

Для расширения подсистемы кэширования мы используем метод PHPextend() класса PHPCacheManager, который используется для привязки стороннего драйвера к управляющему классу и является общим для всех таких классов. Например, для регистрации нового драйвера кэша с именем mongo мы бы сделали следующее:

PHP
Cache::extend('mongo', function($app)
{
  return 
Cache::repository(new MongoStore);
});

Первый параметр, передаваемый методу PHPextend() — имя драйвера. Это имя соответствует значению параметра driver файла настроек config/cache.php. Второй параметр — функция-замыкание, которая должна вернуть объект типа PHPIlluminate\Cache\Repository. Замыкание получит параметр PHP$app — объект PHPIlluminate\Foundation\Application и сервис-контейнер.

Вызов PHPCache::extend может быть сделан в методе PHPboot() в провайдере по умолчанию App\Providers\AppServiceProvider, который входит в новые приложения Laravel. Или вы можете создать свой сервис-провайдер для размещения расширения — только не забудьте зарегистрировать провайдер в массиве провайдеров в config/app.php.

Для создания стороннего драйвера для кэша мы начнём с реализации контракта PHPIlluminate\Contracts\Cache\Store. Итак, наша реализация MongoDB будет выглядеть примерно так:

PHP
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() {}

}

Нам только нужно реализовать каждый из этих методов с использованием подключения к MongoDB. Как только мы это сделали, можно закончить регистрацию нового драйвера:

PHP
Cache::extend('mongo', function($app)
{
  return 
Cache::repository(new MongoStore);
});

Если вы задумались о том, куда поместить код вашего нового драйвера кэша — подумайте о публикации его через Packagist!. Либо вы можете создать пространство имён PHPExtensions в вашей папке app. Однако держите в уме то, что Laravel не имеет жёсткой структуры папок и вы можете организовать свои файлы, как вам удобно.

Сессии

Расширение системы сессий Laravel собственным драйвером так же просто, как и расширение драйвером кэша. Мы вновь используем метод PHPextend() для регистрации собственного кода:

PHP
Session::extend('mongo', function($app)
{
  
// Вернуть объект, реализующий SessionHandlerInterface
});

Где расширять сессии

Код расширения системы сессий следует поместить в метод PHPboot() вашего AppServiceProvider.

Написание расширения сессий

Заметьте, что наш драйвер сессии должен реализовывать интерфейс PHPSessionHandlerInterface. Этот интерфейс содержит несколько простых методов, которые нам нужно написать. Заглушка драйвера MongoDB выглядит так:

PHP
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) {}

}

Эти методы не так легки в понимании, как методы драйвера кэша (PHPStoreInterface), поэтому давайте пробежимся по каждому из них подробнее:

  • Метод open обычно используется при открытии системы сессий, основанной на файлах. Так как Laravel поставляется с драйвером сессий file, вам почти никогда не понадобиться добавлять что-либо в этот метод. Вы можете оставить его пустым. Фактически, это просто плохое решение PHP, из-за которого мы должны написать этот метод (мы обсудим это ниже).
  • Метод close(), аналогично методу PHPopen(), обычно также игнорируется. Для большей части драйверов он не требуется.
  • Метод read() должен вернуть строку — данные сессии, связанные с переданным PHP$sessionId. Нет необходимости сериализовать объекты или делать какие-то другие преобразования при чтении или записи данных сессии в вашем драйвере — Laravel делает это автоматически.
  • Метод write() должен связать строку PHP$data с данными сессии с переданным идентификатором PHP$sessionId, сохранив её в каком-либо постоянном хранилище, таком как MongoDB, Dynamo и др.
  • Метод destroy() должен удалить все данные, связанные с переданным PHP$sessionId, из постоянного хранилища.
  • Метод gc() должен удалить все данные, которые старее переданного PHP$lifetime (отпечатка времени Unix). Для самоочищающихся систем вроде Memcached и Redis этот метод может быть пустым.

Когда SessionHandlerInterface реализован, мы можем зарегистрировать драйвер в управляющем классе сессий:

PHP
Session::extend('mongo', function($app)
{
  return new 
MongoHandler;
});

Когда драйвер сессий зарегистрирован, мы можем использовать драйвер mongo в нашем файле настроек config/session.php.

Внимание: Помните, если вы написали новый драйвер сессии, поделитесь им на Packagist!

Авторизация

Механизм авторизации может быть расширен тем же способом, что и кэш и сессии. Мы используем метод PHPextend(), с которым вы уже знакомы:

PHP
Auth::extend('riak', function($app)
{
  
// Вернуть объект, реализующий Illuminate\Contracts\Auth\UserProvider
});

Реализации UserProvider ответственны только за то, чтобы получать реализацию Illuminate\Contracts\Auth\Authenticatable из постоянного хранилища, такого как MySQL, Riak и др. Эти два интерфейса позволяют работать механизму авторизации Laravel вне зависимости от того, как хранятся пользовательские данные и какой класс используется для их представления.

Давайте посмотрим на контракт UserProvider:

PHP
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);

}

Метод PHPretrieveById() обычно получает числовой ключ, идентифицирующий пользователя — такой, как автоинкрементное числовое поле ID в СУБД MySQL. Метод должен возвращать объект-реализациюPHPAuthenticatable, соответствующий переданному ID.

Метод PHPretrieveByToken() получает пользователя по его уникальному PHP$identifier и токену «запомнить меня»PHP$token, который хранится в поле PHPremember_token. Как и предыдущий метод, он должен возвращать объект-реализацию PHPAuthenticatable.

Метод PHPupdateRememberToken() записывает новое значение PHP$token в поле PHPremember_token для указанного PHP$user. Новый токен может быть как свежим, назначенным при удачном входе с опцией «запомнить меня», так и нулевым, когда пользователь выходит из приложения.

Метод PHPretrieveByCredentials() получает массив данных, которые были переданы методу PHPAuth::attempt() при попытке входа в систему. Этот метод должен запросить своё постоянное хранилище на наличие пользователя с совпадающими данными. Обычно этот метод выполнит SQL-запрос с проверкой на PHP$credentials['username']. А затем он должен вернуть объект-реализацию UserInterface. Этот метод не должен производить сравнение паролей или выполнять вход.

Метод PHPvalidateCredentials() должен сравнить переданный объект пользователя PHP$user с данными для входа PHP$credentials для того, чтобы его авторизовать. К примеру, этот метод может сравнивать строку PHP$user->getAuthPassword с результатом вызова PHPHash::make() на строке PHP$credentials['password']. Этот метод должен только проверять данные пользователя и возвращать значение типа boolean.

Теперь, когда мы узнали о каждом методе интерфейса PHPUserProviderInterface давайте посмотрим на интерфейс PHPAuthenticatable. Как вы помните, провайдер должен вернуть реализацию этого интерфейса из своих методов PHPretrieveById() и PHPretrieveByCredentials():

PHP
interface Authenticatable {

  public function 
getAuthIdentifier();
  public function 
getAuthPassword();
  public function 
getRememberToken();
  public function 
setRememberToken($value);
  public function 
getRememberTokenName();

}

Это простой интерфейс. Метод PHPgetAuthIdentifier() должен просто вернуть «первичный ключ» пользователя. Если используется хранилище MySQL, то это будет автоинкрементное числовое поле-первичный ключ. Метод PHPgetAuthPassword() должен вернуть хэшированный пароль. Этот интерфейс позволяет системе авторизации работать с любым классом пользователя, вне зависимости от используемой ORM или хранилища данных. Изначально Laravel содержит класс User в папке app, который реализует этот интерфейс, поэтому вы можете обратиться к этому классу, чтобы увидеть пример реализации.

Наконец, когда мы написали класс-реализацию PHPUserProvider, мы готовы зарегистрировать наше расширение в фасаде PHPAuth:

PHP
Auth::extend('riak', function($app)
{
  return new 
RiakUserProvider($app['riak.connection']);
});

Когда вы зарегистрировали драйвер методом PHPextend() вы можете активировать его в вашем файле настроек config/auth.php.

Расширения на основе сервис-контейнера

Почти все сервис-провайдеры Laravel получают свои объекты из сервис-контейнера. Вы можете увидеть список провайдеров вашего приложения в файле config/app.php. Вам стоит пробежаться по коду каждого из поставщиков в свободное время — сделав это вы получите намного более чёткое представление о том, какую именно функциональность каждый из них добавляет к фреймворку, а также какие ключи используются для привязки различных услуг в сервис-контейнере.

Например, PHPHashServiceProvider использует привязку ключа hash для получения экземпляра PHPIlluminate\Hashing\BcryptHasher из сервис-контейнера. Вы можете легко расширить и перекрыть этот класс в вашем приложении перекрыв эту привязку. Например:

PHP
<?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;
    });
  }

}

Заметьте, что этот класс наследует PHPHashServiceProvider, а не базовый класс по умолчанию PHPServiceProvider. Когда вы расширили провайдер, измените PHPHashServiceProvider в файле настроек config/app.php на имя вашего нового поставщика услуг.

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

Написать комментарий

Разметка: ? ?

Авторизуйся, чтобы прокомментировать.