イントロダクションIntroduction
Laravelでは多くの点で、フレームワークのコアコンポーネントの動作をカスタマイズでき、完全に置き換えることさえ可能です。例えば、ハッシュ機能はHasherInterface
契約で定義されており、あなたのアプリケーションの要件に添って実装することができます。また、Request
オブジェクトを拡張することもでき、自分の便利な「ヘルパ」メソッドを付け加えることもできます。完全に新しい認証やキャッシュ、セッションドライバーを追加することもできるのです!Laravel offers many extension
points for you to customize the behavior of the
framework's core components, or even replace them
entirely. For example, the hashing facilities are
defined by a HasherInterface
contract,
which you may implement based on your application's
requirements. You may also extend the
Request
object, allowing you to add
your own convenient "helper" methods. You
may even add entirely new authentication, cache, and
session drivers!
一般的にLaravelは2つの方法で拡張できます。IoCコンテナで新しい実装を結合するか、「ファクトリー」デザインパターンの実装であるManager
クラスの拡張を登録するかです。この章では、フレームワークの様々な拡張方法を学び、必要なコードを試していきましょう。Laravel components are generally
extended in two ways: binding new implementations in
the IoC container, or registering an extension with
a Manager
class, which are
implementations of the "Factory" design
pattern. In this chapter we'll explore the various
methods of extending the framework and examine the
necessary code.
Note: Laravelのコンポーネントは通常2つのうちの一方、IoC結合か
Manager
クラスのどちらかで拡張していることを覚えておいてください。Managerクラスは「ファクトリー」デザインパターンの実装として動作し、キャッシュやセッションのようなドライバーベースの機能をインスタンス化することに責任があります。Note: Remember, Laravel components are typically extended in one of two ways: IoC bindings and theManager
classes. The manager classes serve as an implementation of the "factory" design pattern, and are responsible for instantiating driver based facilities such as cache and session.
マネージャーとファクトリーManagers & Factories
ドライバーベースのコンポーネントの作成を管理する、複数のManager
クラスをLaravelは持っています。それらは、キャッシュ、セッション、認証、キューコンポーネントです。Managerクラスはアプリケーションの設定に基づき、特定のドライバーの実装を作成することに責任を持っています。例えば、CacheManager
クラスはAPC、Memcached、ファイル、その他のキャッシュの実装を生成することができます。Laravel has several
Manager
classes that manage the
creation of driver-based components. These include
the cache, session, authentication, and queue
components. The manager class is responsible for
creating a particular driver implementation based on
the application's configuration. For example, the
CacheManager
class can create APC,
Memcached, File, and various other implementations
of cache drivers.
各マネージャーは、新しいドライバーのリゾルバーを簡単にマネージャへ登録できるように、extend
メソッドを備えています。以降では、各カスタムドライバーのサポートを注入する例と一緒に、こうしたマネージャーを説明していきます。Each of these managers includes
an extend
method which may be used to
easily inject new driver resolution functionality
into the manager. We'll cover each of these managers
below, with examples of how to inject custom driver
support into each of them.
Note: どうか時間を取り、
CacheManager
やSessionManager
のような、最初からLaravelに用意されている、様々なManager
クラスを調べてみてください。こうしたクラスを徹底的に読めば、Laravelの内部動作を完全に理解することができます。全Managerクラスは、Illuminate\Support\Manager
ベースクラスを拡張しており、各Managerに共通で便利な機能を提供しています。Note: Take a moment to explore the variousManager
classes that ship with Laravel, such as theCacheManager
andSessionManager
. Reading through these classes will give you a more thorough understanding of how Laravel works under the hood. All manager classes extend theIlluminate\Support\Manager
base class, which provides some helpful, common functionality for each manager.
どこで拡張するかWhere To Extend
このドキュメントは数多くのLaravelのコンポーネントをどのように拡張するかを説明するものです。しかし、拡張のコードをどこで記述するか、皆さん迷っていると思います。他の多くの初期設定コードと同様に、拡張コードをstart
ファイルに設置することができます。キャッシュと認証の拡張はこのアプローチが多分良いでしょう。セッションのような他の拡張コードは、リクエストのライフサイクルの初めの方で記述する必要があるため、サービスプロバイダーのregister
メソッドの中に置きましょう。This documentation covers how to
extend a variety of Laravel's components, but you
may be wondering where to place your extension code.
Like most other bootstrapping code, you are free to
place some extensions in your start
files. Cache and Auth extensions are good candidates
for this approach. Other extensions, like
Session
, must be placed in the
register
method of a service provider
since they are needed very early in the request
life-cycle.
キャッシュ(Cache)Cache
Laravelのキャッシュ機能を拡張するには、CacheManager
のextend
メソッドを使用します。このメソッドはManagerへカスタムドライバーのリゾルバーを結合するために使用され、全Managerクラスで使用できます。例えば、"mongo"という名前のキャッシュドライバーを登録するには、次のようになります。To extend the Laravel cache
facility, we will use the extend
method
on the CacheManager
, which is used to
bind a custom driver resolver to the manager, and is
common across all manager classes. For example, to
register a new cache driver named "mongo",
we would do the following:
Cache::extend('mongo', function($app)
{
// Illuminate\Cache\Repositoryインスタンスを返す…
});
extend
メソッドの最初の引数は、ドライバーの名前です。この名前は、app/config/cache.php
設定ファイルの中のdriver
オプションと対応しています。2つ目の引数はクロージャーで、Illuminate\Cache\Repository
インスタンスをリターンしなければなりません。クロージャーは、Illuminate\Foundation\Application
のインスタンスであり、IoCコンテナでもある、$app
インスタンスへ渡されます。The first argument passed to the
extend
method is the name of the
driver. This will correspond to your
driver
option in the
app/config/cache.php
configuration
file. The second argument is a Closure that should
return an Illuminate\Cache\Repository
instance. The Closure will be passed an
$app
instance, which is an instance of
Illuminate\Foundation\Application
and
an IoC container.
カスタムキャッシュドライバーを作成するために、最初にIlluminate\Cache\StoreInterface
契約を実装する必要があります。ですから、MongoDBキャッシュの実装は、次のようになるでしょう。To create our custom cache
driver, we first need to implement the
Illuminate\Cache\StoreInterface
contract. So, our MongoDB cache implementation would
look something like this:
class MongoStore implements Illuminate\Cache\StoreInterface {
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接続を使用して実装する必要があります。実装を完了したら、カスタムドライバーの登録も完成させましょう。We just need to implement each of these methods using a MongoDB connection. Once our implementation is complete, we can finish our custom driver registration:
use Illuminate\Cache\Repository;
Cache::extend('mongo', function($app)
{
return new Repository(new MongoStore);
});
上の例で見るように、カスタムキャッシュドライバーを作成する場合、
Illuminate\Cache\Repository
をベースとして使用できます。通常、自分でリポジトリークラスを作成する必要はありません。As you can see in the example
above, you may use the base
Illuminate\Cache\Repository
when
creating custom cache drivers. There is typically no
need to create your own repository class.
カスタムキャッシュドライバーコードをどこへ設置しようか迷っているなら、Packagistで使用できるようにすることを考えてください!もしくは、アプリケーションのメインフォルダーに、Extensions
名前空間を作成することもできます。例えば、アプリケーション名がSnappy
であるなら、キャッシュ拡張をapp/Snappy/Extensions/MongoStore.php
として設置します。しかし、Laravelは厳格なアプリケーション構造を持っていないので、好みに合わせ、自由に構造を決めて良いことを覚えておきましょう。If you're wondering where to put
your custom cache driver code, consider making it
available on Packagist! Or, you could create an
Extensions
namespace within your
application's primary folder. For example, if the
application is named Snappy
, you could
place the cache extension in
app/Snappy/Extensions/MongoStore.php
.
However, keep in mind that Laravel does not have a
rigid application structure and you are free to
organize your application according to your
preferences.
Note: ちょっとしたコードをどこに設置するか、未だ迷っているのでしたら、いつもサービスプロバイダーを考慮しましょう。既に学んだ通り、サービスプロバイダーをフレームワークの拡張を組織立てるために使うことは、コードを組織立てる方法として優れています。Note: If you're ever wondering where to put a piece of code, always consider a service provider. As we've discussed, using a service provider to organize framework extensions is a great way to organize your code.
セッション(Session)Session
Laravelにカスタムセッションドライバーを拡張するのは、キャッシュシステムを拡張するのと同様、簡単です。カスタムコードを登録するため、セッションでもextend
メソッドを使用します。Extending Laravel with a custom
session driver is just as easy as extending the
cache system. Again, we will use the
extend
method to register our custom
code:
Session::extend('mongo', function($app)
{
// ReturnSessionHandlerInterfaceの実装を返す
});
セッションをどこで拡張するかWhere To Extend The Session
キャッシュや認証のような拡張とは異なり、セッションの拡張は別のやり方を行います。セッションはリクエストのライフサイクルのとても早い段階から開始するため、start
ファイルの中で拡張しても遅すぎます。その代わりに、サービスプロバイダーが必要になります。サービスプロバイダーのregister
メソッドの中にセッションの拡張コードを設置して下さい。そしてそのプロバイダーをproviders
設定配列中で、Illuminate\Session\SessionServiceProvider
より後ろで設定して下さい。Session extensions need to be
registered differently than other extensions like
Cache and Auth. Since sessions are started very
early in the request-lifecycle, registering the
extensions in a start
file will happen
too late. Instead, a service
provider[/docs/4.2/ioc#service-providers]
will be needed. You should place your session
extension code in the register
method
of your service provider, and the provider should be
placed below the default
Illuminate\Session\SessionServiceProvider
in the providers
configuration
array.
セッションの拡張をコーディングするWriting The Session Extension
カスタムセッションドライバーは、SessionHandlerInterface
を実装する必要があることに注意してください。このインターフェイスは、PHP
5.4のコアに含まれています。もしあなたが、PHP
5.3を使用しているなら、5.4とのコンパチビリティのために、Laravelが代わって定義します。このインターフェイスは、実装する必要のあるシンプルないくつかのメソッドを含んでいます。MongoDB実装のスタブは、以下のようなコードになります。Note that our custom session
driver should implement the
SessionHandlerInterface
. This interface
is included in the PHP 5.4 core. If you are using
PHP 5.3, the interface will be defined for you by
Laravel so you have forward-compatibility. This
interface contains just a few simple methods we need
to implement. A stubbed MongoDB implementation would
look something like this:
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) {}
}
これらのメソッドは、キャシュのStoreInterface
のように、簡単に理解できないため、それぞれのメソッドを簡単に解説しましょう。Since these methods are not as
readily understandable as the cache
StoreInterface
, let's quickly cover
what each of the methods do:
open
メソッドは、通常ファイルベースのセッション保存システムで使用されます。Laravelには最初からfile
セッションドライバーが含まれているため、このメソッドにはほとんど何も記述する必要はないでしょう。空っぽのスタブのままにしておけます。PHPがこのメソッドを私達に実装しろと要求しているのは、実際、インターフェイスの設計がまずいからに過ぎません。(後ほど説明します。)Theopen
method would typically be used in file based session store systems. Since Laravel ships with afile
session driver, you will almost never need to put anything in this method. You can leave it as an empty stub. It is simply a fact of poor interface design (which we'll discuss later) that PHP requires us to implement this method.close
メソッドは、open
メソッドと同様に、通常無視できます。ほとんどのドライバーでは、必要ありません。Theclose
method, like theopen
method, can also usually be disregarded. For most drivers, it is not needed.read
メソッドは、指定された$sessionId
に関係付けられた、文字列のセッションデーターをリターンする必要があります。ドライバーからセッションデーターを取得したり、保存したりする時に、シリアライズや他のエンコードを行う必要はありません。Laravelがシリアライズを行います。Theread
method should return the string version of the session data associated with the given$sessionId
. There is no need to do any serialization or other encoding when retrieving or storing session data in your driver, as Laravel will perform the serialization for you.write
メソッドは$data
文字列を$sessionId
と関連付けて、MongoDBやDynamo、その他の持続的なストレージシステムに保存する必要があります。Thewrite
method should write the given$data
string associated with the$sessionId
to some persistent storage system, such as MongoDB, Dynamo, etc.destroy
メソッドは、$sessionId
に関連付けられたデーターを持続的なストレージから削除します。Thedestroy
method should remove the data associated with the$sessionId
from persistent storage.gc
メソッドは、指定されたUNIXタイムスタンプの$lifetime
より古いセッションデーターを全部破棄しなくてはなりません。MemcachedやRedisのように、自分で古いデーターを破棄するシステムでは、このメソッドは空のままにします。Thegc
method should destroy all session data that is older than the given$lifetime
, which is a UNIX timestamp. For self-expiring systems like Memcached and Redis, this method may be left empty.
SessionHandlerInterface
を実装したら、セッションマネージャーに登録する準備ができました。Once the
SessionHandlerInterface
has been implemented, we are
ready to register it with
the Session
manager:
Session::extend('mongo', function($app)
{
return new MongoHandler;
});
一度セッションドライバーを登録すれば、mongo
ドライバーをapp/config/session.php
設定で使用できます。Once the
session driver has been
registered, we may use the
mongo
driver in
our
app/config/session.php
configuration
file.
Note: カスタムセッションハンドラーを書いたら、Packagistで共有することを思い出してください。Note: Remember, if you write a custom session handler, share it on Packagist!
認証Authentication
キャッシュやセッション機能と同じ方法で、認証も拡張できます。既にお馴染みの、extend
メソッドを今回も使用します。Authentication
may be extended the same way
as the cache and session
facilities. Again, we will
use the extend
method we have become
familiar with:
Auth::extend('riak', function($app)
{
// Return implementation of Illuminate\Auth\UserProviderInterface
});
UserProviderInterface
の実装は、UserInterface
の実装をMySQLやRiakなどの持続するストレージシステムより取得することだけに責任を持っています。どのようにユーザー情報が保存されていようと、どの様なタイプのクラスがユーザーを表していようと、この2つのインターフェイスのおかげで、Laravelの認証メカニズムは機能し続けることができます。The
UserProviderInterface
implementations are only
responsible for fetching a
UserInterface
implementation out of a
persistent storage system,
such as MySQL, Riak, etc.
These two interfaces allow
the Laravel authentication
mechanisms to continue
functioning regardless of
how the user data is stored
or what type of class is
used to represent
it.
UserProviderInterface
に注目しましょう。Let's
take a look at the
UserProviderInterface
:
interface UserProviderInterface {
public function retrieveById($identifier);
public function retrieveByToken($identifier, $token);
public function updateRememberToken(UserInterface $user, $token);
public function retrieveByCredentials(array $credentials);
public function validateCredentials(UserInterface $user, array $credentials);
}
retrieveById
関数は、典型的にはMySQLデータベースの自動増加IDのような、ユーザーを表す数字キーを受け付けます。IDに一致するUserInterface
の実装が取得され、メソッドによりリターンされます。The
retrieveById
function typically receives
a numeric key representing
the user, such as an
auto-incrementing ID from a
MySQL database. The
UserInterface
implementation matching the
ID should be retrieved and
returned by the
method.
retrieveByToken
関数は、一意の$identifier
と、remember_token
フィールドに保存されている"Remember
me"トークンにより、ユーザーを取得します。前のメソッドと同様に、UserInterface
の実装をリターンしなくてはなりません。The
retrieveByToken
function retrieves a user by
their unique
$identifier
and
"remember me"
$token
, stored
in a field
remember_token
.
As with with previous
method, the
UserInterface
implementation should be
returned.
updateRememberToken
メソッドは、$user
のremember_token
フィールドを新しい$token
で更新します。新しいトークンは"Remember
me"によるログインが成功した時に生成される真新しいトークンでも良いですし、もしくはユーザーがログアウトした時はnullでもかまいません。The
updateRememberToken
method updates the
$user
field
remember_token
with the new
$token
. The new
token can be either a fresh
token, assigned on
successfull "remember
me" login attempt, or a
null when user is logged
out.
retrieveByCredentials
メソッドは、アプリケーションにログインするために、Auth::attempt
メソッドに渡された、ログイン情報の配列を受け取ります。メソッドはユーザー情報に一致するユーザーが、裏にある持続的なストレージに存在しているか「クエリー」する必要があります。典型的にメソッドは、"where"条件で$credentials['username']
のクエリーを実行することでしょう。このメソッドでパスワードのバリデーションや認証を試みてはいけません。The
retrieveByCredentials
method receives the array of
credentials passed to the
Auth::attempt
method when attempting to
sign into an application.
The method should then
"query" the
underlying persistent
storage for the user
matching those credentials.
Typically, this method will
run a query with a
"where" condition
on
$credentials['username']
.
This method should
not attempt to do any
password validation or
authentication.
validateCredentials
メソッドは指定された$user
とユーザーを認証するための$credentials
を比較する必要があります。例えば、このメソッドでは
$user->getAuthPassword()
文字列と、Hash::make
した$credentials['password']
を比較する必要があるでしょう。The
validateCredentials
method should compare the
given $user
with the
$credentials
to
authenticate the user. For
example, this method might
compare the
$user->getAuthPassword()
string to a
Hash::make
of
$credentials['password']
.
これでUserProviderInterface
のメソッドをそれぞれ学習し終えました。今度は、UserInterface
に注目していきましょう。プロバイダーはこのインターフェイスの実装をretrieveById
とretrieveByCredentials
から、リターンしなくてはならないことを覚えておいてください。Now that
we have explored each of the
methods on the
UserProviderInterface
,
let's take a look at the
UserInterface
.
Remember, the provider
should return
implementations of this
interface from the
retrieveById
and
retrieveByCredentials
methods:
interface UserInterface {
public function getAuthIdentifier();
public function getAuthPassword();
}
このインターフェイスはシンプルです。getAuthIdentifier
メソッドは、ユーザーの「主キー」を返さなくてはなりません。MySQLがバックエンドなら、ここでも自動増加主キーとなるでしょう。getAuthPassword
は、ユーザーのハッシュ済みのパスワードを返す必要があります。このインターフェイスにより、どんなORMやストレージの抽象クラスを使用してるのかに係わらず、認証システムをユーザークラスに対し動作させることを可能にしています。デフォルトでLaravelはこのインターフェイスを実装している、app/models
ディレクトリーの、User
クラスを含んでいます。ですから、実装のサンプルとして、このクラスを調べてみてください。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/models
directory which implements
this interface, so you may
consult this class for an
implementation
example.
UserProviderInterface
の実装を済ませたら、ついに私達の拡張をAuth
ファサードに登録する準備ができました。Finally,
once we have implemented the
UserProviderInterface
,
we are ready to register our
extension with the
Auth
facade:
Auth::extend('riak', function($app)
{
return new RiakUserProvider($app['riak.connection']);
});
ドライバーをextend
メソッドで登録し終えたら、app/config/auth.php
でその新しいドライバーに切り替えましょう。After you
have registered the driver
with the extend
method, you switch to the
new driver in your
app/config/auth.php
configuration
file.
IoCベースの拡張IoC Based Extension
Laravelフレームワークに含まれている、ほとんどすべてのサービスプロバイダーは、IoCコンテナにオブジェクトを結合しています。app/config/app.php
設定ファイルで、アプリケーションのサービスプロバイダーのリストを見つけられます。時間があれば、プロバイダーそれぞれのソースコードを拾い読みしてください。そうすれば、それぞれのプロバイダーがフレームワークに何を付け加えているのか、同時にIoCコンテナに数々のサービスを結合するため、どんなキーが使用されているかを、もっと知ることができます。Almost
every service provider
included with the Laravel
framework binds objects into
the IoC container. You can
find a list of your
application's service
providers in the
app/config/app.php
configuration file. As you
have time, you should skim
through each of these
provider's source code. By
doing so, you will gain a
much better understanding of
what each provider adds to
the framework, as well as
what keys are used to bind
various services into the
IoC container.
例えば、HashServiceProvider
は、IoCコンテナでhash
キーと結合されており、Illuminate\Hashing\BcryptHasherインスタンスへ解決されます。あなたは自分のアプリケーションの中でIoC結合をオーバーライドすることにより、簡単にクラスを拡張したり、オーバーライドしたりできます。例えば:For
example, the
HashServiceProvider
binds a hash
key into the IoC container,
which resolves into a
Illuminate\Hashing\BcryptHasher
instance. You can easily
extend and override this
class within your own
application by overriding
this IoC binding. For
example:
class SnappyHashProvider extends Illuminate\Hashing\HashServiceProvider {
public function boot()
{
App::bindShared('hash', function()
{
return new Snappy\Hashing\ScryptHasher;
});
parent::boot();
}
}
このクラスはベースクラスのデフォルトServiceProvider
ではなく、
HashServiceProvider
を拡張していることに注意してください。サービスプロバイダーを拡張したら、app/config/app.php
設定ファイルの中の、HashServiceProvider
をあなたが拡張したプロバーダー名へ交換してください。Note that
this class extends the
HashServiceProvider
,
not the default
ServiceProvider
base class. Once you have
extended the service
provider, swap out the
HashServiceProvider
in your
app/config/app.php
configuration file with the
name of your extended
provider.
ここまで、コンテナで結合されたコアクラスを拡張する、一般的な方法を見てきました。基本的に、コンテナ上の全てのコアクラスは、こうした方法で結合されており、オーバーライド可能です。繰りかえしますが、フレームワークに含まれているサービスプロバイダーを全般的に読んでみてください。様々なクラスに親しめますし、どのキーで結合されているか分かります。これは、Laravelがどのように一つにまとめられているのかを詳しく理解できる、素晴らしい方法です。This is the general method of extending any core class that is bound in the container. Essentially every core class is bound in the container in this fashion, and can be overridden. Again, reading through the included framework service providers will familiarize you with where various classes are bound into the container, and what keys they are bound by. This is a great way to learn more about how Laravel is put together.
リクエストの拡張Request Extension
Request
クラスはフレームワークのとても基礎的な部分であり、リクエストサイクルのとても早い段階でインスタンス化されるため、今までの例とは多少異なる動作をしています。Because
it is such a foundational
piece of the framework and
is instantiated very early
in the request cycle,
extending the
Request
class
works a little differently
than the previous
examples.
最初に、通常通りクラスを拡張します。First, extend the class like normal:
<?php namespace QuickBill\Extensions;
class Request extends \Illuminate\Http\Request {
// カスタマイズした、便利なメソッドをここへ…
}
クラスを拡張したら、bootstrap/start.php
ファイルを開きます。このファイルは、アプリケーションのリクエスト毎に、とても早い段階で読み込まれるファイルの一つです。Laravelの$app
インスタンスを生成している、最初のアクションの実行に注目してください。Once you
have extended the class,
open the
bootstrap/start.php
file. This file is one of
the very first files to be
included on each request to
your application. Note that
the first action performed
is the creation of the
Laravel $app
instance:
$app = new \Illuminate\Foundation\Application;
新しいインスタンスが生成されると、新しいIlluminate\Http\Request
インスタンスが生成され、IoCコンテナにrequest
キーとして結合されます。ですから、「デフォルト」リクエストタイプとして使用されるカスタムクラスを指定する方法が必要です。そう、ありがたいことに、アプリケーションインスタンスのrequestClass
メソッドが、これを行います!では、bootstrap/start.php
ファイルの一番最初に、以下の行を付け加えてください。When a
new application instance is
created, it will create a
new
Illuminate\Http\Request
instance and bind it to the
IoC container using the
request
key.
So, we need a way to specify
a custom class that should
be used as the
"default" request
type, right? And,
thankfully, the
requestClass
method on the application
instance does just this! So,
we can add this line at the
very top of our
bootstrap/start.php
file:
use Illuminate\Foundation\Application;
Application::requestClass('QuickBill\Extensions\Request');
カスタムリクエストクラスを指定すると、LaravelはRequest
インスタンスを生成する時、いつもこのクラスを使用します。便利なことに、いつでもカスタムリクエストクラスが利用できます。例えば、ユニットテストの中でも使用可能です!Once you
have specified the custom
request class, Laravel will
use this class anytime it
creates a
Request
instance, conveniently
allowing you to always have
an instance of your custom
request class available,
even in unit
tests!