This document is for CakePHP's development version, which can be significantly different
from previous releases.
You may want to read
current stable release documentation instead.
コンポーネントはコントローラー間で共有されるロジックのパッケージです。 CakePHP には、様々な共通のタスクを支援するための素晴らしいコアコンポーネントが 用意されています。あなた独自のコンポーネントも作成できます。 もしコントローラー間で コピー&ペーストしたい箇所があった場合、その機能を含むコンポーネントの作成を 検討しましょう。コンポーネントを作成することで、コントローラーのコードを綺麗に保ち、 プロジェクト間のコードの再利用につながります。
CakePHP の中に含まれるコンポーネントの詳細については、各コンポーネントの章を チェックしてください。
コアコンポーネントの多くは設定を必要としています。コンポーネントが設定を
必要としている例は、 AuthComponent や
などにあります。これらのコンポーネントや
一般的なコンポーネントの設定は、通常、お使いのコントローラーの initialize()
メソッド内で loadComponent()
を使用するか、 $components
配列を介して行われます。
class PostsController extends AppController
{
public function initialize(): void
{
parent::initialize();
$this->loadComponent('RequestHandler', [
'viewClassMap' => ['json' => 'AppJsonView'],
]);
$this->loadComponent('Security', ['blackholeCallback' => 'blackhole']);
}
}
config()
メソッドを使用して、実行時にコンポーネントを設定することができます。
しばしば、コントローラーの beforeFilter()
メソッドで行われます。
上記は、次のように表現することもできます。
public function beforeFilter(EventInterface $event)
{
$this->RequestHandler->setConfig('viewClassMap', ['rss' => 'MyRssView']);
}
コンポーネントは、ヘルパーと同じように、設定データを取得および設定するために使用されている
getConfig()
と setConfig()
メソッドを実装しています。
// 設定データの読み込み
$this->RequestHandler->getConfig('viewClassMap');
// 設定をセット
$this->Csrf->setConfig('cookieName', 'token');
コンポーネントは、ヘルパーと同じように、config()
でアクセス可能な
$_config
プロパティーを作成するためにコンストラクターの設定で自分の
$_defaultConfig
プロパティーを自動的にマージします。
共通設定の一つに className
オプションがあります。このオプションを使うと
コンポーネントに別名をつけられます。この機能は $this->Auth
や
他のコンポーネントの参照を独自実装に置き換えたい時に便利です。
// src/Controller/PostsController.php
class PostsController extends AppController
{
public function initialize(): void
{
$this->loadComponent('Auth', [
'className' => 'MyAuth'
]);
}
}
// src/Controller/Component/MyAuthComponent.php
use Cake\Controller\Component\AuthComponent;
class MyAuthComponent extends AuthComponent
{
// コア AuthComponent を上書きするコードを追加
}
上記の例ではコントローラーにて MyAuthComponent
に $this->Auth
という
別名 をつけています。
注釈
別名を付けられたコンポーネントはコンポーネントが使われるあらゆる場所の インスタンスを置き換えます。これは、他のコンポーネントの内部を含みます。
すべてのコントローラーアクションで全コンポーネントを使えるようにする必要は
ないかもしれません。このような状況では、お使いのコントローラーで
loadComponent()
メソッドを使用して、実行時にコンポーネントを
ロードすることができます。
// コントローラーのアクションの中で
$this->loadComponent('OneTimer');
$time = $this->OneTimer->getTime();
注釈
動的にロードされたコンポーネントはコールバックされないことに注意してください。
もし、 beforeFilter
または startup
コールバックに依存している場合、
あなたのコンポーネントをロードするときに手動でそれらを呼び出す必要があります。
一旦、コンポーネントをコントローラーに読込んでしまえば、使うのは非常に簡単です。
使用中の各コンポーネントはコントローラーのプロパティーのように見えます。
もし、 Cake\Controller\Component\FlashComponent
を
コントローラーに読込んだ場合、以下のようにアクセスすることができます。
class PostsController extends AppController
{
public function initialize(): void
{
parent::initialize();
$this->loadComponent('Flash');
}
public function delete()
{
if ($this->Post->delete($this->request->getData('Post.id')) {
$this->Flash->success('Post deleted.');
return $this->redirect(['action' => 'index']);
}
}
注釈
モデルとコンポーネントの両方がプロパティーとしてコントローラーに追加されているので、 それらは同じ「名前空間」を共有しています。 コンポーネントとモデルに同じ名前を付けないように注意してください。
アプリケーションの様々な箇所で複雑な数学的処理を必要としている オンラインアプリケーションを仮定して下さい。 これから、コントローラーの様々な箇所で使うための共有ロジックを集約するための コンポーネントを作成します。
はじめに、新しいコンポーネントファイルとクラスを作成します。 src/Controller/Component/MathComponent.php にファイルを作成します 。 コンポーネントのための基本的な構造は次のようになります。
namespace App\Controller\Component;
use Cake\Controller\Component;
class MathComponent extends Component
{
public function doComplexOperation($amount1, $amount2)
{
return $amount1 + $amount2;
}
}
注釈
すべてのコンポーネントは Cake\Controller\Component
を
継承しなければなりません。継承されていない場合、例外が発生します。
一旦コンポーネントが完成してしまえば、コントローラーの initialize()
メソッド中で
それをロードすることによって、アプリケーションのコントローラーで使用することができます。
ロードされた後、コントローラーはそのコンポーネントに由来する名前の新しいプロパティーを与えられ、
そのプロパティーを通してコンポーネントのインスタンスにアクセスできます。
// コントローラーの中で
// 標準の $this->Csrf と同様に
// 新しいコンポーネントを $this->Math として利用可能にします。
public function initialize(): void
{
parent::initialize();
$this->loadComponent('Math');
$this->loadComponent('Csrf');
}
コントローラーの中でコンポーネントを読み込む時、コンポーネントのコンストラクターに渡す バラメータを宣言することもできます。 このパラメーターはコンポーネントによって処理することができます。
// コントローラーの中で
public function initialize(): void
{
parent::initialize();
$this->loadComponent('Math', [
'precision' => 2,
'randomGenerator' => 'srand'
]);
$this->loadComponent('Csrf');
}
上記の例では precision と randomGenerator を含む配列が
MathComponent::initialize()
の $config
パラメーターに渡されます。
作成しているコンポーネントから他のコンポーネントを使いたい時がたまにあります。
その場合、作成中のコンポーネントから他のコンポーネントを読み込むことができ、
その方法はコントローラーから $components
変数を使って読み込む場合と同じです。
// src/Controller/Component/CustomComponent.php
namespace App\Controller\Component;
use Cake\Controller\Component;
class CustomComponent extends Component
{
// あなたのコンポーネントが使っている他のコンポーネント
public $components = ['Existing'];
// あなたのコンポーネントに必要な、その他の追加のセットアップを実行
public function initialize(array $config): void
{
$this->Existing->foo();
}
public function bar()
{
// ...
}
}
// src/Controller/Component/ExistingComponent.php
namespace App\Controller\Component;
use Cake\Controller\Component;
class ExistingComponent extends Component
{
public function foo()
{
// ...
}
}
注釈
コントローラーから読み込んだコンポーネントと違い、コンポーネントから コンポーネントを読み込んだ場合は、コールバックが呼ばれないことに注意して下さい。
コンポーネント内から、_registry を介して現在のコントローラーに アクセスすることができます。
$controller = $this->getController();
また、コンポーネントは、リクエストサイクルを増強することができる、 いくつかのリクエストライフサイクルコールバックを提供しています。
コントローラーの beforeFilter メソッドの前に呼び出されますが、 コントローラーのinitialize() メソッドの 後 です。
コントローラーの beforeFilter メソッドの後、コントローラーの現在の アクションハンドラの前に呼び出されます。
コントローラーがリクエストされたアクションのロジックを実行した後、 ビューとレイアウトが描画される前に呼び出されます。
出力結果がブラウザーに送信される前に呼び出されます。
コントローラーの redirect メソッドが呼び出された時に、
他のアクションより先に呼びだされます。このメソッドが false
を返す時、
コントローラーはリクエストのリダイレクトを中断します。
$url と $response パラメーターを使用すると、リダイレクト先やレスポンスの
任意の他のヘッダーを検査や変更することができます。
コンポーネントのコールバックメソッド内からリダイレクトするには、次のようにします。
public function beforeFilter(EventInterface $event)
{
$event->stopPropagation();
return $this->getController()->redirect('/');
}
イベントを停止することで、CakePHPに他のコンポーネントのコールバックを実行させたくないこと、
そしてコントローラがこれ以上アクションを処理してはいけないことを知らせます。
As of 4.1.0 you can raise a RedirectException
to signal
a redirect:
use Cake\Http\Exception\RedirectException;
use Cake\Routing\Router;
public function beforeFilter(EventInterface $event)
{
throw new RedirectException(Router::url('/'))
}
Raising an exception will halt all other event listeners and create a new
response that doesn't retain or inherit any of the current response's headers.
When raising a RedirectException
you can include additional headers:
throw new RedirectException(Router::url('/'), 302, [
'Header-Key' => 'value',
]);