diff --git a/en/appendices/3-5-migration-guide.rst b/en/appendices/3-5-migration-guide.rst index c277760e0d..4a2a54ae82 100644 --- a/en/appendices/3-5-migration-guide.rst +++ b/en/appendices/3-5-migration-guide.rst @@ -196,7 +196,7 @@ Console Integration Testing The ``Cake\TestSuite\ConsoleIntegrationTestCase`` class was added to make integration testing console applications easier. For more information, visit the :ref:`console-integration-testing` section. This test class is fully -compatible with the current shell dispatcher as well as the new +compatible with the current ``Cake\Console\ShellDispatcher`` as well as the new ``Cake\Console\CommandRunner``. Collection diff --git a/en/development/routing.rst b/en/development/routing.rst index b85e521b47..73cc369eff 100644 --- a/en/development/routing.rst +++ b/en/development/routing.rst @@ -61,7 +61,7 @@ you wish, you can restrict some parameters to conform to a regular expression:: '/articles/:id', ['controller' => 'Articles', 'action' => 'view'], ['id' => '\d+', 'pass' => ['id']] - ) + ); The previous example changed the star matcher by a new placeholder ``:id``. Using placeholders allows us to validate parts of the URL, in this case we used diff --git a/ja/_static/img/middleware-request.png b/ja/_static/img/middleware-request.png new file mode 100644 index 0000000000..7301b09033 Binary files /dev/null and b/ja/_static/img/middleware-request.png differ diff --git a/ja/_static/img/middleware-setup.png b/ja/_static/img/middleware-setup.png new file mode 100644 index 0000000000..5e65f5c499 Binary files /dev/null and b/ja/_static/img/middleware-setup.png differ diff --git a/ja/appendices/3-5-migration-guide.rst b/ja/appendices/3-5-migration-guide.rst index 30b84afeb1..84b7a03bff 100644 --- a/ja/appendices/3-5-migration-guide.rst +++ b/ja/appendices/3-5-migration-guide.rst @@ -1,13 +1,338 @@ -3.5 Migration Guide -################### +3.5 移行ガイド +############## -.. note:: - The documentation is not currently supported in Japanese language for this - page. +CakePHP 3.5 は、3.4 の API の完全上位互換です。 +このページでは、3.5 の変更と改善についてのアウトラインを紹介します。 - Please feel free to send us a pull request on - `Github `_ or use the **Improve This Doc** - button to directly propose your changes. +3.5.xにアップグレードするには、次のComposerコマンドを実行してください。 - You can refer to the English version in the select top menu to have - information about this page's topic. +.. code-block:: bash + + php composer.phar require --update-with-dependencies "cakephp/cakephp:3.5.*" + +非推奨 +====== + +以下は、非推奨のメソッド、プロパティーと動作の一覧です。 +これらの機能は、4.0.0 以後に削除されるまで機能し続けます。 + +* ``Cake\Http\Client\CookieCollection`` は非推奨です。 + 代わりに ``Cake\Http\Cookie\CookieCollection`` を使用してください。 +* ``Cake\View\Helper\RssHelper`` は非推奨です。 + 使用されることがまれなため、RssHelperは非推奨です。 +* ``Cake\Controller\Component\CsrfComponent`` は非推奨です。 + 代わりに :ref:`csrf-middleware` を使用してください。 +* ``Cake\Datasource\TableSchemaInterface`` は非推奨です。 + ``Cake\Database\TableSchemaAwareInterface`` を使用してください。 +* ``Cake\Console\ShellDispatcher`` は非推奨です。アプリケーションでは + ``Cake\Console\CommandRunner`` を代わりに使用するように更新してください。 +* ``Cake\Database\Schema\TableSchema::column()`` は非推奨です。 + 代わりに ``Cake\Database\Schema\TableSchema::getColumn()`` を使用してください。 +* ``Cake\Database\Schema\TableSchema::constraint()`` は非推奨です。 + 代わりに ``Cake\Database\Schema\TableSchema::getConstraint()`` を使用してください。 +* ``Cake\Database\Schema\TableSchema::index()`` は非推奨です。 + 代わりに ``Cake\Database\Schema\TableSchema::getIndex()`` を使用してください。 + +非推奨の複合 get / set メソッド +------------------------------- + +過去には、CakePHP は get / set モードの両方を提供する 'モーダル' メソッドを +利用していました。これらのメソッドにより、IDE の自動補完や、 +将来的に厳格な戻り値の型を追加する機能が複雑になります。 +これらの理由から、複合 get / set メソッドは、個別の get および +set メソッドに分割されています。 + +推奨されなくなり、 ``getX()`` と ``setX()`` メソッドに置き換えられた +メソッドのリストを次に示します。 + +``Cake\Cache\Cache`` + * ``config()`` + * ``registry()`` +``Cake\Console\Shell`` + * ``io()`` +``Cake\Console\ConsoleIo`` + * ``outputAs()`` +``Cake\Console\ConsoleOutput`` + * ``outputAs()`` +``Cake\Database\Connection`` + * ``logger()`` +``Cake\Database\TypedResultInterface`` + * ``returnType()`` +``Cake\Database\TypedResultTrait`` + * ``returnType()`` +``Cake\Database\Log\LoggingStatement`` + * ``logger()`` +``Cake\Datasource\ModelAwareTrait`` + * ``modelType()`` +``Cake\Database\Query`` + * ``valueBinder()`` の getter 部分 (今は ``getValueBinder()``) +``Cake\Database\Schema\TableSchema`` + * ``columnType()`` +``Cake\Datasource\QueryTrait`` + * ``eagerLoaded()`` の getter 部分 (今は ``isEagerLoaded()``) +``Cake\Event\EventDispatcherInterface`` + * ``eventManager()`` +``Cake\Event\EventDispatcherTrait`` + * ``eventManager()`` +``Cake\Error\Debugger`` + * ``outputAs()`` (今は ``getOutputFormat()`` / ``setOutputFormat()``) +``Cake\Http\ServerRequest`` + * ``env()`` (今は ``getEnv()`` / ``withEnv()``) + * ``charset()`` (今は ``getCharset()`` / ``withCharset()``) +``Cake\I18n\I18n`` + * ``locale()`` + * ``translator()`` + * ``defaultLocale()`` + * ``defaultFormatter()`` +``Cake\ORM\Association\BelongsToMany`` + * ``sort()`` +``Cake\ORM\LocatorAwareTrait`` + * ``tableLocator()`` +``Cake\ORM\EntityTrait`` + * ``invalid()`` (今は ``getInvalid()``, ``setInvalid()``, + ``setInvalidField()``, そして ``getInvalidField()``) +``Cake\ORM\Table`` + * ``validator()`` +``Cake\Routing\RouteBuilder`` + * ``extensions()`` + * ``routeClass()`` +``Cake\Routing\RouteCollection`` + * ``extensions()`` +``Cake\TestSuite\TestFixture`` + * ``schema()`` +``Cake\Utility\Security`` + * ``salt()`` +``Cake\View\View`` + * ``template()`` + * ``layout()`` + * ``theme()`` + * ``templatePath()`` + * ``layoutPath()`` + * ``autoLayout()`` (今は ``isAutoLayoutEnabled()`` / ``enableAutoLayout()``) + +振る舞いの変更 +============== + +以下の変更は、API 互換性はありますが、あなたのアプリケーションに影響を及ぼし得る +振る舞いのわずかな差異があります。 + +* ``BehaviorRegistry`` 、 ``HelperRegistry`` 及び ``ComponentRegistry`` では、 + 未知のオブジェクト名で ``unload()`` が呼び出されたときに + 例外を発生させるようになりました。 この変更はタイポをより目立たせることで + エラーを見つけやすくしています。 +* ``HasMany`` は ``BelongsToMany`` と同様にアソシエーションのプロパティーに + 空の値が設定されても正常に処理します。つまり、空の配列と同じ方法で + ``false`` 、 ``null`` 及び空の文字列を処理します。 + ``HasMany`` の場合、関連先の保存方法として ``replace`` が使用されているとき、 + 関連するすべてのレコードが削除/リンク解除されます。 + その結果、フォームを使用して空の文字列を渡すことによって、 + 関連するレコードをすべて削除/リンク解除することができます。 + これまではカスタムマーシャリングを作成する必要がありました。 +* ``ORM\Table::newEntity()`` は 変換された関連付けレコードが + ``dirty`` の場合にのみアソシエーションプロパティーに ``dirty`` を + つけるようになりました。プロパティーを含まない関連エンティティーが作成される場合、 + 空のレコードには永続化させるためのフラグはつきません。 +* ``Http\Client`` はリクエストオブジェクトを作成するときに、 + ``cookie()`` の結果を使用しなくなりました。代わりに ``Cookie`` ヘッダーと + ``CookieCollection`` が使用できます。 + これは、クライアントにカスタムHTTPアダプターを使用しているときにのみ影響があります。 +* シェルを呼び出すときにサブコマンドに複数ワードを用いる場合、 + 名前にはキャメルケースを使用する必要がありました。これからは + アンダースコアでサブコマンドを呼び出すことができます。例えば、 + ``cake tool initMyDb`` は ``cake tool init_my_db`` と呼び出すことができます。 + あなたのシェルが変換規則の異なる2つのサブコマンドを用いていた場合は + 最後に関連付けた規則のコマンドだけが機能します。 +* ``SecurityComponent`` はリクエストデータを持たないPOSTリクエストを破棄します。 + この変更はデータベースのデフォルト値のみを使用してレコードを作成するアクションを + 保護するのに役立ちます。 +* ``Cake\ORM\Table::addBehavior()`` と ``removeBehavior()`` は ``$this`` を + 返すようになりました。これは、テーブルオブジェクトを + 流れるようなインターフェイスで定義するのに便利です。 +* キャッシュエンジンは失敗または誤って構成されたときに例外を発生させなくなりました。 + 代わりに、操作不能な ``NullEngine`` としてフォールバックさせます。フォールバックは + エンジンごとに :ref:`設定 ` することもできます。 +* ``Cake\Database\Type\DateTimeType`` は以前からのフォーマットに加えて + ISO-8859-1 でフォーマットされた日付文字列(例えば、 2017-07-09T12:33:00+00:02) を + 変換するようになりました。DateTimeTypeのサブクラスを作成している場合は + コードを更新する必要があります。 + +新機能の追加 +============ + +スコープ付きミドルウェア +------------------------ + +特定のURLスコープのルートに条件付きでミドルウェアを適用できるようになりました。 +これにより、ミドルウェア内部でURLチェックコードを記述せずに、 +アプリケーションのさまざまな部分に対応するミドルウェア層を構築できます。 +詳しくは、 :ref:`connecting-scoped-middleware` をご覧ください。 + +新しいコンソールランナー +------------------------ + +3.5.0 では ``Cake\Console\CommandRunner`` が追加されました。このクラスは +``Cake\Console\CommandCollection`` とともに、CLI環境と新しい +``Application`` クラスを統合します。 ``Application`` クラスは +``console()`` フックを実装できるようになりました。これは、どのCLIコマンドが +公開されているか、それらがどのように命名されているか、シェルが +どのように依存関係を取得するかを完全に制御できます。この新しいクラスを採用するには +``bin/cake.php`` のファイルの内容を +`こちら `_ の +ファイルに置き換える必要があります。 + + +キャッシュエンジンフォールバック +-------------------------------- + +キャッシュエンジンは、 ``fallback`` キーを用いて定義できるようになりました。 +このキーは処理エンジンが誤って設定されている場合(または使用できない場合)に +フォールバックを使用する構成を定義するものです。 +詳しくは :ref:`cache-configuration-fallback` のフォールバックの設定をご覧ください。 + +アプリケーションのスケルトンに dotenv のサーポートを追加 +-------------------------------------------------------- + +アプリケーションのスケルトンに、「dotenv」の統合機能が追加されました。 +これは、あなたのアプリケーションを環境変数を使用して構成することを容易にします。 +詳しくは :ref:`environment-variables` の章をご覧ください。 + +コンソールの結合テスト +---------------------- + +``Cake\TestSuite\ConsoleIntegrationTestCase`` クラスが追加され、 +コンソールアプリケーションの結合テストがより簡単になりました。 +詳しくは、 :ref:`console-integration-testing` をご覧ください。 +このテストクラスは、現在の ``Cake\Console\ShellDispatcher`` および +新たに追加された ``Cake\Console\CommandRunner`` と完全に互換性があります。 + +コレクション +------------ + +* ``Cake\Collection\Collection::avg()`` が追加されました。 +* ``Cake\Collection\Collection::median()`` が追加されました。 + + +コア +---- + +* ``Cake\Core\Configure::read()`` は、要求されたキーが存在しない場合に用いる + デフォルト値をサポートするようになりました。 +* ``Cake\Core\ObjectRegistry`` に、 ``Countable`` および + ``IteratorAggregate`` インターフェースが実装されました。 + +コンソール +---------- + +* ``Cake\Console\ConsoleOptionParser::setHelpAlias()`` が追加されました。 + このメソッドを使用するすることで、ヘルプ出力を生成するときに使用される + コマンド名を設定できます。デフォルトは ``cake`` です。 +* ``Cake\Console\ShellDispatcher`` の代わりに ``Cake\Console\CommandRunnner`` が + 追加されました。 +* アプリケーションが提供するコマンドラインツールを定義するための + インターフェイスとして ``Cake\Console\CommandCollection`` が追加されました。 + +データベース +------------ + +* SQLiteドライバーに ``mask`` オプションが追加されました。このオプションは + SQLiteデータベースファイルが作成されたときのアクセス権限の設定を可能にします。 + +データソース +------------ + +* ``Cake\Datasource\SchemaInterface`` オプションが追加されました。 +* ``smallinteger`` と ``tinyinteger`` に新しい抽象型が追加されました。 + 既存の ``SMALLINT`` 型と ``TINYINT`` 型がこれらの新しい抽象型として + 反映されるようになりました。 ``TINYINT(1)`` 型は、引き続きMySQLで + boolean型として扱われます。 +* ``Cake\Datasource\PaginatorInterface`` が追加されました。 + ``PaginatorComponent`` は、このインターフェイスを通してページネーションを + 取り扱うようになりました。これにより、他のORMと似た実装で + コンポーネントによってページネーションをできるようになりました。 +* ``Cake\Datasource\Paginator`` は ORM/Database のクエリーインスタンスを + ページ制御するために追加されました。 + +イベント +-------- + +* ``Cake\Event\EventManager::on()`` と ``off()`` はチェーン実装可能になり、 + 複数のイベントを一度に設定することが容易になりました。 + +Http +---- + +* 新たに ``Cookie`` と ``CookieCollection`` クラスが追加されました。 + これらのクラスを使用するとオブジェクト指向でクッキーを扱うことができます。 + また、これらは ``Cake\Http\ServerRequest`` 、 ``Cake\Http\Response`` 、 + ``Cake\Http\Client\Response`` で利用できます。 + 詳しくは、 :ref:`request-cookies` と :ref:`response-cookies` をご覧ください。 +* セキュリティヘッダーの適用が容易になる新しいミドルウエアが追加されました。 + 詳しくは、 :ref:`security-header-middleware` をご覧ください。 +* クッキーデータを透過的に暗号化する新しいミドルウェアが追加されました。 + 詳しくは、 :ref:`encrypted-cookie-middleware` をご覧ください。 +* CSRFに対する保護を容易にする、新しいミドルウェアが追加されました。 + 詳しくは、 :ref:`csrf-middleware` をご覧ください。 +* ``Cake\Http\Client::addCookie()`` が追加されました。 + これはクライアントインスタンスへのクッキー追加を容易にします。 + +インスタンス設定トレイト +------------------------ + +* ``InstanceConfigTrait::getConfig()`` は ``$default`` という + 第二引数を取るようになりました。もし特定の ``key`` に使用できる値がない場合、 + その ``$default`` の値が返却されます。 + +ORM +--- + +* ``Cake\ORM\Query::contain()`` は一つのアソシエーションが入る場合、 + ラッピング配列なしで呼び出すことができるようになり。つまり、 + ``contain('Comments', function (){ ... });`` で動作するようになります。 + この変更で ``leftJoinWith()`` や ``matching()`` のような、他の + イーガーローディング関連のメソッドと ``contain()`` の一貫性を与えています。 + +ルーティング +------------ + +* ``Cake\Routing\Router::reverseToArray()`` が追加されました。 + このメソッドを使用することで、リクエストオブジェクトをURL文字列の生成に + 使用できる配列に変換できます。 +* ``Cake\Routing\RouteBuilder::resources()`` に ``path`` オプションが追加されました。 + このオプションを使用するとコントローラー名に一致しないリソースパスを + 作ることができます。 +* ``Cake\Routing\RouteBuilder`` に、特定のHTTPメソッドのルートを作成するメソッドが + 追加されました。例えば ``get()`` や ``post()`` が追加されています。 +* ``Cake\Routing\RouteBuilder::loadPlugin()`` が追加されました。 +* ``Cake\Routing\Route`` のオプション定義メソッドは + 流れるようなインターフェイスになりました。 + +TestSuite +--------- + +* ``TestCase::loadFixtures()`` は引数が与えられていないとき、 + すべてのフィクスチャーをロードするようになりました。 +* ``IntegrationTestCase::head()`` が追加されました。 +* ``IntegrationTestCase::options()`` が追加されました。 +* ``IntegrationTestCase::disableErrorHandlerMiddleware()`` が追加されました。 + 結合テストのデバッグがより簡単になりました。 + +バリデーション +-------------- + +* ``Cake\Validation\Validator::scalar()`` は、フィールドが非スカラー型データを + 取得しないことを保証するために追加されました。 +* ``Cake\Validation\Validator::regex()`` が追加されました。 + 正規表現パターンでのデータ検証を今までより便利にします。 +* ``Cake\Validation\Validator::addDefaultProvider()`` が追加されました。 + このメソッドでアプリケーションで作成されたすべてのバリデーターに + バリデーションプロバイダーを挿入できます。 +* ``Cake\Validation\ValidatorAwareInterface`` が追加されました。 + これは、 ``Cake\Validation\ValidatorAwareTrait`` によって実装されるメソッドを + 定義します。 + +View +---- + +* ``Cake\View\Helper\PaginatorHelper::limitControl()`` が追加されました。 + このメソッドを使用すると、ページネートされた結果セットのlimit値を + 更新するセレクトボックスのフォームを作ることができます。 diff --git a/ja/controllers/components/cookie.rst b/ja/controllers/components/cookie.rst index a684a52de5..8e51d22b8b 100644 --- a/ja/controllers/components/cookie.rst +++ b/ja/controllers/components/cookie.rst @@ -8,6 +8,10 @@ CookieComponent は PHP に組み込まれている ``setcookie()`` メソッドのラッパーです。 このコンポーネントは、 Cookie の扱いを容易にし、 Cookie のデータを暗号化します。 +.. deprecated:: 3.5.0 + You should use :ref:`encrypted-cookie-middleware` instead of + ``CookieComponent``. + Cookie の設定 ================= diff --git a/ja/controllers/components/csrf.rst b/ja/controllers/components/csrf.rst index 57850c5820..c5489a02cb 100644 --- a/ja/controllers/components/csrf.rst +++ b/ja/controllers/components/csrf.rst @@ -26,6 +26,10 @@ hidden フィールドに CSRF トークンが追加されます。 ``Controller 例外の型が :php:class:`Cake\\Network\\Exception\\ForbiddenException` から :php:class:`Cake\\Network\\Exception\\InvalidCsrfTokenException` に変更されました。 +.. deprecated:: 3.5.0 + You should use :ref:`csrf-middleware` instead of + ``CsrfComponent``. + CsrfComponent を使用する ============================ diff --git a/ja/controllers/middleware.rst b/ja/controllers/middleware.rst index 0733480986..da7f6b09fa 100644 --- a/ja/controllers/middleware.rst +++ b/ja/controllers/middleware.rst @@ -3,12 +3,34 @@ ミドルウェアオブジェクトは、再利用可能で構成可能なリクエスト処理、あるいは レスポンス構築処理の層でアプリケーションを‘ラップ’する機能を提供します。 -ミドルウェアは CakePHP における新しい HTTP スタックの部分で、 PSR-7 のリクエスト -およびレスポンスのインターフェイスを活用しています。 PSR-7 標準の活用によって、 -`Packagist `__ で利用可能な、あらゆる PSR-7 互換の -ミドルウェアを使うことができます。 +視覚的には、アプリケーションは中央で終了し、ミドルウェアはタマネギのように +アプリの周囲を包み込みます。この例では、Routes、Assets、Exception Handling、 +およびCORSヘッダーミドルウェアでラップされたアプリケーションを見て取れます。 -CakePHP はいくつかのミドルウェアを既成で提供します。 +.. image:: /_static/img/middleware-setup.png + +When a request is handled by your application it enters from the outermost +middleware. Each middleware can either delegate the request/response to the next +layer, or return a response. Returning a response prevents lower layers from +ever seeing the request. An example of that is the AssetMiddleware handling +a request for a plugin image during development. + +.. image:: /_static/img/middleware-request.png + +If no middleware take action to handle the request, a controller will be located +and have its action invoked, or an exception will be raised generating an error +page. + +Middleware are part of the new HTTP stack in CakePHP that leverages the PSR-7 +request and response interfaces. Because CakePHP is leveraging the PSR-7 +standard you can use any PSR-7 compatible middleware available on `The Packagist +`__. + +CakePHP にあるミドルウェア +========================== + +CakePHP はWebアプリケーションで一般的なタスクを取り扱うためのいくつかのミドルウェアを +提供します。 * ``Cake\Error\Middleware\ErrorHandlerMiddleware`` はラップされたミドルウェアからくる 例外を捕まえ、 :doc:`/development/errors` の例外ハンドラーを使ってエラーページを描画します。 @@ -19,16 +41,26 @@ CakePHP はいくつかのミドルウェアを既成で提供します。 リクエストにルーティングパラメーターを割り当てるために ``Router`` を使用します。 * ``Cake\I18n\Middleware\LocaleSelectorMiddleware`` はブラウザーによって送られる ``Accept-Language`` ヘッダーによって自動で言語を切り替えられるようにします。 +* ``Cake\Http\Middleware\SecurityHeadersMiddleware`` makes it easy to add + security related headers like ``X-Frame-Options`` to responses. +* ``Cake\Http\Middleware\EncryptedCookieMiddleware`` gives you the ability to + manipulate encrypted cookies in case you need to manipulate cookie with + obfuscated data. +* ``Cake\Http\Middleware\CsrfProtectionMiddleware`` adds CSRF protection to your + application. .. _using-middleware: ミドルウェアの使用 ================== -``App\Application`` クラスの ``middleware`` メソッドの中でミドルウェアを加えることができます。 -もし ``App\Application`` クラスを持っていない場合、詳しくは :ref:`adding-http-stack` -の当該のセクションを参照してください。アプリケーションの ``middleware`` フックメソッドは -リクエスト処理の中で早くに呼ばれて、 ``Middleware`` オブジェクトを加えることができます。 :: +ミドルウェアは、アプリケーションの全体、またはルーティングスコープ個別に適用できます + +すべてのリクエストにミドルウェアを適用するには、 ``App\Application`` クラスの +``middleware`` メソッドを使用します。 ``App\Application`` クラスを持っていなかった場合、 +:ref:`adding-http-stack` の該当のセクションを参照してください。 +アプリケーションの ``middleware`` フックメソッドはリクエスト処理の開始時に +呼ばれて ``MiddlewareQueue`` オブジェクトを加えることができます:: namespace App; @@ -37,11 +69,11 @@ CakePHP はいくつかのミドルウェアを既成で提供します。 class Application extends BaseApplication { - public function middleware($middlewareStack) + public function middleware($middlewareQueue) { // ミドルウェアのキューにエラーハンドラーを結びつけます。 - $middlewareStack->add(new ErrorHandlerMiddleware()); - return $middlewareStack; + $middlewareQueue->add(new ErrorHandlerMiddleware()); + return $middlewareQueue; } } @@ -50,19 +82,19 @@ CakePHP はいくつかのミドルウェアを既成で提供します。 $layer = new \App\Middleware\CustomMiddleware; // 追加されたミドルウェアは行列の末尾になります。 - $middlewareStack->add($layer); + $middlewareQueue->add($layer); // 追加されたミドルウェアは行列の先頭になります。 - $middlewareStack->prepend($layer); + $middlewareQueue->prepend($layer); // 特定の位置に挿入します。もし位置が範囲外の場合、 // 末尾に追加されます。 - $middlewareStack->insertAt(2, $layer); + $middlewareQueue->insertAt(2, $layer); // 別のミドルウェアの前に挿入します。 // もしその名前のクラスが見つからない場合、 // 例外が発生します。 - $middlewareStack->insertBefore( + $middlewareQueue->insertBefore( 'Cake\Error\Middleware\ErrorHandlerMiddleware', $layer ); @@ -70,7 +102,7 @@ CakePHP はいくつかのミドルウェアを既成で提供します。 // 別のミドルウェアの後に挿入します。 // もしその名前のクラスが見つからない場合、 // ミドルウェアは末尾に追加されます。 - $middlewareStack->insertAfter( + $middlewareQueue->insertAfter( 'Cake\Error\Middleware\ErrorHandlerMiddleware', $layer ); @@ -88,8 +120,8 @@ CakePHP はいくつかのミドルウェアを既成で提供します。 EventManager::instance()->on( 'Server.buildMiddleware', - function ($event, $middlewareStack) { - $middlewareStack->add(new ContactPluginMiddleware()); + function ($event, $middlewareQueueStack) { + $middlewareQueueStack->add(new ContactPluginMiddleware()); }); PSR-7 リクエストとレスポンス @@ -238,17 +270,138 @@ PSR-7 リクエストとレスポンス class Application { - public function middleware($middlewareStack) + public function middleware($middlewareQueueStack) { // 単純なミドルウェアをキューに追加します - $middlewareStack->add(new TrackingCookieMiddleware()); + $middlewareQueueStack->add(new TrackingCookieMiddleware()); // もう少しミドルウェアをキューに追加します - return $middlewareStack; + return $middlewareQueueStack; } } +.. _security-header-middleware: + +Adding Security Headers +======================= + +The ``SecurityHeaderMiddleware`` layer makes it easy to apply security related +headers to your application. Once setup the middleware can apply the following +headers to responses: + +* ``X-Content-Type-Options`` +* ``X-Download-Options`` +* ``X-Frame-Options`` +* ``X-Permitted-Cross-Domain-Policies`` +* ``Referrer-Policy`` + +This middleware is configured using a fluent interface before it is applied to +your application's middleware stack:: + + use Cake\Http\Middleware\SecurityHeadersMiddleware; + + $headers = new SecurityHeadersMiddleware(); + $headers + ->setCrossDomainPolicy() + ->setReferrerPolicy() + ->setXFrameOptions() + ->setXssProtection() + ->noOpen() + ->noSniff(); + + $middlewareQueue->add($headers); + +.. versionadded:: 3.5.0 + The ``SecurityHeadersMiddleware`` was added in 3.5.0 + +.. _encrypted-cookie-middleware: + +Encrypted Cookie Middleware +=========================== + +If your application has cookies that contain data you want to obfuscate and +protect against user tampering, you may can use CakePHP's encrypted cookie +middleware to transparently encrypt and decrypt cookie data via middleware. +Cookie data is encrypted with via OpenSSL using AES:: + + use Cake\Http\Middleware\EncryptedCookieMiddleware; + + $cookies = new EncryptedCookieMiddleware( + // Names of cookies to protect + ['secrets', 'protected'], + Configure::read('Security.cookieKey') + ); + + $middlewareQueue->add($cookies); + +.. note:: + It is recommended that the encryption key you use for cookie data, is used + *exclusively* for cookie data. + +The encryption algorithms and padding style used by the cookie middleware are +backwards compatible with ``CookieComponent`` from earlier versions of CakePHP. + +.. versionadded:: 3.5.0 + The ``EncryptedCookieMiddleware`` was added in 3.5.0 + +.. _csrf-middleware: + +Cross Site Request Forgery (CSRF) Middleware +============================================ + +CSRF protection can be applied to your entire application, or to specific scopes +by applying the ``CsrfProtectionMiddleware`` to your middleware stack:: + + use Cake\Http\Middleware\CsrfProtectionMiddleware; + + $options = [ + // ... + ]; + $csrf = new CsrfProtectionMiddleware($options); + + $middlewareQueue->add($csrf); + +Options can be passed into the middleware's constructor. +The available configuration options are: + +- ``cookieName`` The name of the cookie to send. Defaults to ``csrfToken``. +- ``expiry`` How long the CSRF token should last. Defaults to browser session. +- ``secure`` Whether or not the cookie will be set with the Secure flag. That is, + the cookie will only be set on a HTTPS connection and any attempt over normal HTTP + will fail. Defaults to ``false``. +- ``field`` The form field to check. Defaults to ``_csrfToken``. Changing this + will also require configuring FormHelper. + +When enabled, you can access the current CSRF token on the request object:: + + $token = $this->request->getParam('_csrfToken'); + +.. versionadded:: 3.5.0 + The ``CsrfProtectionMiddleware`` was added in 3.5.0 + + +Integration with FormHelper +--------------------------- + +The ``CsrfProtectionMiddleware`` integrates seamlessly with ``FormHelper``. Each +time you create a form with ``FormHelper``, it will insert a hidden field containing +the CSRF token. + +.. note:: + + When using CSRF protection you should always start your forms with the + ``FormHelper``. If you do not, you will need to manually create hidden inputs in + each of your forms. + +CSRF Protection and AJAX Requests +--------------------------------- + +In addition to request data parameters, CSRF tokens can be submitted through +a special ``X-CSRF-Token`` header. Using a header often makes it easier to +integrate a CSRF token with JavaScript heavy applications, or XML/JSON based API +endpoints. + .. _adding-http-stack: 既存アプリケーションへの新しい HTTP スタック追加 diff --git a/ja/controllers/request-response.rst b/ja/controllers/request-response.rst index 0b57e63ea1..d5e8aee6b3 100644 --- a/ja/controllers/request-response.rst +++ b/ja/controllers/request-response.rst @@ -409,8 +409,35 @@ Accept ヘッダーの確認 $acceptsSpanish = $this->request->acceptLanguage('es-es'); +.. _request-cookies: + +Cookies +------- + +Request cookies can be read through a number of methods:: + + // Get the cookie value, or null if the cookie is missing. + $rememberMe = $this->request->getCookie('remember_me'); + + // Read the value, or get the default of 0 + $rememberMe = $this->request->getCookie('remember_me', 0); + + // Get all cookies as an hash + $cookies = $this->request->getCookieParams(); + + // Get a CookieCollection instance (starting with 3.5.0) + $cookies = $this->request->getCookieCollection() + +See the :php:class:`Cake\\Http\\Cookie\\CookieCollection` documentation for how +to work with cookie collection. + +.. versionadded:: 3.5.0 + ``ServerRequest::getCookieCollection()`` was added in 3.5.0 + .. index:: $this->response + + レスポンス ========== @@ -821,6 +848,34 @@ Not-Modified レスポンスの送信 return $this->response; } +.. _response-cookies: + +Setting Cookies +=============== + +Cookies can be added to response using either an array or a :php:class:`Cookie`` +object:: + + // Add a cookie as an array using the immutable API (3.4.0+) + $this->response = $this->response->withCookie('remember_me', [ + 'value' => 'yes', + 'path' => '/', + 'httpOnly' => true, + 'secure' => false, + 'expire' => strtotime('+1 year') + ]); + + // Before 3.4.0 + $this->response->cookie('remember', [ + 'value' => 'yes', + 'path' => '/', + 'httpOnly' => true, + 'secure' => false, + 'expire' => strtotime('+1 year') + ]); + +See the :ref:`creating-cookies` section for how to use the cookie object. + .. _cors-headers: クロスオリジンリクエストヘッダー(CORS)の設定 @@ -866,6 +921,105 @@ CakePHP 3.4.0 以降、レスポンスオブジェクトはレスポンスを不 $this->response = $this->response->withHeader('X-CakePHP', 'yes!'); +.. php:namespace:: Cake\Http\Cookie + +Cookie Collections +================== + +.. php:class:: CookieCollection + +``CookieCollection`` objects are accessible from the request and response objects. +They let you interact with groups of cookies using immutable patterns, which +allow the immutability of the request and response to be preserved. + +.. _creating-cookies: + +Creating Cookies +---------------- + +``Cookie`` objects can be defined through constructor objects, or by using the +fluent interface that follows immutable patterns:: + + use Cake\Http\Cookie\Cookie; + + // All arguments in the constructor + $cookie = new Cookie( + 'remember_me', // name + 1, // value + new DateTime('+1 year'), // expiration time, if applicable + '/', // path, if applicable + 'example.com', // domain, if applicable + false, // secure only? + true // http only ? + ); + + // Using the builder methods + $cookie = (new Cookie('remember_me')) + ->withValue('1') + ->withExpiry(new DateTime('+1 year')) + ->withPath('/') + ->withDomain('example.com') + ->withSecure(false) + ->withHttpOnly(true); + +Once you have created a cookie, you can add it to a new or existing +``CookieCollection``:: + + use Cake\Http\Cookie\CookieCollection; + + // Create a new collection + $cookies = new CookieCollection([$cookie]); + + // Add to an existing collection + $cookies = $cookies->add($cookie); + + // Remove a cookie by name + $cookies = $cookies->remove('remember_me'); + +.. note:: + Remember that collections are immutable and adding cookies into, or removing + cookies from a collection, creates a *new* collection object. + +You should use the ``withCookie()`` method to add cookies to ``Response`` +objects as it is simpler to use:: + + $response = $this->response->withCookie($cookie); + +Cookies set to responses can be encrypted using the +:ref:`encrypted-cookie-middleware`. + +Reading Cookies +--------------- + +Once you have a ``CookieCollection`` instance, you can access the cookies it +contains:: + + // Check if a cookie exists + $cookies->has('remember_me'); + + // Get the number of cookies in the collection + count($cookies); + + // Get a cookie instance + $cookie = $cookies->get('remember_me'); + +Once you have a ``Cookie`` object you can interact with it's state and modify +it. Keep in mind that cookies are immutable, so you'll need to update the +collection if you modify a cookie:: + + // Get the value + $value = $cookie->getValue() + + // Access data inside a JSON value + $id = $cookie->read('User.id'); + + // Check state + $cookie->isHttpOnly(); + $cookie->isSecure(); + +.. versionadded:: 3.5.0 + ``CookieCollection`` and ``Cookie`` were added in 3.5.0. + .. meta:: :title lang=ja: リクエストとレスポンスオブジェクト :keywords lang=ja: request controller,request parameters,array indexes,purpose index,response objects,domain information,request object,request data,interrogating,params,previous versions,introspection,dispatcher,rout,data structures,arrays,ip address,migration,indexes,cakephp,PSR-7,immutable diff --git a/ja/core-libraries/caching.rst b/ja/core-libraries/caching.rst index cc6e251225..08032ffbc4 100644 --- a/ja/core-libraries/caching.rst +++ b/ja/core-libraries/caching.rst @@ -120,6 +120,38 @@ DSN を使用するとき、追加のクエリー文字列要素としてパラ FileEndine 使用時に、正しいパーミッションでのキャッシュファイルを指定して作成するには、 ``mask`` オプションの設定が必要です。 +.. _cache-configuration-fallback: + +Configuring Cache Fallbacks +--------------------------- + +In the event that an engine is not available, such as the ``FileEngine`` trying +to write to an unwritable folder or the ``RedisEngine`` failing to connect to +Redis, the engine will fall back to the noop ``NullEngine`` and trigger a loggable +error. This prevents the application from throwing an uncaught exception due to +cache failure. + +You can configure Cache configurations to fall back to a specified config using +the ``fallback`` configuration key:: + + Cache::config('redis', [ + 'className' => 'Redis', + 'duration' => '+1 hours', + 'prefix' => 'cake_redis_', + 'host' => '127.0.0.1', + 'port' => 6379, + 'fallback' => 'default', + ]); + +If the Redis server unexpectedly failed, writing to the ``redis`` cache +configuration would fall back to writing to the ``default`` cache configuration. +If writing to the ``default`` cache configuration *also* failed in this scenario, the +engine would fall back once again to the ``NullEngine`` and prevent the application +from throwing an uncaught exception. + +.. versionadded:: 3.5.0 + Cache engine fallbacks were added. + 設定されたキャッシュエンジンを削除する -------------------------------------- diff --git a/ja/development/routing.rst b/ja/development/routing.rst index 4514c758a9..526d44fa0f 100644 --- a/ja/development/routing.rst +++ b/ja/development/routing.rst @@ -40,14 +40,22 @@ URL の構造を全部のコードの書き直しをせずにリファクタリ index メソッドを実行します。時々、複数のパラメーターを受け取る動的なルートが 必要になると思います。それが必要になるケースは、例えば、記事の内容を表示するためのルートです。 :: - Router::connect('/articles/*', ['controller' => 'Articles', 'action' => 'view']); + $routes->connect('/articles/*', ['controller' => 'Articles', 'action' => 'view']); 上記のルートは、 ``/articles/15`` のような URL を受け取り、 ``ArticlesController`` の ``view(15)`` メソッドを呼びます。しかし、これは ``/articles/foobar`` のような URL からの アクセスを防ぐわけではありません。もし、あなたが望むなら、いくつかのパラメーターを正規表現に従うように 修正できます。 :: - Router::connect( + $routes->connect( + '/articles/:id', + ['controller' => 'Articles', 'action' => 'view'], + ) + ->setPatterns(['id' => '\d+']) + ->setPass(['id']); + + // Prior to 3.5 use the options array + $routes->connect( '/articles/:id', ['controller' => 'Articles', 'action' => 'view'], ['id' => '\d+', 'pass' => ['id']] @@ -71,14 +79,15 @@ URL 文字列を生成できることを意味します。 :: ルートは一意の名前を付けることもできます。これは、リンクを構築する際に、 ルーティングパラメーターをそれぞれ指定する代わりに、ルートを素早く参照することができます。 :: - use Cake\Routing\Router; - - Router::connect( + // In routes.php + $routes->connect( '/login', ['controller' => 'Users', 'action' => 'login'], ['_name' => 'login'] ); + use Cake\Routing\Router; + echo Router::url(['_name' => 'login']); // 出力結果 /login @@ -106,11 +115,10 @@ URL 文字列を生成できることを意味します。 :: ルートを接続 ============ -.. php:staticmethod:: connect($route, $defaults = [], $options = []) +.. php:method:: connect($route, $defaults = [], $options = []) コードを :term:`DRY` に保つために 'ルーティングスコープ' を使用してください。 ルーティングスコープはコードを DRY に保つためだけではなく、Router の操作を最適化します。 -上記を参照すると、 ``Router::connect()`` をルートを接続するために使えることがわかります。 このメソッドは ``/`` スコープがデフォルトです。スコープを作成しいくつかのルートを 接続するために、 ``scope()`` メソッドを使います。 :: @@ -118,6 +126,7 @@ URL 文字列を生成できることを意味します。 :: use Cake\Routing\Route\DashedRoute; Router::scope('/', function ($routes) { + // Connect the generic fallback routes. $routes->fallbacks(DashedRoute::class); }); @@ -129,7 +138,7 @@ URL 文字列を生成できることを意味します。 :: ルートを定義するための基本のフォーマットは、次の通りです。 :: $routes->connect( - 'URL テンプレート', + 'url/template', ['default' => 'defaultValue'], ['option' => 'matchingRegex'] ); @@ -187,7 +196,7 @@ Router の別の一般的な使い方は、コントローラーの "エイリ '/cooks/:action/*', ['controller' => 'Users'] ); -これは Router に ``/cooks/`` で始まるすべての URL は users コントローラーに送るように +これは Router に ``/cooks/`` で始まるすべての URL は ``UsersController`` に送るように 伝えています。 アクションは ``:action`` パラメーターの値によって呼ばれるかどうか決まります。 :ref:`route-elements` を使って、ユーザーの入力や変数を受け付けるいろいろなルーティングが できます。上記のルーティングの方法は、貧欲なスター (greedy star) を使います。 @@ -198,6 +207,40 @@ URL を生成するときにもルーティングは使われます。もし最 ``['controller' => 'users', 'action' => 'some_action', 5]`` を使って ``/cooks/some_action/5`` と出力します。 +The routes we've connected so far will match any HTTP verb. If you are building +a REST API you'll often want to map HTTP actions to different controller methods. +The ``RouteBuilder`` provides helper methods that make defining routes for +specific HTTP verbs simpler:: + + // Create a route that only responds to GET requests. + $routes->get( + '/cooks/:id', + ['controller' => 'Users', 'action' => 'view'], + 'users:view' + ); + + // Create a route that only responds to PUT requests + $routes->put( + '/cooks/:id', + ['controller' => 'Users', 'action' => 'update'], + 'users:update' + ); + +The above routes map the same URL to different controller actions based on the +HTTP verb used. GET requests will go to the 'view' action, while PUT requests +will go to the 'update' action. There are HTTP helper methods for: + +* GET +* POST +* PUT +* PATCH +* DELETE +* OPTIONS +* HEAD + +All of these methods return the route instance allowing you to leverage the +:ref:`fluent setters ` to further configure your route. + .. _route-elements: ルート要素 @@ -210,6 +253,12 @@ URL のどこに配置すべきなのかを定義することができます。 これは CakePHP にどんな URL が正しいフォーマットなのかを伝えます。 正規表現を使用しなかった場合、 ``/`` 以外の文字はパラメーターの一部として扱われます。 :: + $routes->connect( + '/:controller/:id', + ['action' => 'view'] + )->setPatterns(['id' => '[0-9]+']); + + // Prior to 3.5 use the options array $routes->connect( '/:controller/:id', ['action' => 'view'], @@ -228,11 +277,19 @@ CakePHP は小文字とダッシュによって表された URL を ``:controlle use Cake\Routing\Route\DashedRoute; - $routes->connect( - '/:controller/:id', - ['action' => 'view'], - ['id' => '[0-9]+', 'routeClass' => DashedRoute::class] - ); + // Create a builder with a different route class. + $routes->scope('/', function ($routes) { + $routes->setRouteClass(DashedRoute::class); + $routes->connect('/:controller/:id', ['action' => 'view']) + ->setPatterns(['id' => '[0-9]+']); + + // Prior to 3.5 use options array + $routes->connect( + '/:controller/:id', + ['action' => 'view'], + ['id' => '[0-9]+'] + ); + }); ``DashedRoute`` クラス ``:controller`` を確認し、 ``:plugin`` パラメーターを正しく小文字とダッシュによって表します。 @@ -258,23 +315,23 @@ ApplesController の ``view()`` メソッドを呼びます。 ``view()`` メ もし、大文字小文字を区別しない URL を提供したい場合、正規表現インライン修飾子を使います。 :: + // 3.5以前ではsetPatterns()の代わりにオプション配列を用いていました $routes->connect( '/:userShortcut', ['controller' => 'Teachers', 'action' => 'profile', 1], - ['userShortcut' => '(?i:principal)'] - ); + )->setPatterns(['userShortcut' => '(?i:principal)']); もう一つ例を挙げます。これであなたはルーティングのプロです。 :: + // 3.5以前ではsetPatterns()の代わりにオプション配列を用いていました $routes->connect( '/:controller/:year/:month/:day', - ['action' => 'index'], - [ - 'year' => '[12][0-9]{3}', - 'month' => '0[1-9]|1[012]', - 'day' => '0[1-9]|[12][0-9]|3[01]' - ] - ); + ['action' => 'index'] + )->setPatterns([ + 'year' => '[12][0-9]{3}', + 'month' => '0[1-9]|1[012]', + 'day' => '0[1-9]|[12][0-9]|3[01]' + ]); これは、いっそう複雑になりますが、ルーティングがとても強力になったことを示しています。 この URL は4つのルート要素を持っています。1番目は、なじみがあります。デフォルトのルート要素で @@ -314,6 +371,44 @@ CakePHP には、いくつかの特別な意味を持つルート要素があり * ``_name`` ルートの名前。名前付きルートをセットアップするときに、 それを指定するためのキーとして使えます。 +.. _route-fluent-methods: + +Configuring Route Options +------------------------- + +There are a number of route options that can be set on each route. After +connecting a route you can use its fluent builder methods to further configure +the route. These methods replace many of the keys in the ``$options`` parameter +of ``connect()``:: + + $routes->connect( + '/:lang/articles/:slug', + ['controller' => 'Articles', 'action' => 'view'], + ) + // Allow GET and POST requests. + ->setMethods(['GET', 'POST']) + + // Only match on the blog subdomain. + ->setHost('blog.example.com') + + // Set the route elements that should be converted to passed arguments + ->setPass(['slug']) + + // Set the matching patterns for route elements + ->setPatterns([ + 'slug' => '[a-z0-9-_]+', + 'lang' => 'en|fr|es', + ]) + + // Also allow JSON file extensions + ->setExtenions(['json']) + + // Set lang to be a persistent parameter + ->setPersist(['lang']); + +.. versionadded:: 3.5.0 + Fluent builder methods were added in 3.5.0 + アクションへのパラメーター渡し ------------------------------ @@ -332,15 +427,15 @@ CakePHP には、いくつかの特別な意味を持つルート要素があり $routes->connect( '/blog/:id-:slug', // 例えば /blog/3-CakePHP_Rocks ['controller' => 'Blogs', 'action' => 'view'], - [ - // 関数に引数を渡すためのルーティングテンプレートの中で、ルート要素を定義します。 - // テンプレートの中で、ルート要素を定義します。 - // ":id" をアクション内の $articleId にマップします。 - 'pass' => ['id', 'slug'], - // `id` が一致するパターンを定義します。 - 'id' => '[0-9]+' - ] - ); + ) + // 関数に引数を渡すためのルーティングテンプレートの中で、ルート要素を定義します。 + // テンプレートの中で、ルート要素を定義します。 + // ":id" をアクション内の $articleId にマップします。 + ->setPass(['id', 'slug']) + // `id` が一致するパターンを定義します。 + ->setPatterns([ + 'id' => '[0-9]+', + ]); }); 今、リバースルーティング機能のおかげで、下記のように URL 配列を渡し、 @@ -380,8 +475,16 @@ CakePHP はルートに定義された URL をどのように整えるのかを ['_name' => 'login'] ); + // HTTPメソッドで固有のルートを命名する (3.5.0以降) + $routes->post( + '/logout', + ['controller' => 'Users', 'action' => 'logout'], + 'logout' + ); + + // 名前付きルートで URL の生成 - $url = Router::url(['_name' => 'login']); + $url = Router::url(['_name' => 'logout']); // クエリー文字列引数付きの // 名前付きルートで URL の生成 @@ -401,7 +504,7 @@ CakePHP は、各スコープで名前のプレフィックスを定義するこ Router::scope('/api', ['_namePrefix' => 'api:'], function ($routes) { // このルートの名前は `api:ping` になります。 - $routes->connect('/ping', ['controller' => 'Pings'], ['_name' => 'ping']); + $routes->get('/ping', ['controller' => 'Pings'], 'ping'); }); // ping ルートのための URL を生成 Router::url(['_name' => 'api:ping']); @@ -422,7 +525,7 @@ CakePHP は、各スコープで名前のプレフィックスを定義するこ Router::plugin('Contacts', ['_namePrefix' => 'contacts:'], function ($routes) { $routes->scope('/api', ['_namePrefix' => 'api:'], function ($routes) { // このルートの名前は `contacts:api:ping` になります。 - $routes->connect('/ping', ['controller' => 'Pings'], ['_name' => 'ping']); + $routes->get('/ping', ['controller' => 'Pings'], 'ping'); }); }); @@ -598,18 +701,35 @@ SEO に親和性があるルーティング 指定した HTTP メソッドとの照合 ------------------------------ -ルートは、 ``_method`` ルーティングキーを使用して指定した HTTP メソッドとマッチできます。 :: +ルートは、HTTP動詞へルパーを使用して指定した HTTP メソッドとマッチできます。 :: Router::scope('/', function($routes) { // このルートは POST リクエスト上でのみマッチします。 - $routes->connect( + $routes->post( '/reviews/start', - ['controller' => 'Reviews', 'action' => 'start', '_method' => 'POST'] + ['controller' => 'Reviews', 'action' => 'start'] ); + + // 複数HTTPメソッドとマッチさせる + // 3.5以前では $options['_method'] をメソッドにセットして使用します。 + $routes->connect( + '/reviews/start', + [ + 'controller' => 'Reviews', + 'action' => 'start', + ] + )->setMethods(['POST', 'PUT']); }); 配列を使うことで複数の HTTP メソッドとマッチできます。 ``_method`` パラメーターは ルーティングキーなので、 URL の解析と URL の生成の両方に使われます。 +メソッド固有のルートのURLを生成するには、URLを生成する際に ``_method`` キーを含む必要があります。:: + + $url = Router::url([ + 'controller' => 'Reviews', + 'action' => 'start', + '_method' => 'POST', + ]); 指定したホスト名との照合 ------------------------ @@ -619,18 +739,17 @@ SEO に親和性があるルーティング Router::scope('/', function($routes) { // このルートは http://images.example.com のみマッチします。 + // 3.5以前では_hostオプションを使用します。 $routes->connect( '/images/default-logo.png', - ['controller' => 'Images', 'action' => 'default'], - ['_host' => 'images.example.com'] - ); + ['controller' => 'Images', 'action' => 'default'] + )->setHost('images.example.com'); // このルートは http://*.example.com のみマッチします。 $routes->connect( '/images/old-log.png', - ['controller' => 'Images', 'action' => 'oldLogo'], - ['_host' => '*.example.com'] - ); + ['controller' => 'Images', 'action' => 'oldLogo'] + )->setHost('images.example.com'); }); ``_host`` オプションは URL 生成でも使用されます。 ``_host`` オプションで正確なドメインを @@ -640,15 +759,14 @@ SEO に親和性があるルーティング // このルートを持つ場合、 $routes->connect( '/images/old-log.png', - ['controller' => 'Images', 'action' => 'oldLogo'], - ['_host' => '*.example.com'] - ); + ['controller' => 'Images', 'action' => 'oldLogo'] + )->setHost('images.example.com'); // url を生成するために指定が必要です。 echo Router::url([ 'controller' => 'Images', 'action' => 'oldLogo', - '_host' => 'images.example.com' + '_host' => 'images.example.com', ]); .. versionadded:: 3.4.0 @@ -671,15 +789,15 @@ SEO に親和性があるルーティング これは、スコープに関係なく、 **以後に** 接続された **全て** のルートに影響します。 -拡張子を特定のスコープに制限するために、 :php:meth:`Cake\\Routing\\RouteBuilder::extensions()` +拡張子を特定のスコープに制限するために、 :php:meth:`Cake\\Routing\\RouteBuilder::setExtensions()` メソッドを使用して定義することができます。 :: Router::scope('/', function ($routes) { - $routes->extensions(['json', 'xml']); - // ... + // 3.5.0 以前では `extensions()` を使用します。 + $routes->setExtensions(['json', 'xml']); }); -これは、 ``extensions()`` が呼ばれた **後の** スコープの中で接続されている +これは、 ``setExtensions()`` が呼ばれた **後の** スコープの中で接続されている 全てのルートのために名前付き拡張子を有効にします。それは、ネストされたスコープの中で 接続されているルートも含まれます。グローバルの :php:meth:`Router::extensions()` メソッドと 同様に、呼び出し前に接続されたルートは、拡張子を継承しません。 @@ -697,14 +815,11 @@ SEO に親和性があるルーティング 以下を使ってルートを設定します。 :: Router::scope('/page', function ($routes) { - $routes->extensions(['json', 'xml', 'html']); + $routes->setExtensions(['json', 'xml', 'html']); $routes->connect( '/:title', - ['controller' => 'Pages', 'action' => 'view'], - [ - 'pass' => ['title'] - ] - ); + ['controller' => 'Pages', 'action' => 'view'] + )->setPass(['title']); }); そして、ルートに対応するリンクを生成するために、以下のようにします。 :: @@ -717,6 +832,82 @@ SEO に親和性があるルーティング 拡張子が :doc:`/controllers/components/request-handling` で使われ、それによって コンテンツタイプに合わせた自動的なビューの切り替えを行います。 +.. _connecting-scoped-middleware: + +Connecting Scoped Middleware +---------------------------- + +While Middleware can be applied to your entire application, applying middleware +to specific routing scopes offers more flexibility, as you can apply middleware +only where it is needed allowing your middleware to not concern itself with +how/where it is being applied. + +Before middleware can be applied to a scope, it needs to be +registered into the route collection:: + + // in config/routes.php + use Cake\Http\Middleware\CsrfProtectionMiddleware; + use Cake\Http\Middleware\EncryptedCookieMiddleware; + + Router::scope('/', function ($routes) { + $routes->registerMiddleware('csrf', new CsrfProtectionMiddleware()); + $routes->registerMiddleware('cookies', new EncryptedCookiesMiddleware()); + }); + +Once registered, scoped middleware can be applied to specific +scopes:: + + $routes->scope('/cms', function ($routes) { + // Enable CSRF & cookies middleware + $routes->applyMiddleware('csrf', 'cookies'); + $routes->get('/articles/:action/*', ['controller' => 'Articles']) + }); + +In situations where you have nested scopes, inner scopes will inherit the +middleware applied in the containing scope:: + + $routes->scope('/api', function ($routes) { + $routes->applyMiddleware('ratelimit', 'auth.api'); + $routes->scope('/v1', function ($routes) { + $routes->applyMiddleware('v1compat'); + // Define routes here. + }); + }); + +In the above example, the routes defined in ``/v1`` will have 'ratelimit', +'auth.api', and 'v1compat' middleware applied. If you re-open a scope, the +middleware applied to routes in each scope will be isolated:: + + $routes->scope('/blog', function ($routes) { + $routes->applyMiddleware('auth'); + // Connect the authenticated actions for the blog here. + }); + $routes->scope('/blog', function ($routes) { + // Connect the public actions for the blog here. + }); + +In the above example, the two uses of the ``/blog`` scope do not share +middleware. However, both of these scopes will inherit middleware defined in +their enclosing scopes. + +Grouping Middleware +------------------- + +To help keep your route code :abbr:`DRY (Do not Repeat Yourself)` middleware can +be combined into groups. Once combined groups can be applied like middleware +can:: + + $routes->registerMiddleware('cookie', new EncryptedCookieMiddleware()); + $routes->registerMiddleware('auth', new AuthenticationMiddleware()); + $routes->registerMiddleware('csrf', new CsrfProtectionMiddleware()); + $routes->middlewareGroup('web', ['cookie', 'auth', 'csrf']); + + // Apply the group + $routes->applyMiddleware('web'); + +.. versionadded:: 3.5.0 + Scoped middleware & middleware groups were added in 3.5.0 + .. _resource-routes: RESTful なルートの作成 @@ -729,7 +920,7 @@ recipe コントローラーに REST アクセスできるようにしたい場 // config/routes.php 内で... Router::scope('/', function ($routes) { - $routes->extensions(['json']); + $routes->setExtensions(['json']); $routes->resources('Recipes'); }); @@ -1011,6 +1202,7 @@ URL を生成するときに、特別なルート要素が使用できます。 現在のスキーマにデフォルト設定されています。 * ``_host`` リンクのためのホストを設定します。デフォルトは、現在のホストです。 * ``_port`` 非標準なポートのリンクを作成するときにポートを設定します。 +* ``_method`` URLが存在するHTTPメソッドを定義します。 * ``_full`` ``true`` にすると、 ``FULL_BASE_URL`` 定数 が 生成された URL の前に加えられます。 * ``_ssl`` ``true`` にすると普通の URL から https に変換します。 @@ -1078,6 +1270,16 @@ URL を文字列で生成します。URL パラメーターがルートに一致 ['routeClass' => 'SlugRoute'] ); + // また、あなたのスコープ内にrouteClassを設定することもできます。 + $routes->scope('/', function ($routes) { + // 3.5.0 以前では `routeClass()` を使用します。 + $routes->setRouteClass('SlugRoute'); + $routes->connect( + '/:slug', + ['controller' => 'Articles', 'action' => 'view'] + ); + }); + このルートは ``SlugRoute`` のインスタンスを生成し、カスタムパラメーター処理を実装することができます。 標準的な :term:`プラグイン記法` を使ってプラグインルートクラスを使用できます。 diff --git a/ja/development/testing.rst b/ja/development/testing.rst index b5385fbc48..42fdfe854f 100644 --- a/ja/development/testing.rst +++ b/ja/development/testing.rst @@ -883,12 +883,17 @@ CakePHP は特殊な ``IntegrationTestCase`` クラスを提供しています * ``put()`` PUT リクエストを送信します。 * ``delete()`` DELETE リクエストを送信します。 * ``patch()`` PATCH リクエストを送信します。 +* ``options()`` OPTIONS リクエストを送信します。 +* ``head()`` HEAD リクエストを送信します。 ``get()`` と ``delete()`` を除く全てのメソッドは、あなたがリクエストボディーを送信することを 可能にする二番目のパラメーターを受け入れます。リクエストをディスパッチした後、あなたのリクエストに対して 正しく動作したことを確実にするために ``IntegrationTestCase`` や、PHPUnit が提供するさまざまな アサーションを使用することができます。 +.. versionadded:: 3.5.0 + ``options()`` と ``head()`` は 3.5.0 で追加されました。 + リクエストの設定 ---------------- @@ -1131,6 +1136,26 @@ JSON を返すコントローラーの簡単な例を示します。 :: CakePHP の組込み JsonView で、 ``debug`` が有効になっている場合、 ``JSON_PRETTY_PRINT`` オプションを使用します。 +Disabling Error Handling Middleware in Tests +-------------------------------------------- + +When debugging tests that are failing because your application is encountering +errors it can be helpful to temporarily disable the error handling middleware to +allow the underlying error to bubble up. You can use +``disableErrorHandlerMiddleware()`` to do this:: + + public function testGetMissing() + { + $this->disableErrorHandlerMiddleware(); + $this->get('/markers/not-there'); + $this->assertResponseCode(404); + } + +In the above example, the test would fail and the underlying exception message +and stack trace would be displayed instead of the rendered error page being +checked. + +.. versionadded:: 3.5.0 アサーションメソッド -------------------- @@ -1257,6 +1282,286 @@ CakePHP の組込み JsonView で、 ``debug`` が有効になっている場合 # # modified: tests/comparisons/example.php +.. _console-integration-testing: + +Console Integration Testing +=========================== + +To make testing console applications easier, CakePHP comes with a +``ConsoleIntegrationTestCase`` class that can be used to test console applications +and assert against their results. + +.. versionadded:: 3.5.0 + + The ``ConsoleIntegrationTestCase`` was added. + +To get started testing your console application, create a test case that extends +``Cake\TestSuite\ConsoleIntegrationTestCase``. This class contains a method +``exec()`` that is used to execute your command. You can pass the same string +you would use in the CLI to this method. + +Let's start with a very simple shell, located in **src/Shell/MyConsoleShell.php**:: + + namespace App\Shell; + + use Cake\Console\ConsoleOptionParser; + use Cake\Console\Shell; + + class MyConsoleShell extends Shell + { + public function getOptionParser() + { + $parser = new ConsoleOptionParser(); + $parser->setDescription('My cool console app'); + + return $parser; + } + } + +To write an integration test for this shell, we would create a test case in +**tests/TestCase/Shell/MyConsoleShellTest.php** that extends +``Cake\TestSuite\ConsoleIntegrationTestCase``. This shell doesn't do much at the +moment, but let's just test that our shell's description is displayed in ``stdout``:: + + namespace App\Test\TestCase\Shell; + + use Cake\TestSuite\ConsoleIntegrationTestCase; + + class MyConsoleShellTest extends ConsoleIntegrationTestCase + { + public function testDescriptionOutput() + { + $this->exec('my_console'); + $this->assertOutputContains('My cool console app'); + } + } + +Our test passes! While this is very trivial example, it shows that creating an +integration test case for console applications is quite easy. Let's continue by +adding some subcommands and options to our shell:: + + namespace App\Shell; + + use Cake\Console\ConsoleOptionParser; + use Cake\I18n\FrozenTime; + + class MyConsoleShell extends Shell + { + public function getOptionParser() + { + $parser = new ConsoleOptionParser(); + + $updateModifiedParser = new ConsoleOptionParser(); + $updateModifiedParser->addArgument('table', [ + 'help' => 'Table to update', + 'required' => true + ]); + + $parser + ->setDescription('My cool console app') + ->addSubcommand('updateModified', [ + 'parser' => $updateModifiedParser + ]); + + return $parser; + } + + public function updateModified() + { + $table = $this->args[0]; + $this->loadModel($table); + $this->{$table}->query() + ->update() + ->set([ + 'modified' => new FrozenTime() + ]) + ->execute(); + } + } + +This is a more complete shell that has a subcommand with its own parser. Let's +test the ``updateModified`` subcommand. Modify your test case to the following +snippet of code:: + + namespace Cake\Test\TestCase\Shell; + + use Cake\Console\Shell; + use Cake\I18n\FrozenTime; + use Cake\ORM\TableRegistry; + use Cake\TestSuite\ConsoleIntegrationTestCase; + + class MyConsoleShellTest extends ConsoleIntegrationTestCase + { + + public $fixtures = [ + // assumes you have a UsersFixture + 'app.users' + ]; + + public function testDescriptionOutput() + { + $this->exec('my_console'); + $this->assertOutputContains('My cool console app'); + } + + public function testUpdateModified() + { + $now = new FrozenTime('2017-01-01 00:00:00'); + FrozenTime::setTestNow($now); + + $this->loadFixtures('Users'); + + $this->exec('my_console update_modified Users'); + $this->assertExitCode(Shell::CODE_SUCCESS); + + $user = TableRegistry::get('Users')->get(1); + $this->assertSame($user->modified->timestamp, $now->timestamp); + + FrozenTime::setTestNow(null); + } + } + +As you can see from the ``testUpdateModified`` method, we are testing that our +``update_modified`` subcommand updates the table that we are passing as the first +argument. First, we assert that the shell exited with the proper status code, +``0``. Then we check that our subcommand did its work, that is, updated the +table we provided and set the ``modified`` column to the current time. + +Remember, ``exec()`` will take the same string you type into your CLI, so you +can include options and arguments in your command string. + +Testing Interactive Shells +-------------------------- + +Consoles are often interactive. Testing interactive shells with the +``Cake\TestSuite\ConsoleIntegrationTestCase`` class only requires passing the +inputs you expect as the second parameter of ``exec()``. They should be +included as an array in the order that you expect them. + +Continuing with our example shell, let's add an interactive subcommand. Update +the shell class to the following:: + + namespace App\Shell; + + use Cake\Console\ConsoleOptionParser; + use Cake\Console\Shell; + use Cake\I18n\FrozenTime; + + class MyConsoleShell extends Shell + { + public function getOptionParser() + { + $parser = new ConsoleOptionParser(); + + $updateModifiedParser = new ConsoleOptionParser(); + $updateModifiedParser->addArgument('table', [ + 'help' => 'Table to update', + 'required' => true + ]); + + $parser + ->setDescription('My cool console app') + ->addSubcommand('updateModified', [ + 'parser' => $updateModifiedParser + ]) + // add a new subcommand + ->addSubcommand('bestFramework'); + + return $parser; + } + + public function updateModified() + { + $table = $this->args[0]; + $this->loadModel($table); + $this->{$table}->query() + ->update() + ->set([ + 'modified' => new FrozenTime() + ]) + ->execute(); + } + + // create this interactive subcommand + public function bestFramework() + { + $this->out('Hi there!'); + + $framework = $this->in('What is the best PHP framework?'); + if ($framework !== 'CakePHP') { + $this->err("I disagree that '$framework' is the best."); + $this->_stop(Shell::CODE_ERROR); + } + + $this->out('I agree!'); + } + } + +Now that we have an interactive subcommand, we can add a test case that tests +that we receive the proper response, and one that tests that we receive an +incorrect response. Add the following methods to +**tests/TestCase/Shell/MyConsoleShellTest.php**:: + + public function testBestFramework() + { + $this->exec('my_console best_framework', [ + 'CakePHP' + ]); + $this->assertExitCode(Shell::CODE_SUCCESS); + $this->assertOutputContains('I agree!'); + } + + public function testBestFrameworkWrongAnswer() + { + $this->exec('my_console best_framework', [ + 'my homemade framework' + ]); + $this->assertExitCode(Shell::CODE_ERROR); + $this->assertErrorRegExp("/I disagree that \'(.+)\' is the best\./"); + } + +As you can see from the ``testBestFramework``, it responds to the first input +request with "CakePHP". Since this is the correct answer according to our +subcommand, the shell will exit successfully after outputting a response. + +The second test case, ``testBestFrameworkWrongAnswer``, provides an incorrect +answer which causes our shell to fail and exit with ``1``. We also assert +that ``stderr`` was given our error, which includes the name of the incorrect +answer. + +Testing the CommandRunner +------------------------- + +To test shells that are dispatched using the ``CommandRunner`` class, enable it +in your test case with the following method:: + + $this->useCommandRunner(); + +.. versionadded:: 3.5.0 + + The ``CommandRunner`` class was added. + +Assertion methods +----------------- + +The ``Cake\TestSuite\ConsoleIntegrationTestCase`` class provides a number of +assertion methods that make it easy to assert against console output:: + + // assert that the shell exited with the expected code + $this->assertExitCode($expected); + + // assert that stdout contains a string + $this->assertOutputContains($expected); + + // assert that stderr contains a string + $this->assertErrorContains($expected); + + // assert that stdout matches a regular expression + $this->assertOutputRegExp($expected); + + // assert that stderr matches a regular expression + $this->assertErrorRegExp($expected); + ビューのテスト ==============