# Table of Contents - [Welcome | CakePHP](#welcome-cakephp) - [Not Found | CakePHP](#not-found-cakephp) - [ページが見つかりません。 | CakePHP](#-cakephp) - [Appendices | CakePHP](#appendices-cakephp) - [付録 | CakePHP](#-cakephp) - [Url | CakePHP](#url-cakephp) - [Tutorials & Examples | CakePHP](#tutorials-examples-cakephp) - [Using CakePHP | CakePHP](#using-cakephp-cakephp) - [Bookmarker Tutorial | CakePHP](#bookmarker-tutorial-cakephp) - [Bookmarker Tutorial Part 2 | CakePHP](#bookmarker-tutorial-part-2-cakephp) - [Phinx Migrations | CakePHP](#phinx-migrations-cakephp) - [Content Management Tutorial | CakePHP](#content-management-tutorial-cakephp) - [CMS Tutorial - Tags and Users | CakePHP](#cms-tutorial-tags-and-users-cakephp) - [Blog Tutorial - Authentication and Authorization | CakePHP](#blog-tutorial-authentication-and-authorization-cakephp) - [Form | CakePHP](#form-cakephp) - [Upgrade Tool | CakePHP](#upgrade-tool-cakephp) - [Flash | CakePHP](#flash-cakephp) - [CMS Tutorial - Authentication | CakePHP](#cms-tutorial-authentication-cakephp) - [ビューセル | CakePHP](#-cakephp) - [Security | CakePHP](#security-cakephp) - [Views | CakePHP](#views-cakephp) - [Blog Tutorial - Part 2 | CakePHP](#blog-tutorial-part-2-cakephp) - [チュートリアルと例 | CakePHP](#-cakephp) - [Bake コンソール - 2.x](#bake-2-x) - [Bake でコード生成 - 2.x](#bake-2-x) - [Chronos - 2.x](#chronos-2-x) - [ElasticSearch - 3.x](#elasticsearch-3-x) - [Chronos - 1.x](#chronos-1-x) - [ElasticSearch - 2.x](#elasticsearch-2-x) - [Bake コンソール - 1.x](#bake-1-x) - [Migrations - 3.x](#migrations-3-x) - [Migrations - 2.x](#migrations-2-x) - [Debug Kit - 3.x](#debug-kit-3-x) - [ビュー | CakePHP](#-cakephp) - [コンテンツ管理チュートリアル | CakePHP](#-cakephp) - [クイック スタート - 3.x](#-3-x) - [Quick Start - 3.x](#quick-start-3-x) - [アップグレードツール | CakePHP](#-cakephp) - [セキュリティ | CakePHP](#-cakephp) - [CMS チュートリアル - 認証 | CakePHP](#cms-cakephp) - [Flash | CakePHP](#flash-cakephp) - [Themes | CakePHP](#themes-cakephp) - [データの検証 | CakePHP](#-cakephp) - [プラグイン | CakePHP](#-cakephp) - [JSON and XML views | CakePHP](#json-and-xml-views-cakephp) - [View Cells | CakePHP](#view-cells-cakephp) - [CMS Tutorial - Creating the Database | CakePHP](#cms-tutorial-creating-the-database-cakephp) - [Time | CakePHP](#time-cakephp) - [Helpers | CakePHP](#helpers-cakephp) - [Session | CakePHP](#session-cakephp) - [Rss | CakePHP](#rss-cakephp) - [Plugins | CakePHP](#plugins-cakephp) - [Number | CakePHP](#number-cakephp) - [Text | CakePHP](#text-cakephp) - [CMS Tutorial - Creating the Articles Controller | CakePHP](#cms-tutorial-creating-the-articles-controller-cakephp) - [Breadcrumbs | CakePHP](#breadcrumbs-cakephp) - [Blog Tutorial | CakePHP](#blog-tutorial-cakephp) - [Paginator | CakePHP](#paginator-cakephp) - [ヘルパー | CakePHP](#-cakephp) - [Blog Tutorial - Part 3 | CakePHP](#blog-tutorial-part-3-cakephp) - [Html | CakePHP](#html-cakephp) - [クイックスタートガイド | CakePHP](#-cakephp) - [Quick Start Guide | CakePHP](#quick-start-guide-cakephp) - [Form | CakePHP](#form-cakephp) - [CakePHP 6 (dev) Documentation - Build Better Web Applications Faster | CakePHP](#cakephp-6-dev-documentation-build-better-web-applications-faster-cakephp) - [Welcome | CakePHP](#welcome-cakephp) - [Welcome | CakePHP](#welcome-cakephp) - [Url | CakePHP](#url-cakephp) - [CakePHP の利用 | CakePHP](#cakephp-cakephp) - [ブックマークチュートリアル | CakePHP](#-cakephp) - [ブックマークチュートリアル パート2 | CakePHP](#-2-cakephp) - [Phinx マイグレーション | CakePHP](#phinx-cakephp) - [CMS チュートリアル - タグとユーザー | CakePHP](#cms-cakephp) - [シンプルな認証と認可のアプリケーション | CakePHP](#-cakephp) - [ブログチュートリアル - パート2 | CakePHP](#-2-cakephp) - [CMS チュートリアル - データベース作成 | CakePHP](#cms-cakephp) - [ - 2.x](#-no-title-2-x) - [CMS チュートリアル - Articles コントローラーの作成 | CakePHP](#cms-articles-cakephp) - [Bake の拡張 - 2.x](#bake-2-x) - [ - 2.x](#-no-title-2-x) - [Contents - 3.x](#contents-3-x) - [ - 1.x](#-no-title-1-x) - [ - 1.x](#-no-title-1-x) - [ - 3.x](#-no-title-3-x) - [Contents - 2.x](#contents-2-x) - [ - 2.x](#-no-title-2-x) - [Bake でコード生成 - 1.x](#bake-1-x) - [Contents - 3.x](#contents-3-x) - [ - 3.x](#-no-title-3-x) - [Contents - 3.x](#contents-3-x) - [JSON と XML ビュー | CakePHP](#json-xml-cakephp) - [Debug Kit - 4.x](#debug-kit-4-x) - [Bake の拡張 - 1.x](#bake-1-x) - [ポリシーリゾルバー - 3.x](#-3-x) - [Policies - 3.x](#policies-3-x) - [AuthorizationComponent - 3.x](#authorizationcomponent-3-x) - [認可の確認 - 3.x](#-3-x) - [認証機能 - 3.x](#-3-x) - [リクエスト認証ミドルウェア - 3.x](#-3-x) - [2.0 Migration Guide - 3.x](#2-0-migration-guide-3-x) - [認可ミドルウェア - 3.x](#-3-x) - [Identifiers - 3.x](#identifiers-3-x) - [Identity Objects - 3.x](#identity-objects-3-x) - [認証 Component - 3.x](#-component-3-x) - [Password Hashers - 3.x](#password-hashers-3-x) - [URL チェッカー - 3.x](#url-3-x) - [認証コンポーネントから移行 - 3.x](#-3-x) - [View Helper - 3.x](#view-helper-3-x) - [認証によるテスト - 3.x](#-3-x) - [クイック スタート - 2.x](#-2-x) - [Middleware - 3.x](#middleware-3-x) - [Quick Start - 2.x](#quick-start-2-x) - [ - 4.x](#-no-title-4-x) - [Form Protection Component | CakePHP](#form-protection-component-cakephp) - [Timestamp | CakePHP](#timestamp-cakephp) - [CounterCache | CakePHP](#countercache-cakephp) - [App Class | CakePHP](#app-class-cakephp) - [Registry Objects | CakePHP](#registry-objects-cakephp) - [Security Utility | CakePHP](#security-utility-cakephp) - [Plugin Class | CakePHP](#plugin-class-cakephp) - [Constants & Functions | CakePHP](#constants-functions-cakephp) - [Flash | CakePHP](#flash-cakephp) - [Inflector | CakePHP](#inflector-cakephp) - [Cache Tool | CakePHP](#cache-tool-cakephp) - [Request Handling | CakePHP](#request-handling-cakephp) - [FlashHelper | CakePHP](#flashhelper-cakephp) - [TextHelper | CakePHP](#texthelper-cakephp) - [HtmlHelper | CakePHP](#htmlhelper-cakephp) - [Sessions | CakePHP](#sessions-cakephp) - [SessionHelper | CakePHP](#sessionhelper-cakephp) - [Filesystem | CakePHP](#filesystem-cakephp) - [Tree | CakePHP](#tree-cakephp) - [Xml | CakePHP](#xml-cakephp) - [Running Shells as Cron Jobs | CakePHP](#running-shells-as-cron-jobs-cakephp) - [Security | CakePHP](#security-cakephp) - [TimeHelper | CakePHP](#timehelper-cakephp) - [Console Commands | CakePHP](#console-commands-cakephp) - [I18N Tool | CakePHP](#i18n-tool-cakephp) - [Server Tool | CakePHP](#server-tool-cakephp) - [Schema Cache Tool | CakePHP](#schema-cache-tool-cakephp) - [Data Sanitization | CakePHP](#data-sanitization-cakephp) - [CakeNumber | CakePHP](#cakenumber-cakephp) - [Inflector | CakePHP](#inflector-cakephp) - [Deleting Data | CakePHP](#deleting-data-cakephp) - [Timestamp | CakePHP](#timestamp-cakephp) - [Logging | CakePHP](#logging-cakephp) - [Text | CakePHP](#text-cakephp) - [Translate | CakePHP](#translate-cakephp) - [Checking HTTP Cache | CakePHP](#checking-http-cache-cakephp) - [Command Input/Output | CakePHP](#command-input-output-cakephp) - [Pagination | CakePHP](#pagination-cakephp) - [Folder & File | CakePHP](#folder-file-cakephp) - [App Class | CakePHP](#app-class-cakephp) - [CounterCache | CakePHP](#countercache-cakephp) - [Schema System | CakePHP](#schema-system-cakephp) - [Flash | CakePHP](#flash-cakephp) - [Security | CakePHP](#security-cakephp) - [Date & Time | CakePHP](#date-time-cakephp) - [Http Client | CakePHP](#http-client-cakephp) - [RssHelper | CakePHP](#rsshelper-cakephp) - [CakeTime | CakePHP](#caketime-cakephp) - [Code Generation with Bake | CakePHP](#code-generation-with-bake-cakephp) - [Test shell | CakePHP](#test-shell-cakephp) - [Development | CakePHP](#development-cakephp) - [PaginatorHelper | CakePHP](#paginatorhelper-cakephp) - [Events System | CakePHP](#events-system-cakephp) - [Mailer | CakePHP](#mailer-cakephp) - [Security | CakePHP](#security-cakephp) - [ACL Shell | CakePHP](#acl-shell-cakephp) - [Upgrade shell | CakePHP](#upgrade-shell-cakephp) - [Completion Shell | CakePHP](#completion-shell-cakephp) - [HttpSocket | CakePHP](#httpsocket-cakephp) - [App Class | CakePHP](#app-class-cakephp) - [Content Security Policy Middleware | CakePHP](#content-security-policy-middleware-cakephp) - [NumberHelper | CakePHP](#numberhelper-cakephp) - [Components | CakePHP](#components-cakephp) - [REST | CakePHP](#rest-cakephp) - [Validation | CakePHP](#validation-cakephp) - [Internationalization & Localization | CakePHP](#internationalization-localization-cakephp) - [Command Objects | CakePHP](#command-objects-cakephp) - [Sessions | CakePHP](#sessions-cakephp) - [Configuration | CakePHP](#configuration-cakephp) --- # Welcome | CakePHP [Skip to content](https://book.cakephp.org/3.x#VPContent) On this page Welcome [​](https://book.cakephp.org/3.x#welcome) ================================================== Unsupported Version You are viewing documentation for an **unsupported version** of CakePHP. For the most recent stable version, please visit the [official documentation](https://book.cakephp.org/) . CakePHP 3 is a web development framework running on PHP **7.4** (min. PHP _5.6_). Read [CakePHP at a Glance](https://book.cakephp.org/intro.html) to get an introduction to the fundamentals of CakePHP 3. The CakePHP cookbook is an openly developed and community editable documentation project. Notice the pencil icon button fixated against the right wall; it will direct you to the GitHub online editor of the active page, allowing you to contribute any additions, deletions, or corrections to the documentation. **Read the Book Anywhere** ![image](https://book.cakephp.org/3.x/read-the-book.jpg) Enjoy the CakePHP cookbook almost anywhere. Available as both a PDF and EPUB, you can now read it on more devices, as well as offline. * [PDF](https://book.cakephp.org/_downloads/en/CakePHPBook.pdf) * [EPUB](https://book.cakephp.org/_downloads/en/CakePHP.epub) * [Original Source](https://github.com/cakephp/docs) Getting Help [​](https://book.cakephp.org/3.x#getting-help) ------------------------------------------------------------ If you're stuck, there are a number of places [you can get help](https://book.cakephp.org/intro/where-to-get-help.html) . First Steps [​](https://book.cakephp.org/3.x#first-steps) ---------------------------------------------------------- Learning a new framework can be intimidating and exciting at the same time. To help you along, we have created a cookbook packed with examples and recipes to get the common tasks completed. If you are new, you should start off with the [Quick Start Guide](https://book.cakephp.org/quickstart.html) as it will give you a quick tour of what CakePHP has to offer and how it works. After you've finished the Quickstart tutorial, you can brush up on the key elements in a CakePHP application: * The [CakePHP request cycle](https://book.cakephp.org/intro.html#request-cycle) * The [conventions](https://book.cakephp.org/intro/conventions.html) that CakePHP uses. * [Controllers](https://book.cakephp.org/controllers.html) handle requests and co-ordinate your models and the responses your application creates. * [Views](https://book.cakephp.org/views.html) are the presentation layer in your application. They give you powerful tools to create HTML, JSON and the other outputs your application needs. * [Models](https://book.cakephp.org/orm.html) are the key ingredient in any application. They handle validation, and domain logic within your application. --- # Not Found | CakePHP [Skip to content](https://book.cakephp.org/3.x/404.html#VPContent) Return to top orphan True Not Found [​](https://book.cakephp.org/3.x/404.html#not-found) =============================================================== The page you're looking for cannot be found. Try using the search bar to find what you're looking for. --- # ページが見つかりません。 | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/404.html#VPContent) Return to top orphan True ページが見つかりません。 [​](https://book.cakephp.org/3.x/ja/404.html#%E3%83%98%E3%82%9A%E3%83%BC%E3%82%B7%E3%82%99%E3%81%8B%E3%82%99%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82) =================================================================================================================================================================================================== お探しのページが見つかりません。お探しのページを見つけるために検索バーをお試しください。 --- # Appendices | CakePHP [Skip to content](https://book.cakephp.org/3.x/appendices.html#VPContent) On this page Appendices [​](https://book.cakephp.org/3.x/appendices.html#appendices) ======================================================================== Appendices contain information regarding the new features introduced in each version and the migration path between versions. 3.x Migration Guide [​](https://book.cakephp.org/3.x/appendices.html#_3-x-migration-guide) ------------------------------------------------------------------------------------------- * [3.x Migration Guide](https://book.cakephp.org/3.x/appendices/3-x-migration-guide.html) Forwards Compatibility Shimming [​](https://book.cakephp.org/3.x/appendices.html#forwards-compatibility-shimming) ------------------------------------------------------------------------------------------------------------------ FC shimming can prepare your 3.x app for the next major release (4.x). If you already want to shim 4.x behavior in 3.x, check out the [Shim plugin](https://github.com/dereuromark/cakephp-shim) that can help mitigate some BC breaking changes. The closer your 3.x app is to 4.x, the smaller will be the diff of changes, and the smoother will be the final upgrade. General Information [​](https://book.cakephp.org/3.x/appendices.html#general-information) ------------------------------------------------------------------------------------------ * [CakePHP Development Process](https://book.cakephp.org/3.x/appendices/cakephp-development-process.html) * [Glossary](https://book.cakephp.org/3.x/appendices/glossary.html) --- # 付録 | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/appendices.html#VPContent) On this page 付録 [​](https://book.cakephp.org/3.x/ja/appendices.html#%E4%BB%98%E9%8C%B2) =========================================================================== ここでは、各バージョンで導入された新機能に関する情報と、 バージョン間の移行手順を解説します。 3.x 移行ガイド [​](https://book.cakephp.org/3.x/ja/appendices.html#_3-x-%E7%A7%BB%E8%A1%8C%E3%82%AB%E3%82%99%E3%82%A4%E3%83%88%E3%82%99) ------------------------------------------------------------------------------------------------------------------------------------ * [3.x 移行ガイド](https://book.cakephp.org/3.x/ja/appendices/3-x-migration-guide.html) 一般的な情報 [​](https://book.cakephp.org/3.x/ja/appendices.html#%E4%B8%80%E8%88%AC%E7%9A%84%E3%81%AA%E6%83%85%E5%A0%B1) ------------------------------------------------------------------------------------------------------------------- * [CakePHP の開発プロセス](https://book.cakephp.org/3.x/ja/appendices/cakephp-development-process.html) * [用語集](https://book.cakephp.org/3.x/ja/appendices/glossary.html) --- # Url | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/helpers/url.html#VPContent) Return to top Url [​](https://book.cakephp.org/3.x/views/helpers/url.html#url) ================================================================= `class` Cake\\View\\Helper\\**UrlHelper**(View $view, array $config = \[\]) The UrlHelper makes it easy for you to generate URLs from your other helpers. It also gives you a single place to customize how URLs are generated by overriding the core helper with an application one. See the [Aliasing Helpers](https://book.cakephp.org/3.x/views/helpers.html#aliasing-helpers) section for how to do this. Generating URLs [​](https://book.cakephp.org/3.x/views/helpers/url.html#generating-urls) ----------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\UrlHelper::**build**(mixed $url = null, boolean|array $full = false) Returns a URL pointing to a combination of controller and action. If `$url` is empty, it returns the `REQUEST_URI`, otherwise it generates the URL for the controller and action combo. If `full` is `true`, the full base URL will be prepended to the result: echo $this->Url->build([\ "controller" => "Posts",\ "action" => "view",\ "bar",\ ]); // Output /posts/view/bar 1 2 3 4 5 6 7 8 Here are a few more usage examples: URL with extension: echo $this->Url->build([\ "controller" => "Posts",\ "action" => "list",\ "_ext" => "rss",\ ]); // Output /posts/list.rss 1 2 3 4 5 6 7 8 URL (starting with '/') with the full base URL prepended: echo $this->Url->build('/posts', true); // Output http://somedomain.com/posts 1 2 3 4 URL with GET parameters and fragment anchor: echo $this->Url->build([\ "controller" => "Posts",\ "action" => "search",\ "?" => ["foo" => "bar"],\ "#" => "first",\ ]); // Output /posts/search?foo=bar#first 1 2 3 4 5 6 7 8 9 The above example uses the `?` key which is useful when you want to be explicit about the query string parameters you are using, or if you want a query string parameter that shares a name with one of your route placeholders. URL for named route: // Assuming a route is setup as a named route: // $router->connect( // '/products/:slug', // [\ // 'controller' => 'Products',\ // 'action' => 'view',\ // ], // [\ // '_name' => 'product-page',\ // ] // ); echo $this->Url->build(['_name' => 'product-page', 'slug' => 'i-m-slug']); // Will result in: /products/i-m-slug 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 The 2nd parameter allows you to define options controlling HTML escaping, and whether or not the base path should be added: $this->Url->build('/posts', [\ 'escape' => false,\ 'fullBase' => true,\ ]); 1 2 3 4 URL with asset timestamp wrapped by a ``, here pre-loading a font. Note: The file must exist and `Configure::read('Asset.timestamp')` must return `true` or `'force'` for the timestamp to be appended: echo $this->Html->meta([\ 'rel' => 'preload',\ 'href' => $this->Url->assetUrl(\ '/assets/fonts/yout-font-pack/your-font-name.woff2'\ ),\ 'as' => 'font',\ ]); 1 2 3 4 5 6 7 Added in version 3.3.5 `build()` accepts an array as the 2nd argument as of 3.3.5 Added in version 3.6.0 The `timestamp` option was added to `build()`. If you are generating URLs for CSS, Javascript or image files there are helper methods for each of these asset types: // Outputs /img/icon.png $this->Url->image('icon.png'); // Outputs /js/app.js $this->Url->script('app.js'); // Outputs /css/app.css $this->Url->css('app.css'); // Force timestamps for one method call. $this->Url->css('app.css', ['timestamp' => 'force']); // Or disable timestamps for one method call. $this->Url->css('app.css', ['timestamp' => false]); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Added in version 3.2.4 The asset helper methods were added in 3.2.4. Added in version 3.6.0 The `timestamp` option was added to asset helper methods. For further information check [Router::url](https://api.cakephp.org/3.x/class-Cake.Routing.Router.html#_url) in the API. --- # Tutorials & Examples | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples.html#VPContent) Return to top Tutorials & Examples [​](https://book.cakephp.org/3.x/tutorials-and-examples.html#tutorials-examples) ====================================================================================================== In this section, you can walk through typical CakePHP applications to see how all of the pieces come together. Alternatively, you can refer to the non-official CakePHP plugin repository [CakePackages](https://plugins.cakephp.org/) and the [Bakery](https://bakery.cakephp.org/) for existing applications and components. * [Content Management Tutorial](https://book.cakephp.org/3.x/tutorials-and-examples/cms/installation.html) * [CMS Tutorial - Creating the Database](https://book.cakephp.org/3.x/tutorials-and-examples/cms/database.html) * [CMS Tutorial - Creating the Articles Controller](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html) * [CMS Tutorial - Tags and Users](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html) * [CMS Tutorial - Authentication](https://book.cakephp.org/3.x/tutorials-and-examples/cms/authentication.html) --- # Using CakePHP | CakePHP [Skip to content](https://book.cakephp.org/3.x/topics.html#VPContent) Return to top Using CakePHP [​](https://book.cakephp.org/3.x/topics.html#using-cakephp) ========================================================================== Introduction to all the key parts of CakePHP: * [Installation](https://book.cakephp.org/3.x/installation.html) * [Configuration](https://book.cakephp.org/3.x/development/configuration.html) * [Routing](https://book.cakephp.org/3.x/development/routing.html) * [Request & Response Objects](https://book.cakephp.org/3.x/controllers/request-response.html) * [Controllers](https://book.cakephp.org/3.x/controllers.html) * [Components](https://book.cakephp.org/3.x/controllers/components.html) * [The Pages Controller](https://book.cakephp.org/3.x/controllers/pages-controller.html) * [Views](https://book.cakephp.org/3.x/views.html) * [View Cells](https://book.cakephp.org/3.x/views/cells.html) * [Helpers](https://book.cakephp.org/3.x/views/helpers.html) * [JSON and XML views](https://book.cakephp.org/3.x/views/json-and-xml-views.html) * [Database Access & ORM](https://book.cakephp.org/3.x/orm.html) * [Table Objects](https://book.cakephp.org/3.x/orm/table-objects.html) * [Query Builder](https://book.cakephp.org/3.x/orm/query-builder.html) * [Entities](https://book.cakephp.org/3.x/orm/entities.html) * [Error & Exception Handling](https://book.cakephp.org/3.x/development/errors.html) * [Caching](https://book.cakephp.org/3.x/core-libraries/caching.html) * [Logging](https://book.cakephp.org/3.x/core-libraries/logging.html) * [Modelless Forms](https://book.cakephp.org/3.x/core-libraries/form.html) * [Sessions](https://book.cakephp.org/3.x/development/sessions.html) * [REST](https://book.cakephp.org/3.x/development/rest.html) * [AuthComponent](https://book.cakephp.org/3.x/controllers/components/authentication.html) * [Pagination](https://book.cakephp.org/3.x/controllers/components/pagination.html) * [Cross Site Request Forgery](https://book.cakephp.org/3.x/controllers/components/csrf.html) * [Email](https://book.cakephp.org/3.x/core-libraries/email.html) * [Form](https://book.cakephp.org/3.x/views/helpers/form.html) * [Html](https://book.cakephp.org/3.x/views/helpers/html.html) * [Validation](https://book.cakephp.org/3.x/core-libraries/validation.html) * [Testing](https://book.cakephp.org/3.x/development/testing.html) * [Deployment](https://book.cakephp.org/3.x/deployment.html) * [Console Tools, Shells & Tasks](https://book.cakephp.org/3.x/console-and-shells.html) * [Contributing](https://book.cakephp.org/3.x/contributing.html) * [Tutorials & Examples](https://book.cakephp.org/3.x/tutorials-and-examples.html) --- # Bookmarker Tutorial | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html#VPContent) Return to top Bookmarker Tutorial [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html#bookmarker-tutorial) ====================================================================================================================== This tutorial will walk you through the creation of a simple bookmarking application (bookmarker). To start with, we'll be installing CakePHP, creating our database, and using the tools CakePHP provides to get our application up fast. Here's what you'll need: 1. A database server. We're going to be using MySQL server in this tutorial. You'll need to know enough about SQL in order to create a database: CakePHP will be taking the reins from there. Since we're using MySQL, also make sure that you have `pdo_mysql` enabled in PHP. 2. Basic PHP knowledge. Before starting you should make sure that you have got an up to date PHP version: php -v 1 You should at least have got installed PHP _5.6_ (CLI) or higher. Your webserver's PHP version must also be of _5.6_ or higher, and should best be the same version your command line interface (CLI) PHP version is of. If you'd like to see the completed application, checkout [cakephp/bookmarker](https://github.com/cakephp/bookmarker-tutorial) . Let's get started! Getting CakePHP [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html#getting-cakephp) -------------------------------------------------------------------------------------------------------------- The easiest way to install CakePHP is to use Composer. Composer is a simple way of installing CakePHP from your terminal or command line prompt. First, you'll need to download and install Composer if you haven't done so already. If you have cURL installed, it's as easy as running the following: curl -s https://getcomposer.org/installer | php Or, you can download `composer.phar` from the [Composer website](https://getcomposer.org/download/) . Then simply type the following line in your terminal from your installation directory to install the CakePHP application skeleton in the **bookmarker** directory: php composer.phar create-project --prefer-dist cakephp/app:"^3.10" bookmarker If you downloaded and ran the [Composer Windows Installer](https://getcomposer.org/Composer-Setup.exe) , then type the following line in your terminal from your installation directory (ie. C:\\wamp\\www\\dev\\cakephp3): composer self-update && composer create-project --prefer-dist cakephp/app:"^3.10" bookmarker The advantage to using Composer is that it will automatically complete some important set up tasks, such as setting the correct file permissions and creating your **config/app.php** file for you. There are other ways to install CakePHP. If you cannot or don't want to use Composer, check out the [Installation](https://book.cakephp.org/3.x/installation.html) section. Regardless of how you downloaded and installed CakePHP, once your set up is completed, your directory setup should look something like the following: /bookmarker /bin /config /logs /plugins /src /tests /tmp /vendor /webroot .editorconfig .gitignore .htaccess .travis.yml composer.json index.php phpunit.xml.dist README.md Now might be a good time to learn a bit about how CakePHP's directory structure works: check out the [CakePHP Folder Structure](https://book.cakephp.org/3.x/intro/cakephp-folder-structure.html) section. Checking our Installation [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html#checking-our-installation) ---------------------------------------------------------------------------------------------------------------------------------- We can quickly check that our installation is correct, by checking the default home page. Before you can do that, you'll need to start the development server: bin/cake server NOTE For Windows, the command needs to be `bin\cake server` (note the backslash). This will start PHP's built-in webserver on port 8765. Open up **[http://localhost:8765](http://localhost:8765/) ** in your web browser to see the welcome page. All the bullet points should be checkmarks other than CakePHP being able to connect to your database. If not, you may need to install additional PHP extensions, or set directory permissions. Creating the Database [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html#creating-the-database) -------------------------------------------------------------------------------------------------------------------------- Next, let's set up the database for our bookmarking application. If you haven't already done so, create an empty database for use in this tutorial, with a name of your choice, e.g. `cake_bookmarks`. You can execute the following SQL to create the necessary tables: CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, email VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, created DATETIME, modified DATETIME ); CREATE TABLE bookmarks ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, title VARCHAR(50), description TEXT, url TEXT, created DATETIME, modified DATETIME, FOREIGN KEY user_key (user_id) REFERENCES users(id) ); CREATE TABLE tags ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255), created DATETIME, modified DATETIME, UNIQUE KEY (title) ); CREATE TABLE bookmarks_tags ( bookmark_id INT NOT NULL, tag_id INT NOT NULL, PRIMARY KEY (bookmark_id, tag_id), FOREIGN KEY tag_key(tag_id) REFERENCES tags(id), FOREIGN KEY bookmark_key(bookmark_id) REFERENCES bookmarks(id) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 You may have noticed that the `bookmarks_tags` table used a composite primary key. CakePHP supports composite primary keys almost everywhere, making it easier to build multi-tenanted applications. The table and column names we used were not arbitrary. By using CakePHP's [naming conventions](https://book.cakephp.org/3.x/intro/conventions.html) , we can leverage CakePHP better and avoid having to configure the framework. CakePHP is flexible enough to accommodate even inconsistent legacy database schemas, but adhering to the conventions will save you time. Database Configuration [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html#database-configuration) ---------------------------------------------------------------------------------------------------------------------------- Next, let's tell CakePHP where our database is and how to connect to it. For many, this will be the first and last time you will need to configure anything. The configuration should be pretty straightforward: just replace the values in the `Datasources.default` array in the **config/app.php** file with those that apply to your setup. A sample completed configuration array might look something like the following: return [\ // More configuration above.\ 'Datasources' => [\ 'default' => [\ 'className' => 'Cake\Database\Connection',\ 'driver' => 'Cake\Database\Driver\Mysql',\ 'persistent' => false,\ 'host' => 'localhost',\ 'username' => 'cakephp',\ 'password' => 'AngelF00dC4k3~',\ 'database' => 'cake_bookmarks',\ 'encoding' => 'utf8',\ 'timezone' => 'UTC',\ 'cacheMetadata' => true,\ ],\ ],\ // More configuration below.\ ]; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Once you've saved your **config/app.php** file, you should see that 'CakePHP is able to connect to the database' section have a checkmark. NOTE A copy of CakePHP's default configuration file is found in **config/app.default.php**. Generating Scaffold Code [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html#generating-scaffold-code) -------------------------------------------------------------------------------------------------------------------------------- Because our database is following the CakePHP conventions, we can use the [bake console](https://book.cakephp.org/3.x/bake/usage.html) application to quickly generate a basic application. In your command line run the following commands: // On Windows you'll need to use bin\cake instead. bin/cake bake all users bin/cake bake all bookmarks bin/cake bake all tags 1 2 3 4 This will generate the controllers, models, views, their corresponding test cases, and fixtures for our users, bookmarks and tags resources. If you've stopped your server, restart it and go to **[http://localhost:8765/bookmarks](http://localhost:8765/bookmarks) **. You should see a basic but functional application providing data access to your application's database tables. Once you're at the list of bookmarks, add a few users, bookmarks, and tags. Adding Password Hashing [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html#adding-password-hashing) ------------------------------------------------------------------------------------------------------------------------------ When you created your users (by visiting **[http://localhost:8765/users](http://localhost:8765/users) **), you probably noticed that the passwords were stored in plain text. This is pretty bad from a security point of view, so let's get that fixed. This is also a good time to talk about the model layer in CakePHP. In CakePHP, we separate the methods that operate on a collection of objects, and a single object into different classes. Methods that operate on the collection of entities are put in the `Table` class, while features belonging to a single record are put on the `Entity` class. For example, password hashing is done on the individual record, so we'll implement this behavior on the entity object. Because, we want to hash the password each time it is set, we'll use a mutator/setter method. CakePHP will call convention based setter methods any time a property is set in one of your entities. Let's add a setter for the password. In **src/Model/Entity/User.php** add the following: namespace App\Model\Entity; use Cake\Auth\DefaultPasswordHasher; //include this line use Cake\ORM\Entity; class User extends Entity { // Code from bake. protected function _setPassword($value) { $hasher = new DefaultPasswordHasher(); return $hasher->hash($value); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Now update one of the users you created earlier, if you change their password, you should see a hashed password instead of the original value on the list or view pages. CakePHP hashes passwords with [bcrypt](https://codahale.com/how-to-safely-store-a-password/) by default. You can also use sha1 or md5 if you're working with an existing database. NOTE If the password doesn't get hashed, make sure you followed the same case for the password member of the class while naming the setter function Getting Bookmarks with a Specific Tag [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html#getting-bookmarks-with-a-specific-tag) ---------------------------------------------------------------------------------------------------------------------------------------------------------- Now that we're storing passwords safely, we can build out some more interesting features in our application. Once you've amassed a collection of bookmarks, it is helpful to be able to search through them by tag. Next we'll implement a route, controller action, and finder method to search through bookmarks by tag. Ideally, we'd have a URL that looks like **[http://localhost:8765/bookmarks/tagged/funny/cat/gifs](http://localhost:8765/bookmarks/tagged/funny/cat/gifs) **. This would let us find all the bookmarks that have the 'funny', 'cat' or 'gifs' tags. Before we can implement this, we'll add a new route. Your **config/routes.php** should look like: 'Bookmarks'], function ($routes) { $routes->connect('/tagged/*', ['action' => 'tags']); } ); Router::scope('/', function ($routes) { // Connect the default home and /pages/* routes. $routes->connect('/', [\ 'controller' => 'Pages',\ 'action' => 'display', 'home'\ ]); $routes->connect('/pages/*', [\ 'controller' => 'Pages',\ 'action' => 'display'\ ]); // Connect the conventions based default routes. $routes->fallbacks(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 The above defines a new 'route' which connects the **/bookmarks/tagged/** path, to `BookmarksController::tags()`. By defining routes, you can isolate how your URLs look, from how they are implemented. If we were to visit **[http://localhost:8765/bookmarks/tagged](http://localhost:8765/bookmarks/tagged) **, we would see a helpful error page from CakePHP informing you that the controller action does not exist. Let's implement that missing method now. In **src/Controller/BookmarksController.php** add the following: public function tags() { // The 'pass' key is provided by CakePHP and contains all // the passed URL path segments in the request. $tags = $this->request->getParam('pass'); // Use the BookmarksTable to find tagged bookmarks. $bookmarks = $this->Bookmarks->find('tagged', [\ 'tags' => $tags\ ]); // Pass variables into the view template context. $this->set([\ 'bookmarks' => $bookmarks,\ 'tags' => $tags\ ]); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 To access other parts of the request data, consult the [Cake Request](https://book.cakephp.org/3.x/controllers/request-response.html#cake-request) section. ### Creating the Finder Method [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html#creating-the-finder-method) In CakePHP we like to keep our controller actions slim, and put most of our application's logic in the models. If you were to visit the **/bookmarks/tagged** URL now you would see an error that the `findTagged()` method has not been implemented yet, so let's do that. In **src/Model/Table/BookmarksTable.php** add the following: // The $query argument is a query builder instance. // The $options array will contain the 'tags' option we passed // to find('tagged') in our controller action. public function findTagged(Query $query, array $options) { $bookmarks = $this->find() ->select(['id', 'url', 'title', 'description']); if (empty($options['tags'])) { $bookmarks ->leftJoinWith('Tags') ->where(['Tags.title IS' => null]); } else { $bookmarks ->innerJoinWith('Tags') ->where(['Tags.title IN ' => $options['tags']]); } return $bookmarks->group(['Bookmarks.id']); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 We just implemented a [custom finder method](https://book.cakephp.org/3.x/orm/retrieving-data-and-resultsets.html#custom-find-methods) . This is a very powerful concept in CakePHP that allows you to package up re-usable queries. Finder methods always get a [Query Builder](https://book.cakephp.org/3.x/orm/query-builder.html) object and an array of options as parameters. Finders can manipulate the query and add any required conditions or criteria. When complete, finder methods must return a modified query object. In our finder we've leveraged the `innerJoinWith()`, `where()` and `group()` methods which allow us to find distinct bookmarks that have a matching tag. When no tags are provided we use a `leftJoinWith()` and modify the 'where' condition, finding bookmarks without tags. ### Creating the View [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html#creating-the-view) Now if you visit the **/bookmarks/tagged** URL, CakePHP will show an error letting you know that you have not made a view file. Next, let's build the view file for our `tags()` action. In **src/Template/Bookmarks/tags.ctp** put the following content:

Bookmarks tagged with Text->toList(h($tags)) ?>

Html->link($bookmark->title, $bookmark->url) ?>

url) ?> Text->autoParagraph(h($bookmark->description)) ?>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 In the above code we use the [Html](https://book.cakephp.org/3.x/views/helpers/html.html) and [Text](https://book.cakephp.org/3.x/views/helpers/text.html) helpers to assist in generating our view output. We also use the `h` shortcut function to HTML encode output. You should remember to always use `h()` when outputting user data to prevent HTML injection issues. The **tags.ctp** file we just created follows the CakePHP conventions for view template files. The convention is to have the template use the lower case and underscored version of the controller action name. You may notice that we were able to use the `$tags` and `$bookmarks` variables in our view. When we use the `set()` method in our controller, we set specific variables to be sent to the view. The view will make all passed variables available in the templates as local variables. You should now be able to visit the **/bookmarks/tagged/funny** URL and see all the bookmarks tagged with 'funny'. So far, we've created a basic application to manage bookmarks, tags and users. However, everyone can see everyone else's tags. In the next chapter, we'll implement authentication and restrict the visible bookmarks to only those that belong to the current user. Now continue to [Bookmarker Tutorial Part 2](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html) to continue building your application or [dive into the documentation](https://book.cakephp.org/3.x/topics.html) to learn more about what CakePHP can do for you. --- # Bookmarker Tutorial Part 2 | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#VPContent) Return to top Bookmarker Tutorial Part 2 [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#bookmarker-tutorial-part-2) ======================================================================================================================================= After finishing [the first part of this tutorial](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/intro.html) you should have a very basic bookmarking application. In this chapter we'll be adding authentication and restricting the bookmarks each user can see/modify to only the ones they own. Adding Login [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#adding-login) ----------------------------------------------------------------------------------------------------------- In CakePHP, authentication is handled by [Components](https://book.cakephp.org/3.x/controllers/components.html) . Components can be thought of as ways to create reusable chunks of controller code related to a specific feature or concept. Components can also hook into the controller's event life-cycle and interact with your application that way. To get started, we'll add the [AuthComponent](https://book.cakephp.org/3.x/controllers/components/authentication.html) to our application. We'll pretty much want every method to require authentication, so we'll add AuthComponent in our AppController: // In src/Controller/AppController.php namespace App\Controller; use Cake\Controller\Controller; class AppController extends Controller { public function initialize() { $this->loadComponent('Flash'); $this->loadComponent('Auth', [\ 'authenticate' => [\ 'Form' => [\ 'fields' => [\ 'username' => 'email',\ 'password' => 'password'\ ]\ ]\ ],\ 'loginAction' => [\ 'controller' => 'Users',\ 'action' => 'login'\ ],\ 'unauthorizedRedirect' => $this->referer() // If unauthorized, return them to page they were just on\ ]); // Allow the display action so our pages controller // continues to work. $this->Auth->allow(['display']); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 We've just told CakePHP that we want to load the `Flash` and `Auth` components. In addition, we've customized the configuration of AuthComponent, as our users table uses `email` as the username. Now, if you go to any URL you'll be kicked to **/users/login**, which will show an error page as we have not written that code yet. So let's create the login action: // In src/Controller/UsersController.php public function login() { if ($this->request->is('post')) { $user = $this->Auth->identify(); if ($user) { $this->Auth->setUser($user); return $this->redirect($this->Auth->redirectUrl()); } $this->Flash->error('Your username or password is incorrect.'); } } 1 2 3 4 5 6 7 8 9 10 11 12 And in **src/Template/Users/login.ctp** add the following:

Login

Form->create() ?> Form->control('email') ?> Form->control('password') ?> Form->button('Login') ?> Form->end() ?> 1 2 3 4 5 6 NOTE The `control()` method is available since 3.4. For prior versions you can use the `input()` method instead. Now that we have a simple login form, we should be able to log in with one of the users that has a hashed password. NOTE If none of your users have hashed passwords, comment the `loadComponent('Auth')` line. Then go and edit the user, saving a new password for them. Adding Logout [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#adding-logout) ------------------------------------------------------------------------------------------------------------- Now that people can log in, you'll probably want to provide a way to log out as well. Again, in the `UsersController`, add the following code: public function initialize() { parent::initialize(); $this->Auth->allow(['logout']); } public function logout() { $this->Flash->success('You are now logged out.'); return $this->redirect($this->Auth->logout()); } 1 2 3 4 5 6 7 8 9 10 11 This code whitelists the `logout` action as a public action, and implements the logout method. Now you can visit `/users/logout` to log out. You should then be sent to the login page. Enabling Registrations [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#enabling-registrations) ------------------------------------------------------------------------------------------------------------------------------- If you aren't logged in and you try to visit **/users/add** you will be kicked to the login page. We should fix that as we want to allow people to sign up for our application. In the `UsersController` add the following: public function initialize() { parent::initialize(); // Add the 'add' action to the allowed actions list. $this->Auth->allow(['logout', 'add']); } 1 2 3 4 5 6 The above tells `AuthComponent` that the `add()` action does _not_ require authentication or authorization. You may want to take the time to clean up the **Users/add.ctp** and remove the misleading links, or continue on to the next section. We won't be building out user editing, viewing or listing in this tutorial so they will not work as `AuthComponent` will deny you access to those controller actions. Restricting Bookmark Access [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#restricting-bookmark-access) ----------------------------------------------------------------------------------------------------------------------------------------- Now that users can log in, we'll want to limit the bookmarks they can see to the ones they made. We'll do this using an 'authorization' adapter. Since our requirements are pretty simple, we can write some simple code in our `BookmarksController`. But before we do that, we'll want to tell the AuthComponent how our application is going to authorize actions. In your `AppController` add the following: public function isAuthorized($user) { return false; } 1 2 3 4 Also, add the following to the configuration for `Auth` in your `AppController`: 'authorize' => 'Controller', 1 Your `initialize()` method should now look like: public function initialize() { $this->loadComponent('Flash'); $this->loadComponent('Auth', [\ 'authorize'=> 'Controller',//added this line\ 'authenticate' => [\ 'Form' => [\ 'fields' => [\ 'username' => 'email',\ 'password' => 'password'\ ]\ ]\ ],\ 'loginAction' => [\ 'controller' => 'Users',\ 'action' => 'login'\ ],\ 'unauthorizedRedirect' => $this->referer()\ ]); // Allow the display action so our pages controller // continues to work. $this->Auth->allow(['display']); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 We'll default to denying access, and incrementally grant access where it makes sense. First, we'll add the authorization logic for bookmarks. In your `BookmarksController` add the following: public function isAuthorized($user) { $action = $this->request->getParam('action'); // The add and index actions are always allowed. if (in_array($action, ['index', 'add', 'tags'])) { return true; } // All other actions require an id. if (!$this->request->getParam('pass.0')) { return false; } // Check that the bookmark belongs to the current user. $id = $this->request->getParam('pass.0'); $bookmark = $this->Bookmarks->get($id); if ($bookmark->user_id == $user['id']) { return true; } return parent::isAuthorized($user); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Now if you try to view, edit or delete a bookmark that does not belong to you, you should be redirected back to the page you came from. If no error message is displayed, add the following to your layout: // In src/Template/Layout/default.ctp Flash->render() ?> 1 2 You should now see the authorization error messages. Fixing List view and Forms [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#fixing-list-view-and-forms) --------------------------------------------------------------------------------------------------------------------------------------- While view and delete are working, edit, add and index have a few problems: 1. When adding a bookmark you can choose the user. 2. When editing a bookmark you can choose the user. 3. The list page shows bookmarks from other users. Let's tackle the add form first. To begin with remove the `control('user_id')` from **src/Template/Bookmarks/add.ctp**. With that removed, we'll also update the `add()` action from **src/Controller/BookmarksController.php** to look like: public function add() { $bookmark = $this->Bookmarks->newEntity(); if ($this->request->is('post')) { $bookmark = $this->Bookmarks->patchEntity($bookmark, $this->request->getData()); $bookmark->user_id = $this->Auth->user('id'); if ($this->Bookmarks->save($bookmark)) { $this->Flash->success('The bookmark has been saved.'); return $this->redirect(['action' => 'index']); } $this->Flash->error('The bookmark could not be saved. Please, try again.'); } $tags = $this->Bookmarks->Tags->find('list'); $this->set(compact('bookmark', 'tags')); $this->set('_serialize', ['bookmark']); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 By setting the entity property with the session data, we remove any possibility of the user modifying which user a bookmark is for. We'll do the same for the edit form and action. Your `edit()` action from **src/Controller/BookmarksController.php** should look like: public function edit($id = null) { $bookmark = $this->Bookmarks->get($id, [\ 'contain' => ['Tags']\ ]); if ($this->request->is(['patch', 'post', 'put'])) { $bookmark = $this->Bookmarks->patchEntity($bookmark, $this->request->getData()); $bookmark->user_id = $this->Auth->user('id'); if ($this->Bookmarks->save($bookmark)) { $this->Flash->success('The bookmark has been saved.'); return $this->redirect(['action' => 'index']); } $this->Flash->error('The bookmark could not be saved. Please, try again.'); } $tags = $this->Bookmarks->Tags->find('list'); $this->set(compact('bookmark', 'tags')); $this->set('_serialize', ['bookmark']); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ### List View [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#list-view) Now, we only need to show bookmarks for the currently logged in user. We can do that by updating the call to `paginate()`. Make your `index()` action from **src/Controller/BookmarksController.php** look like: public function index() { $this->paginate = [\ 'conditions' => [\ 'Bookmarks.user_id' => $this->Auth->user('id'),\ ]\ ]; $this->set('bookmarks', $this->paginate($this->Bookmarks)); $this->set('_serialize', ['bookmarks']); } 1 2 3 4 5 6 7 8 9 10 We should also update the `tags()` action and the related finder method, but we'll leave that as an exercise you can complete on your own. Improving the Tagging Experience [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#improving-the-tagging-experience) --------------------------------------------------------------------------------------------------------------------------------------------------- Right now, adding new tags is a difficult process, as the `TagsController` disallows all access. Instead of allowing access, we can improve the tag selection UI by using a comma separated text field. This will let us give a better experience to our users, and use some more great features in the ORM. ### Adding a Computed Field [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#adding-a-computed-field) Because we'll want a simple way to access the formatted tags for an entity, we can add a virtual/computed field to the entity. In **src/Model/Entity/Bookmark.php** add the following: use Cake\Collection\Collection; protected function _getTagString() { if (isset($this->_properties['tag_string'])) { return $this->_properties['tag_string']; } if (empty($this->tags)) { return ''; } $tags = new Collection($this->tags); $str = $tags->reduce(function ($string, $tag) { return $string . $tag->title . ', '; }, ''); return trim($str, ', '); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 This will let us access the `$bookmark->tag_string` computed property. We'll use this property in controls later on. Remember to add the `tag_string` property to the `_accessible` list in your entity, as we'll want to 'save' it later on. In **src/Model/Entity/Bookmark.php** add the `tag_string` to `$_accessible` this way: protected $_accessible = [\ 'user_id' => true,\ 'title' => true,\ 'description' => true,\ 'url' => true,\ 'user' => true,\ 'tags' => true,\ 'tag_string' => true,\ ]; 1 2 3 4 5 6 7 8 9 ### Updating the Views [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#updating-the-views) With the entity updated we can add a new control for our tags. In **src/Template/Bookmarks/add.ctp** and **src/Template/Bookmarks/edit.ctp**, replace the existing `tags._ids` control with the following: echo $this->Form->control('tag_string', ['type' => 'text']); 1 ### Persisting the Tag String [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#persisting-the-tag-string) Now that we can view existing tags as a string, we'll want to save that data as well. Because we marked the `tag_string` as accessible, the ORM will copy that data from the request into our entity. We can use a `beforeSave()` hook method to parse the tag string and find/build the related entities. Add the following to **src/Model/Table/BookmarksTable.php**: public function beforeSave($event, $entity, $options) { if ($entity->tag_string) { $entity->tags = $this->_buildTags($entity->tag_string); } } protected function _buildTags($tagString) { // Trim tags $newTags = array_map('trim', explode(',', $tagString)); // Remove all empty tags $newTags = array_filter($newTags); // Reduce duplicated tags $newTags = array_unique($newTags); $out = []; $query = $this->Tags->find() ->where(['Tags.title IN' => $newTags]); // Remove existing tags from the list of new tags. foreach ($query->extract('title') as $existing) { $index = array_search($existing, $newTags); if ($index !== false) { unset($newTags[$index]); } } // Add existing tags. foreach ($query as $tag) { $out[] = $tag; } // Add new tags. foreach ($newTags as $tag) { $out[] = $this->Tags->newEntity(['title' => $tag]); } return $out; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 While this code is a bit more complicated than what we've done so far, it helps to showcase how powerful the ORM in CakePHP is. You can manipulate query results using the [Collections](https://book.cakephp.org/3.x/core-libraries/collections.html) methods, and handle scenarios where you are creating entities on the fly with ease. Wrapping Up [​](https://book.cakephp.org/3.x/tutorials-and-examples/bookmarks/part-two.html#wrapping-up) --------------------------------------------------------------------------------------------------------- We've expanded our bookmarking application to handle authentication and basic authorization/access control scenarios. We've also added some nice UX improvements by leveraging the FormHelper and ORM capabilities. Thanks for taking the time to explore CakePHP. Next, you can complete the [Blog Tutorial](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html) , learn more about the [Database Access & ORM](https://book.cakephp.org/3.x/orm.html) , or you can peruse the [Using CakePHP](https://book.cakephp.org/3.x/topics.html) . --- # Phinx Migrations | CakePHP [Skip to content](https://book.cakephp.org/3.x/phinx.html#VPContent) Return to top Phinx Migrations [​](https://book.cakephp.org/3.x/phinx.html#phinx-migrations) =============================================================================== This page has [moved](https://book.cakephp.org/phinx/) . --- # Content Management Tutorial | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples/cms/installation.html#VPContent) Return to top Content Management Tutorial [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/installation.html#content-management-tutorial) ======================================================================================================================================= This tutorial will walk you through the creation of a simple `CMS (Content Management System)` application. To start with, we'll be installing CakePHP, creating our database, and building simple article management. Here's what you'll need: 1. A database server. We're going to be using MySQL server in this tutorial. You'll need to know enough about SQL in order to create a database, and run SQL snippets from the tutorial. CakePHP will handle building all the queries your application needs. Since we're using MySQL, also make sure that you have `pdo_mysql` enabled in PHP. 2. Basic PHP knowledge. Before starting you should make sure that you have got an up to date PHP version: php -v 1 You should at least have got installed PHP _5.6_ (CLI) or higher. Your webserver's PHP version must also be of _5.6_ or higher, and should be the same version your command line interface (CLI) PHP is. Getting CakePHP [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/installation.html#getting-cakephp) --------------------------------------------------------------------------------------------------------------- The easiest way to install CakePHP is to use Composer. Composer is a simple way of installing CakePHP from your terminal or command line prompt. First, you'll need to download and install Composer if you haven't done so already. If you have cURL installed, it's as easy as running the following: curl -s https://getcomposer.org/installer | php 1 Or, you can download `composer.phar` from the [Composer website](https://getcomposer.org/download/) . Then simply type the following line in your terminal from your installation directory to install the CakePHP application skeleton in the **cms** directory of the current working directory: php composer.phar create-project --prefer-dist cakephp/app:"^3.10" cms 1 If you downloaded and ran the [Composer Windows Installer](https://getcomposer.org/Composer-Setup.exe) , then type the following line in your terminal from your installation directory (ie. C:\\wamp\\www\\dev\\cakephp3): composer self-update && composer create-project --prefer-dist cakephp/app:"^3.10" cms 1 The advantage to using Composer is that it will automatically complete some important set up tasks, such as setting the correct file permissions and creating your **config/app.php** file for you. There are other ways to install CakePHP. If you cannot or don't want to use Composer, check out the [Installation](https://book.cakephp.org/3.x/installation.html) section. Regardless of how you downloaded and installed CakePHP, once your set up is completed, your directory setup should look something like the following: /cms /bin /config /logs /plugins /src /tests /tmp /vendor /webroot .editorconfig .gitignore .htaccess .travis.yml composer.json index.php phpunit.xml.dist README.md Now might be a good time to learn a bit about how CakePHP's directory structure works: check out the [CakePHP Folder Structure](https://book.cakephp.org/3.x/intro/cakephp-folder-structure.html) section. If you get lost during this tutorial, you can see the finished result [on GitHub](https://github.com/cakephp/cms-tutorial) . Checking our Installation [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/installation.html#checking-our-installation) ----------------------------------------------------------------------------------------------------------------------------------- We can quickly check that our installation is correct, by checking the default home page. Before you can do that, you'll need to start the development server: cd /path/to/our/app bin/cake server 1 2 3 NOTE For Windows, the command needs to be `bin\cake server` (note the backslash). This will start PHP's built-in webserver on port 8765. Open up **[http://localhost:8765](http://localhost:8765/) ** in your web browser to see the welcome page. All the bullet points should be green chef hats other than CakePHP being able to connect to your database. If not, you may need to install additional PHP extensions, or set directory permissions. Next, we will build our [Database and create our first model](https://book.cakephp.org/3.x/tutorials-and-examples/cms/database.html) . --- # CMS Tutorial - Tags and Users | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#VPContent) Return to top CMS Tutorial - Tags and Users [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#cms-tutorial-tags-and-users) =========================================================================================================================================== With the basic article creation functionality built, we need to enable multiple authors to work in our CMS. Previously, we built all the models, views and controllers by hand. This time around we're going to use [Bake Console](https://book.cakephp.org/3.x/bake.html) to create our skeleton code. Bake is a powerful code generation `CLI (Command Line Interface)` tool that leverages the conventions CakePHP uses to create skeleton `CRUD (Create, Read, Update, Delete)` applications very efficiently. We're going to use `bake` to build our users code: cd /path/to/our/app bin/cake bake model users bin/cake bake controller users bin/cake bake template users 1 2 3 4 5 These 3 commands will generate: * The Table, Entity, Fixture files. * The Controller * The CRUD templates. * Test cases for each generated class. Bake will also use the CakePHP conventions to infer the associations, and validation your models have. Adding Tagging to Articles [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#adding-tagging-to-articles) --------------------------------------------------------------------------------------------------------------------------------------- With multiple users able to access our small `CMS` it would be nice to have a way to categorize our content. We'll use tags and tagging to allow users to create free-form categories and labels for their content. Again, we'll use `bake` to quickly generate some skeleton code for our application: # Generate all the code at once. bin/cake bake all tags 1 2 Once you have the scaffold code created, create a few sample tags by going to **[http://localhost:8765/tags/add](http://localhost:8765/tags/add) **. Now that we have a Tags table, we can create an association between Articles and Tags. We can do so by adding the following to the `initialize` method on the ArticlesTable: public function initialize(array $config) { $this->addBehavior('Timestamp'); $this->belongsToMany('Tags'); // Add this line } 1 2 3 4 5 This association will work with this simple definition because we followed CakePHP conventions when creating our tables. For more information, read [Associations - Linking Tables Together](https://book.cakephp.org/3.x/orm/associations.html) . Updating Articles to Enable Tagging [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#updating-articles-to-enable-tagging) --------------------------------------------------------------------------------------------------------------------------------------------------------- Now that our application has tags, we need to enable users to tag their articles. First, update the `add` action to look like: // in src/Controller/ArticlesController.php namespace App\Controller; use App\Controller\AppController; class ArticlesController extends AppController { public function add() { $article = $this->Articles->newEntity(); if ($this->request->is('post')) { $article = $this->Articles->patchEntity($article, $this->request->getData()); // Hardcoding the user_id is temporary, and will be removed later // when we build authentication out. $article->user_id = 1; if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to add your article.')); } // Get a list of tags. $tags = $this->Articles->Tags->find('list'); // Set tags to the view context $this->set('tags', $tags); $this->set('article', $article); } // Other actions } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 The added lines load a list of tags as an associative array of `id => title`. This format will let us create a new tag input in our template. Add the following to the PHP block of controls in **src/Template/Articles/add.ctp**: echo $this->Form->control('tags._ids', ['options' => $tags]); 1 This will render a multiple select element that uses the `$tags` variable to generate the select box options. You should now create a couple new articles that have tags, as in the following section we'll be adding the ability to find articles by tags. You should also update the `edit` method to allow adding or editing tags. The edit method should now look like: public function edit($slug) { $article = $this->Articles ->findBySlug($slug) ->contain('Tags') // load associated Tags ->firstOrFail(); if ($this->request->is(['post', 'put'])) { $this->Articles->patchEntity($article, $this->request->getData()); if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been updated.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to update your article.')); } // Get a list of tags. $tags = $this->Articles->Tags->find('list'); // Set tags to the view context $this->set('tags', $tags); $this->set('article', $article); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Remember to add the new tags multiple select control we added to the **add.ctp** template to the **src/Template/Articles/edit.ctp** template as well. Finding Articles By Tags [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#finding-articles-by-tags) ----------------------------------------------------------------------------------------------------------------------------------- Once users have categorized their content, they will want to find that content by the tags they used. For this feature we'll implement a route, controller action, and finder method to search through articles by tag. Ideally, we'd have a URL that looks like **[http://localhost:8765/articles/tagged/funny/cat/gifs](http://localhost:8765/articles/tagged/funny/cat/gifs) **. This would let us find all the articles that have the 'funny', 'cat' or 'gifs' tags. Before we can implement this, we'll add a new route. Your **config/routes.php** should look like: registerMiddleware('csrf', new CsrfProtectionMiddleware([\ 'httpOnly' => true\ ])); $routes->applyMiddleware('csrf'); $routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']); $routes->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']); $routes->fallbacks(DashedRoute::class); }); // Add this // New route we're adding for our tagged action. // The trailing `*` tells CakePHP that this action has // passed parameters. Router::scope('/articles', function (RouteBuilder $routes) { $routes->connect('/tagged/*', ['controller' => 'Articles', 'action' => 'tags']); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 The above defines a new 'route' which connects the **/articles/tagged/** path, to `ArticlesController::tags()`. By defining routes, you can isolate how your URLs look, from how they are implemented. If we were to visit **[http://localhost:8765/articles/tagged](http://localhost:8765/articles/tagged) **, we would see a helpful error page from CakePHP informing you that the controller action does not exist. Let's implement that missing method now. In **src/Controller/ArticlesController.php** add the following: public function tags() { // The 'pass' key is provided by CakePHP and contains all // the passed URL path segments in the request. $tags = $this->request->getParam('pass'); // Use the ArticlesTable to find tagged articles. $articles = $this->Articles->find('tagged', [\ 'tags' => $tags\ ]); // Pass variables into the view template context. $this->set([\ 'articles' => $articles,\ 'tags' => $tags\ ]); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 To access other parts of the request data, consult the [Cake Request](https://book.cakephp.org/3.x/controllers/request-response.html#cake-request) section. Since passed arguments are passed as method parameters, you could also write the action using PHP's variadic argument: public function tags(...$tags) { // Use the ArticlesTable to find tagged articles. $articles = $this->Articles->find('tagged', [\ 'tags' => $tags\ ]); // Pass variables into the view template context. $this->set([\ 'articles' => $articles,\ 'tags' => $tags\ ]); } 1 2 3 4 5 6 7 8 9 10 11 12 13 ### Creating the Finder Method [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#creating-the-finder-method) In CakePHP we like to keep our controller actions slim, and put most of our application's logic in the model layer. If you were to visit the **/articles/tagged** URL now you would see an error that the `findTagged()` method has not been implemented yet, so let's do that. In **src/Model/Table/ArticlesTable.php** add the following: // add this use statement right below the namespace declaration to import // the Query class use Cake\ORM\Query; // The $query argument is a query builder instance. // The $options array will contain the 'tags' option we passed // to find('tagged') in our controller action. public function findTagged(Query $query, array $options) { $columns = [\ 'Articles.id', 'Articles.user_id', 'Articles.title',\ 'Articles.body', 'Articles.published', 'Articles.created',\ 'Articles.slug',\ ]; $query = $query ->select($columns) ->distinct($columns); if (empty($options['tags'])) { // If there are no tags provided, find articles that have no tags. $query->leftJoinWith('Tags') ->where(['Tags.title IS' => null]); } else { // Find articles that have one or more of the provided tags. $query->innerJoinWith('Tags') ->where(['Tags.title IN' => $options['tags']]); } return $query->group(['Articles.id']); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 We just implemented a [custom finder method](https://book.cakephp.org/3.x/orm/retrieving-data-and-resultsets.html#custom-find-methods) . This is a very powerful concept in CakePHP that allows you to package up re-usable queries. Finder methods always get a [Query Builder](https://book.cakephp.org/3.x/orm/query-builder.html) object and an array of options as parameters. Finders can manipulate the query and add any required conditions or criteria. When complete, finder methods must return a modified query object. In our finder we've leveraged the `distinct()` and `leftJoin()` methods which allow us to find distinct articles that have a 'matching' tag. ### Creating the View [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#creating-the-view) Now if you visit the **/articles/tagged** URL again, CakePHP will show a new error letting you know that you have not made a view file. Next, let's build the view file for our `tags()` action. In **src/Template/Articles/tags.ctp** put the following content:

Articles tagged with Text->toList(h($tags), 'or') ?>

Html->link( $article->title, ['controller' => 'Articles', 'action' => 'view', $article->slug] ) ?>

created) ?>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 In the above code we use the [Html](https://book.cakephp.org/3.x/views/helpers/html.html) and [Text](https://book.cakephp.org/3.x/views/helpers/text.html) helpers to assist in generating our view output. We also use the `h` shortcut function to HTML encode output. You should remember to always use `h()` when outputting data to prevent HTML injection issues. The **tags.ctp** file we just created follows the CakePHP conventions for view template files. The convention is to have the template use the lower case and underscored version of the controller action name. You may notice that we were able to use the `$tags` and `$articles` variables in our view template. When we use the `set()` method in our controller, we set specific variables to be sent to the view. The View will make all passed variables available in the template scope as local variables. You should now be able to visit the **/articles/tagged/funny** URL and see all the articles tagged with 'funny'. Improving the Tagging Experience [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#improving-the-tagging-experience) --------------------------------------------------------------------------------------------------------------------------------------------------- Right now, adding new tags is a cumbersome process, as authors need to pre-create all the tags they want to use. We can improve the tag selection UI by using a comma separated text field. This will let us give a better experience to our users, and use some more great features in the ORM. ### Adding a Computed Field [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#adding-a-computed-field) Because we'll want a simple way to access the formatted tags for an entity, we can add a virtual/computed field to the entity. In **src/Model/Entity/Article.php** add the following: // add this use statement right below the namespace declaration to import // the Collection class use Cake\Collection\Collection; // Update the accessible property to contain `tag_string` protected $_accessible = [\ //other fields...\ 'tag_string' => true\ ]; protected function _getTagString() { if (isset($this->_properties['tag_string'])) { return $this->_properties['tag_string']; } if (empty($this->tags)) { return ''; } $tags = new Collection($this->tags); $str = $tags->reduce(function ($string, $tag) { return $string . $tag->title . ', '; }, ''); return trim($str, ', '); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 This will let us access the `$article->tag_string` computed property. We'll use this property in controls later on. ### Updating the Views [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#updating-the-views) With the entity updated we can add a new control for our tags. In **src/Template/Articles/add.ctp** and **src/Template/Articles/edit.ctp**, replace the existing `tags._ids` control with the following: echo $this->Form->control('tag_string', ['type' => 'text']); 1 We'll also need to update the article view template. In **src/Template/Articles/view.ctp** add the line as shown:

title) ?>

body) ?>

// Add the following line

Tags: tag_string) ?>

1 2 3 4 5 6 ### Persisting the Tag String [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#persisting-the-tag-string) Now that we can view existing tags as a string, we'll want to save that data as well. Because we marked the `tag_string` as accessible, the ORM will copy that data from the request into our entity. We can use a `beforeSave()` hook method to parse the tag string and find/build the related entities. Add the following to **src/Model/Table/ArticlesTable.php**: public function beforeSave($event, $entity, $options) { if ($entity->tag_string) { $entity->tags = $this->_buildTags($entity->tag_string); } // Other code } protected function _buildTags($tagString) { // Trim tags $newTags = array_map('trim', explode(',', $tagString)); // Remove all empty tags $newTags = array_filter($newTags); // Reduce duplicated tags $newTags = array_unique($newTags); $out = []; $query = $this->Tags->find() ->where(['Tags.title IN' => $newTags]); // Remove existing tags from the list of new tags. foreach ($query->extract('title') as $existing) { $index = array_search($existing, $newTags); if ($index !== false) { unset($newTags[$index]); } } // Add existing tags. foreach ($query as $tag) { $out[] = $tag; } // Add new tags. foreach ($newTags as $tag) { $out[] = $this->Tags->newEntity(['title' => $tag]); } return $out; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 If you now create or edit articles, you should be able to save tags as a comma separated list of tags, and have the tags and linking records automatically created. While this code is a bit more complicated than what we've done so far, it helps to showcase how powerful the ORM in CakePHP is. You can manipulate query results using the [Collections](https://book.cakephp.org/3.x/core-libraries/collections.html) methods, and handle scenarios where you are creating entities on the fly with ease. Auto-populating the Tag String [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html#auto-populating-the-tag-string) ----------------------------------------------------------------------------------------------------------------------------------------------- Before we finish up, we'll need a mechanism that will load the associated tags (if any) whenever we load an article. In your **src/Model/Table/ArticlesTable.php**, change: public function initialize(array $config) { $this->addBehavior('Timestamp'); // Change this line $this->belongsToMany('Tags', [\ 'joinTable' => 'articles_tags',\ 'dependent' => true\ ]); } 1 2 3 4 5 6 7 8 9 This will tell the Articles table model that there is a join table associated with tags. The 'dependent' option tells the table to delete any associated records from the join table if an article is deleted. Lastly, update the findBySlug() method calls in **src/Controller/ArticlesController.php**: public function edit($slug) { // Update this line $article = $this->Articles->findBySlug($slug)->contain(['Tags']) ->firstOrFail(); ... } public function view($slug = null) { // Update this line $article = $this->Articles->findBySlug($slug)->contain(['Tags']) ->firstOrFail(); $this->set(compact('article')); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 The contain() method tells the ArticlesTable object to also populate the Tags association when the article is loaded. Now when tag\_string is called for an Article entity, there will be data present to create the string! Next we'll be adding [authentication](https://book.cakephp.org/3.x/tutorials-and-examples/cms/authentication.html) . --- # Blog Tutorial - Authentication and Authorization | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples/blog-auth-example/auth.html#VPContent) Return to top Blog Tutorial - Authentication and Authorization [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog-auth-example/auth.html#blog-tutorial-authentication-and-authorization) ===================================================================================================================================================================================== Following our [Blog Tutorial](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html) example, imagine we wanted to secure access to certain URLs, based on the logged-in user. We also have another requirement: to allow our blog to have multiple authors who can create, edit, and delete their own articles while disallowing other authors from making changes to articles they do not own. Creating All User-Related Code [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog-auth-example/auth.html#creating-all-user-related-code) --------------------------------------------------------------------------------------------------------------------------------------------------- First, let's create a new table in our blog database to hold our users' data: CREATE TABLE users ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50), password VARCHAR(255), role VARCHAR(20), created DATETIME DEFAULT NULL, modified DATETIME DEFAULT NULL ); 1 2 3 4 5 6 7 8 We have adhered to the CakePHP conventions in naming tables, but we're also taking advantage of another convention: By using the username and password columns in a users table, CakePHP will be able to auto-configure most things for us when implementing the user login. Next step is to create our UsersTable class, responsible for finding, saving and validating any user data: // src/Model/Table/UsersTable.php namespace App\Model\Table; use Cake\ORM\Table; use Cake\Validation\Validator; class UsersTable extends Table { public function validationDefault(Validator $validator) { return $validator ->notEmpty('username', 'A username is required') ->notEmpty('password', 'A password is required') ->notEmpty('role', 'A role is required') ->add('role', 'inList', [\ 'rule' => ['inList', ['admin', 'author']],\ 'message' => 'Please enter a valid role'\ ]); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Let's also create our UsersController. The following content corresponds to parts of a basic baked UsersController class using the code generation utilities bundled with CakePHP: // src/Controller/UsersController.php namespace App\Controller; use App\Controller\AppController; use Cake\Event\Event; class UsersController extends AppController { public function beforeFilter(Event $event) { parent::beforeFilter($event); $this->Auth->allow('add'); } public function index() { $this->set('users', $this->Users->find('all')); } public function view($id) { $user = $this->Users->get($id); $this->set(compact('user')); } public function add() { $user = $this->Users->newEntity(); if ($this->request->is('post')) { // Prior to 3.4.0 $this->request->data() was used. $user = $this->Users->patchEntity($user, $this->request->getData()); if ($this->Users->save($user)) { $this->Flash->success(__('The user has been saved.')); return $this->redirect(['action' => 'add']); } $this->Flash->error(__('Unable to add the user.')); } $this->set('user', $user); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 In the same way we created the views for our articles by using the code generation tool, we can implement the user views. For the purpose of this tutorial, we will show just the add.ctp:
Form->create($user) ?>
Form->control('username') ?> Form->control('password') ?> Form->control('role', [\ 'options' => ['admin' => 'Admin', 'author' => 'Author']\ ]) ?>
Form->button(__('Submit')); ?> Form->end() ?>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Authentication (Login and Logout) [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog-auth-example/auth.html#authentication-login-and-logout) ------------------------------------------------------------------------------------------------------------------------------------------------------- We're now ready to add our authentication layer. In CakePHP this is handled by the `Cake\Controller\Component\AuthComponent`, a class responsible for requiring login for certain actions, handling user login and logout, and also authorizing logged-in users to the actions they are allowed to reach. To add this component to your application open your **src/Controller/AppController.php** file and add the following lines: // src/Controller/AppController.php namespace App\Controller; use Cake\Controller\Controller; use Cake\Event\Event; class AppController extends Controller { //... public function initialize() { $this->loadComponent('Flash'); $this->loadComponent('Auth', [\ 'loginRedirect' => [\ 'controller' => 'Articles',\ 'action' => 'index'\ ],\ 'logoutRedirect' => [\ 'controller' => 'Pages',\ 'action' => 'display',\ 'home'\ ]\ ]); } public function beforeFilter(Event $event) { $this->Auth->allow(['index', 'view', 'display']); } //... } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 There is not much to configure, as we used the conventions for the users table. We just set up the URLs that will be loaded after the login and logout actions is performed, in our case to `/articles/` and `/` respectively. What we did in the `beforeFilter()` function was to tell the AuthComponent to not require a login for all `index()` and `view()` actions, in every controller. We want our visitors to be able to read and list the entries without registering in the site. Now, we need to be able to register new users, save their username and password, and more importantly, hash their password so it is not stored as plain text in our database. Let's tell the AuthComponent to let un-authenticated users access the users add function and implement the login and logout action: // src/Controller/UsersController.php namespace App\Controller; use App\Controller\AppController; use Cake\Event\Event; class UsersController extends AppController { // Other methods.. public function beforeFilter(Event $event) { parent::beforeFilter($event); // Allow users to register and logout. // You should not add the "login" action to allow list. Doing so would // cause problems with normal functioning of AuthComponent. $this->Auth->allow(['add', 'logout']); } public function login() { if ($this->request->is('post')) { $user = $this->Auth->identify(); if ($user) { $this->Auth->setUser($user); return $this->redirect($this->Auth->redirectUrl()); } $this->Flash->error(__('Invalid username or password, try again')); } } public function logout() { return $this->redirect($this->Auth->logout()); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 Password hashing is not done yet, we need an Entity class for our User in order to handle its own specific logic. Create the **src/Model/Entity/User.php** entity file and add the following: // src/Model/Entity/User.php namespace App\Model\Entity; use Cake\Auth\DefaultPasswordHasher; use Cake\ORM\Entity; class User extends Entity { // Make all fields mass assignable except for primary key field "id". protected $_accessible = [\ '*' => true,\ 'id' => false\ ]; // ... protected function _setPassword($password) { if (strlen($password) > 0) { return (new DefaultPasswordHasher)->hash($password); } } // ... } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Now every time the password property is assigned to the user it will be hashed using the `DefaultPasswordHasher` class. We're just missing a template view file for the login function. Open up your **src/Template/Users/login.ctp** file and add the following lines:
Flash->render() ?> Form->create() ?>
Form->control('username') ?> Form->control('password') ?>
Form->button(__('Login')); ?> Form->end() ?>
1 2 3 4 5 6 7 8 9 10 11 12 13 You can now register a new user by accessing the `/users/add` URL and log in with the newly created credentials by going to `/users/login` URL. Also, try to access any other URL that was not explicitly allowed such as `/articles/add`, you will see that the application automatically redirects you to the login page. And that's it! It looks too simple to be true. Let's go back a bit to explain what happened. The `beforeFilter()` function is telling the AuthComponent to not require a login for the `add()` action in addition to the `index()` and `view()` actions that were already allowed in the AppController's `beforeFilter()` function. The `login()` action calls the `$this->Auth->identify()` function in the AuthComponent, and it works without any further config because we are following conventions as mentioned earlier. That is, having a Users table with a username and a password column, and use a form posted to a controller with the user data. This function returns whether the login was successful or not, and in the case it succeeds, then we redirect the user to the configured redirection URL that we used when adding the AuthComponent to our application. The logout works by just accessing the `/users/logout` URL and will redirect the user to the configured logoutUrl formerly described. This URL is the result of the `AuthComponent::logout()` function on success. Authorization (who's allowed to access what) [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog-auth-example/auth.html#authorization-who-s-allowed-to-access-what) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- As stated before, we are converting this blog into a multi-user authoring tool, and in order to do this, we need to modify the articles table a bit to add the reference to the Users table: ALTER TABLE articles ADD COLUMN user_id INT(11); 1 Also, a small change in the ArticlesController is required to store the currently logged in user as a reference for the created article: // src/Controller/ArticlesController.php public function add() { $article = $this->Articles->newEntity(); if ($this->request->is('post')) { // Prior to 3.4.0 $this->request->data() was used. $article = $this->Articles->patchEntity($article, $this->request->getData()); // Added this line $article->user_id = $this->Auth->user('id'); // You could also do the following //$newData = ['user_id' => $this->Auth->user('id')]; //$article = $this->Articles->patchEntity($article, $newData); if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to add your article.')); } $this->set('article', $article); // Just added the categories list to be able to choose // one category for an article $categories = $this->Articles->Categories->find('treeList'); $this->set(compact('categories')); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 The `user()` function provided by the component returns any column from the currently logged in user. We used this method to add the data into the request info that is saved. Let's secure our app to prevent some authors from editing or deleting the others' articles. Basic rules for our app are that admin users can access every URL, while normal users (the author role) can only access the permitted actions. Again, open the AppController class and add a few more options to the Auth config: // src/Controller/AppController.php public function initialize() { $this->loadComponent('Flash'); $this->loadComponent('Auth', [\ 'authorize' => ['Controller'], // Added this line\ 'loginRedirect' => [\ 'controller' => 'Articles',\ 'action' => 'index'\ ],\ 'logoutRedirect' => [\ 'controller' => 'Pages',\ 'action' => 'display',\ 'home'\ ]\ ]); } public function isAuthorized($user) { // Admin can access every action if (isset($user['role']) && $user['role'] === 'admin') { return true; } // Default deny return false; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 We just created a simple authorization mechanism. Users with the `admin` role will be able to access any URL in the site when logged-in. All other users -- those with the `author` role -- will have the same access as users who aren't logged-in. This is not exactly what we want. We need to supply more rules to our `isAuthorized()` method. However instead of doing it in AppController, we'll delegate supplying those extra rules to each individual controller. The rules we're going to add to ArticlesController should permit authors to create articles but prevent authors from editing articles they do not own. Add the following content to your **ArticlesController.php**: // src/Controller/ArticlesController.php public function isAuthorized($user) { // All registered users can add articles // Prior to 3.4.0 $this->request->param('action') was used. if ($this->request->getParam('action') === 'add') { return true; } // The owner of an article can edit and delete it // Prior to 3.4.0 $this->request->param('action') was used. if (in_array($this->request->getParam('action'), ['edit', 'delete'])) { // Prior to 3.4.0 $this->request->params('pass.0') $articleId = (int)$this->request->getParam('pass.0'); if ($this->Articles->isOwnedBy($articleId, $user['id'])) { return true; } } return parent::isAuthorized($user); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 We're now overriding the AppController's `isAuthorized()` call and internally checking if the parent class is already authorizing the user. If he isn't, then just allow him to access the add action, and conditionally access edit and delete. One final thing has not been implemented. To tell whether or not the user is authorized to edit the article, we're calling a `isOwnedBy()` function in the Articles table. Let's then implement that function: // src/Model/Table/ArticlesTable.php public function isOwnedBy($articleId, $userId) { return $this->exists(['id' => $articleId, 'user_id' => $userId]); } 1 2 3 4 5 6 This concludes our simple authentication and authorization tutorial. For securing the UsersController you can follow the same technique we did for ArticlesController. You could also be more creative and code something more general in AppController based on your own rules. Should you need more control, we suggest you read the complete Auth guide in the [AuthComponent](https://book.cakephp.org/3.x/controllers/components/authentication.html) section where you will find more about configuring the component, creating custom Authorization classes, and much more. ### Suggested Follow-up Reading [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog-auth-example/auth.html#suggested-follow-up-reading) 1. [Code Generation with Bake](https://book.cakephp.org/3.x/bake/usage.html) Generating basic CRUD code 2. [AuthComponent](https://book.cakephp.org/3.x/controllers/components/authentication.html) : User registration and login --- # Form | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/views/helpers/form.html#VPContent) Return to top Form [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#form) ======================================================================= `class` Cake\\View\\Helper\\**FormHelper**(View $view, array $config = \[\]) FormHelper は、フォーム作成時の力作業のほとんどを代行してくれます。 FormHelper は、フォームを素早く作成し、検証、再配置、レイアウトを効率化します。 FormHelper は、柔軟でもあります。通常は規約に沿ってほとんどのことをやってくれますが、 特定のメソッドを使って必要な機能だけを使うこともできます。 フォームの開始 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AE%E9%96%8B%E5%A7%8B) ------------------------------------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\FormHelper::**create**(mixed $context = null, array $options = \[\]) * `$context` - フォームが定義されているコンテキスト。 ORM エンティティー、 ORM 結果セット、 メタデータの配列もしくは `false/null` (モデルのないフォームを作成するため) です。 * `$options` - オプションまたは HTML 属性の配列。 FormHelper を活用するために最初に使うメソッドは `create()` です。 このメソッドは、フォームの開始タグを出力します。 パラメーターはすべてオプションです。 `create()` が、パラメーターなしで呼ばれた場合、 現在の URL を元に現在のコントローラーに送信するためのフォームを作ろうとしているものとみなします。 フォーム送信のためのデフォルトのメソッドは POST です。 `UsersController::add()` のビューの中で `create()` を呼んだ場合、描画されたビューの中で次のような出力が表示されます。
1 `$context` 引数は、フォームの「コンテキスト」として使用されます。 いくつかの組み込みフォームのコンテキストがあり、独自に追加することができます。次のセクションで説明します。 組み込みのプロバイダーは、 `$context` の次の値とマップします。 * `Entity` インスタンスまたはイテレーターは、 [EntityContext](https://api.cakephp.org/3.x/class-Cake.View.Form.EntityContext.html) にマップされます。このコンテキストは、FormHelper が組み込みの ORM の結果を処理できるようにします。 * `schema` キーを含む配列は、 [ArrayContext](https://api.cakephp.org/3.x/class-Cake.View.Form.ArrayContext.html) にマップされます。これは単純なデータ構造を作成してフォームを構築することができます。 * `null` と `false` は、 [NullContext](https://api.cakephp.org/3.x/class-Cake.View.Form.NullContext.html) にマップされます。 このコンテキストクラスは、FormHelper が必要とするインターフェイスを単に満たすだけです。 このコンテキストは、ORM の永続性を必要としない短いフォームを作成したい場合に便利です。 すべてのコンテキストクラスは、リクエストデータにアクセスできるため、フォームを簡単に作成できます。 コンテキストを持ったフォームが作成されると、作成したすべてのコントロールはアクティブなコンテキストを使用します。 ORM バックエンドフォームの場合、FormHelper は関連データ、検証エラー、およびスキーマメタデータに アクセスできます。 `end()` メソッドを使用したり、再度 `create()` を呼び出すことによって、 アクティブなコンテキストを閉じることができます。 エンティティーのフォームを作成するには、次の手順を実行します。 : // /articles/add において // $article は、空の Article エンティティーである必要があります。 echo $this->Form->create($article); 1 2 3 出力結果: 1 これは ArticlesController の `add()` アクションにフォームデータを POST します。 また、編集フォームを作成するために、同じロジックを使用することができます。 FormHelper は、 _追加_ または _編集_ のフォームを作成するかどうかを自動的に検出するために、 `Entity` オブジェクトを使用します。 提供されたエンティティーが「新しくない」場合は、 _編集_ フォームとして作成されます。 例えば、 **[http://example.org/articles/edit/5](http://example.org/articles/edit/5) ** を閲覧すると、次のことができます。 : // src/Controller/ArticlesController.php: public function edit($id = null) { if (empty($id)) { throw new NotFoundException; } $article = $this->Articles->get($id); // 保存ロジックがここに入ります $this->set('article', $article); } // View/Articles/edit.ctp: // $article->isNew() は false なので、編集フォームが得られます Form->create($article) ?> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 出力結果: 1 2 NOTE これは _編集_ フォームなので、デフォルトの HTTP メソッドを上書きするために hidden `input` フィールドが生成されます。 場合によっては、フォームの `action` の URL の最後にエンティティーの ID が自動的に付加されます。 URL に ID が付加されることを避けたい場合、 `$options['url']` に `'/my-acount'` や `\Cake\Routing\Router::url(['controller' => 'Users', 'action' => 'myAccount'])` のように文字列を渡すことができます。 ### フォーム作成のためのオプション [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E4%BD%9C%E6%88%90%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%82%AA%E3%83%95%E3%82%9A%E3%82%B7%E3%83%A7%E3%83%B3) `$options` 配列は、ほとんどのフォーム設定が行われる場所です。この特別な配列には、 form タグの生成方法に影響を与えるさまざまなキーと値のペアが含まれます。 有効な値: * `'type'` - 作成するフォームの種類を選択できます。type が未指定の場合、 フォームコンテキストに基づいて自動的に決まります。 有効な値: * `'get'` - フォームの method に HTTP GET を設定します。 * `'file'` - フォームの method に POST を設定し、 `enctype` に "multipart/form-data" を設定します。 * `'post'` - method に POST を設定します。 * `'put', 'delete', 'patch'` - フォームの送信時に、HTTP メソッドを PUT、 DELETE もしくは PATCH に上書きします。 * `'method'` - 有効な値は、上記と同じです。フォームの method を明示的に上書きできます。 * `'url'` - フォームを送信する URL を指定します。文字列および URL 配列を指定できます。 * `'encoding'` - フォームに `accept-charset` エンコーディングをセットします。 デフォルトは、 `Configure::read('App.encoding')` です。 * `'enctype'` - 明示的にフォームのエンコーディングをセットできます。 * `'templates'` - このフォームで使用したいテンプレート。指定したテンプレートは、 既に読み込まれたテンプレートの上にマージされます。 `/config` のファイル名 (拡張子を除く) か、 使用したいテンプレートの配列のいずれかを指定します。 * `'context'` - フォームコンテキストクラスの追加オプション。(例えば、 `EntityContext` は、フォームのベースとなる特定の Table クラスを設定するための `'table'` オプションを受け付けます。) * `'idPrefix'` - 生成された ID 属性のプレフィックス。 * `'templateVars'` - `formStart` テンプレートのためのテンプレート変数を提供することができます。 * `autoSetCustomValidity` - コントロールの HTML5 検証メッセージでカスタム必須および notBlank 検証メッセージを使用するには、 `true` を設定します。デフォルトは `false` です。 TIP 上記のオプションの他に、 `$options` 引数の中で、 作成した `form` 要素に渡したい 有効な HTML 属性を指定できます。 ### クエリー文字列からフォームの値を取得 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%AF%E3%82%A8%E3%83%AA%E3%83%BC%E6%96%87%E5%AD%97%E5%88%97%E3%81%8B%E3%82%89%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AE%E5%80%A4%E3%82%92%E5%8F%96%E5%BE%97) Added in version 3.4.0 FormHelper の値ソースは、input タグなどの描画される要素がどこから値を受け取るかを定義します。 デフォルトでは、FormHelper は、「コンテキスト」をもとにその値を描画します。 `EntityContext` などのデフォルトのコンテキストは、現在のエンティティーや `$request->getData()` からデータを取得します。 しかし、クエリー文字列から読み込む必要があるフォームを構築している場合は、 `FormHelper` の `valueSource()` を使って、どこから入力データを読み込むかを変更できます。 : // コンテキストでクエリー文字列の優先順位をつける echo $this->Form->create($article, [\ 'valueSources' => ['query', 'context']\ ]); // 同じ効果: echo $this->Form ->setValueSources(['query', 'context']) ->create($articles); // クエリー文字列からのみのデータの読み取り echo $this->Form->create($article); $this->Form->setValueSources('query'); // 同じ効果: echo $this->Form->create($article, ['valueSources' => 'query']); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 サポートするソースは、 `context`, `data` そして `query` です。 単一または複数のソースを使用できます。 `FormHelper` によって生成されたウィジェットは 設定した順序でソースから値を集めます。 `end()` が呼ばれた時、値ソースはデフォルト (`['context']`) にリセットされます。 ### フォームの HTTP メソッドを変更 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AE-http-%E3%83%A1%E3%82%BD%E3%83%83%E3%83%88%E3%82%99%E3%82%92%E5%A4%89%E6%9B%B4) `type` オプションを使用することにより、フォームが使用する HTTP メソッドを変更することができます。 : echo $this->Form->create($article, ['type' => 'get']); 1 出力結果: 1 `type` の値に `'file'` を指定すると、フォームの送信方法は、'POST' に変更し、form タグに "multipart/form-data" の `enctype` が含まれます。 これは、フォーム内部に file 要素がある場合に使用されます。 適切な `enctype` 属性が存在しない場合は、ファイルのアップロードが機能しない原因となります。 例: echo $this->Form->create($article, ['type' => 'file']); 1 出力結果: 1 `'type'` の値として `'put'` 、 `'patch'` または `'delete'` を使用すると、 フォームは機能的に 'post' フォームに相当しますが、送信されると、HTTP リクエストメソッドは、 それぞれ 'PUT'、 'PATCH' または 'DELETE' で上書きされます。 これで、CakePHP は、ウェブブラウザーで適切な REST サポートをエミュレートすることができます。 ### フォームの URL を設定 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%81%AE-url-%E3%82%92%E8%A8%AD%E5%AE%9A) `url` オプションを使うと、フォームを現在のコントローラーやアプリケーションの別のコントローラーの 特定のアクションに向けることができます。 例えば、フォームを現在のコントローラーの `publish()` アクションに向けるには、次のような `$options` 配列を与えます。 : echo $this->Form->create($article, ['url' => ['action' => 'publish']]); 1 出力結果: 1 目的のフォームアクションが現在のコントローラーにない場合は、フォームアクションの完全な URL を指定できます。 出力される URL は CakePHP アプリケーションに対する相対になります。 : echo $this->Form->create(null, [\ 'url' => [\ 'controller' => 'Articles',\ 'action' => 'publish'\ ]\ ]); 1 2 3 4 5 6 出力結果: 1 または外部ドメインを指定することができます。 : echo $this->Form->create(null, [\ 'url' => 'https://www.google.com/search',\ 'type' => 'get'\ ]); 1 2 3 4 出力結果: 1 フォームアクションに URL を出力したくない場合、 `'url' => false` を使用してください。 ### カスタムバリデーターの利用 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%8F%E3%82%99%E3%83%AA%E3%83%86%E3%82%99%E3%83%BC%E3%82%BF%E3%83%BC%E3%81%AE%E5%88%A9%E7%94%A8) 多くの場合、モデルには複数の検証セットがあり、コントローラーアクションが適用される 特定の検証ルールに基づいて必要なフィールドに FormHelper を設定する必要があります。 たとえば、Users テーブルには、アカウントの登録時にのみ適用される特定の検証ルールがあります。 : echo $this->Form->create($user, [\ 'context' => ['validator' => 'register']\ ]); 1 2 3 上記では `UsersTable::validationRegister()` で定義されている `register` バリデーターの中で定義されたルールを `$user` と関連するすべてのアソシエーションに使用します。 関連付けられたエンティティーのフォームを作成する場合は、配列を使用して各アソシエーションの検証ルールを 定義できます。 : echo $this->Form->create($user, [\ 'context' => [\ 'validator' => [\ 'Users' => 'register',\ 'Comments' => 'default'\ ]\ ]\ ]); 1 2 3 4 5 6 7 8 上記は、ユーザーには `register` 、そしてユーザーのコメントには `default` を使用します。 ### コンテキストクラスの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E4%BD%9C%E6%88%90) 組み込みのコンテキストクラスは基本的なケースをカバーすることを目的としていますが、 異なる ORM を使用している場合は新しいコンテキストクラスを作成する必要があります。 このような状況では、 [Cake\\View\\Form\\ContextInterface](https://api.cakephp.org/3.x/class-Cake.View.Form.ContextInterface.html) を実装する必要があります。 このインターフェイスを実装すると、新しいコンテキストを FormHelper に追加することができます。 `View.beforeRender` イベントリスナーやアプリケーションビュークラスで行うのが最善の方法です。 : $this->Form->addContextProvider('myprovider', function ($request, $data) { if ($data['entity'] instanceof MyOrmClass) { return new MyProvider($request, $data); } }); 1 2 3 4 5 コンテキストのファクトリー関数では、正しいエンティティータイプのフォームオプションを確認するための ロジックを追加できます。一致する入力データが見つかった場合は、オブジェクトを返すことができます。 一致するものがない場合は null を返します。 フォームコントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\FormHelper::**control**(string $fieldName, array $options = \[\]) * `$fieldName` - `'Modelname.fieldname'` の形式のフィールド名。 * `$options` - [Control Specific Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#control-specific-options) や (様々な HTML 要素を生成するために `control()` が内部的に使用する) 他のメソッドのオプション、および有効な HTML 属性を 含むオプション配列。 `control()` メソッドを使うと完全なフォームコントロールを生成できます。これらのコントロールには、 必要に応じて、囲い込む `div` 、 `label` 、コントロールウィジェット、および検証エラーが含まれます。 フォームコンテキストでメタデータを使用することにより、このメソッドは各フィールドに適切な コントロールタイプを選択します。内部的に `control()` は FormHelper の他のメソッドを使います。 TIP `control()` メソッドによって生成されたフィールドは、このページでは一般的に "入力" と呼ばれますが、技術的にいえば、 `control()` メソッドは、 HTML の `input` 型の要素だけでなく、他の HTML フォーム要素 (`select` 、 `button` 、 `textarea` など) も生成できることに注意してください。 デフォルトでは、 `control()` メソッドは、次のウィジェットテンプレートを使用します。 : 'inputContainer' => '
{{content}}
' 'input' => '' 1 2 検証エラーが発生した場合は、以下も使われます。 : 'inputContainerError' => '
{{content}}{{error}}
' 1 作成されたコントロールの型(生成された要素タイプを指定する追加のオプションを指定しない場合)は、 モデルの内部で推測され、列のデータ型に依存します。 作成されるコントロールの型は、カラムのデータ型に依存します。 カラムの型 得られたフォームのフィールド string, uuid (char, varchar, その他) text boolean, tinyint(1) checkbox decimal number float number integer number text textarea text で、名前が password, passwd password text で、名前が email email text で、名前が tel, telephone, または phone tel date day, month, および year の select datetime, timestamp day, month, year, hour, minute, および meridian の select time hour, minute, および meridian の select binary file `$options` パラメーターを使うと、必要な場合に特定のコントロールタイプを選択することができます。 : echo $this->Form->control('published', ['type' => 'checkbox']); 1 TIP とても些細なことですが、 `control()` フォームメソッドを使用して特定の要素を生成すると、 デフォルトでは `div` の囲い込みが常に生成されます。特定のフォームメソッド(例えば `$this->Form->checkbox('published');` )を使用して同じタイプの要素を生成すると、 ほとんどの場合、 `div` の囲い込みが生成されません。 あなたのニーズに応じて、どちらかを使うことができます。 モデルのフィールドの検証ルールで入力が必須であり、空を許可しない場合は、囲い込む `div` は、 クラス名に `required` が追加されます。 `required` オプションを使用して自動的に必須フラグを無効にすることができます。 : echo $this->Form->control('title', ['required' => false]); 1 フォーム全体のブラウザー検証トリガーをスキップするには、 `Cake\View\Helper\FormHelper::submit()` を使って生成する入力ボタンに対して `'formnovalidate' => true` オプションを設定したり、 `Cake\View\Helper\FormHelper::create()` のオプションで `'novalidate' => true` を設定できます。 たとえば、Users モデルに _username_ (varchar), _password_ (varchar), _approved_ (datetime) および _quote_ (text) のフィールドがあるとします。FormHelper の `control()` メソッドを使用すると、 これらのフォームフィールドすべてに適切なコントロールを作成できます。 : echo $this->Form->create($user); // 以下は、テキスト入力を生成します echo $this->Form->control('username'); // 以下は、パスワード入力を生成します echo $this->Form->control('password'); // 'approved' を datetime か timestamp フィールドとみなし、 // 以下は、日・月・年・時・分を生成します echo $this->Form->control('approved'); // 以下は、テキストエリア要素を生成します echo $this->Form->control('quote'); echo $this->Form->button('Add'); echo $this->Form->end(); 1 2 3 4 5 6 7 8 9 10 11 12 13 日付フィールドのいくつかのオプションを示すより広範な例: echo $this->Form->control('birth_dt', [\ 'label' => '生年月日',\ 'minYear' => date('Y') - 70,\ 'maxYear' => date('Y') - 18,\ ]); 1 2 3 4 5 特定の [Control Specific Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#control-specific-options) に加えて、選択された (または CakePHP によって推論された) コントロールタイプや HTML 属性 (例えば `onfocus`) に対応する特定のメソッドによって 受け入れられるオプションを指定することができます。 _belongsTo_ または _hasOne_ を使用していて `select` フィールドを作成する場合は、 Users コントローラーに次のものを追加できます(User _belongsTo_ Group を前提とします)。 : $this->set('groups', $this->Users->Groups->find('list')); 1 その後、ビューテンプレートに以下を追加します。 : echo $this->Form->control('group_id', ['options' => $groups]); 1 _belongsToMany_ で関連付く Groups の `select` ボックスを作成するには、 UsersController に以下を追加します。 : $this->set('groups', $this->Users->Groups->find('list')); 1 その後、ビューテンプレートに以下を追加します。 : echo $this->Form->control('groups._ids', ['options' => $groups]); 1 モデル名が2つ以上の単語 (たとえば "UserGroup") で構成されている場合、 `set()` を使用してデータを渡すときは、データを次のように複数形と [ローワーキャメルケース](https://en.wikipedia.org/wiki/Camel_case#Variations_and_synonyms) で名前を付ける必要があります。 : $this->set('userGroups', $this->UserGroups->find('list')); 1 NOTE 送信ボタンを生成するために `FormHelper::control()` を使用しないでください。 代わりに `Cake\View\Helper\FormHelper::submit()` を使用してください。 ### フィールドの命名規則 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%88%E3%82%99%E3%81%AE%E5%91%BD%E5%90%8D%E8%A6%8F%E5%89%87) コントロールウィジェットを作成するときは、フィールドの名前をフォームのエンティティーに一致する属性の後に 指定する必要があります。たとえば、 `$article` エンティティーのフォームを作成した場合、 そのプロパティーの名前を付けたフィールドを作成します。例えば `title` 、 `body` と `published` 。 `association.fieldname` を最初のパラメーターとして渡すことで、関連するモデルや任意のモデルの コントロールを作成できます。 : echo $this->Form->control('association.fieldname'); 1 フィールド名のドットは、ネストされたリクエストデータに変換されます。 たとえば、 `0.comments.body` という名前のフィールドを作成した場合、 `0[comments][body]` のような名前属性が得られます。 この規則により、ORM でデータを簡単に保存できます。 さまざまなアソシエーションタイプの詳細は、 [Associated Form Inputs](https://book.cakephp.org/3.x/ja/views/helpers/form.html#associated-form-inputs) セクションにあります。 datetime に関連するコントロールを作成する場合、FormHelper はフィールドのサフィックスを追加します。 `year` 、 `month` 、 `day` 、 `hour` 、 `minute` 、または `meridian` というフィールドが追加されていることがあります。エンティティーがマーシャリングされると、 これらのフィールドは自動的に `DateTime` オブジェクトに変換されます。 ### コントロールのオプション [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E3%82%AA%E3%83%95%E3%82%9A%E3%82%B7%E3%83%A7%E3%83%B3) `FormHelper::control()` は、その `$options` 引数を通して、多数のオプションをサポートしています。 `control()` 自身のオプションに加えて、生成されたコントロールタイプに対するオプションと HTML 属性を受け付けます。以下は `FormHelper::control()` で特有のオプションについて説明します。 * `$options['type']` - 生成するためのウィジェットタイプを指定する文字列。 [Automagic Form Elements](https://book.cakephp.org/3.x/ja/views/helpers/form.html#automagic-form-elements) にあるフィールド型に加えて、 `'file'` 、 `'password'` 、 および HTML5 でサポートされているすべてのタイプを作成することもできます。 `'type'` を指定することで、モデルの設定を上書きして、コントロールのタイプを強制することができます。 デフォルトは `null` 。 例: echo $this->Form->control('field', ['type' => 'file']); echo $this->Form->control('email', ['type' => 'email']); 1 2 出力結果:
1 2 3 4 5 6 7 8 * `$options['label']` - 文字列の見出しや [ラベルのオプション](https://book.cakephp.org/3.x/ja/views/helpers/form.html#create-label) の配列。 このキーは、通常は `input` HTML 要素に付随するラベル内に表示したい文字列に設定することができます。 デフォルトは `null` です。 例: echo $this->Form->control('name', [\ 'label' => 'The User Alias'\ ]); 1 2 3 出力結果:
1 2 3 4 あるいは、 `label` 要素の出力を無効にするには、このキーに `false` を設定します。 例: echo $this->Form->control('name', ['label' => false]); 1 出力結果:
1 2 3 これに配列を設定すると、 `label` 要素の追加オプションが提供されます。 これを行う場合、配列中の `text` キーを使ってラベルテキストをカスタマイズすることができます。 例: echo $this->Form->control('name', [\ 'label' => [\ 'class' => 'thingy',\ 'text' => 'The User Alias'\ ]\ ]); 1 2 3 4 5 6 出力結果:
1 2 3 4 * `$options['options']` - ここには、アイテムの配列を引数として必要とする `radio` や `select` のようなウィジェットのために、生成される要素を含む配列を提供することができます (詳細は、 [Create Radio Button](https://book.cakephp.org/3.x/ja/views/helpers/form.html#create-radio-button) と [Create Select Picker](https://book.cakephp.org/3.x/ja/views/helpers/form.html#create-select-picker) をご覧ください)。 デフォルトは、 `null` です。 * `$options['error']` - このキーを使用すると、デフォルトのモデルエラーメッセージを 無効にすることができ、たとえば国際化メッセージを設定するために使用できます。 エラーメッセージの出力とフィールドクラスを無効にするには、 `'error'` キーを `false` に設定してください。デフォルトは `null` 。 例: echo $this->Form->control('name', ['error' => false]); 1 モデルのエラーメッセージを上書きするには、 元の検証エラーメッセージと一致するキーを持つ配列を使用します。 例: $this->Form->control('name', [\ 'error' => ['Not long enough' => __('This is not long enough')]\ ]); 1 2 3 上記のように、モデルにある各検証ルールに対してエラーメッセージを設定することができます。 さらに、フォームに国際化メッセージを提供することもできます。 * `$options['nestedInput']` - チェックボックスとラジオボタンで使用。 input 要素を `label` 要素の内側か外側に生成するかどうかを制御します。 `control()` がチェックボックスやラジオボタンを生成する時、これに `false` を設定して、 `label` 要素の外側に HTML の `input` 要素を強制的に生成することができます。 一方、任意のコントロールタイプに対して、これを `true` に設定することで、 生成された input 要素をラベルの中に強制的に入れることができます。 これをラジオボタンで変更する場合は、デフォルトの [radioWrapper](https://book.cakephp.org/3.x/ja/views/helpers/form.html#create-radio-button) テンプレートも変更する必要があります。生成されるコントロールタイプによっては、 デフォルトが `true` や `false` になります。 * `$options['templates']` - この入力に使用するテンプレート。 指定したテンプレートは、既に読み込まれたテンプレートの上にマージされます。 このオプションは、ロードするテンプレートを含む `/config` のファイル名 (拡張子を除く) か、 使用するテンプレートの配列のいずれかです。 * `$options['labelOptions']` - これを `false` に設定すると nestedWidgets の周りのラベルを無効にします。または、 `label` タグに提供される属性の配列を設定します。 コントロールの特定のタイプを生成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E7%89%B9%E5%AE%9A%E3%81%AE%E3%82%BF%E3%82%A4%E3%83%95%E3%82%9A%E3%82%92%E7%94%9F%E6%88%90) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 汎用的な `control()` メソッドに加えて、 `FormHelper` には様々な種類の コントロールタイプを生成するために個別のメソッドがあります。 これらは、コントロールウィジェットそのものを生成するのに使えますが、 完全に独自のフォームレイアウトを生成するために `Cake\View\Helper\FormHelper::label()` や `Cake\View\Helper\FormHelper::error()` といった 他のメソッドを組み合わせることができます。 ### 特定のコントロールのための共通オプション [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E7%89%B9%E5%AE%9A%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E5%85%B1%E9%80%9A%E3%82%AA%E3%83%95%E3%82%9A%E3%82%B7%E3%83%A7%E3%83%B3) さまざまなコントロール要素メソッドは、共通のオプションをサポートしており、 使用されるフォームメソッドに応じて、 `$options` または `$attributes` 配列の引数の中に 指定する必要があります。これらのオプションはすべて、 `control()` でもサポートされています。 繰り返しを減らすために、すべてのコントロールメソッドで共有される共通オプションは次の通りです。 * `'id'` - このキーを設定すると、コントロールの DOM id の値が強制的に設定されます。 これにより、設定可能な `'idPrefix'` が上書きされます。 * `'default'` コントロールフィールドのデフォルト値を設定します。 この値は、フォームに渡されるデータにそのフィールドに関する値が含まれていない場合 (または、一切データが渡されない場合) に使われます。 明示的なデフォルト値は、スキーマで定義されたデフォルト値を上書きします。 使用例: echo $this->Form->text('ingredient', ['default' => 'Sugar']); 1 `select` フィールドを持つ例("Medium" サイズがデフォルトで選択されます) : $sizes = ['s' => 'Small', 'm' => 'Medium', 'l' => 'Large']; echo $this->Form->select('size', $sizes, ['default' => 'm']); 1 2 NOTE checkbox をチェックする目的では `default` は使えません。その代わり、コントローラーで `$this->request->getData()` の中の値をセットするか、またはコントロールオプションの `checked` を `true` にします。 デフォルト値への代入の際 `false` を使うのは注意が必要です。 `false` 値はコントロールフィールドのオプションを無効または除外するために使われます。 そのため `'default' => false` では値を全く設定しません。 代わりに `'default' => 0` を使用してください。 * `'value'` - コントロールフィールドに特定の値を設定するために使用します。 これは、Form、Entity、 `request->getData()` などのコンテキストから 注入される可能性のある値を上書きします。 NOTE コンテキストや valuesSource から値を取得しないようにフィールドを設定したい場合、 `'value'` を `''` に設定する必要があります (もしくは `null` に設定) 。 上記のオプションに加えて、任意の HTML 属性を混在させることができます。 特に規定のないオプション名は HTML 属性として扱われ、生成された HTML のコントロール要素に反映されます。 Changed in version 3.3.0 3.3.0 では、FormHelper は、自動的にデータベーススキーマで定義されたデフォルト値を使用します。 `schemaDefault` オプションを `false` に設定することで、この動作を無効にすることができます。 input 要素の作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#input-%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BD%9C%E6%88%90) ----------------------------------------------------------------------------------------------------------------------------- FormHelper で利用可能なメソッドには、さらに特定のフォーム要素を作成するためのものがあります。 これらのメソッドの多くでは、特別な `$options` や `$attributes` パラメーターを指定できます。 ただし、この場合、このパラメーターは主に (フォーム要素の DOM id の値のような) HTML タグの属性を 指定するために使われます。 ### テキスト入力の作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E5%85%A5%E5%8A%9B%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**text**(string $name, array $options) * `$name` - `'Modelname.fieldname'` の形式のフィールド名。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) や有効な HTML 属性を含むオプション配列。 シンプルな `text` 型の `input` HTML 要素を作成します。 例: echo $this->Form->text('username', ['class' => 'users']); 1 出力結果: 1 ### パスワード入力の作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%8F%E3%82%9A%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%88%E3%82%99%E5%85%A5%E5%8A%9B%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**password**(string $fieldName, array $options) * `$fieldName` - `'Modelname.fieldname'` の形式のフィールド名。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) や有効な HTML 属性を含むオプション配列。 シンプルな `password` 型の `input` 要素を作成します。 例: echo $this->Form->password('password'); 1 出力結果: 1 ### 非表示入力の作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E9%9D%9E%E8%A1%A8%E7%A4%BA%E5%85%A5%E5%8A%9B%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**hidden**(string $fieldName, array $options) * `$fieldName` - `'Modelname.fieldname'` の形式のフィールド名。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) や有効な HTML 属性を含むオプション配列。 非表示のフォーム入力を作成します。 例: echo $this->Form->hidden('id'); 1 出力結果: 1 ### テキストエリアの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%A8%E3%83%AA%E3%82%A2%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**textarea**(string $fieldName, array $options) * `$fieldName` - `'Modelname.fieldname'` の形式のフィールド名。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) やテキストエリア特有のオプション (下記参照) と、有効な HTML 属性を含むオプション配列。 textarea コントロールフィールドを作成します。使用されるデフォルトのウィジェットテンプレートは、 : 'textarea' => '' 1 例: echo $this->Form->textarea('notes'); 1 出力結果: 1 フォームが編集されると(すなわち、配列 `$this->request->getData()` に `User` モデルに渡すために保存された情報が含まれている場合)、生成される HTML には `notes` フィールドに対応する値が自動的に含まれます。 例: 1 2 3 **テキストエリアのオプション** [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) に加えて、 `textarea()` はいくつかの固有のオプションを サポートします。 * `'escape'` - テキストエリアの内容をエスケープするかどうかを指定します。 デフォルトは `true` です。 例: echo $this->Form->textarea('notes', ['escape' => false]); // もしくは.... echo $this->Form->control('notes', ['type' => 'textarea', 'escape' => false]); 1 2 3 * `'rows', 'cols'` - これらの2つのキーを使用して、 `textarea` フィールドの行数と列数を 指定する HTML 属性を設定することができます。 例: echo $this->Form->textarea('comment', ['rows' => '5', 'cols' => '5']); 1 出力結果: 1 2 ### セレクト、チェックボックス、ラジオコントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%BB%E3%83%AC%E3%82%AF%E3%83%88%E3%80%81%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%83%9B%E3%82%99%E3%83%83%E3%82%AF%E3%82%B9%E3%80%81%E3%83%A9%E3%82%B7%E3%82%99%E3%82%AA%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) これらのコントロールは、いくつかの共通点といくつかのオプションを共有し、 それらは簡単に参照するために、このサブセクションで全てグループ化します。 #### セレクト、チェックボックス、ラジオに関するオプション [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%BB%E3%83%AC%E3%82%AF%E3%83%88%E3%80%81%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%83%9B%E3%82%99%E3%83%83%E3%82%AF%E3%82%B9%E3%80%81%E3%83%A9%E3%82%B7%E3%82%99%E3%82%AA%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E3%82%AA%E3%83%95%E3%82%9A%E3%82%B7%E3%83%A7%E3%83%B3) `select()` 、 `checkbox()` そして `radio()` によって共有されるオプションは次の通りです。 (各メソッドの独自のセクションには、そのメソッド特有のオプションが記述されています。) * `'value'` - 影響を受ける要素の値を設定または選択します。 * チェックボックスの場合、 `input` 要素に割り当てられた HTML の `'value'` 属性を、 値として提供するものに設定します。 * ラジオボタンまたは選択ピッカーの場合は、フォームが描画されるときに選択される要素を定義します (この場合、 `'value'` は有効で存在する要素の値を割り当てなければなりません)。 `date()` 、 `time()` 、 `dateTime()` のようなセレクト型コントロールと 組み合わせて使用することもできます。 : echo $this->Form->time('close_time', [\ 'value' => '13:30:00'\ ]); 1 2 3 NOTE `date()` および `dateTime()` コントロールの `'value'` キーには、 UNIX タイムスタンプまたは DateTime オブジェクトを使用することもできます。 `multiple` 属性を `true` に設定した `select` コントロールでは、 デフォルトで選択したい値の配列を使うことができます。 : // 値に 1 と 3 を持つ HTML ' 1 2 以下も使用します。 : 'optgroup' => '{{content}}' 'selectMultiple' => '' 1 2 **選択ピッカーの属性** * `'multiple'` - `true` をセットすると、選択ピッカー内で複数選択ができます。 `'checkbox'` をセットすると、複数チェックボックスが代わりに作成されます。 デフォルトは `null` です。 * `'escape'` - ブール値。 `true` の場合、選択ピッカー内の `option` 要素の内容は エンコードされた HTML エンティティーになります。デフォルトは `true` です。 * `'val'` - 選択ピッカーで値を事前に選択できるようにします。 * `'disabled'` - `disabled` 属性を制御します。 `true` をセットした場合、選択ピッカー全体を無効にします。 配列をセットした場合、配列に含まれている値を持つ特定の `option` のみ無効にします。 `$options` 引数は、 `select` コントロールの `option` 要素の内容を手動で指定できます。 例: echo $this->Form->select('field', [1, 2, 3, 4, 5]); 1 出力結果: 1 2 3 4 5 6 7 `$options` の配列はキーと値のペアとしても指定することができます。 例: echo $this->Form->select('field', [\ 'Value 1' => 'Label 1',\ 'Value 2' => 'Label 2',\ 'Value 3' => 'Label 3'\ ]); 1 2 3 4 5 出力結果: 1 2 3 4 5 optgroup 付きで `select` を生成したい場合は、データを階層形式 (ネストした配列) で渡すだけです。 これは複数のチェックボックスとラジオボタンでも機能しますが、 `optgroup` の代わりに `fieldset` 要素で囲みます。 例: $options = [\ 'Group 1' => [\ 'Value 1' => 'Label 1',\ 'Value 2' => 'Label 2'\ ],\ 'Group 2' => [\ 'Value 3' => 'Label 3'\ ]\ ]; echo $this->Form->select('field', $options); 1 2 3 4 5 6 7 8 9 10 出力結果: 1 2 3 4 5 6 7 8 9 `option` タグ内で HTML 属性を生成するには: $options = [\ [ 'text' => 'Description 1', 'value' => 'value 1', 'attr_name' => 'attr_value 1' ],\ [ 'text' => 'Description 2', 'value' => 'value 2', 'attr_name' => 'attr_value 2' ],\ [ 'text' => 'Description 3', 'value' => 'value 3', 'other_attr_name' => 'other_attr_value' ],\ ]; echo $this->Form->select('field', $options); 1 2 3 4 5 6 出力結果: 1 2 3 4 5 **属性による選択ピッカーの制御** `$attributes` パラメーター内の特定のオプションを使用することにより、 `select()` メソッドの特定の振る舞いを制御することができます。 * `'empty'` - `$attributes` 引数の中で `'empty'` キーを `true` にセットすると (デフォルトの値は `false`)、ドロップダウンリストの先頭に空の値の空白オプションを追加できます。 例: $options = ['M' => 'Male', 'F' => 'Female']; echo $this->Form->select('gender', $options, ['empty' => true]); 1 2 出力結果: 1 2 3 4 5 * `'escape'` - `select()` メソッドは `'escape'` という属性が使用でき、 ブール値を受け取り、HTML エンティティーに select オプションの内容をエンコードするかどうかを決定します。 例: // これで、各オプション要素の内容の HTML エンコードを止められます $options = ['M' => 'Male', 'F' => 'Female']; echo $this->Form->select('gender', $options, ['escape' => false]); 1 2 3 * `'multiple'` - `true` にセットすると、選択ピッカーは複数選択ができます。 例: echo $this->Form->select('field', $options, ['multiple' => true]); 1 または、関連するチェックボックスのリストを出力するために `'multiple'` を `'checkbox'` に設定します。 : $options = [\ 'Value 1' => 'Label 1',\ 'Value 2' => 'Label 2'\ ]; echo $this->Form->select('field', $options, [\ 'multiple' => 'checkbox'\ ]); 1 2 3 4 5 6 7 出力結果:
1 2 3 4 5 6 7 8 9 10 11 12 13 * `'disabled'` - このオプションを設定して、すべてまたは一部の `select` の `option` 項目を 無効にすることができます。すべての項目を無効にするには、 `'disabled'` に `true` を 設定します。特定の項目のみを無効にするには、無効にする項目をキーに含む配列を `'disabled'` に 設定してください。 すべてのチェックボックスを無効にするには disabled を `true` にします。 例: $options = [\ 'M' => 'Masculine',\ 'F' => 'Feminine',\ 'N' => 'Neuter'\ ]; echo $this->Form->select('gender', $options, [\ 'disabled' => ['M', 'N']\ ]); 1 2 3 4 5 6 7 8 出力結果: 1 2 3 4 5 このオプションは `'multiple'` が `'checkbox'` に設定されている場合にも有効です。 : $options = [\ 'Value 1' => 'Label 1',\ 'Value 2' => 'Label 2'\ ]; echo $this->Form->select('field', $options, [\ 'multiple' => 'checkbox',\ 'disabled' => ['Value 1']\ ]); 1 2 3 4 5 6 7 8 出力結果:
1 2 3 4 5 6 7 8 9 10 11 12 13 ### ファイル入力の作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%85%A5%E5%8A%9B%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**file**(string $fieldName, array $options) * `$fieldName` - `'Modelname.fieldname'` の形式のフィールド名。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) や有効な HTML 属性を含むオプション配列。 フォームの中にファイルアップロードフィールドを作成します。 デフォルトで使用されるウィジェットテンプレートは: 'file' => '' 1 フォームにファイルアップロードフィールドを追加するためには、まずフォームの enctype に `'multipart/form-data'` がセットされていることを確認してください。 まずは、次のように `create()` メソッドを使用してください。 : echo $this->Form->create($document, ['enctype' => 'multipart/form-data']); // または echo $this->Form->create($document, ['type' => 'file']); 1 2 3 次にフォームのビューファイルに以下のいずれかを追加します。 : echo $this->Form->control('submittedfile', [\ 'type' => 'file'\ ]); // または echo $this->Form->file('submittedfile'); 1 2 3 4 5 6 NOTE HTML 自体の制限により、'file' タイプの入力フィールドにデフォルト値を設定することはできません。 フォームを表示するたびに、内部の値は空に設定されます。 フォームの送信に際して file フィールドは、フォームを受信しようとしているスクリプトに対して拡張された data 配列を提供します。 CakePHP が Windows サーバー上にインストールされている場合、上記の例について、 送信されるデータ配列内の値は次のように構成されます (Unix 環境では `'tmp_name'` が異なったパスになります)。 : $this->request->data['submittedfile'] // 次の配列を含みます: [\ 'name' => 'conference_schedule.pdf',\ 'type' => 'application/pdf',\ 'tmp_name' => 'C:/WINDOWS/TEMP/php1EE.tmp',\ 'error' => 0, // Windows の場合、文字列になります。\ 'size' => 41737,\ ]; 1 2 3 4 5 6 7 8 9 10 この配列は PHP 自身によって生成されます。PHP が file フィールドを通してデータを どう処理しているのかについては、 [PHP マニュアルのファイルアップロードのセクションをご覧ください](https://secure.php.net/features.file-upload) 。 NOTE `$this->Form->file()` を使う場合、 `$this->Form->create()` の中の `'type'` オプションを `'file'` に設定することで、フォームのエンコーディングのタイプを設定できます。 ### 日付と時刻に関するコントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E6%97%A5%E4%BB%98%E3%81%A8%E6%99%82%E5%88%BB%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) 日時関連の方法は、多くの共通の特性とオプションを共有しているため、 このサブセクションにまとめられています。 #### 日付と時刻のコントロールの共通オプション [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E6%97%A5%E4%BB%98%E3%81%A8%E6%99%82%E5%88%BB%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E5%85%B1%E9%80%9A%E3%82%AA%E3%83%95%E3%82%9A%E3%82%B7%E3%83%A7%E3%83%B3) これらのオプションは、日付と時刻に関するコントロールに共通します。 * `'empty'` - `true` の場合、余分の空の `option` HTML 要素が、 `select` の中のリストの先頭に追加されます。文字列の場合、 その文字列は空の要素として表示されます。デフォルトは `true` です。 * `'default'` | `value` - 2つのいずれかを使用して、 フィールドに表示されるデフォルト値を設定します。 フィールド名と一致する `$this->request->getData()` の値は、この値を上書きします。 デフォルトが指定されていない場合、 `time()` が使用されます。 - `'year', 'month', 'day', 'hour', 'minute', 'second', 'meridian'` -これらのオプションを使用すると、コントロール要素が生成されるかどうか制御できます。 これらのオプションを `false` にセットすることにより、特定の選択ピッカーの生成を 無効にすることができます (デフォルトでは、使用されたメソッドの中で描画されます) 。 さらに、各オプションでは、HTML 属性を指定した `select` 要素に渡すことができます。 #### 日付関連コントロールのオプション [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E6%97%A5%E4%BB%98%E9%96%A2%E9%80%A3%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E3%82%AA%E3%83%95%E3%82%9A%E3%82%B7%E3%83%A7%E3%83%B3) これらのオプションは、日付関連のメソッド、つまり `year()` 、 `month()` 、 `day()` 、 `dateTime()` そして `date()` に関連しています。 * `'monthNames'` - `false` の場合は、選択ピッカーの月の表示で テキストの代わりに2桁の数字が使用されます。配列をセットした場合 (例 `['01' => 'Jan', '02' => 'Feb', ...]`)、指定された配列が使用されます。 * `'minYear'` - 年の select フィールドで使用される最小の年。 * `'maxYear'` - 年の select フィールドで使用される最大の年。 * `'orderYear'` - 年選択ピッカー内の年の値の順序。 利用可能な値は `'asc'` と `'desc'` 。デフォルトは `'desc'` です。 * `'year', 'month', 'day'` - これらのオプションを使用すると、コントロール要素が生成されるかどうか制御できます。 これらのオプションを `false` にセットすることにより、特定の選択ピッカーの生成を 無効にすることができます (デフォルトでは、使用されたメソッドの中で描画されます) 。 さらに、各オプションでは、HTML 属性を指定した `select` 要素に渡すことができます。 #### 時刻関連コントロールのオプション [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E6%99%82%E5%88%BB%E9%96%A2%E9%80%A3%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E3%82%AA%E3%83%95%E3%82%9A%E3%82%B7%E3%83%A7%E3%83%B3) これらのオプションは、時刻関連のメソッド、 `hour()` 、 `minute()` 、 `second()` 、 `dateTime()` そして `time()` に関連しています。 * `'interval'` - 分選択ピッカーの `option` 要素の中に表示される分の値の間隔。 デフォルトは 1 です。 * `'round'` - 値が一定の間隔にきちんと収まらないときに、いずれかの方向に丸めるようにしたい場合は、 `up` または `down` に設定します。デフォルトは `null` です。 * `timeFormat` - `dateTime()` と `time()` に適用されます。 選択ピッカーで使用する時刻の書式は、 `12` または `24` のいずれかです。 このオプションに `24` 以外の何かをセットした場合、書式は自動的に `12` がセットされ、 秒選択ピッカーの右側に `meridian` 選択ピッカーが自動的に表示されます。 デフォルトは 24 です。 * `format` - `hour()` に適用されます。 選択ピッカーで使用する時刻の書式は、 `12` または `24` のいずれかです。 `12` をセットした場合、 `meridian` 選択ピッカーは自動的に表示されません。 それを追加するか、フォームコンテキストから適切な期間を推論する方法を提供するかは、 あなた次第です。デフォルトは 24 です。 * `second` - `dateTime()` と `time()` に適用されます。 秒を有効にするために `true` に設定します。デフォルトは `false` です。 * `'hour', 'minute', 'second', 'meridian'` - これらのオプションを使用すると、コントロール要素が生成されるかどうか制御できます。 これらのオプションを `false` にセットすることにより、特定の選択ピッカーの生成を 無効にすることができます (デフォルトでは、使用されたメソッドの中で描画されます) 。 さらに、各オプションでは、HTML 属性を指定した `select` 要素に渡すことができます。 #### 日時入力の作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E6%97%A5%E6%99%82%E5%85%A5%E5%8A%9B%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**dateTime**($fieldName, $options = \[\]) * `$fieldName` - `select` 要素の HTML `name` 属性のプレフィックスとして使用される文字列。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) または日時特有のオプション (下記参照)、 そして有効な HTML 属性を含むオプション配列。 日付と時刻の `select` 要素のセットを生成します。 コントロールの順序、およびコントロール間の要素/内容を制御するには、 `dateWidget` テンプレートを上書きします。デフォルトで `dateWidget` テンプレートは: {{year}}{{month}}{{day}}{{hour}}{{minute}}{{second}}{{meridian}} 1 オプションを指定せずにメソッドを呼び出すと、デフォルトでは、年(4桁)、月(英語の完全名)、 曜日(数値)、時間(数値)、分(数値)の5つの選択ピッカーが生成されます。 例: form->dateTime('registered') ?> 1 出力結果: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 特定の select ボックスにカスタムクラス/属性を含む datetime コントロールを作成するには、 `$options` 引数の中で各コンポーネントのオプションの配列として指定します。 例: echo $this->Form->dateTime('released', [\ 'year' => [\ 'class' => 'year-classname',\ ],\ 'month' => [\ 'class' => 'month-class',\ 'data-type' => 'month',\ ],\ ]); 1 2 3 4 5 6 7 8 9 これは、次の2つの選択ピッカーを作成します。 1 2 3 4 5 6 7 8 9 10 11 #### 日付コントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E6%97%A5%E4%BB%98%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**date**($fieldName, $options = \[\]) * `$fieldName` - `select` 要素の HTML `name` 属性のプレフィックスとして使用される文字列。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) 、 [Datetime Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#datetime-options) 、 適用可能な [Time Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#time-options) 、そして有効な HTML 属性を含むオプション配列。 デフォルトでは、年(4桁)、月(英語の完全名)、日(数値)の値が設定された 3つの選択ピッカーを作成します。 生成された `select` 要素をさらに制御するには、オプションを追加します。 例: // 今年が 2017 年だと仮定すると、これは日ピッカーを無効にし、年ピッカーの空の // オプションを削除し、最低年を制限し、年の HTML 属性を追加し、 // 月の文字列の 'empty' オプションを追加し、月を数値に変更します。 Form->date('registered', [\ 'minYear' => 2018,\ 'monthNames' => false, // 月は数字で表示されます。\ 'empty' => [\ 'year' => false, // 年選択コントロールは空の値のオプションを持ちません。\ 'month' => 'Choose month...' // しかしながら、月選択コントロールは持ちます。\ ],\ 'day' => false, // 日付選択コントールを表示しない。\ 'year' => [\ 'class' => 'cool-years',\ 'title' => 'Registration Year'\ ]\ ]); ?> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 出力結果: 1 2 3 4 5 6 7 8 9 10 11 12 #### 時間コントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E6%99%82%E9%96%93%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**time**($fieldName, $options = \[\]) * `$fieldName` - `select` 要素の HTML `name` 属性のプレフィックスとして使用される文字列。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) 、 [Datetime Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#datetime-options) 、 適用可能な [Time Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#time-options) 、そして有効な HTML 属性を含むオプション配列。 デフォルトでは、 24 時間と 60 分の値が入力された2つの `select` 要素 (`hour` と `minute`) を生成します。さらに、HTML 属性は、特定のコンポーネントごとに `$options` で指定することができます。 `$options['empty']` が `false` の場合、選択ピッカーは空のデフォルトオプションを含みません。 たとえば、15 分単位で選択できる時間範囲を作成し、各 select ボックスにクラスを適用するには、 次のようにします。 : echo $this->Form->time('released', [\ 'interval' => 15,\ 'hour' => [\ 'class' => 'foo-class',\ ],\ 'minute' => [\ 'class' => 'bar-class',\ ],\ ]); 1 2 3 4 5 6 7 8 9 これは、次の2つの選択ピッカーを作成します。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #### 年コントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E5%B9%B4%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**year**(string $fieldName, array $options = \[\]) * `$fieldName` - `select` 要素の HTML `name` 属性のプレフィックスとして使用される文字列。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) 、 [Datetime Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#datetime-options) 、 適用可能な [Time Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#time-options) 、そして有効な HTML 属性を含むオプション配列。 `minYear` から `maxYear` (これらのオプションが提供されているとき)、 または今日から数えて-5年から+5年までの値を持つ `select` 要素を作成します。 さらに、HTML 属性は、 `$options` で指定することができます。 `$options ['empty']` が `false` の場合、選択ピッカーはリスト内に空の項目を含みません。 たとえば、2000 年から今年までの年を作成するには、次のようにします。 : echo $this->Form->year('purchased', [\ 'minYear' => 2000,\ 'maxYear' => date('Y')\ ]); 1 2 3 4 2009 年だった場合は、次のようになるでしょう。 1 2 3 4 5 6 7 8 9 10 11 12 13 #### 月コントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E6%9C%88%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**month**(string $fieldName, array $attributes) * `$fieldName` - `select` 要素の HTML `name` 属性のプレフィックスとして使用される文字列。 * `$attributes` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) 、 [Datetime Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#datetime-options) 、 適用可能な [Time Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#time-options) 、そして有効な HTML 属性を含むオプション配列。 月の名前を列挙した `select` 要素を作成します。 例: echo $this->Form->month('mob'); 1 出力結果: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 `'monthNames'` 属性に独自の月の名前を配列で設定することもできます。 また `false` を指定すると、月が数字で表示されます。 例: echo $this->Form->month('mob', ['monthNames' => false]); 1 NOTE デフォルトの月は、CakePHP の [国際化と地域化](https://book.cakephp.org/3.x/ja/core-libraries/internationalization-and-localization.html) 機能でローカライズすることができます。 #### 日コントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E6%97%A5%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**day**(string $fieldName, array $attributes) * `$fieldName` - `select` 要素の HTML `name` 属性のプレフィックスとして使用される文字列。 * `$attributes` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) 、 [Datetime Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#datetime-options) 、 適用可能な [Time Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#time-options) 、そして有効な HTML 属性を含むオプション配列。 (数字の)日を列挙する `select` 要素を作成します。 あなたの選択した指示テキストで空の `option` を作成するには(たとえば、 最初のオプションは 'Day')、 `'empty'` パラメーターにテキストを指定できます。 例: echo $this->Form->day('created', ['empty' => 'Day']); 1 出力結果: 1 2 3 4 5 6 7 8 #### 時間コントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E6%99%82%E9%96%93%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90-1) `method` Cake\\View\\Helper\\FormHelper::**hour**(string $fieldName, array $attributes) * `$fieldName` - `select` 要素の HTML `name` 属性のプレフィックスとして使用される文字列。 * `$attributes` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) 、 [Datetime Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#datetime-options) 、 適用可能な [Time Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#time-options) 、そして有効な HTML 属性を含むオプション配列。 時を列挙した `select` 要素を作成します。 `format` オプションを使用して、12 時間または 24 時間のピッカーを作成することができます。 : echo $this->Form->hour('created', [\ 'format' => 12\ ]); echo $this->Form->hour('created', [\ 'format' => 24\ ]); 1 2 3 4 5 6 #### 分コントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E5%88%86%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**minute**(string $fieldName, array $attributes) * `$fieldName` - `select` 要素の HTML `name` 属性のプレフィックスとして使用される文字列。 * `$attributes` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) 、 [Datetime Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#datetime-options) 、 適用可能な [Time Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#time-options) 、そして有効な HTML 属性を含むオプション配列。 分の値を列挙した `select` 要素を作成します。 `interval` オプションを使用して特定の値のみを含む選択ピッカーを作成することができます。 たとえば、10 分ずつ増やしたい場合は、次のようにします。 : // ビューテンプレートファイルの中で echo $this->Form->minute('arrival', [\ 'interval' => 10\ ]); 1 2 3 4 これは、以下を出力します。 1 2 3 4 5 6 7 8 9 #### 午前と午後コントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E5%8D%88%E5%89%8D%E3%81%A8%E5%8D%88%E5%BE%8C%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**meridian**(string $fieldName, array $attributes) * `$fieldName` - `select` 要素の HTML `name` 属性のプレフィックスとして使用される文字列。 * `$attributes` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) と有効な HTML 属性を含むオプション配列。 'am' と 'pm' を列挙した `select` 要素を生成します。これは、時間の書式を `24` の代わりに `12` をセットした時に便利で、時間が属する期間を指定することができます。 ラベルの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%A9%E3%83%98%E3%82%99%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) ------------------------------------------------------------------------------------------------------------------------------------ `method` Cake\\View\\Helper\\FormHelper::**label**(string $fieldName, string $text, array $options) * `$fieldName` - `'Modelname.fieldname'` の形式のフィールド名。 * `$text` - ラベルの見出しテキストを指定するためのオプション文字列。 * `$options` - オプション。[General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) と有効な HTML 属性を含む配列。 `label` 要素を作成します。引数の `$fieldName` は、要素の HTML `for` 属性を 生成するために使われます。 `$text` が未定義の場合、 `$fieldName` はラベルの `text` 属性を変えるために使われます。 例: echo $this->Form->label('name'); echo $this->Form->label('name', 'Your username'); 1 2 出力結果: 1 2 第3パラメーター `$options` に id や class を設定できます。 : echo $this->Form->label('name', null, ['id' => 'user-label']); echo $this->Form->label('name', 'Your username', ['class' => 'highlight']); 1 2 出力結果: 1 2 エラーの表示と確認 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E8%A1%A8%E7%A4%BA%E3%81%A8%E7%A2%BA%E8%AA%8D) --------------------------------------------------------------------------------------------------------------------------------------------------------- FormHelper は、フィールドエラーを簡単にチェックしたり、必要に応じてカスタマイズされた エラーメッセージを表示できる、いくつかのメソッドを公開しています。 ### エラーの表示 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E8%A1%A8%E7%A4%BA) `method` Cake\\View\\Helper\\FormHelper::**error**(string $fieldName, mixed $text, array $options) * `$fieldName` - `'Modelname.fieldname'` の形式のフィールド名。 * `$text` - オプション。エラーメッセージを提供する文字列または配列。 配列の場合、 キー名 => メッセージのハッシュになります。デフォルトは `null` 。 * `$options` - `'escape'` キーのブール値のみを含みます。これは、 エラーメッセージの内容を HTML エスケープするかどうかを定義します。デフォルトは `true` です。 検証エラーが発生した際に、与えられたフィールドの `$text` で指定された、 検証エラーメッセージを表示します。フィールドの `$text` がない場合、 そのフィールドのデフォルトの検証エラーメッセージが使用されます。 次のテンプレートウィジェットを使います。 : 'error' => '
{{content}}
' 'errorList' => '
    {{content}}
' 'errorItem' => '
  • {{text}}
  • ' 1 2 3 `'errorList'` と `'errorItem'` テンプレートは、1つのフィールドに複数の エラーメッセージを書式化するために使用されます。 例: // TicketsTable に 'notEmpty' 検証ルールがある場合: public function validationDefault(Validator $validator) { $validator ->requirePresence('ticket', 'create') ->notEmpty('ticket'); } // そして、 Templates/Tickets/add.ctp の中が次のような場合: echo $this->Form->text('ticket'); if ($this->Form->isFieldError('ticket')) { echo $this->Form->error('ticket', 'Completely custom error message!'); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 もし、 _Ticket_ フィールドの値を指定せずにフォームの _Submit_ ボタンをクリックした場合、 フォームは次のように出力されます。
    Completely custom error message!
    1 2 NOTE `Cake\View\Helper\FormHelper::control()` を使用している時、 デフォルトではエラーは描画されますので、 `isFieldError()` を使用したり、 手動で `error()` を呼び出す必要はありません。 TIP あるモデルのフィールドを使用して、 `control()` で複数のフォームフィールドを生成し、 それぞれ同じ検証エラーメッセージを表示させたい場合、それぞれの [検証ルール](https://book.cakephp.org/3.x/ja/core-libraries/validation.html#creating-validators) の中でカスタムエラーメッセージを 定義する方が良いでしょう。 Add examples. ### エラーの確認 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E7%A2%BA%E8%AA%8D) `method` Cake\\View\\Helper\\FormHelper::**isFieldError**(string $fieldName) * `$fieldName` - `'Modelname.fieldname'` の形式のフィールド名。 指定された `$fieldName` に有効な検証エラーがある場合は `true` を返します。 そうでなければ `fales` を返します。 例: if ($this->Form->isFieldError('gender')) { echo $this->Form->error('gender'); } 1 2 3 HTML5 検証メッセージにバリデーションメッセージを表示 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#html5-%E6%A4%9C%E8%A8%BC%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B7%E3%82%99%E3%81%AB%E3%83%8F%E3%82%99%E3%83%AA%E3%83%86%E3%82%99%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B7%E3%82%99%E3%82%92%E8%A1%A8%E7%A4%BA) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Added in version 3.7.0 `autoSetCustomValidity` FormHelper オプションが `true` に設定されている場合、 デフォルトのブラウザーの HTML5 必須メッセージの代わりに、フィールドの必須および notBlank バリデーションメッセージに対するエラーメッセージが使用されます。 このオプションを有効にすると、フィールドに `onvalid` と `oninvalid` イベント属性が追加されます。 例えば、 : 1 カスタム Javascript を使用してこれらのイベントを手動で設定したい場合は、 `autoSetCustomValidity` オプションを `false` に設定して、 代わりに 特別な `customValidityMessage` テンプレート変数を使用することができます。 このテンプレート変数はフィールドが必須の場合に追加されます。 : // テンプレート例 [\ 'input' => '',\ ] // このような input が作成されます 1 2 3 4 5 6 7 それから Javascript を使って `onvalid` と `oninvalid` イベントを好きなように設定できます。 ボタンと submit 要素の作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%9B%E3%82%99%E3%82%BF%E3%83%B3%E3%81%A8-submit-%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BD%9C%E6%88%90) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### Submit 要素の作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#submit-%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**submit**(string $caption, array $options) * `$caption` - ボタンのテキスト見出しまたは画像へのパスを提供するオプション文字列。 デフォルトは、 `'Submit'` です。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) 、または submit 特有のオプション (下記参照) 。 `$caption` を値としてもつ `submit` タイプの `input` 要素を作成します。 指定された `$caption` が画像の URL である場合 (つまり、 '😕/' を含む文字列または、拡張子 '.jpg, .jpe, .jpeg, .gif' を含む場合)、画像の送信ボタンが生成され、指定された画像が 存在する場合は、それを使用します。最初の文字が '/' の場合、画像は _webroot_ からの 相対パスになり、最初の文字が '/' ではない場合、画像は _webroot/img_ からの相対パスになります。 デフォルトで次のウィジェットテンプレートを使用します。 : 'inputSubmit' => '' 'submitContainer' => '
    {{content}}
    ' 1 2 **Submit のオプション** * `'type'` - リセットボタンを生成するためにこのオプションに `'reset'` を設定します。 デフォルトは `'submit'` です。 * `'templateVars'` - input 要素や、そのコンテナーにテンプレート変数を追加するために、 この配列を設定します。 * その他の指定された属性は `input` 要素に割り当てられます。 例: echo $this->Form->submit('Click me'); 1 出力結果:
    1 見出しテキストの代わりに見出しパラメーターとして画像への相対 URL または 絶対 URL を渡すことができます。 : echo $this->Form->submit('ok.png'); 1 出力結果:
    1 submit 入力は、基本的なテキストやイメージが必要な場合に便利です。 より複雑なボタンの内容が必要な場合は、 `button()` を使用してください。 ### ボタン要素の作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%9B%E3%82%99%E3%82%BF%E3%83%B3%E8%A6%81%E7%B4%A0%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**button**(string $title, array $options = \[\]) * `$title` - ボタンの見出しテキストを提供する必須の文字列。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) やボタン特有のオプション (下記参照)と 有効な HTML 属性を含むオプション配列。 指定されたタイトルと `'button'` のデフォルトタイプの HTML ボタンを作成します。 **ボタンのオプション** * `$options['type']` - これを設定すると、次の3つの button タイプのどれかが出力されます。 1. `'submit'` - `$this->Form->submit()` と同様に送信ボタンを作成します。 しかしながら、 `submit()` のように `div` の囲い込みは生成しません。 これがデフォルトのタイプです。 2. `'reset'` - フォームのリセットボタンを作成します。 3. `'button'` - 標準の押しボタンを作成します。 * `$options['escape']` - ブール値。 `true` をセットした場合、 `$title` で指定された値を HTML エンコードします。デフォルトは `false` です。 例: echo $this->Form->button('ボタン'); echo $this->Form->button('別のボタン', ['type' => 'button']); echo $this->Form->button('フォームのリセット', ['type' => 'reset']); echo $this->Form->button('フォームの送信', ['type' => 'submit']); 1 2 3 4 出力結果: 1 2 3 4 `'escape'` オプションの使用例: // エスケープされた HTML を描画します。 echo $this->Form->button('Submit Form', [\ 'type' => 'submit',\ 'escape' => true\ ]); 1 2 3 4 5 フォームを閉じる [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%82%92%E9%96%89%E3%81%97%E3%82%99%E3%82%8B) -------------------------------------------------------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\FormHelper::**end**($secureAttributes = \[\]) * `$secureAttributes` - オプション。SecurityComponent 用に生成された非表示の input 要素に HTML 属性として渡されるセキュアな属性を提供できます。 `end()` は、フォームを閉じて完成します。 多くの場合、 `end()` は終了タグだけを出力しますが、 `end()` を使うと、 FormHelper が `Cake\Controller\Component\SecurityComponent` に必要な hidden フォーム要素を挿入できるようになります。 Form->create(); ?> Form->end(); ?> 1 2 3 4 5 生成された hidden 入力に属性を追加する必要がある場合は、 `$secureAttributes` 引数を使用できます。 : echo $this->Form->end(['data-type' => 'hidden']); 1 出力結果:
    1 2 3 4 5 6 NOTE アプリケーションで `Cake\Controller\Component\SecurityComponent` を使用している場合は、必ずフォームを `end()` で終わらせてください。 単独のボタンと POST リンクの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E5%8D%98%E7%8B%AC%E3%81%AE%E3%83%9B%E3%82%99%E3%82%BF%E3%83%B3%E3%81%A8-post-%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%AE%E4%BD%9C%E6%88%90) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### POST ボタンの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#post-%E3%83%9B%E3%82%99%E3%82%BF%E3%83%B3%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**postButton**(string $title, mixed $url, array $options = \[\]) * `$title` - ボタンの見出しテキストを提供する必須の文字列。 デフォルトでは HTML エンコードされません。 * `$url` - 文字列や配列として提供される URL。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) 、特定のオプション(下記参照)と 有効な HTML 属性を含むオプション配列。 デフォルトでは、POST で送信する `` 要素で囲まれた `
    1 2 3 4 5 6 7 8 9 10 11 このメソッドは `form` 要素を作成します。 なので、開かれたフォームの中でこのメソッドを使用しないでください。 代わりに `Cake\View\Helper\FormHelper::submit()` または `Cake\View\Helper\FormHelper::button()` を使用して、 開かれたフォームの中でボタンを作成してください。 ### POST リンクの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#post-%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**postLink**(string $title, mixed $url = null, array $options = \[\]) * `$title` - `` タグに囲まれたテキストを提供する必須の文字列。 * `$url` - オプション。フォームの URL (相対 URL 、または `http://` で始まる外部 URL) を含む文字列または配列。 * `$options` - [General Control Options](https://book.cakephp.org/3.x/ja/views/helpers/form.html#general-control-options) 、特有のオプション(下記参照)と 有効な HTML 属性を含むオプション配列。 HTML リンクを作成しますが、指定した方法 (デフォルトは POST)で URL にアクセスします。 ブラウザーで有効にするには JavaScript が必要です。 **POST リンクのオプション** * `'data'` - hidden 入力に渡すキーと値の配列。 * `'method'` - 使用するリクエスト方法。例えば、 `'delete'` をセットすると、 HTTP/1.1 DELETE リクエストをシミュレートします。デフォルトは `'post'` です。 * `'confirm'` - クリック時に表示される確認メッセージ。デフォルトは `null` です。 * `'block'` - ビューブロック `'postLink'` へフォームの追加するために このオプションに `true` をセットしたり、カスタムブロック名を指定します。 デフォルトは `null` です。 * また、 `postLink` メソッドは、 `link()` メソッドの有効なオプションを受け付けます。 このメソッドは `
    ` 要素を作成します。 このメソッドを既存のフォームの中で使いたい場合は、 `block` オプションを使用して、 新しいフォームがメインフォームの外部でレンダリング可能な [ビューブロック](https://book.cakephp.org/3.x/ja/views.html#view-blocks) に設定されるようにする必要があります。 あなたが探しているものがフォームを送信するボタンであれば、代わりに `Cake\View\Helper\FormHelper::button()` または `Cake\View\Helper\FormHelper::submit()` を使用してください。 NOTE 開いているフォームの中に postLink を入れないように注意してください。 代わりに、 `block` オプションを使ってフォームを [ビューブロック](https://book.cakephp.org/3.x/ja/views.html#view-blocks) にバッファリングしてください。 FormHelper で使用するテンプレートのカスタマイズ [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#formhelper-%E3%81%A6%E3%82%99%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E3%83%86%E3%83%B3%E3%83%95%E3%82%9A%E3%83%AC%E3%83%BC%E3%83%88%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%B9%E3%82%99) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- CakePHP の多くのヘルパーと同じように、FormHelper は、 作成する HTML をフォーマットするための文字列テンプレートを使用しています。 既定のテンプレートは、合理的な既定値のセットを意図していますが、 アプリケーションに合わせてテンプレートをカスタマイズする必要があるかもしれません。 ヘルパーが読み込まれたときにテンプレートを変更するには、コントローラーにヘルパーを含めるときに `templates` オプションを設定することができます。 : // View クラスの中で $this->loadHelper('Form', [\ 'templates' => 'app_form',\ ]); 1 2 3 4 これは、\*\*config/app\_form.php\*\*ファイルを作成し **config/app\_form.php** の中のタグを読み込みます。 このファイルには、名前で索引付けされたテンプレートの配列が含まれている必要があります。 : // config/app_form.php の中で return [\ 'inputContainer' => '
    {{content}}
    ',\ ]; 1 2 3 4 定義したテンプレートは、ヘルパーに含まれるデフォルトのテンプレートを置き換えます。 置き換えられていないテンプレートは引き続きデフォルト値を使用します。 `setTemplates()` メソッドを使って実行時にテンプレートを変更することもできます。 : $myTemplates = [\ 'inputContainer' => '
    {{content}}
    ',\ ]; $this->Form->setTemplates($myTemplates); // 3.4 より前 $this->Form->templates($myTemplates); 1 2 3 4 5 6 WARNING パーセント記号 (`%`) を含むテンプレート文字列には特別な注意が必要です。 この文字の先頭に `%%` のようにもう一つパーセンテージを付ける必要があります。 なぜなら、内部的なテンプレートは `sprintf()` で使用されるためにコンパイルされているからです。 例: `'
    '` ### テンプレート一覧 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%86%E3%83%B3%E3%83%95%E3%82%9A%E3%83%AC%E3%83%BC%E3%83%88%E4%B8%80%E8%A6%A7) デフォルトのテンプレートのリスト、それらのデフォルトのフォーマット、そして期待される変数は [FormHelper API ドキュメント](https://api.cakephp.org/3.x/class-Cake.View.Helper.FormHelper.html#%24_defaultConfig) で見つけることができます。 #### 異なるカスタムコントロールコンテナーの使用 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E7%95%B0%E3%81%AA%E3%82%8B%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%83%BC%E3%81%AE%E4%BD%BF%E7%94%A8) これらのテンプレートに加えて、 `control()` メソッドはコントロールコンテナーごとに異なるテンプレートを 使用しようとします。たとえば、datetime コントロールを作成する場合、 `datetimeContainer` が存在する場合にはそれが使用されます。 そのコンテナーがない場合、 `inputContainer` テンプレートが使用されます。 例えば: // 独自の HTML で囲まれた radio を追加 $this->Form->templates([\ 'radioContainer' => '
    {{content}}
    '\ ]); // 独自の div で囲まれた radio セットを作成 echo $this->Form->control('email_notifications', [\ 'options' => ['y', 'n'],\ 'type' => 'radio'\ ]); 1 2 3 4 5 6 7 8 9 10 #### 異なるカスタムフォームグループの使用 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E7%95%B0%E3%81%AA%E3%82%8B%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%82%AF%E3%82%99%E3%83%AB%E3%83%BC%E3%83%95%E3%82%9A%E3%81%AE%E4%BD%BF%E7%94%A8) コンテナーの制御と同様に、 `control()` メソッドはフォームグループごとに異なるテンプレートを 使用しようとします。フォームグループは、ラベルとコントロールの組み合わせです。 例えば、radio 入力を作成する時、 `radioFormGroup` が存在する場合、それが使用されます。 そのテンプレートが存在しない場合、デフォルトでは、ラベル&入力の各セットは、 `formGroup` テンプレートを使用して描画されます。 例: // 独自の radio フォームグループを追加 $this->Form->setTemplates([\ 'radioFormGroup' => '
    {{label}}{{input}}
    '\ ]); 1 2 3 4 ### テンプレートにテンプレート変数を追加 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%86%E3%83%B3%E3%83%95%E3%82%9A%E3%83%AC%E3%83%BC%E3%83%88%E3%81%AB%E3%83%86%E3%83%B3%E3%83%95%E3%82%9A%E3%83%AC%E3%83%BC%E3%83%88%E5%A4%89%E6%95%B0%E3%82%92%E8%BF%BD%E5%8A%A0) カスタムテンプレートにテンプレートプレースホルダを追加し、 コントロールを生成するときにプレースホルダを設定することができます。 例: // help プレースホルダ付きでテンプレートを追加 $this->Form->setTemplates([\ 'inputContainer' => '
    \ {{content}} {{help}}
    '\ ]); // help 変数を設定し入力を生成 echo $this->Form->control('password', [\ 'templateVars' => ['help' => '少なくとも 8 文字の長さ。']\ ]); 1 2 3 4 5 6 7 8 9 10 出力結果:
    少なくとも 8 文字の長さ。
    1 2 3 4 5 6 7 Added in version 3.1 templateVars オプションは 3.1.0 で追加されました。 ### チェックボックスとラジオのラベル外への移動 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%83%9B%E3%82%99%E3%83%83%E3%82%AF%E3%82%B9%E3%81%A8%E3%83%A9%E3%82%B7%E3%82%99%E3%82%AA%E3%81%AE%E3%83%A9%E3%83%98%E3%82%99%E3%83%AB%E5%A4%96%E3%81%B8%E3%81%AE%E7%A7%BB%E5%8B%95) デフォルトでは、CakePHP は、 `control()` で作成されたチェックボックスと `control()` と `radio()` の両方で作成されたラジオボタンをラベル要素内でネストします。 これにより、人気の CSS フレームワークとの統合に役立ちます。 ラベルの外に checkbox/radio 入力を配置する必要がある場合は、 テンプレートを変更することで行うことができます。 : $this->Form->setTemplates([\ 'nestingLabel' => '{{hidden}}{{input}}{{text}}',\ 'formGroup' => '{{input}}{{label}}',\ ]); 1 2 3 4 これにより、ラジオボタンとチェックボックスがラベルの外側に描画されます。 フォーム全体の生成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E5%85%A8%E4%BD%93%E3%81%AE%E7%94%9F%E6%88%90) --------------------------------------------------------------------------------------------------------------------------------------------------------- ### 複数のコントロールの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E8%A4%87%E6%95%B0%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**controls**(array $fields = \[\], $options = \[\]) * `$fields` - 生成するフィールドの配列。指定した各フィールドのカスタムタイプ、 ラベル、その他のオプションを設定できます。 * `$options` - オプション。オプションの配列。有効なキーは: 1. `'fieldset'` - filedset を無効にするために `false` を設定してください。 空の配列を渡すと、fieldset は有効になります。 HTML 属性として適用するパラメーターの配列を `fieldset` タグに渡すこともできます。 2. `legend` - `legend` のテキストをカスタマイズするための文字列。 生成された入力セットの legend を無効にするために `false` を設定してください。 `fieldset` で囲まれた指定された一連のコントロールセットを生成します。 生成されたフィールドを含めることで指定できます。 : echo $this->Form->controls([\ 'name',\ 'email'\ ]); 1 2 3 4 オプションを使用して legend のテキストをカスタマイズすることができます。 : echo $this->Form->controls($fields, ['legend' => 'Update news post']); 1 `$fields` パラメーターで追加のオプションを定義することによって、 生成されたコントロールをカスタマイズすることができます。 : echo $this->Form->controls([\ 'name' => ['label' => 'カスタムラベル']\ ]); 1 2 3 `$fields` をカスタマイズする場合、生成された legend/fieldset を制御するために `$options` パラメーターを使用することができます。 例えば: echo $this->Form->controls( [\ 'name' => ['label' => 'カスタムラベル']\ ], ['legend' => 'Update your post'] ); 1 2 3 4 5 6 `fieldset` を無効にすると、 `legend` は出力されません。 ### エンティティー全体のコントロールを作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3%E3%83%BC%E5%85%A8%E4%BD%93%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%82%92%E4%BD%9C%E6%88%90) `method` Cake\\View\\Helper\\FormHelper::**allControls**(array $fields, $options = \[\]) * `$fields` - オプション。生成するフィールドのカスタマイズ配列。 カスタムタイプ、ラベル、その他のオプションを設定できます。 * `$options` - オプション。オプションの配列。有効なキーは: 1. `'fieldset'` - これに `false` を設定すると fieldset が無効になります。 空の場合、fieldset は有効になります。パラメーターの配列を渡すと、 `fieldset` の HTML 属性として適用されます。 2. `legend` - `legend` テキストをカスタマイズするための文字列。 これに `false` を設定すると、生成されたコントロールセットの `legend` が無効になります。 このメソッドは `controls()` と密接に関係していますが、 `$fields` 引数は 現在のトップレベルエンティティーの _全ての_ フィールドにデフォルト設定されています。 生成されたコントロールから特定のフィールドを除外するには、 `$fields` パラメーターで `false` を設定します。 : echo $this->Form->allControls(['password' => false]); // 3.4.0 より前の場合: echo $this->Form->allInputs(['password' => false]); 1 2 3 関連データの入力を作成 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E9%96%A2%E9%80%A3%E3%83%86%E3%82%99%E3%83%BC%E3%82%BF%E3%81%AE%E5%85%A5%E5%8A%9B%E3%82%92%E4%BD%9C%E6%88%90) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 関連するデータのフォームを作成するのは簡単で、エンティティーのデータ内のパスに密接に関連しています。 次のテーブルリレーションを仮定します。 * Authors HasOne Profiles * Authors HasMany Articles * Articles HasMany Comments * Articles BelongsTo Authors * Articles BelongsToMany Tags アソシエーション付きで読み込まれた記事を編集していた場合、次のコントロールを作成できます。 : $this->Form->create($article); // Article コントロール echo $this->Form->control('title'); // Author コントロール (belongsTo) echo $this->Form->control('author.id'); echo $this->Form->control('author.first_name'); echo $this->Form->control('author.last_name'); // Author の profile (belongsTo + hasOne) echo $this->Form->control('author.profile.id'); echo $this->Form->control('author.profile.username'); // 別々の入力として、 // Tags コントロール (belongsToMany) echo $this->Form->control('tags.0.id'); echo $this->Form->control('tags.0.name'); echo $this->Form->control('tags.1.id'); echo $this->Form->control('tags.1.name'); // 結合テーブルの入力 (articles_tags) echo $this->Form->control('tags.0._joinData.starred'); echo $this->Form->control('tags.1._joinData.starred'); // Comments コントロール (hasMany) echo $this->Form->control('comments.0.id'); echo $this->Form->control('comments.0.comment'); echo $this->Form->control('comments.1.id'); echo $this->Form->control('comments.1.comment'); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 上記のコントロールは、コントローラー内の次のコードを使用して完成したエンティティーグラフに マーシャリングすることができます。 : $article = $this->Articles->patchEntity($article, $this->request->getData(), [\ 'associated' => [\ 'Authors',\ 'Authors.Profiles',\ 'Tags',\ 'Comments'\ ]\ ]); 1 2 3 4 5 6 7 8 上記の例は、各エンティティーと結合データレコードに対して別々の入力を持つ、 多数の関連するデータセットの拡張された例を示しています。 また、多数の関連に属する複数選択入力を作成することもできます。 : // belongsToMany の複数選択要素 // _joinData をサポートしません echo $this->Form->control('tags._ids', [\ 'type' => 'select',\ 'multiple' => true,\ 'options' => $tagList,\ ]); 1 2 3 4 5 6 7 独自ウィジェットの追加 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E7%8B%AC%E8%87%AA%E3%82%A6%E3%82%A3%E3%82%B7%E3%82%99%E3%82%A7%E3%83%83%E3%83%88%E3%81%AE%E8%BF%BD%E5%8A%A0) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- CakePHP を使うと、アプリケーションに独自のコントロールウィジェットを簡単に追加でき、 他のコントロールタイプと同様に使用することができます。 すべてのコアコントロールタイプはウィジェットとして実装されています。 つまり、独自の実装でコアウィジェットを上書きすることができます。 ### Widget クラスの構築 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#widget-%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E6%A7%8B%E7%AF%89) Widget クラスは、とても単純で必須のインターフェイスを持っています。 これらは `Cake\View\Widget\WidgetInterface` を実装しなければなりません。 このインターフェイスを実装するには、 `render(array $data)` メソッドと `secureFields(array $data)` メソッドが必要です。 `render()` メソッドは、ウィジェットを構築するためのデータ配列を受け取り、 ウィジェットの HTML 文字列を返すことが期待されています。 `secureFields()` メソッドは、同様にデータ配列を受け取り、 このウィジェットで保護するフィールドのリストを含む配列を返すことが期待されています。 CakePHP がウィジェットを構築している場合、最初の引数として `Cake\View\StringTemplate` インスタンスを取得し、その後にあなたが定義した依存関係が続くことが期待できます。 autocomplete ウィジェットを作成したい場合、以下を実行できます。 : namespace App\View\Widget; use Cake\View\Form\ContextInterface; use Cake\View\Widget\WidgetInterface; class AutocompleteWidget implements WidgetInterface { protected $_templates; public function __construct($templates) { $this->_templates = $templates; } public function render(array $data, ContextInterface $context) { $data += [\ 'name' => '',\ ]; return $this->_templates->format('autocomplete', [\ 'name' => $data['name'],\ 'attrs' => $this->_templates->formatAttributes($data, ['name'])\ ]); } public function secureFields(array $data) { return [$data['name']]; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 明らかに、これは非常に簡単な例ですが、独自ウィジェットの構築方法を示しています。 ### ウィジェットの使用 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#%E3%82%A6%E3%82%A3%E3%82%B7%E3%82%99%E3%82%A7%E3%83%83%E3%83%88%E3%81%AE%E4%BD%BF%E7%94%A8) FormHelper を読み込むときや、 `addWidget()` メソッドを使って独自のウィジェットを読み込むことができます。 FormHelper を読み込むとき、ウィジェットは設定として定義されます。 : // View クラスの中で $this->loadHelper('Form', [\ 'widgets' => [\ 'autocomplete' => ['Autocomplete']\ ]\ ]); 1 2 3 4 5 6 あなたのウィジェットが他のウィジェットを必要とする場合は、それらの依存関係を宣言することによって FormHelper に取り込ませることができます。 : $this->loadHelper('Form', [\ 'widgets' => [\ 'autocomplete' => [\ 'App\View\Widget\AutocompleteWidget',\ 'text',\ 'label'\ ]\ ]\ ]); 1 2 3 4 5 6 7 8 9 上記の例では、 `autocomplete` ウィジェットは `text` と `label` ウィジェットに依存します。 ウィジェットがビューにアクセスする必要がある場合は、 `_view` 'ウィジェット' を使用してください。 autocomplete ウィジェットが作成されると、 `text` と `label` の名前に関連するウィジェットオブジェクトが渡されます。 `addWidget()` メソッドを使ってウィジェットを追加すると、次のようになります。 : // classname の使用。 $this->Form->addWidget( 'autocomplete', ['Autocomplete', 'text', 'label'] ); // インスタンスの使用 - 依存関係を解決する必要があります。 // 3.6.0 より前は、ウィジェットの取得に widgetRegistry() を使用。 $autocomplete = new AutocompleteWidget( $this->Form->getTemplater(), $this->Form->getWidgetLocator()->get('text'), $this->Form->getWidgetLocator()->get('label'), ); $this->Form->addWidget('autocomplete', $autocomplete); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 追加/置換されると、ウィジェットはコントロールの 'type' として使用できます。 : echo $this->Form->control('search', ['type' => 'autocomplete']); 1 これは、 `controls()` とまったく同じように `label` と囲い込む `div` を持つ独自ウィジェットを作成します。 あるいは、マジックメソッドを使用してコントロールウィジェットだけを作成することもできます。 : echo $this->Form->autocomplete('search', $options); 1 SecurityComponent との連携 [​](https://book.cakephp.org/3.x/ja/views/helpers/form.html#securitycomponent-%E3%81%A8%E3%81%AE%E9%80%A3%E6%90%BA) ------------------------------------------------------------------------------------------------------------------------------------------- `Cake\Controller\Component\SecurityComponent` には、 フォームをより安全で安全にするためのいくつかの機能があります。 コントローラーに `SecurityComponent` を含めるだけで、 フォームの改ざん防止機能が自動的に有効になります。 SecurityComponent を利用する際は、前述のようにフォームを閉じる際は、 必ず `Cake\View\Helper\FormHelper::end()` を使う必要があります。 これにより特別な `_Token` 入力が生成されます。 `method` Cake\\View\\Helper\\FormHelper::**unlockField**($name) * `$name` - オプション。ドット区切りのフィールド名。 `SecurityComponent` によるフィールドのハッシュ化が行われないようにフィールドのロックを 解除します。またこれにより、そのフィールドを JavaScript で操作できるようになります。 `$name` には入力のためのエンティティーのプロパティー名を指定します。 : $this->Form->unlockField('id'); 1 `method` Cake\\View\\Helper\\FormHelper::**secure**(array $fields = \[\], array $secureAttributes = \[\]) * `$fields` - オプション。ハッシュの生成に使用するフィールドの一覧を含む配列。 指定がない場合、 `$this->fields` が使用されます。 * `$secureAttributes` - オプション。生成される hidden 入力要素の中に渡す HTML 属性の配列。 フォームで使用されるフィールドに基づくセキュリティーハッシュをもつ 非表示の `input` フィールドを生成し、または、保護されたフォームが使用されていない場合は 空の文字列を生成します。 `$secureAttributes` を設定した場合、これらの HTML 属性は、 SecurityCompnent によって生成された非表示の input タグの中にマージされます。 これは、 `'form'` のような HTML5 属性を設定するのに特に便利です。 --- # Upgrade Tool | CakePHP [Skip to content](https://book.cakephp.org/3.x/upgrade-tool.html#VPContent) Return to top Upgrade Tool [​](https://book.cakephp.org/3.x/upgrade-tool.html#upgrade-tool) ============================================================================== Upgrading to CakePHP 3 from CakePHP 2.x requires a number of transformations that can be automated, such as adding namespaces. To assist in making these mechanical changes easier, CakePHP provides a CLI based upgrade tool. Installation [​](https://book.cakephp.org/3.x/upgrade-tool.html#installation) ------------------------------------------------------------------------------ The upgrade tool is installed as a standalone application. You'll need to clone the upgrade tool with git, and install the dependencies with composer: git clone https://github.com/cakephp/upgrade.git -b 3.x cd upgrade php ../composer.phar install At this point you should be able to get the help for the upgrade tool: cd upgrade bin/cake upgrade --help The above should output something like the following: Welcome to CakePHP v3.0.8 Console --------------------------------------------------------------- App : src Path: /Users/markstory/Sites/cake_plugins/upgrade/src/ --------------------------------------------------------------- A shell to help automate upgrading from CakePHP 2.x to 3.x. Be sure to have a backup of your application before running these commands. Usage: cake upgrade [subcommand] [-h] [-v] [-q] Subcommands: locations Move files/directories around. Run this *before* adding namespaces with the namespaces command. namespaces Add namespaces to files based on their file path. Only run this *after* you have moved files. app_uses Replace App::uses() with use statements rename_classes Rename classes that have been moved/renamed. Run after replacing App::uses() with use statements. rename_collections Rename HelperCollection, ComponentCollection, and TaskCollection. Will also rename component constructor arguments and _Collection properties on all objects. method_names Update many of the methods that were renamed during 2.x -> 3.0 method_signatures Update many of the method signatures that were changed during 2.x -> 3.0 fixtures Update fixtures to use new index/constraint features. This is necessary before running tests. tests Update test cases regarding fixtures. i18n Update translation functions regarding placeholders. skeleton Add basic skeleton files and folders from the "app" repository. prefixed_templates Move view templates for prefixed actions. all Run all tasks except for skeleton. That task should only be run manually, and only for apps (not plugins). To see help on a subcommand use `cake upgrade [subcommand] --help` Options: --help, -h Display this help. --verbose, -v Enable verbose output. --quiet, -q Enable quiet output. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 Usage [​](https://book.cakephp.org/3.x/upgrade-tool.html#usage) ---------------------------------------------------------------- Once you have correctly installed the upgrade tool, you are ready to start using it on a 2.x application. WARNING Make sure you have backups/version control for your application's code. It is also a good idea to make a backup/commits after each sub-command. To start off run the `locations` command: # View the options for the command bin/cake upgrade locations --help # Run the command in dry run mode. bin/cake upgrade locations --dry-run /path/to/app 1 2 3 4 5 The above will give a dry run output of what would happen. When you are ready to run the command for real, remove the `--dry-run` flag. By using the `--git` flag the upgrade tool can automate moving files in git. Once file locations have been updated, you can add namespaces to your code using the `namespaces` command: # View the options for the command bin/cake upgrade namespaces --help # Run the command in dry run mode bin/cake upgrade namespaces --dry-run /path/to/app # Run the command for real bin/cake upgrade namespaces /path/to/app 1 2 3 4 5 6 7 8 After these two commands, you can run the remaining subcommands in any order. --- # Flash | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/views/helpers/flash.html#VPContent) Return to top Flash [​](https://book.cakephp.org/3.x/ja/views/helpers/flash.html#flash) ========================================================================== `class` Cake\\View\\Helper\\**FlashHelper**(View $view, array $config = \[\]) FlashHelperは、 [FlashComponent](https://book.cakephp.org/3.x/ja/controllers/components/flash.html) によって `$_SESSION` にセットされたフラッシュメッセージを描画する方法を提供しています。 [FlashComponent](https://book.cakephp.org/3.x/ja/controllers/components/flash.html) および FlashHelper はフラッシュメッセージを描画するためのエレメントを使用します。 フラッシュエレメントは **src/Template/Element/Flash** ディレクトリー以下に存在します。 CakePHP の App テンプレートには、 **success.ctp** 、 **default.ctp** と **error.ctp** の 3つのフラッシュエレメントが付属しています。 フラッシュメッセージの描画 [​](https://book.cakephp.org/3.x/ja/views/helpers/flash.html#%E3%83%95%E3%83%A9%E3%83%83%E3%82%B7%E3%83%A5%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B7%E3%82%99%E3%81%AE%E6%8F%8F%E7%94%BB) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- フラッシュメッセージを描画するためには、テンプレートファイルの中で FlashHelper の `render()` メソッドを使用します。 : Flash->render() ?> 1 デフォルトでは、CakePHP は、フラッシュメッセージのためにセッション中の "flash" キーを使用します。 しかし、 [FlashComponent](https://book.cakephp.org/3.x/ja/controllers/components/flash.html) の中でフラッシュメッセージを 設定した時にキーを指定した場合、そのキーを指定して描画します。 : Flash->render('other') ?> 1 FlashComponent の中で設定したオプションを上書きすることもできます。 : // コントローラーの中で $this->Flash->set('The user has been saved.', [\ 'element' => 'success'\ ]); // テンプレートファイルの中で、 success.ctp の代わりに great_success.ctp を使用 Flash->render('flash', [\ 'element' => 'great_success'\ ]); 1 2 3 4 5 6 7 8 9 NOTE フラッシュメッセージの独自テンプレートを作成する場合、全てのユーザーデータを適切に HTML エンコードしてください。CakePHP は、フラッシュメッセージのパラメーターをエスケープしません。 Added in version 3.1 [FlashComponent](https://book.cakephp.org/3.x/ja/controllers/components/flash.html) はメッセージをスタックしています。 複数のフラッシュメッセージをセットした場合、 `render()` を呼び出すと、それぞれのメッセージが 設定された順番でそれぞれのエレメントの中で描画されます。 使用できる配列オプションについてもっと知りたい場合は、 [FlashComponent](https://book.cakephp.org/3.x/ja/controllers/components/flash.html) セクションをご覧ください。 ルーティングのプレフィックスとフラッシュメッセージ [​](https://book.cakephp.org/3.x/ja/views/helpers/flash.html#%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%AF%E3%82%99%E3%81%AE%E3%83%95%E3%82%9A%E3%83%AC%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E3%82%B9%E3%81%A8%E3%83%95%E3%83%A9%E3%83%83%E3%82%B7%E3%83%A5%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B7%E3%82%99) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Added in version 3.0.1 設定したルーティングのプレフィックスがある場合、フラッシュエレメントを **src/Template/{Prefix}/Element/Flash** に置きます。 これにより、アプリケーションの各部分に特定のメッセージレイアウトを設定できます。 例えば、フロントエンドと管理者のセクションで異なるレイアウトを使用する場合です。 フラッシュメッセージとテーマ [​](https://book.cakephp.org/3.x/ja/views/helpers/flash.html#%E3%83%95%E3%83%A9%E3%83%83%E3%82%B7%E3%83%A5%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B7%E3%82%99%E3%81%A8%E3%83%86%E3%83%BC%E3%83%9E) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- FlashHelper は、メッセージを描画するために標準のエレメントを使用し、指定したテーマに従います。 そのため、テーマが **src/Template/Element/Flash/error.ctp** ファイルを持つ場合、 エレメントやビューと同様に使用されます。 --- # CMS Tutorial - Authentication | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples/cms/authentication.html#VPContent) Return to top CMS Tutorial - Authentication [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/authentication.html#cms-tutorial-authentication) =========================================================================================================================================== Now that our CMS has users, we should enable them to login, and apply some basic access control to the article creation & editing experiences. Adding Password Hashing [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/authentication.html#adding-password-hashing) --------------------------------------------------------------------------------------------------------------------------------- If you were to create/update a user at this point in time, you might notice that the passwords are stored in plain text. This is really bad from a security point of view, so lets fix that. This is also a good time to talk about the model layer in CakePHP. In CakePHP, we separate the methods that operate on a collection of objects, and a single object into different classes. Methods that operate on the collection of entities are put in the `Table` class, while features belonging to a single record are put on the `Entity` class. For example, password hashing is done on the individual record, so we'll implement this behavior on the entity object. Because we want to hash the password each time it is set, we'll use a mutator/setter method. CakePHP will call convention based setter methods any time a property is set in one of your entities. Let's add a setter for the password. In **src/Model/Entity/User.php** add the following: hash($value); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Now, point your browser to **[http://localhost:8765/users](http://localhost:8765/users) ** to see a list of users. You can edit the default user that was created during [Installation](https://book.cakephp.org/3.x/installation.html) . If you change that user's password, you should see a hashed password instead of the original value on the list or view pages. CakePHP hashes passwords with [bcrypt](https://codahale.com/how-to-safely-store-a-password/) by default. You can also use SHA-1 or MD5 if you're working with an existing database, but we recommend bcrypt for all new applications. NOTE Create a hashed password for at least one of the user accounts now! It will be needed in the next steps. ### Adding Login [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/authentication.html#adding-login) In CakePHP, authentication is handled by [Components](https://book.cakephp.org/3.x/controllers/components.html) . Components can be thought of as ways to create reusable chunks of controller code related to a specific feature or concept. Components can hook into the controller's event life-cycle and interact with your application that way. To get started, we'll add the [AuthComponent](https://book.cakephp.org/3.x/controllers/components/authentication.html) to our application. We'll want the create, update and delete methods to require authentication, so we'll add AuthComponent in our AppController: // In src/Controller/AppController.php namespace App\Controller; use Cake\Controller\Controller; class AppController extends Controller { public function initialize() { // Existing code $this->loadComponent('Auth', [\ 'authenticate' => [\ 'Form' => [\ 'fields' => [\ 'username' => 'email',\ 'password' => 'password'\ ]\ ]\ ],\ 'loginAction' => [\ 'controller' => 'Users',\ 'action' => 'login'\ ],\ // If unauthorized, return them to page they were just on\ 'unauthorizedRedirect' => $this->referer()\ ]); // Allow the display action so our PagesController // continues to work. Also enable the read only actions. $this->Auth->allow(['display', 'view', 'index']); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 We've just told CakePHP that we want to load the `Auth` component. We've customized the configuration of AuthComponent, as our users table uses `email` as the username. Now, if you go any protected URL, such as `/articles/add`, you'll be redirected to **/users/login**, which will show an error page as we have not written that code yet. So let's create the login action: // In src/Controller/UsersController.php public function login() { if ($this->request->is('post')) { $user = $this->Auth->identify(); if ($user) { $this->Auth->setUser($user); return $this->redirect($this->Auth->redirectUrl()); } $this->Flash->error('Your username or password is incorrect.'); } } 1 2 3 4 5 6 7 8 9 10 11 12 Create a new template **src/Template/Users/login.ctp** and add the following:

    Login

    Form->create() ?> Form->control('email') ?> Form->control('password') ?> Form->button('Login') ?> Form->end() ?> 1 2 3 4 5 6 Now that we have a simple login form, we should be able to log in with one of the users that has a hashed password. NOTE If none of your users have hashed passwords, comment the `loadComponent('Auth')` block and `$this->Auth->allow()` calls. Then go and edit the user, saving a new password for them. After saving a new password for the user, make sure to uncomment the lines we just temporarily commented! Try it out! Before logging in, visit `/articles/add`. Since this action is not allowed, you will be redirected to the login page. After logging in successfully, CakePHP will automatically redirect you back to `/articles/add`. ### Adding Logout [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/authentication.html#adding-logout) Now that people can log in, you'll probably want to provide a way to log out as well. Again, in the `UsersController`, add the following code: public function initialize() { parent::initialize(); $this->Auth->allow(['logout']); } public function logout() { $this->Flash->success('You are now logged out.'); return $this->redirect($this->Auth->logout()); } 1 2 3 4 5 6 7 8 9 10 11 This code adds the `logout` action to the list of actions that do not require authentication and implements the logout method. Now you can visit `/users/logout` to log out. You should then be sent to the login page. ### Enabling Registrations [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/authentication.html#enabling-registrations) If you aren't logged in and you try to visit **/users/add** you will be redirected to the login page. We should fix that as we want to allow people to sign up for our application. In the `UsersController` add the following: public function initialize() { parent::initialize(); // Add the 'add' action to the allowed actions list. $this->Auth->allow(['logout', 'add']); } 1 2 3 4 5 6 The above tells `AuthComponent` that the `add()` action of the `UsersController` does _not_ require authentication or authorization. You may want to take the time to clean up the **Users/add.ctp** and remove the misleading links, or continue on to the next section. We won't be building out user editing, viewing or listing in this tutorial, but that is an exercise you can complete on your own. ### Restricting Article Access [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/authentication.html#restricting-article-access) Now that users can log in, we'll want to limit users to only edit articles that they created. We'll do this using an 'authorization' adapter. Since our requirements are basic, we can use a controller hook method in our `ArticlesController`. But before we do that, we'll want to tell the `AuthComponent` how our application is going to authorize actions. Update your `AppController` adding the following: public function isAuthorized($user) { // By default deny access. return false; } 1 2 3 4 5 Next we'll tell `AuthComponent` that we want to use controller hook methods for authorization. Your `AppController::initialize()` method should now look like: public function initialize() { // Existing code $this->loadComponent('Flash'); $this->loadComponent('Auth', [\ // Added this line\ 'authorize'=> 'Controller',\ 'authenticate' => [\ 'Form' => [\ 'fields' => [\ 'username' => 'email',\ 'password' => 'password'\ ]\ ]\ ],\ 'loginAction' => [\ 'controller' => 'Users',\ 'action' => 'login'\ ],\ // If unauthorized, return them to page they were just on\ 'unauthorizedRedirect' => $this->referer()\ ]); // Allow the display action so our pages controller // continues to work. Also enable the read only actions. $this->Auth->allow(['display', 'view', 'index']); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 We'll default to denying access, and incrementally grant access where it makes sense. First, we'll add the authorization logic for articles. In your `ArticlesController` add the following: public function isAuthorized($user) { $action = $this->request->getParam('action'); // The add and tags actions are always allowed to logged in users. if (in_array($action, ['add', 'tags'])) { return true; } // All other actions require a slug. $slug = $this->request->getParam('pass.0'); if (!$slug) { return false; } // Check that the article belongs to the current user. $article = $this->Articles->findBySlug($slug)->first(); return $article->user_id === $user['id']; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Now if you try to edit or delete an article that does not belong to you, you should be redirected back to the page you came from. If no error message is displayed, add the following to your layout: // In src/Template/Layout/default.ctp Flash->render() ?> 1 2 Next you should add the `tags` action to the actions allowed for unauthenticated users, by adding the following to `initialize()` in **src/Controller/ArticlesController.php**: $this->Auth->allow(['tags']); 1 While the above is fairly simplistic it illustrates how you could build more complex logic that combines the current user and request data to build flexible authorization logic. ### Fixing the Add & Edit Actions [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/authentication.html#fixing-the-add-edit-actions) While we've blocked access to the edit action, we're still open to users changing the `user_id` attribute of articles during edit. We will solve these problems next. First up is the `add` action. When creating articles, we want to fix the `user_id` to be the currently logged in user. Replace your add action with the following: // in src/Controller/ArticlesController.php public function add() { $article = $this->Articles->newEntity(); if ($this->request->is('post')) { $article = $this->Articles->patchEntity($article, $this->request->getData()); // Changed: Set the user_id from the session. $article->user_id = $this->Auth->user('id'); if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to add your article.')); } $this->set('article', $article); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Next we'll update the `edit` action. Replace the edit method with the following: // in src/Controller/ArticlesController.php public function edit($slug) { $article = $this->Articles ->findBySlug($slug) ->contain('Tags') // load associated Tags ->firstOrFail(); if ($this->request->is(['post', 'put'])) { $this->Articles->patchEntity($article, $this->request->getData(), [\ // Added: Disable modification of user_id.\ 'accessibleFields' => ['user_id' => false]\ ]); if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been updated.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to update your article.')); } $this->set('article', $article); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Here we're modifying which properties can be mass-assigned, via the options for `patchEntity()`. See the [Changing Accessible Fields](https://book.cakephp.org/3.x/orm/saving-data.html#changing-accessible-fields) section for more information. Remember to remove the `user_id` control from **src/Template/Articles/edit.ctp** as we no longer need it. ### Wrapping Up [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/authentication.html#wrapping-up) We've built a simple CMS application that allows users to login, post articles, tag them, explore posted articles by tag, and applied basic access control to articles. We've also added some nice UX improvements by leveraging the FormHelper and ORM capabilities. Thank you for taking the time to explore CakePHP. Next, you should learn more about the [Database Access & ORM](https://book.cakephp.org/3.x/orm.html) , or you peruse the [Using CakePHP](https://book.cakephp.org/3.x/topics.html) . --- # ビューセル | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/views/cells.html#VPContent) Return to top ビューセル [​](https://book.cakephp.org/3.x/ja/views/cells.html#%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E3%82%BB%E3%83%AB) =================================================================================================================== ビューセルはビュー処理やテンプレート出力を実行できる小さな小さなコントローラーです。 セルのアイディアは [Ruby のセル](https://github.com/trailblazer/cells) から拝借したもので、 同様の役割と目的を果たします。 セルを使う時 [​](https://book.cakephp.org/3.x/ja/views/cells.html#%E3%82%BB%E3%83%AB%E3%82%92%E4%BD%BF%E3%81%86%E6%99%82) -------------------------------------------------------------------------------------------------------------------- セルは、モデルとの対話、ビュー処理、および出力処理を必要とする、再利用可能なページ部品を 構築するのに理想的です。単純な例はオンライン店舗の買い物かご、あるいは CMS のデータ駆動型の ナビゲーションメニューなどになるでしょう。 セルの作成 [​](https://book.cakephp.org/3.x/ja/views/cells.html#%E3%82%BB%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) ---------------------------------------------------------------------------------------------------------- セルを作成するには、 **src/View/Cell** にクラスを、 **src/Template/Cell/** にテンプレートを 定義します。この例では、ユーザーの通知受信トレイにいくつかのメッセージを表示するために セルを作ることにします。まず、クラスファイルを作ります。中身はこのようになります。 : namespace App\View\Cell; use Cake\View\Cell; class InboxCell extends Cell { public function display() { } } 1 2 3 4 5 6 7 8 9 10 11 12 このファイルを **src/View/Cell/InboxCell.php** に保存します。ご覧の通り、 CakePHP の他のクラスと同様に、セルはいくつかの規約を持っています。 * セルは `App\View\Cell` 名前空間に置かれます。もしプラグインの中でセルを作るのであれば、 その名前空間は `PluginName\View\Cell` になります。 * クラス名は Cell で終わらなければなりません。 * クラスは `Cake\View\Cell` を継承しなければなりません。 私たちのセルには空の `display()` メソッドを追加しましたが、これはセルを描画する時の 規約上の既定のメソッドです。この文書の後ろで、他のメソッドの使い方についても扱います。 さて、ファイル **src/Template/Cell/Inbox/display.ctp** を作成しましょう。 これは、私たちの新しいセルのためのテンプレートになります。 `bake` を使って手早くこのスタブコードを生成することもできます。 : bin/cake bake cell Inbox これは上記で作成したコードを生成してくれるでしょう。 セルの実装 [​](https://book.cakephp.org/3.x/ja/views/cells.html#%E3%82%BB%E3%83%AB%E3%81%AE%E5%AE%9F%E8%A3%85) ---------------------------------------------------------------------------------------------------------- ユーザー同士で互いにメッセージを送りあえるアプリケーションを開発しているとしましょう。 私たちは `Messages` モデルを持っていて、そして AppController を汚さずに 未読メッセージの数を表示したいとします。これはまさにセルを使用するケースです。 先ほど作ったクラスに、以下を追加します。 : namespace App\View\Cell; use Cake\View\Cell; class InboxCell extends Cell { public function display() { $this->loadModel('Messages'); $unread = $this->Messages->find('unread'); $this->set('unread_count', $unread->count()); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 セルは `ModelAwareTrait` と `ViewVarsTrait` を使用しているため、コントローラーに とてもよく似たふるまいをします。コントローラー中とまったく同じように、 `loadModel()` や `set()` メソッドを使うことができます。テンプレートファイルの中に、 以下を追加します。 :
    未読メッセージが 件あります。
    1 2 3 4 NOTE セルのテンプレートは分離したスコープを持っていて、現在のコントローラーのアクション または他のセル用のテンプレートやレイアウトを描画するのに使われたビューのインスタンスを 共有しません。したがって、アクションのテンプレートやレイアウト中でのヘルパーの呼び出し あるいはブロックのセットなどには気付きません。 セルの呼び出し [​](https://book.cakephp.org/3.x/ja/views/cells.html#%E3%82%BB%E3%83%AB%E3%81%AE%E5%91%BC%E3%81%B2%E3%82%99%E5%87%BA%E3%81%97) --------------------------------------------------------------------------------------------------------------------------------------- セルは `cell()` メソッドを使ってビューから呼び出すことができて、下のいずれのコンテキストでも 同様に動きます。 : // アプリケーションのセルの呼び出し $cell = $this->cell('Inbox'); // プラグインのセルの呼び出し $cell = $this->cell('Messaging.Inbox'); 1 2 3 4 5 上記は当該の名前のセルを呼び出して、その `display()` メソッドを実行します。 以下のようにして、他のメソッドを実行することもできます。 : // Inbox セル上の expanded() メソッドを実行します $cell = $this->cell('Inbox::expanded'); 1 2 もしもリクエスト中でどのセルを呼び出すかを決定するためのコントローラー処理が必要な場合、 コントローラー中で `cell()` メソッドを有効にするために `CellTrait` を使用することができます。 : namespace App\Controller; use App\Controller\AppController; use Cake\View\CellTrait; class DashboardsController extends AppController { use CellTrait; // 他のコード。 } 1 2 3 4 5 6 7 8 9 10 11 セルに引数を渡す [​](https://book.cakephp.org/3.x/ja/views/cells.html#%E3%82%BB%E3%83%AB%E3%81%AB%E5%BC%95%E6%95%B0%E3%82%92%E6%B8%A1%E3%81%99) ---------------------------------------------------------------------------------------------------------------------------------------- セルをより柔軟にするために、パラメーター付きのセルのメソッドが必要になることも多いでしょう。 添字付きの配列として `cell()` の第二、第三引数を使用することで、アクションのパラメーターや、 追加のオプションをセルクラスに渡すことができます。 : $cell = $this->cell('Inbox::recent', ['-3 days']); 1 上記は以下のような関数の定義になるでしょう。 : public function recent($since) { } 1 2 3 ビューの描画 [​](https://book.cakephp.org/3.x/ja/views/cells.html#%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E3%81%AE%E6%8F%8F%E7%94%BB) ----------------------------------------------------------------------------------------------------------------------------- セルが呼び出されて実行された後は、おそらくそれを描画したいはずです。セルを描画するための 最も簡単な方法はそれをエコーすることです。 : 1 これはアクション名を小文字にしてアンダースコアー区切りにしたものに一致するテンプレートを 描画します。例えば **display.ctp** です。 セルはテンプレートを描画するために `View` を使用しますので、もし必要であれば セルのテンプレートの中で追加のセルを呼び出すこともできます。 NOTE セルをエコーすると PHP のマジックメソッド `__toString()` を使用するため 致命的なエラーが発生した際にファイル名や行番号を表示するのを抑制してしまいます。 意味のあるエラーメッセージを得るためには、例えば `render() ?>` のようにして、 `Cell::render()` メソッドを使用することを推奨します。 ### 別のテンプレートの描画 [​](https://book.cakephp.org/3.x/ja/views/cells.html#%E5%88%A5%E3%81%AE%E3%83%86%E3%83%B3%E3%83%95%E3%82%9A%E3%83%AC%E3%83%BC%E3%83%88%E3%81%AE%E6%8F%8F%E7%94%BB) 規約ではセルは実行するアクションに一致するテンプレートを描画します。 もし、異なるビューテンプレートを描画する必要があれば、セルを描画する時に 使用するテンプレートを指定することができます。 : // 明示的に render() を呼び出します echo $this->cell('Inbox::recent', ['-3 days'])->render('messages'); // セルをエコーする前にテンプレートを設定します。 $cell = $this->cell('Inbox'); $cell->viewBuilder()->setTemplate('messages'); // 3.4 より前 $cell->viewBuilder()->template('messages'); // 3.1 より前 $cell->template = 'messages'; echo $cell; 1 2 3 4 5 6 7 8 9 10 11 ### セルの出力のキャッシュ [​](https://book.cakephp.org/3.x/ja/views/cells.html#%E3%82%BB%E3%83%AB%E3%81%AE%E5%87%BA%E5%8A%9B%E3%81%AE%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5) もしも出力内容が頻繁には変わらない、あるいはアプリケーションのパフォーマンス向上のために、 セルを描画する際にその出力をキャッシュしたいかもしれません。キャッシュを有効にする、あるいは 設定するために、セルを作成する時に `cache` オプションを定義することができます。 : // 既定の設定と生成キーを使用してキャッシュします $cell = $this->cell('Inbox', [], ['cache' => true]); // 特定のキャッシュ設定と生成キーでキャッシュします $cell = $this->cell('Inbox', [], ['cache' => ['config' => 'cell_cache']]); // 使用するキーと設定を指定します。 $cell = $this->cell('Inbox', [], [\ 'cache' => ['config' => 'cell_cache', 'key' => 'inbox_' . $user->id]\ ]); 1 2 3 4 5 6 7 8 9 10 キーが生成される場合には、そのクラスとテンプレートの名前をアンダースコアー区切りにしたものが 使用されます。 NOTE 各セルを描画するために新しい `View` インスタンスが作成され、それらの新しいオブジェクトは メインのテンプレート/レイアウトとはコンテキストを共有しません。各セルは内包されていて、 `View::cell()` の呼び出しの引数として渡された変数にのみアクセスが可能です。 セル内のデータのページ制御 [​](https://book.cakephp.org/3.x/ja/views/cells.html#%E3%82%BB%E3%83%AB%E5%86%85%E3%81%AE%E3%83%86%E3%82%99%E3%83%BC%E3%82%BF%E3%81%AE%E3%83%98%E3%82%9A%E3%83%BC%E3%82%B7%E3%82%99%E5%88%B6%E5%BE%A1) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ページ制御された結果セットを描画するセルを作成するには、ORM の `Paginator` クラスを利用します。 ユーザーのお気に入りメッセージをページ制御する例は次のようになります。 : namespace App\View\Cell; use Cake\View\Cell; use Cake\Datasource\Paginator; class FavoritesCell extends Cell { public function display($user) { $this->loadModel('Messages'); // paginator の作成 $paginator = new Paginator(); // モデルをページ制御 $results = $paginator->paginate( $this->Messages, $this->request->getQueryParams(), [\ // パラメーター付きカスタムファインダーを使用\ 'finder' => ['favorites' => [$user]],\ \ // スコープ指定のクエリー文字列パラメーターを使用\ 'scope' => 'favorites',\ ] ); $paging = $paginator->getPagingParams() + (array)$request->getParam('paging'); $this->request = $this->request->withParam('paging', $paging)); $this->set('favorites', $results); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 上記のセルは、 [スコープ指定のページ制御パラメーター](https://book.cakephp.org/3.x/ja/controllers/components/pagination.html#paginating-multiple-queries) を使用して `Messages` モデルをページ制御します。 Added in version 3.5.0 `Cake\Datasource\Paginator` は 3.5.0 で追加されました。 セルのオプション [​](https://book.cakephp.org/3.x/ja/views/cells.html#%E3%82%BB%E3%83%AB%E3%81%AE%E3%82%AA%E3%83%95%E3%82%9A%E3%82%B7%E3%83%A7%E3%83%B3) ------------------------------------------------------------------------------------------------------------------------------------------------- セルは、セルオブジェクトの作成時にプロパティーに変換されるコンストラクターオプションを宣言できます。 : namespace App\View\Cell; use Cake\View\Cell; use Cake\Datasource\Paginator; class FavoritesCell extends Cell { protected $_validCellOptions = ['limit']; protected $limit = 3; public function display($userId) { $this->loadModel('Users'); $result = $this->Users->find('friends', ['for' => $userId]); $this->set('favorites', $result); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ここでは、 `$limit` プロパティーを定義し、 `limit` をセルのオプションとして追加しました。 これにより、セルの作成時にオプションを定義することができます。 : $cell = $this->cell('Favorites', [$user->id], ['limit' => 10]) 1 セルのオプションは、データをプロパティーとして使用してデフォルト値を オーバーライドできるようにする場合に便利です。 --- # Security | CakePHP [Skip to content](https://book.cakephp.org/3.x/security.html#VPContent) Return to top Security [​](https://book.cakephp.org/3.x/security.html#security) ================================================================== CakePHP provides you some tools to secure your application. The following sections cover those tools: * [Security Utility](https://book.cakephp.org/3.x/core-libraries/security.html) * [Cross Site Request Forgery](https://book.cakephp.org/3.x/controllers/components/csrf.html) * [Security Component](https://book.cakephp.org/3.x/controllers/components/security.html) --- # Views | CakePHP [Skip to content](https://book.cakephp.org/3.x/views.html#VPContent) Return to top Views [​](https://book.cakephp.org/3.x/views.html#views) ========================================================= `class` Cake\\View\\**View** Views are the **V** in MVC. Views are responsible for generating the specific output required for the request. Often this is in the form of HTML, XML, or JSON, but streaming files and creating PDFs that users can download are also responsibilities of the View Layer. CakePHP comes with a few built-in View classes for handling the most common rendering scenarios: * To create XML or JSON webservices you can use the [JSON and XML views](https://book.cakephp.org/3.x/views/json-and-xml-views.html) . * To serve protected files, or dynamically generated files, you can use [Cake Response File](https://book.cakephp.org/3.x/controllers/request-response.html#cake-response-file) . * To create multiple themed views, you can use [Themes](https://book.cakephp.org/3.x/views/themes.html) . The App View [​](https://book.cakephp.org/3.x/views.html#the-app-view) ----------------------------------------------------------------------- `AppView` is your application’s default View class. `AppView` itself extends the `Cake\View\View` class included in CakePHP and is defined in **src/View/AppView.php** as follows: loadHelper('MyUtils'); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 View Templates [​](https://book.cakephp.org/3.x/views.html#view-templates) --------------------------------------------------------------------------- The view layer of CakePHP is how you speak to your users. Most of the time your views will be rendering HTML/XHTML documents to browsers, but you might also need to reply to a remote application via JSON, or output a CSV file for a user. CakePHP template files have a default extension of **.ctp** (CakePHP Template) and utilize the [alternative PHP syntax](https://php.net/manual/en/control-structures.alternative-syntax.php) for control structures and output. These files contain the logic necessary to prepare the data received from the controller into a presentation format that is ready for your audience. ### Alternative Echos [​](https://book.cakephp.org/3.x/views.html#alternative-echos) Echo, or print a variable in your template: 1 Using Short Tag support: 1 ### Alternative Control Structures [​](https://book.cakephp.org/3.x/views.html#alternative-control-structures) Control structures, like `if`, `for`, `foreach`, `switch`, and `while` can be written in a simplified format. Notice that there are no braces. Instead, the end brace for the `foreach` is replaced with `endforeach`. Each of the control structures listed above has a similar closing syntax: `endif`, `endfor`, `endforeach`, and `endwhile`. Also notice that instead of using a `semicolon` after each structure (except the last one), there is a `colon`. The following is an example using `foreach`:
    1 2 3 4 5 Another example, using if/elseif/else. Notice the colons:

    Hi Sally

    Hi Joe

    Hi unknown user

    1 2 3 4 5 6 7 If you'd prefer using a templating language like [Twig](https://twig.sensiolabs.org/) , a subclass of View will bridge your templating language and CakePHP. Template files are stored in **src/Template/**, in a folder named after the controller that uses the files, and named after the action it corresponds to. For example, the view file for the `Products` controller's `view()` action, would normally be found in **src/Template/Products/view.ctp**. The view layer in CakePHP can be made up of a number of different parts. Each part has different uses, and will be covered in this chapter: * **templates**: Templates are the part of the page that is unique to the action being run. They form the meat of your application's response. * **elements**: small, reusable bits of view code. Elements are usually rendered inside views. * **layouts**: template files that contain presentational code that wraps many interfaces in your application. Most views are rendered inside a layout. * **helpers**: these classes encapsulate view logic that is needed in many places in the view layer. Among other things, helpers in CakePHP can help you build forms, build AJAX functionality, paginate model data, or serve RSS feeds. * **cells**: these classes provide miniature controller-like features for creating self contained UI components. See the [View Cells](https://book.cakephp.org/3.x/views/cells.html) documentation for more information. ### View Variables [​](https://book.cakephp.org/3.x/views.html#view-variables) Any variables you set in your controller with `set()` will be available in both the view and the layout your action renders. In addition, any set variables will also be available in any element. If you need to pass additional variables from the view to the layout you can either call `set()` in the view template, or use a [View Blocks](https://book.cakephp.org/3.x/views.html#view-blocks) . You should remember to **always** escape any user data before outputting it as CakePHP does not automatically escape output. You can escape user content with the `h()` function: bio); ?> 1 ### Setting View Variables [​](https://book.cakephp.org/3.x/views.html#setting-view-variables) `method` Cake\\View\\View::**set**(string $var, mixed $value) Views have a `set()` method that is analogous to the `set()` found in Controller objects. Using set() from your view file will add the variables to the layout and elements that will be rendered later. See [Setting View Variables](https://book.cakephp.org/3.x/controllers.html#setting-view-variables) for more information on using `set()`. In your view file you can do: $this->set('activeMenuButton', 'posts'); 1 Then, in your layout, the `$activeMenuButton` variable will be available and contain the value 'posts'. ### Extending Views [​](https://book.cakephp.org/3.x/views.html#extending-views) View extending allows you to wrap one view in another. Combining this with [view blocks](https://book.cakephp.org/3.x/views.html#view-blocks) gives you a powerful way to keep your views `DRY`. For example, your application has a sidebar that needs to change depending on the specific view being rendered. By extending a common view file, you can avoid repeating the common markup for your sidebar, and only define the parts that change:

    fetch('title')) ?>

    fetch('content') ?>

    Related actions

      fetch('sidebar') ?>
    1 2 3 4 5 6 7 8 9 10 The above view file could be used as a parent view. It expects that the view extending it will define the `sidebar` and `title` blocks. The `content` block is a special block that CakePHP creates. It will contain all the uncaptured content from the extending view. Assuming our view file has a `$post` variable with the data about our post, the view could look like: extend('/Common/view'); $this->assign('title', $post->title); $this->start('sidebar'); ?>
  • Html->link('edit', [\ 'action' => 'edit',\ $post->id\ ]); ?>
  • end(); ?> // The remaining content will be available as the 'content' block // In the parent view. body) ?> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 The post view above shows how you can extend a view, and populate a set of blocks. Any content not already in a defined block will be captured and put into a special block named `content`. When a view contains a call to `extend()`, execution continues to the bottom of the current view file. Once it is complete, the extended view will be rendered. Calling `extend()` more than once in a view file will override the parent view that will be processed next: $this->extend('/Common/view'); $this->extend('/Common/index'); 1 2 The above will result in **/Common/index.ctp** being rendered as the parent view to the current view. You can nest extended views as many times as necessary. Each view can extend another view if desired. Each parent view will get the previous view's content as the `content` block. NOTE You should avoid using `content` as a block name in your application. CakePHP uses this for uncaptured content in extended views. You can get the list of all populated blocks using the `blocks()` method: $list = $this->blocks(); 1 Using View Blocks [​](https://book.cakephp.org/3.x/views.html#using-view-blocks) --------------------------------------------------------------------------------- View blocks provide a flexible API that allows you to define slots or blocks in your views/layouts that will be defined elsewhere. For example, blocks are ideal for implementing things such as sidebars, or regions to load assets at the bottom/top of the layout. Blocks can be defined in two ways: either as a capturing block, or by direct assignment. The `start()`, `append()`, `prepend()`, `assign()`, `fetch()`, and `end()` methods allow you to work with capturing blocks: // Create the sidebar block. $this->start('sidebar'); echo $this->element('sidebar/recent_topics'); echo $this->element('sidebar/recent_comments'); $this->end(); // Append into the sidebar later on. $this->start('sidebar'); echo $this->fetch('sidebar'); echo $this->element('sidebar/popular_topics'); $this->end(); 1 2 3 4 5 6 7 8 9 10 11 You can also append into a block using `append()`: $this->append('sidebar'); echo $this->element('sidebar/popular_topics'); $this->end(); // The same as the above. $this->append('sidebar', $this->element('sidebar/popular_topics')); 1 2 3 4 5 6 If you need to clear or overwrite a block there are a couple of alternatives. The `reset()` method will clear or overwrite a block at any time. The `assign()` method with an empty content string can also be used to clear the specified block.: // Clear the previous content from the sidebar block. $this->reset('sidebar'); // Assigning an empty string will also clear the sidebar block. $this->assign('sidebar', ''); 1 2 3 4 5 Added in version 3.2 View::reset() was added in 3.2 Assigning a block's content is often useful when you want to convert a view variable into a block. For example, you may want to use a block for the page title, and sometimes assign the title as a view variable in the controller: // In view file or layout above $this->fetch('title') $this->assign('title', $title); 1 2 The `prepend()` method allows you to prepend content to an existing block: // Prepend to sidebar $this->prepend('sidebar', 'this content goes on top of sidebar'); 1 2 ### Displaying Blocks [​](https://book.cakephp.org/3.x/views.html#displaying-blocks) You can display blocks using the `fetch()` method. `fetch()` will output a block, returning '' if a block does not exist: fetch('sidebar') ?> 1 You can also use fetch to conditionally show content that should surround a block should it exist. This is helpful in layouts, or extended views where you want to conditionally show headings or other markup: // In src/Template/Layout/default.ctp fetch('menu')): ?> 1 2 3 4 5 6 7 You can also provide a default value for a block if it does not exist. This allows you to add placeholder content when a block does not exist. You can provide a default value using the second argument:

    Your Cart

    fetch('cart', 'Your cart is empty') ?>
    1 2 3 4 ### Using Blocks for Script and CSS Files [​](https://book.cakephp.org/3.x/views.html#using-blocks-for-script-and-css-files) The `HtmlHelper` ties into view blocks, and its `script()`, `css()`, and `meta()` methods each update a block with the same name when used with the `block = true` option: Html->script('carousel', ['block' => true]); $this->Html->css('carousel', ['block' => true]); ?> // In your layout file. <?= h($this->fetch('title')) ?> fetch('script') ?> fetch('css') ?> // Rest of the layout follows 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 The `Cake\View\Helper\HtmlHelper` also allows you to control which block the scripts and CSS go to: // In your view $this->Html->script('carousel', ['block' => 'scriptBottom']); // In your layout fetch('scriptBottom') ?> 1 2 3 4 5 Layouts [​](https://book.cakephp.org/3.x/views.html#layouts) ------------------------------------------------------------- A layout contains presentation code that wraps around a view. Anything you want to see in all of your views should be placed in a layout. CakePHP's default layout is located at **src/Template/Layout/default.ctp**. If you want to change the overall look of your application, then this is the right place to start, because controller-rendered view code is placed inside of the default layout when the page is rendered. Other layout files should be placed in **src/Template/Layout**. When you create a layout, you need to tell CakePHP where to place the output of your views. To do so, make sure your layout includes a place for `$this->fetch('content')` Here's an example of what a default layout might look like: <?= h($this->fetch('title')) ?> fetch('meta'); echo $this->fetch('css'); echo $this->fetch('script'); ?> fetch('content') ?> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 The `script`, `css` and `meta` blocks contain any content defined in the views using the built-in HTML helper. Useful for including JavaScript and CSS files from views. NOTE When using `HtmlHelper::css()` or `HtmlHelper::script()` in template files, specify `'block' => true` to place the HTML source in a block with the same name. (See API for more details on usage). The `content` block contains the contents of the rendered view. You can set the `title` block content from inside your view file: $this->assign('title', 'View Active Users'); 1 Empty values for the `title` block will be automatically replaced with a representation of the current template path, such as `'Admin/Articles'`. You can create as many layouts as you wish: just place them in the **src/Template/Layout** directory, and switch between them inside of your controller actions using the controller or view's `$layout` property: // From a controller public function view() { // Set the layout. $this->viewBuilder()->setLayout('admin'); // Before 3.4 $this->viewBuilder()->layout('admin'); // Before 3.1 $this->layout = 'admin'; } // From a view file $this->layout = 'loggedin'; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 For example, if a section of my site included a smaller ad banner space, I might create a new layout with the smaller advertising space and specify it as the layout for all controllers' actions using something like: namespace App\Controller; class UsersController extends AppController { public function viewActive() { $this->set('title', 'View Active Users'); $this->viewBuilder()->setLayout('default_small_ad'); // or the following before 3.4 $this->viewBuilder()->layout('default_small_ad'); // or the following before 3.1 $this->layout = 'default_small_ad'; } public function viewImage() { $this->viewBuilder()->setLayout('image'); // Output user image } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Besides a default layout CakePHP's official skeleton app also has an 'ajax' layout. The Ajax layout is handy for crafting AJAX responses - it's an empty layout. (Most AJAX calls only require a bit of markup in return, rather than a fully-rendered interface.) The skeleton app also has a default layout to help generate RSS. ### Using Layouts from Plugins [​](https://book.cakephp.org/3.x/views.html#using-layouts-from-plugins) If you want to use a layout that exists in a plugin, you can use `plugin syntax`. For example, to use the contact layout from the Contacts plugin: namespace App\Controller; class UsersController extends AppController { public function viewActive() { $this->viewBuilder()->setLayout('Contacts.contact'); // or the following before 3.4 $this->viewBuilder()->layout('Contacts.contact'); // or the following before 3.1 $this->layout = 'Contacts.contact'; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 Elements [​](https://book.cakephp.org/3.x/views.html#elements) --------------------------------------------------------------- `method` Cake\\View\\View::**element**(string $elementPath, array $data, array $options = \[\]) Many applications have small blocks of presentation code that need to be repeated from page to page, sometimes in different places in the layout. CakePHP can help you repeat parts of your website that need to be reused. These reusable parts are called Elements. Ads, help boxes, navigational controls, extra menus, login forms, and callouts are often implemented in CakePHP as elements. An element is basically a mini-view that can be included in other views, in layouts, and even within other elements. Elements can be used to make a view more readable, placing the rendering of repeating elements in its own file. They can also help you re-use content fragments in your application. Elements live in the **src/Template/Element/** folder, and have the .ctp filename extension. They are output using the element method of the view: echo $this->element('helpbox'); 1 ### Passing Variables into an Element [​](https://book.cakephp.org/3.x/views.html#passing-variables-into-an-element) You can pass data to an element through the element's second argument: echo $this->element('helpbox', [\ "helptext" => "Oh, this text is very helpful."\ ]); 1 2 3 Inside the element file, all the passed variables are available as members of the parameter array. In the above example, the **src/Template/Element/helpbox.ctp** file can use the `$helptext` variable: // Inside src/Template/Element/helpbox.ctp echo $helptext; // Outputs "Oh, this text is very helpful." 1 2 Keep in mind that in those view vars are merged with the view vars from the view itself. So all view vars set using `Controller::set()` in the controller and `View::set()` in the view itself are also available inside the element. The `View::element()` method also supports options for the element. The options supported are 'cache' and 'callbacks'. An example: echo $this->element('helpbox', [\ "helptext" => "This is passed to the element as $helptext",\ "foobar" => "This is passed to the element as $foobar",\ ], [\ // uses the "long_view" cache configuration\ "cache" => "long_view",\ // set to true to have before/afterRender called for the element\ "callbacks" => true\ ] ); 1 2 3 4 5 6 7 8 9 10 11 Element caching is facilitated through the `Cache` class. You can configure elements to be stored in any Cache configuration you've set up. This gives you a great amount of flexibility to decide where and for how long elements are stored. To cache different versions of the same element in an application, provide a unique cache key value using the following format: $this->element('helpbox', [], [\ "cache" => ['config' => 'short', 'key' => 'unique value']\ ] ); 1 2 3 4 If you need more logic in your element, such as dynamic data from a datasource, consider using a View Cell instead of an element. Find out more [about View Cells](https://book.cakephp.org/3.x/views/cells.html) . ### Caching Elements [​](https://book.cakephp.org/3.x/views.html#caching-elements) You can take advantage of CakePHP view caching if you supply a cache parameter. If set to `true`, it will cache the element in the 'default' Cache configuration. Otherwise, you can set which cache configuration should be used. See [Caching](https://book.cakephp.org/3.x/core-libraries/caching.html) for more information on configuring `Cache`. A simple example of caching an element would be: echo $this->element('helpbox', [], ['cache' => true]); 1 If you render the same element more than once in a view and have caching enabled, be sure to set the 'key' parameter to a different name each time. This will prevent each successive call from overwriting the previous `element()` call's cached result. For example: echo $this->element( 'helpbox', ['var' => $var], ['cache' => ['key' => 'first_use', 'config' => 'view_long']] ); echo $this->element( 'helpbox', ['var' => $differenVar], ['cache' => ['key' => 'second_use', 'config' => 'view_long']] ); 1 2 3 4 5 6 7 8 9 10 11 The above will ensure that both element results are cached separately. If you want all element caching to use the same cache configuration, you can avoid some repetition by setting `View::$elementCache` to the cache configuration you want to use. CakePHP will use this configuration when none is given. ### Requesting Elements from a Plugin [​](https://book.cakephp.org/3.x/views.html#requesting-elements-from-a-plugin) If you are using a plugin and wish to use elements from within the plugin, just use the familiar `plugin syntax`. If the view is being rendered for a plugin controller/action, the plugin name will automatically be prefixed onto all elements used, unless another plugin name is present. If the element doesn't exist in the plugin, it will look in the main APP folder: echo $this->element('Contacts.helpbox'); 1 If your view is a part of a plugin, you can omit the plugin name. For example, if you are in the `ContactsController` of the Contacts plugin, the following: echo $this->element('helpbox'); // and echo $this->element('Contacts.helpbox'); 1 2 3 are equivalent and will result in the same element being rendered. For elements inside subfolder of a plugin (e.g., **plugins/Contacts/Template/Element/sidebar/helpbox.ctp**), use the following: echo $this->element('Contacts.sidebar/helpbox'); 1 ### Routing prefix and Elements [​](https://book.cakephp.org/3.x/views.html#routing-prefix-and-elements) Added in version 3.0.1 If you have a Routing prefix configured, the Element path resolution can switch to a prefix location, as Layouts and action View do. Assuming you have a prefix "Admin" configured and you call: echo $this->element('my_element'); 1 The element first be looked for in **src/Template/Admin/Element/**. If such a file does not exist, it will be looked for in the default location. ### Caching Sections of Your View [​](https://book.cakephp.org/3.x/views.html#caching-sections-of-your-view) `method` Cake\\View\\View::**cache**(callable $block, array $options = \[\]) Sometimes generating a section of your view output can be expensive because of rendered [View Cells](https://book.cakephp.org/3.x/views/cells.html) or expensive helper operations. To help make your application run faster CakePHP provides a way to cache view sections: // Assuming some local variables echo $this->cache(function () use ($user, $article) { echo $this->cell('UserProfile', [$user]); echo $this->cell('ArticleFull', [$article]); }, ['key' => 'my_view_key']); 1 2 3 4 5 By default cached view content will go into the `View::$elementCache` cache config, but you can use the `config` option to change this. View Events [​](https://book.cakephp.org/3.x/views.html#view-events) --------------------------------------------------------------------- Like Controller, view trigger several events/callbacks that you can use to insert logic around the rendering life-cycle: ### Event List [​](https://book.cakephp.org/3.x/views.html#event-list) * `View.beforeRender` * `View.beforeRenderFile` * `View.afterRenderFile` * `View.afterRender` * `View.beforeLayout` * `View.afterLayout` You can attach application [event listeners](https://book.cakephp.org/3.x/core-libraries/events.html) to these events or use [Helper Callbacks](https://book.cakephp.org/3.x/views/helpers.html#helper-api) . Creating Your Own View Classes [​](https://book.cakephp.org/3.x/views.html#creating-your-own-view-classes) ----------------------------------------------------------------------------------------------------------- You may need to create custom view classes to enable new types of data views, or add additional custom view-rendering logic to your application. Like most components of CakePHP, view classes have a few conventions: * View class files should be put in **src/View**. For example: **src/View/PdfView.php** * View classes should be suffixed with `View`. For example: `PdfView`. * When referencing view class names you should omit the `View` suffix. For example: `$this->viewBuilder()->setClassName('Pdf');`. You'll also want to extend `View` to ensure things work correctly: // In src/View/PdfView.php namespace App\View; use Cake\View\View; class PdfView extends View { public function render($view = null, $layout = null) { // Custom logic here. } } 1 2 3 4 5 6 7 8 9 10 11 12 Replacing the render method lets you take full control over how your content is rendered. More About Views [​](https://book.cakephp.org/3.x/views.html#more-about-views) ------------------------------------------------------------------------------- * [View Cells](https://book.cakephp.org/3.x/views/cells.html) * [Themes](https://book.cakephp.org/3.x/views/themes.html) * [JSON and XML views](https://book.cakephp.org/3.x/views/json-and-xml-views.html) * [Helpers](https://book.cakephp.org/3.x/views/helpers.html) --- # Blog Tutorial - Part 2 | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#VPContent) Return to top Blog Tutorial - Part 2 [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#blog-tutorial-part-2) ======================================================================================================================== Create an Article Model [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#create-an-article-model) ---------------------------------------------------------------------------------------------------------------------------- Models are the bread and butter of CakePHP applications. By creating a CakePHP model that will interact with our database, we'll have the foundation in place needed to do our view, add, edit, and delete operations later. CakePHP's model class files are split between `Table` and `Entity` objects. `Table` objects provide access to the collection of entities stored in a specific table and go in **src/Model/Table**. The file we'll be creating will be saved to **src/Model/Table/ArticlesTable.php**. The completed file should look like this: // src/Model/Table/ArticlesTable.php namespace App\Model\Table; use Cake\ORM\Table; class ArticlesTable extends Table { public function initialize(array $config) { $this->addBehavior('Timestamp'); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 Naming conventions are very important in CakePHP. By naming our Table object `ArticlesTable`, CakePHP can automatically infer that this Table object will be used in the `ArticlesController`, and will be tied to a database table called `articles`. NOTE CakePHP will dynamically create a model object for you if it cannot find a corresponding file in **src/Model/Table**. This also means that if you accidentally name your file wrong (i.e. articlestable.php or ArticleTable.php), CakePHP will not recognize any of your settings and will use the generated model instead. For more on models, such as callbacks, and validation, check out the [Database Access & ORM](https://book.cakephp.org/3.x/orm.html) chapter of the Manual. NOTE If you completed [Part 1 of the Blog Tutorial](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html) and created the `articles` table in our Blog database you can leverage CakePHP's bake console and its code generation capabilities to create the `ArticlesTable` model: bin/cake bake model Articles 1 For more on bake and its code generation features please visit [Code Generation with Bake](https://book.cakephp.org/3.x/bake/usage.html) . Create the Articles Controller [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#create-the-articles-controller) ------------------------------------------------------------------------------------------------------------------------------------------ Next, we'll create a controller for our articles. The controller is where all interaction with articles will happen. In a nutshell, it's the place where you play with the business logic contained in the models and get work related to articles done. We'll place this new controller in a file called **ArticlesController.php** inside the **src/Controller** directory. Here's what the basic controller should look like: // src/Controller/ArticlesController.php namespace App\Controller; class ArticlesController extends AppController { } 1 2 3 4 5 6 7 Now, let's add an action to our controller. Actions often represent a single function or interface in an application. For example, when users request www.example.com/articles/index (which is also the same as www.example.com/articles/), they might expect to see a listing of articles. The code for that action would look like this: // src/Controller/ArticlesController.php namespace App\Controller; class ArticlesController extends AppController { public function index() { $articles = $this->Articles->find('all'); $this->set(compact('articles')); } } 1 2 3 4 5 6 7 8 9 10 11 12 By defining function `index()` in our `ArticlesController`, users can now access the logic there by requesting www.example.com/articles/index. Similarly, if we were to define a function called `foobar()`, users would be able to access that at www.example.com/articles/foobar. WARNING You may be tempted to name your controllers and actions a certain way to obtain a certain URL. Resist that temptation. Follow [CakePHP Conventions](https://book.cakephp.org/3.x/intro/conventions.html) (capitalization, plural names, etc.) and create readable, understandable action names. You can map URLs to your code using [Routing](https://book.cakephp.org/3.x/development/routing.html) covered later on. The single instruction in the action uses `set()` to pass data from the controller to the view (which we'll create next). The line sets the view variable called 'articles' equal to the return value of the `find('all')` method of the `ArticlesTable` object. NOTE If you completed [Part 1 of the Blog Tutorial](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html) and created the `articles` table in your Blog database you can leverage CakePHP's bake console and its code generation capabilities to create the ArticlesController class: bin/cake bake controller Articles 1 For more on bake and its code generation features please visit [Code Generation with Bake](https://book.cakephp.org/3.x/bake/usage.html) . To learn more about CakePHP's controllers, check out the [Controllers](https://book.cakephp.org/3.x/controllers.html) chapter. Creating Article Views [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#creating-article-views) -------------------------------------------------------------------------------------------------------------------------- Now that we have our data flowing from our model, and our application logic is defined by our controller, let's create a view for the index action we created above. CakePHP views are just presentation-flavored fragments that fit inside an application's layout. For most applications, they're HTML mixed with PHP, but they may end up as XML, CSV, or even binary data. A layout is presentation code that is wrapped around a view. Multiple layouts can be defined, and you can switch between them, but for now, let's just use the default. Remember in the last section how we assigned the 'articles' variable to the view using the `set()` method? That would hand down the query object collection to the view to be invoked with a `foreach` iteration. CakePHP's template files are stored in **src/Template** inside a folder named after the controller they correspond to (we'll have to create a folder named 'Articles' in this case). To format this article data in a nice table, our view code might look something like this:

    Blog articles

    Id Title Created
    id ?> Html->link($article->title, ['action' => 'view', $article->id]) ?> created->format(DATE_RFC850) ?>
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Hopefully this should look somewhat simple. You might have noticed the use of an object called `$this->Html`. This is an instance of the CakePHP `Cake\View\Helper\HtmlHelper` class. CakePHP comes with a set of view helpers that make things like linking, form output a snap. You can learn more about how to use them in [Helpers](https://book.cakephp.org/3.x/views/helpers.html) , but what's important to note here is that the `link()` method will generate an HTML link with the given title (the first parameter) and URL (the second parameter). When specifying URLs in CakePHP, it is recommended that you use the array format. This is explained in more detail in the section on Routes. Using the array format for URLs allows you to take advantage of CakePHP's reverse routing capabilities. You can also specify URLs relative to the base of the application in the form of `/controller/action/param1/param2` or use [named routes](https://book.cakephp.org/3.x/development/routing.html#named-routes) . At this point, you should be able to point your browser to [http://www.example.com/articles/index](http://www.example.com/articles/index) . You should see your view, correctly formatted with the title and table listing of the articles. If you happened to have clicked on one of the links we created in this view (that link a article's title to a URL `/articles/view/some\_id`), you were probably informed by CakePHP that the action hasn't yet been defined. If you were not so informed, either something has gone wrong, or you actually did define it already, in which case you are very sneaky. Otherwise, we'll create it in the `ArticlesController` now: // src/Controller/ArticlesController.php namespace App\Controller; class ArticlesController extends AppController { public function index() { $this->set('articles', $this->Articles->find('all')); } public function view($id = null) { $article = $this->Articles->get($id); $this->set(compact('article')); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 The `set()` call should look familiar. Notice we're using `get()` rather than `find('all')` because we only really want a single article's information. Notice that our view action takes a parameter: the ID of the article we'd like to see. This parameter is handed to the action through the requested URL. If a user requests `/articles/view/3`, then the value '3' is passed as `$id`. We also do a bit of error checking to ensure a user is actually accessing a record. By using the `get()` function in the Articles table, we make sure the user has accessed a record that exists. In case the requested article is not present in the database, or the id is false the `get()` function will throw a `NotFoundException`. Now let's create the view for our new 'view' action and place it in **src/Template/Articles/view.ctp**

    title) ?>

    body) ?>

    Created: created->format(DATE_RFC850) ?>

    1 2 3 4 5 Verify that this is working by trying the links at `/articles/index` or manually requesting an article by accessing `/articles/view/{id}`, replacing `{id}` by an article 'id'. Adding Articles [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#adding-articles) ------------------------------------------------------------------------------------------------------------ Reading from the database and showing us the articles is a great start, but let's allow for the adding of new articles. First, start by creating an `add()` action in the `ArticlesController`: // src/Controller/ArticlesController.php namespace App\Controller; use App\Controller\AppController; class ArticlesController extends AppController { public function initialize() { parent::initialize(); $this->loadComponent('Flash'); // Include the FlashComponent } public function index() { $this->set('articles', $this->Articles->find('all')); } public function view($id) { $article = $this->Articles->get($id); $this->set(compact('article')); } public function add() { $article = $this->Articles->newEntity(); if ($this->request->is('post')) { // Prior to 3.4.0 $this->request->data() was used. $article = $this->Articles->patchEntity($article, $this->request->getData()); if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to add your article.')); } $this->set('article', $article); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 NOTE You need to include the [Flash](https://book.cakephp.org/3.x/controllers/components/flash.html) component in any controller where you will use it. If necessary, include it in your `AppController`. Here's what the `add()` action does: if the HTTP method of the request was POST, try to save the data using the Articles model. If for some reason it doesn't save, just render the view. This gives us a chance to show the user validation errors or other warnings. Every CakePHP request includes a `ServerRequest` object which is accessible using `$this->request`. The request object contains useful information regarding the request that was just received, and can be used to control the flow of your application. In this case, we use the `Cake\Http\ServerRequest::is()` method to check that the request is a HTTP POST request. When a user uses a form to POST data to your application, that information is available in `$this->request->getData()` ( Or `$this->request->data()` for CakePHP v3.3 and under ). You can use the `pr()` or `debug()` functions to print it out if you want to see what it looks like. We use FlashComponent's `success()` and `error()` methods to set a message to a session variable. These methods are provided using PHP's [magic method features](https://php.net/manual/en/language.oop5.overloading.php#object.call) . Flash messages will be displayed on the page after redirection. In the layout we have `Flash->render() ?>` which displays the message and clears the corresponding session variable. The controller's `Cake\Controller\Controller::redirect` function redirects to another URL. The param `['action' => 'index']` translates to URL /articles i.e the index action of the `ArticlesController`. You can refer to `Cake\Routing\Router::url()` function on the [API](https://api.cakephp.org/) to see the formats in which you can specify a URL for various CakePHP functions. Calling the `save()` method will check for validation errors and abort the save if any occur. We'll discuss how those errors are handled in the following sections. Data Validation [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#data-validation) ------------------------------------------------------------------------------------------------------------ CakePHP goes a long way toward taking the monotony out of form input validation. Everyone hates coding up endless forms and their validation routines. CakePHP makes it easier and faster. To take advantage of the validation features, you'll need to use CakePHP's [Form](https://book.cakephp.org/3.x/views/helpers/form.html) helper in your views. The `Cake\View\Helper\FormHelper` is available by default to all views at `$this->Form`. Here's our add view:

    Add Article

    Form->create($article); echo $this->Form->control('title'); echo $this->Form->control('body', ['rows' => '3']); echo $this->Form->button(__('Save Article')); echo $this->Form->end(); ?> 1 2 3 4 5 6 7 8 9 10 We use the FormHelper to generate the opening tag for an HTML form. Here's the HTML that `$this->Form->create()` generates: 1 If `create()` is called with no parameters supplied, it assumes you are building a form that submits via POST to the current controller's `add()` action (or `edit()` action when `id` is included in the form data). The `$this->Form->control()` method is used to create form elements of the same name. The first parameter tells CakePHP which field they correspond to, and the second parameter allows you to specify a wide array of options - in this case, the number of rows for the textarea. There's a bit of introspection and automagic here: `control()` will output different form elements based on the model field specified. The `$this->Form->end()` call ends the form. Outputting hidden inputs if CSRF/Form Tampering prevention is enabled. Now let's go back and update our **src/Template/Articles/index.ctp** view to include a new "Add Article" link. Before the ``, add the following line: Html->link('Add Article', ['action' => 'add']) ?> 1 You may be wondering: how do I tell CakePHP about my validation requirements? Validation rules are defined in the model. Let's look back at our Articles model and make a few adjustments: // src/Model/Table/ArticlesTable.php namespace App\Model\Table; use Cake\ORM\Table; use Cake\Validation\Validator; class ArticlesTable extends Table { public function initialize(array $config) { $this->addBehavior('Timestamp'); } public function validationDefault(Validator $validator) { $validator ->notEmpty('title') ->requirePresence('title') ->notEmpty('body') ->requirePresence('body'); return $validator; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 The `validationDefault()` method tells CakePHP how to validate your data when the `save()` method is called. Here, we've specified that both the body and title fields must not be empty, and are required for both create and update operations. CakePHP's validation engine is strong, with a number of pre-built rules (credit card numbers, email addresses, etc.) and flexibility for adding your own validation rules. For more information on that setup, check the [Validation](https://book.cakephp.org/3.x/core-libraries/validation.html) documentation. Now that your validation rules are in place, use the app to try to add an article with an empty title or body to see how it works. Since we've used the `Cake\View\Helper\FormHelper::control()` method of the FormHelper to create our form elements, our validation error messages will be shown automatically. Editing Articles [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#editing-articles) -------------------------------------------------------------------------------------------------------------- Post editing: here we go. You're a CakePHP pro by now, so you should have picked up a pattern. Make the action, then the view. Here's what the `edit()` action of the `ArticlesController` would look like: // src/Controller/ArticlesController.php public function edit($id = null) { $article = $this->Articles->get($id); if ($this->request->is(['post', 'put'])) { // Prior to 3.4.0 $this->request->data() was used. $this->Articles->patchEntity($article, $this->request->getData()); if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been updated.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to update your article.')); } $this->set('article', $article); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 This action first ensures that the user has tried to access an existing record. If they haven't passed in an `$id` parameter, or the article does not exist, we throw a `NotFoundException` for the CakePHP ErrorHandler to take care of. Next the action checks whether the request is either a POST or a PUT request. If it is, then we use the POST data to update our article entity by using the `patchEntity()` method. Finally we use the table object to save the entity back or kick back and show the user validation errors. The edit view might look something like this:

    Edit Article

    Form->create($article); echo $this->Form->control('title'); echo $this->Form->control('body', ['rows' => '3']); echo $this->Form->button(__('Save Article')); echo $this->Form->end(); ?> 1 2 3 4 5 6 7 8 9 10 This view outputs the edit form (with the values populated), along with any necessary validation error messages. CakePHP will determine whether a `save()` generates an insert or an update statement based on the state of the entity. You can now update your index view with links to edit specific articles:

    Blog articles

    Html->link("Add Article", ['action' => 'add']) ?>

    Id Title Created Action
    id ?> Html->link($article->title, ['action' => 'view', $article->id]) ?> created->format(DATE_RFC850) ?> Html->link('Edit', ['action' => 'edit', $article->id]) ?>
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 Deleting Articles [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#deleting-articles) ---------------------------------------------------------------------------------------------------------------- Next, let's make a way for users to delete articles. Start with a `delete()` action in the `ArticlesController`: // src/Controller/ArticlesController.php public function delete($id) { $this->request->allowMethod(['post', 'delete']); $article = $this->Articles->get($id); if ($this->Articles->delete($article)) { $this->Flash->success(__('The article with id: {0} has been deleted.', h($id))); return $this->redirect(['action' => 'index']); } } 1 2 3 4 5 6 7 8 9 10 11 12 This logic deletes the article specified by `$id`, and uses `$this->Flash->success()` to show the user a confirmation message after redirecting them on to `/articles`. If the user attempts to do a delete using a GET request, the `allowMethod()` will throw an Exception. Uncaught exceptions are captured by CakePHP's exception handler, and a nice error page is displayed. There are many built-in [Exceptions](https://book.cakephp.org/3.x/development/errors.html) that can be used to indicate the various HTTP errors your application might need to generate. Because we're just executing some logic and redirecting, this action has no view. You might want to update your index view with links that allow users to delete articles, however:

    Blog articles

    Html->link('Add Article', ['action' => 'add']) ?>

    Id Title Created Actions
    id ?> Html->link($article->title, ['action' => 'view', $article->id]) ?> created->format(DATE_RFC850) ?> Form->postLink( 'Delete', ['action' => 'delete', $article->id], ['confirm' => 'Are you sure?']) ?> Html->link('Edit', ['action' => 'edit', $article->id]) ?>
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 Using `Cake\View\Helper\FormHelper::postLink()` will create a link that uses JavaScript to do a POST request deleting our article. WARNING Allowing content to be deleted using GET requests is dangerous, as web crawlers could accidentally delete all your content. NOTE This view code also uses the `FormHelper` to prompt the user with a JavaScript confirmation dialog before they attempt to delete an article. Routes [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#routes) ------------------------------------------------------------------------------------------ For some, CakePHP's default routing works well enough. Developers who are sensitive to user-friendliness and general search engine compatibility will appreciate the way that CakePHP's URLs map to specific actions. So we'll just make a quick change to routes in this tutorial. For more information on advanced routing techniques, see [Routes Configuration](https://book.cakephp.org/3.x/development/routing.html#routes-configuration) . By default, CakePHP responds to a request for the root of your site (e.g., [http://www.example.com](http://www.example.com/) ) using its `PagesController`, rendering a view called "home". Instead, we'll replace this with our ArticlesController by creating a routing rule. CakePHP's routing is found in **config/routes.php**. You'll want to comment out or remove the line that defines the default root route. It looks like this: $routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']); 1 This line connects the URL '/' with the default CakePHP home page. We want it to connect with our own controller, so replace that line with this one: $routes->connect('/', ['controller' => 'Articles', 'action' => 'index']); 1 This should connect users requesting '/' to the `index()` action of our `ArticlesController`. NOTE CakePHP also makes use of 'reverse routing'. If, with the above route defined, you pass `['controller' => 'Articles', 'action' => 'index']` to a function expecting an array, the resulting URL used will be '/'. It's therefore a good idea to always use arrays for URLs as this means your routes define where a URL goes, and also ensures that links point to the same place. Conclusion [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#conclusion) -------------------------------------------------------------------------------------------------- Keep in mind that this tutorial was very basic. CakePHP has _many_ more features to offer, and is flexible in ways we didn't wish to cover here for simplicity's sake. Use the rest of this manual as a guide for building more feature-rich applications. Now that you've created a basic CakePHP application, you can either continue to [Blog Tutorial - Part 3](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-three.html) , or start your own project. You can also peruse the [Using CakePHP](https://book.cakephp.org/3.x/topics.html) or [API](https://api.cakephp.org/) to learn more about CakePHP. If you need help, there are many ways to get the help you need - please see the [Where to Get Help](https://book.cakephp.org/3.x/intro/where-to-get-help.html) page. Welcome to CakePHP! ### Suggested Follow-up Reading [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html#suggested-follow-up-reading) These are common tasks people learning CakePHP usually want to study next: 1. [View Layouts](https://book.cakephp.org/3.x/views.html#view-layouts) : Customizing your website layout 2. [View Elements](https://book.cakephp.org/3.x/views.html#view-elements) : Including and reusing view snippets 3. [Code Generation with Bake](https://book.cakephp.org/3.x/bake/usage.html) : Generating basic CRUD code 4. [Blog Tutorial - Authentication and Authorization](https://book.cakephp.org/3.x/tutorials-and-examples/blog-auth-example/auth.html) : User authentication and authorization tutorial --- # チュートリアルと例 | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/tutorials-and-examples.html#VPContent) Return to top チュートリアルと例 [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples.html#%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB%E3%81%A8%E4%BE%8B) ============================================================================================================================================================= このセクションで、典型的な CakePHP アプリケーションのデモンストレーションを行い、 全てのピースがどう組み合わさっていくかを学ぶことができます。 その他にも、既存のアプリケーションやコンポーネントについて、非公式の CakePHP プラグイン倉庫 [CakePackages](https://plugins.cakephp.org/) や、 [Bakery](https://bakery.cakephp.org/) を参考にすることもできます。 * [コンテンツ管理チュートリアル](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/installation.html) * [CMS チュートリアル - データベース作成](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/database.html) * [CMS チュートリアル - Articles コントローラーの作成](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/articles-controller.html) * [CMS チュートリアル - タグとユーザー](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/tags-and-users.html) * [CMS チュートリアル - 認証](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/authentication.html) --- # Bake コンソール - 2.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/bake/edit/2.x/docs/ja/index.rst) [](https://book.cakephp.org/bake/2/ja/index.html#page-contents) ### Page Contents * [Bake コンソール](https://book.cakephp.org/bake/2/ja/index.html#) * [インストール手順](https://book.cakephp.org/bake/2/ja/index.html#id1) Bake コンソール[¶](https://book.cakephp.org/bake/2/ja/index.html#bake "この見出しへのパーマリンク") ================================================================================== CakePHP の bake コンソールは、迅速に CakePHP を動作させるまでを支援します。 bake コンソールは、CakePHP の基本的な素材(モデル、ビヘイビアー、ビュー、ヘルパー、 コントローラー、コンポーネント、テストケース、フィクスチャー、プラグイン)を作成できます。 その為のスケルトンクラスについては、ここでは省略しますが、 bake は数分で完全に機能するアプリケーションを作成できます。 要するに、bake は足場の組まれたアプリケーションをいっぺんに手に入れるためにうってつけの方法です。 インストール手順[¶](https://book.cakephp.org/bake/2/ja/index.html#id1 "この見出しへのパーマリンク") ------------------------------------------------------------------------------- bake を使用したり拡張する前に、アプリケーションに bake をインストールしておいてください。 bake は Composer を使ってインストールするプラグインとして提供されています。 composer require \--dev cakephp/bake:"^2.0" 上記のコマンドは、bake を開発環境で使用するパッケージとしてインストールします。 この入れ方の場合、本番環境としてデプロイする際には、 bake はインストールされません。 Twig テンプレートを使用する場合、 `Cake/TwigView` プラグインをブートストラップとともに 読み込んでいることを確認してください。それを完全に省略して、 Bake プラグインにこのプラグインを読み込ませることもできます。 [](https://phpc.social/@cakephp "Mastodon") [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://slack-invite.cakephp.org/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") --- # Bake でコード生成 - 2.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/bake/edit/2.x/docs/ja/usage.rst) [](https://book.cakephp.org/bake/2/ja/usage.html#page-contents) ### Page Contents * [Bake でコード生成](https://book.cakephp.org/bake/2/ja/usage.html#) * [Bake テーマオプション](https://book.cakephp.org/bake/2/ja/usage.html#id1) Bake でコード生成[¶](https://book.cakephp.org/bake/2/ja/usage.html#bake "この見出しへのパーマリンク") =================================================================================== cake コンソールは、 PHP CLI (command line interface) で実行します。 もしスクリプトの実行に問題があるなら、以下を満たしてください。 1. PHP CLI がインストールされているか適切なモジュールが有効か確認してください (例:MySQL, intl)。 2. データベースのホストが 'localhost' で問題があるなら、代わりに '127.0.0.1' を使って下さい。 PHP CLI でこの問題がおこる可能性があります。 3. 使っているコンピューターの設定に応じて、 `bin/cake bake` で使用する cake bash スクリプトの 実行権限を設定する必要があります。 bake を実行する前にデータベースとの接続を確認しましょう。 `bin/cake bake` を引数無しで実行すると可能なタスクを表示できます。 Windows システムの場合、 `bin\cake bake` を試してみてください。 それは以下のように表示されます。 $ bin/cake bake Welcome to CakePHP v3.1.6 Console \--------------------------------------------------------------- App : src Path: /var/www/cakephp.dev/src/ PHP: 5.5.8 \--------------------------------------------------------------- The following commands can be used to generate skeleton code for your application. Available bake commands: \- all \- behavior \- cell \- component \- controller \- fixture \- form \- helper \- mailer \- migration \- migration\_snapshot \- model \- plugin \- shell \- shell\-helper \- template \- test By using \`cake bake \[name\]\` you can invoke a specific bake task. より詳しい各コマンドの情報を得るには、 `--help` オプションをつけ実行してください。 $ bin/cake bake controller \--help Welcome to CakePHP v3.1.6 Console \--------------------------------------------------------------- App : src Path: /var/www/cakephp.dev/src/ \--------------------------------------------------------------- Bake a controller skeleton. Usage: cake bake controller \[subcommand\] \[options\] \[\] Subcommands: all Bake all controllers with CRUD methods. To see help on a subcommand use \`cake bake controller \[subcommand\] --help\` Options: \--help, \-h Display this help. \--verbose, \-v Enable verbose output. \--quiet, \-q Enable quiet output. \--plugin, \-p Plugin to bake into. \--force, \-f Force overwriting existing files without prompting. \--connection, \-c The datasource connection to get data from. (default: default) \--theme, \-t The theme to use when baking code. \--components The comma separated list of components to use. \--helpers The comma separated list of helpers to use. \--prefix The namespace/routing prefix to use. \--no\-test Do not generate a test skeleton. \--no\-actions Do not generate basic CRUD action methods. Arguments: name Name of the controller to bake. Can use Plugin.name to bake controllers into plugins. (optional) Bake テーマオプション[¶](https://book.cakephp.org/bake/2/ja/usage.html#id1 "この見出しへのパーマリンク") ------------------------------------------------------------------------------------ テーマオプションは全 bake コマンドで一般的です。また、bake テンプレートファイルを変更することができます。 テーマを作るには、 [Bake テーマ作成ドキュメント](https://book.cakephp.org/bake/2/ja/development.html#creating-a-bake-theme) をご覧ください。 [](https://phpc.social/@cakephp "Mastodon") [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://slack-invite.cakephp.org/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") --- # Chronos - 2.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/chronos/edit/2.x/docs/ja/index.rst) [](https://book.cakephp.org/chronos/2/ja/#page-contents) ### Page Contents * [Chronos](https://book.cakephp.org/chronos/2/ja/#) * [インストール](https://book.cakephp.org/chronos/2/ja/#id1) * [概要](https://book.cakephp.org/chronos/2/ja/#id2) * [インスタンスの作成](https://book.cakephp.org/chronos/2/ja/#id3) * [イミュータブルオブジェクトの動作](https://book.cakephp.org/chronos/2/ja/#id4) * [日付オブジェクト](https://book.cakephp.org/chronos/2/ja/#id5) * [変更メソッド](https://book.cakephp.org/chronos/2/ja/#id6) * [比較メソッド](https://book.cakephp.org/chronos/2/ja/#id7) * [差の生成](https://book.cakephp.org/chronos/2/ja/#id8) * [フォーマットの設定](https://book.cakephp.org/chronos/2/ja/#id9) * [日付要素の抽出](https://book.cakephp.org/chronos/2/ja/#id10) * [テストの支援](https://book.cakephp.org/chronos/2/ja/#id11) Chronos[¶](https://book.cakephp.org/chronos/2/ja/#chronos "この見出しへのパーマリンク") =========================================================================== Chronos (クロノス) は、 `DateTime` オブジェクトへの拡張の依存関係の無いコレクションを提供します。 便利なメソッドに加えて、Chronos は以下を提供します。 * カレンダー日付のための `ChronosDate` オブジェクト * イミュータブルな日付と日時オブジェクト * プラグインのような翻訳システム。ライブラリーは英語のみの翻訳を含んでいます。 しかし、全ての言語サポートのために、 `cakephp/i18n` を使うことができます。 インストール[¶](https://book.cakephp.org/chronos/2/ja/#id1 "この見出しへのパーマリンク") ---------------------------------------------------------------------- Chronos をインストールするためには、 `composer` を利用することができます。 アプリケーションの ROOT ディレクトリー(composer.json ファイルのある場所) で以下のように実行します。 php composer.phar require cakephp/chronos "@stable" 概要[¶](https://book.cakephp.org/chronos/2/ja/#id2 "この見出しへのパーマリンク") ------------------------------------------------------------------ Chronos は PHP が提供する DateTime オブジェクトのいくつかの拡張を提供します。 Chronos は `DateInterval` の拡張機能および、ミュータブル(変更可能)と イミュータブル(変更不可)な 日付/時刻 の派生系をカバーする5つのクラスを提供します。 * `Cake\Chronos\Chronos` はイミュータブルな _日付と時刻_ オブジェクト。 * `Cake\Chronos\ChronosDate` はイミュータブルな _日付_ オブジェクト。 * `Cake\Chronos\MutableDateTime` はミュータブルな _日付と時刻_ オブジェクト。 * `Cake\Chronos\MutableDate` はミュータブルな _日付_ オブジェクト。 * `Cake\Chronos\ChronosInterval` は `DateInterval` の拡張機能。 最後に、もしあなたが Chronos が提供する 日付/時刻 のオブジェクトに対して型宣言を行ないたい場合、 `Cake\Chronos\ChronosInterface` を使用することができます。 全ての日付と時間のオブジェクトはこのインターフェイスを実装しています。 インスタンスの作成[¶](https://book.cakephp.org/chronos/2/ja/#id3 "この見出しへのパーマリンク") ------------------------------------------------------------------------- Chronos または Date のインスタンスを取得するためには、多くの方法があります。 異なる引数セットで動作する多くのファクトリーメソッドがあります。 use Cake\\Chronos\\Chronos; $now \= Chronos::now(); $today \= Chronos::today(); $yesterday \= Chronos::yesterday(); $tomorrow \= Chronos::tomorrow(); // 相対式のパース $date \= Chronos::parse('+2 days, +3 hours'); // 日付と時間の整数値 $date \= Chronos::create(2015, 12, 25, 4, 32, 58); // 日付または時間の整数値 $date \= Chronos::createFromDate(2015, 12, 25); $date \= Chronos::createFromTime(11, 45, 10); // 整形した値にパース $date \= Chronos::createFromFormat('m/d/Y', '06/15/2015'); イミュータブルオブジェクトの動作[¶](https://book.cakephp.org/chronos/2/ja/#id4 "この見出しへのパーマリンク") -------------------------------------------------------------------------------- もしあなたが、PHP の `DateTime` オブジェクトを使用したことがあるなら、 _ミュータブル_ オブジェクトは簡単に使用できます。 Chronos はミュータブルオブジェクトを提供しますが、これは _イミュータブル_ オブジェクトにもなります。 イミュータブルオブジェクトはオブジェクトが変更されるたびにオブジェクトのコピーを作ります。 なぜなら、日時周りの変更メソッドは必ずしも透明でないため、データが誤って、 または開発者が知らない内に変更してしまうからです。 イミュータブルオブジェクトはデータが誤って変更されることを防止し、 順序ベースの依存関係の問題の無いコードを作ります。 不変性は、変更時に忘れずに変数を置き換える必要があることを意味しています。 // このコードはイミュータブルオブジェクトでは動作しません $time\->addDay(1); doSomething($time); return $time // このコードは期待通りに動作します $time \= $time\->addDay(1); $time \= doSomething($time); return $time 各修正の戻り値をキャプチャーすることによって、コードは期待通りに動作します。 イミュータブルオブジェクトを持っていて、ミュータブルオブジェクトを作りたい場合、 `toMutable()` が使用できます。 $inplace \= $time\->toMutable(); 日付オブジェクト[¶](https://book.cakephp.org/chronos/2/ja/#id5 "この見出しへのパーマリンク") ------------------------------------------------------------------------ PHP は単純な DateTime オブジェクトだけを提供します。このクラスのカレンダー日付の表現で、 タイムゾーンおよび、本当に「日」の概念に属していないタイムコンポーネントを含むと、 少し厄介な可能性があります。 Chronos は日時表現のための `ChronosDate` オブジェクトを提供します。 これらのオブジェクトの時間とタイムゾーンは常に `00:00:00 UTC` に固定されており、 全ての書式/差分のメソッドは一日単位で動作します。 use Cake\\Chronos\\ChronosDate; $today \= ChronosDate::today(); // 時間/タイムゾーンの変更は無視されます $today\->modify('+1 hours'); // 出力 '2015-12-20' echo $today; 変更メソッド[¶](https://book.cakephp.org/chronos/2/ja/#id6 "この見出しへのパーマリンク") ---------------------------------------------------------------------- Chronos オブジェクトは細やかに値を変更できるメソッドを提供します。 // 日時の値のコンポーネントを設定 $halloween \= Chronos::create() \->year(2015) \->month(10) \->day(31) \->hour(20) \->minute(30); また、日時の部分を相対的に変更することもできます。 $future \= Chronos::create() \->addYear(1) \->subMonth(2) \->addDays(15) \->addHours(20) \->subMinutes(2); また、ある時間の中で、定義された時点に飛ぶことも可能です。 $time \= Chronos::create(); $time\->startOfDay(); $time\->endOfDay(); $time\->startOfMonth(); $time\->endOfMonth(); $time\->startOfYear(); $time\->endOfYear(); $time\->startOfWeek(); $time\->endOfWeek(); また、1週間中の特定の日にも飛べます。 $time\->next(ChronosInterface::TUESDAY); $time\->previous(ChronosInterface::MONDAY); DST の遷移の前後で日付/時間を変更すると、 あなたの操作で時間が増減するかもしれませんが、その結果、意図しない時間の値になります。 これらの問題を回避するには、最初にタイムゾーンを `UTC` に変更し、時間を変更します。 // 余分な時間が追加されました $time \= new Chronos('2014-03-30 00:00:00', 'Europe/London'); debug($time\->modify('+24 hours')); // 2014-03-31 01:00:00 // 最初に UTC に切り替え、そして更新 $time \= $time\->setTimezone('UTC') \->modify('+24 hours'); 時間を変更すると、元のタイムゾーンを追加してローカライズされた時間を取得することができます。 比較メソッド[¶](https://book.cakephp.org/chronos/2/ja/#id7 "この見出しへのパーマリンク") ---------------------------------------------------------------------- Chronos の日付/時間オブジェクトの2つのインスタンスを様々な方法で比較することができます。 // 比較のフルセットが存在します // ne, gt, lt, lte. $first\->eq($second); $first\->gte($second); // カレントオブジェクトが2つのオブジェクトの間にあるかどうかを確認します。 $now\->between($start, $end); // どちらの引数が最も近い (closest) か、または最も遠い (farthest) かを見つけます。 $now\->closest($june, $november); $now\->farthest($june, $november); また、与えられた値のカレンダーに当たる場所について問い合わせできます。 $now\->isToday(); $now\->isYesterday(); $now\->isFuture(); $now\->isPast(); // 曜日をチェック $now\->isWeekend(); // 他の曜日のメソッドも全て存在します。 $now\->isMonday(); また、値が相対的な期間内にあったかどうかを見つけることができます。 $time\->wasWithinLast('3 days'); $time\->isWithinNext('3 hours'); 差の生成[¶](https://book.cakephp.org/chronos/2/ja/#id8 "この見出しへのパーマリンク") -------------------------------------------------------------------- 日時比較に加えて、2つの値の差や変化の計算は一般的なタスクです。 // 差をあらわす DateInterval を取得 $first\->diff($second); // 特定の単位での差を取得 $first\->diffInHours($second); $first\->diffInDays($second); $first\->diffInWeeks($second); $first\->diffInYears($second); フィードやタイムラインで使用するのに適した、人が読める形式の差を生成することができます。 // 現在からの差 echo $date\->diffForHumans(); // 別の時点からの差 echo $date\->diffForHumans($other); // 1時間前; フォーマットの設定[¶](https://book.cakephp.org/chronos/2/ja/#id9 "この見出しへのパーマリンク") ------------------------------------------------------------------------- Chronos は、出力した日時オブジェクトを表示するための多くのメソッドを提供します。 // setToStringFormat() が制御するフォーマットを使用します echo $date; // 別の標準フォーマット echo $time\->toAtomString(); // 1975-12-25T14:15:16-05:00 echo $time\->toCookieString(); // Thursday, 25-Dec-1975 14:15:16 EST echo $time\->toIso8601String(); // 1975-12-25T14:15:16-05:00 echo $time\->toRfc822String(); // Thu, 25 Dec 75 14:15:16 -0500 echo $time\->toRfc850String(); // Thursday, 25-Dec-75 14:15:16 EST echo $time\->toRfc1036String(); // Thu, 25 Dec 75 14:15:16 -0500 echo $time\->toRfc1123String(); // Thu, 25 Dec 1975 14:15:16 -0500 echo $time\->toRfc2822String(); // Thu, 25 Dec 1975 14:15:16 -0500 echo $time\->toRfc3339String(); // 1975-12-25T14:15:16-05:00 echo $time\->toRssString(); // Thu, 25 Dec 1975 14:15:16 -0500 echo $time\->toW3cString(); // 1975-12-25T14:15:16-05:00 // クォーター/週数を取得 echo $time\->toQuarter(); // 4; echo $time\->toWeek(); // 52 // 一般的なフォーマット echo $time\->toTimeString(); // 14:15:16 echo $time\->toDateString(); // 1975-12-25 echo $time\->toDateTimeString(); // 1975-12-25 14:15:16 echo $time\->toFormattedDateString(); // Dec 25, 1975 echo $time\->toDayDateTimeString(); // Thu, Dec 25, 1975 2:15 PM 日付要素の抽出[¶](https://book.cakephp.org/chronos/2/ja/#id10 "この見出しへのパーマリンク") ------------------------------------------------------------------------ 日付オブジェクトのプロパティーに直接アクセスして要素を取得することができます。 $time \= new Chronos('2015-12-31 23:59:58'); $time\->year; // 2015 $time\->month; // 12 $time\->day; // 31 $time\->hour // 23 $time\->minute // 59 $time\->second // 58 以下のプロパティーにもアクセスできます。 : * timezone * timezoneName * micro * dayOfWeek * dayOfMonth * dayOfYear * daysInMonth * timestamp * quarter テストの支援[¶](https://book.cakephp.org/chronos/2/ja/#id11 "この見出しへのパーマリンク") ----------------------------------------------------------------------- 単体テストを書いている時、現在時刻を固定すると便利です。Chronos は、 各クラスの現在時刻を修正することができます。 テストスイートの bootstrap 処理に以下を含めることができます。 Chronos::setTestNow(Chronos::now()); MutableDateTime::setTestNow(MutableDateTime::now()); ChronosDate::setTestNow(ChronosDate::now()); MutableDate::setTestNow(MutableDate::now()); これでテストスイートが開始された時点で全てのオブジェクトの現在時刻を修正します。 例えば、 `Chronos` を過去のある瞬間に固定した場合、新たな `Chronos` のインスタンスが生成する `now` または相対時刻の文字列は、 固定された時刻の相対を返却します。 Chronos::setTestNow(new Chronos('1975-12-25 00:00:00')); $time \= new Chronos(); // 1975-12-25 00:00:00 $time \= new Chronos('1 hour ago'); // 1975-12-24 23:00:00 固定をリセットするには、 `setTestNow()` をパラメーター無し、または `null` を設定して 再び呼び出してください。 [](https://phpc.social/@cakephp "Mastodon") [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://slack-invite.cakephp.org/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") --- # ElasticSearch - 3.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/elastic-search/edit/3.x/docs/ja/index.rst) [](https://book.cakephp.org/elasticsearch/3/ja/#page-contents) ### Page Contents * [ElasticSearch](https://book.cakephp.org/elasticsearch/3/ja/#) * [インストール](https://book.cakephp.org/elasticsearch/3/ja/#id2) * [概要](https://book.cakephp.org/elasticsearch/3/ja/#id3) * [Document オブジェクト](https://book.cakephp.org/elasticsearch/3/ja/#document) * [インデックス付きドキュメントの検索](https://book.cakephp.org/elasticsearch/3/ja/#id4) * [データのバリデーションとアプリケーションルールの使用](https://book.cakephp.org/elasticsearch/3/ja/#id5) * [新しいドキュメントの保存](https://book.cakephp.org/elasticsearch/3/ja/#id6) * [既存ドキュメントの更新](https://book.cakephp.org/elasticsearch/3/ja/#id7) * [ドキュメントの削除](https://book.cakephp.org/elasticsearch/3/ja/#id8) * [埋め込みドキュメント](https://book.cakephp.org/elasticsearch/3/ja/#id9) * [Type インスタンスの取得](https://book.cakephp.org/elasticsearch/3/ja/#type) * [レジストリーのフラッシュ](https://book.cakephp.org/elasticsearch/3/ja/#id10) * [テストフィクスチャー](https://book.cakephp.org/elasticsearch/3/ja/#id11) ElasticSearch[¶](https://book.cakephp.org/elasticsearch/3/ja/#elasticsearch "この見出しへのパーマリンク") ============================================================================================= ElasticSearch プラグインは、[elasticsearch](https://www.elastic.co/products/elasticsearch) の上に ORM のような抽象化を提供します。そのプラグインは、テストの作成、 ドキュメントのインデックス作成、インデックスをより簡単に検索などの機能を提供します。 インストール[¶](https://book.cakephp.org/elasticsearch/3/ja/#id2 "この見出しへのパーマリンク") ---------------------------------------------------------------------------- ElasticSearch プラグインをインストールするには、 `composer` が利用できます。(composer.json ファイルが置かれている) アプリケーションの ROOT ディレクトリーから次のコマンドを実行します。 php composer.phar require cakephp/elastic\-search "@stable" 以下の1行をあなたのアプリケーションの **src/Application.php** ファイルに追加する必要があります。 $this\->addPlugin('Cake/ElasticSearch', \['bootstrap' \=> true\]); // 3.6.0 より前は、Plugin::load() を使用する必要があります 追加で 'elastic' のデータソースの接続を **config/app.php** ファイルに設定する必要があります。 設定例は以下のようになります。 // config/app.php の中で 'Datasources' \=> \[\ // 他のデータソース\ 'elastic' \=> \[\ 'className' \=> 'Cake\\ElasticSearch\\Datasource\\Connection',\ 'driver' \=> 'Cake\\ElasticSearch\\Datasource\\Connection',\ 'host' \=> '127.0.0.1',\ 'port' \=> 9200,\ 'index' \=> 'my\_apps\_index',\ \],\ \] 概要[¶](https://book.cakephp.org/elasticsearch/3/ja/#id3 "この見出しへのパーマリンク") ------------------------------------------------------------------------ ElasticSearch プラグインは elasticsearch インデックスと作用することを簡単にし、 [ORM](https://book.cakephp.org/3/ja/orm.html) に似たインタフェースを提供します。まず最初に `Type` オブジェクトを 作成しなければいけません。 `Type` オブジェクトは elasticsearch 内では "Repository" もしくは Table のようなクラスです。 // src/Model/Type/ArticlesType.php の中で namespace App\\Model\\Type; use Cake\\ElasticSearch\\Type; class ArticlesType extends Type { } コントローラーで Type クラスを利用できます。 public function beforeFilter(Event $event) { parent::beforeFilter($event); // 'Elastic' プロバイダーを利用して Type を読み込む $this\->loadModel('Articles', 'Elastic'); } public function add() { $article \= $this\->Articles\->newEntity(); if ($this\->request\->is('post')) { $article \= $this\->Articles\->patchEntity($article, $this\->request\->getData()); if ($this\->Articles\->save($article)) { $this\->Flash\->success('It saved'); } } $this\->set(compact('article')); } インデックスされた articles の基本的なビューを作成する必要があります。 // src/Template/Articles/add.ctp の中で Form\->create($article) ?> Form\->control('title') ?> Form\->control('body') ?> Form\->button('Save') ?> Form\->end() ?> これで、フォームの送信が可能になり、新しいドキュメントが elasticsearch に追加されました。 Document オブジェクト[¶](https://book.cakephp.org/elasticsearch/3/ja/#document "この見出しへのパーマリンク") ------------------------------------------------------------------------------------------ ORM と同様に、Elasticsearch ODM は [エンティティー](https://book.cakephp.org/3.0/ja/orm/entities.html) のようなクラスを使用しています。 継承しなければならない基底クラスは `Cake\ElasticSearch\Document` です。 Document クラスは、アプリケーションやプラグイン内の `Model\Document` 名前空間に配置します。 namespace App\\Model\\Document; use Cake\\ElasticSearch\\Document; class Article extends Document { } elasticsearch からのデータで Document を動作させるコンストラクターロジックの外側、 インターフェイスと `Document` によって提供される機能は、 [Entities](https://book.cakephp.org/3.0/ja/orm/entities.html) 内にあるものと同じです。 インデックス付きドキュメントの検索[¶](https://book.cakephp.org/elasticsearch/3/ja/#id4 "この見出しへのパーマリンク") --------------------------------------------------------------------------------------- いくつかのドキュメントをインデックスに登録した後、あなたはそれらを検索したいと思うでしょう。 ElasticSearch プラグインを使用すると、検索クエリーを構築するためのクエリービルダーを提供します。 $query \= $this\->Articles\->find() \->where(\[\ 'title' \=> 'special',\ 'or' \=> \[\ 'tags in' \=> \['cake', 'php'\],\ 'tags not in' \=> \['c#', 'java'\]\ \]\ \]); foreach ($query as $article) { echo $article\->title; } フィルタリング条件を追加するために `QueryBuilder` を使用することができます。 $query\->where(function ($builder) { return $builder\->and( $builder\->gt('views', 99), $builder\->term('author.name', 'sally') ); }); [QueryBuilder のソース](https://github.com/cakephp/elastic-search/blob/master/src/QueryBuilder.php) は、多くの一般的に使用されるメソッドの例となるメソッドの完全なリストを持っています。 データのバリデーションとアプリケーションルールの使用[¶](https://book.cakephp.org/elasticsearch/3/ja/#id5 "この見出しへのパーマリンク") ------------------------------------------------------------------------------------------------ ORMと同様に、ElasticSearch プラグインは、ドキュメントをマーシャリングするときに データを検証することができます。リクエストデータのバリデート、およびアプリケーションルールの 適用は、リレーショナルORMと同じ動作をします。詳細については、 [エンティティー構築前のデータ検証](https://book.cakephp.org/3.0/ja/orm/validation.html#validating-request-data) と [条件付き/動的なエラーメッセージ](https://book.cakephp.org/3.0/ja/orm/validation.html#id17) のセクションをご覧ください。 新しいドキュメントの保存[¶](https://book.cakephp.org/elasticsearch/3/ja/#id6 "この見出しへのパーマリンク") ---------------------------------------------------------------------------------- elasticsearch にいくつかのデータをインデックスする準備ができたら、最初にインデックスが付けられる `Document` にデータを変換する必要があります。 $article \= $this\->Articles\->newEntity($data); if ($this\->Articles\->save($article)) { // Document はインデックスされました } ドキュメントをマーシャリングするとき、 `associated` キーを使用してマーシャリングしたい 埋め込みドキュメントを指定することができます。 $article \= $this\->Articles\->newEntity($data, \['associated' \=> \['Comments'\]\]); ドキュメントを保存すると、次のイベントがトリガーされます: * `Model.beforeSave` - ドキュメントが保存される前に発生します。 このイベントを停止することによって保存操作を防ぐことができます。 * `Model.buildRules` - ルールチェッカーが最初に構築されているときに発生します。 * `Model.afterSave` - ドキュメントが保存された後に発生します。 注釈 親ドキュメントとすべての埋め込みドキュメントを1つの操作で保存するため、 埋め込みドキュメントのためのイベントはありません。 既存ドキュメントの更新[¶](https://book.cakephp.org/elasticsearch/3/ja/#id7 "この見出しへのパーマリンク") --------------------------------------------------------------------------------- データの再インデックスが必要な場合、既存のエンティティーにパッチを適用すると再保存できます。 $query \= $this\->Articles\->find()\->where(\['user.name' \=> 'jill'\]); foreach ($query as $doc) { $doc\->set($newProperties); $this\->Articles\->save($doc); } ドキュメントの削除[¶](https://book.cakephp.org/elasticsearch/3/ja/#id8 "この見出しへのパーマリンク") ------------------------------------------------------------------------------- ドキュメントを検索した後、それを削除することができます。 $doc \= $this\->Articles\->get($id); $this\->Articles\->delete($doc); また、特定の条件に一致するドキュメントを削除することができます。 $this\->Articles\->deleteAll(\['user.name' \=> 'bob'\]); 埋め込みドキュメント[¶](https://book.cakephp.org/elasticsearch/3/ja/#id9 "この見出しへのパーマリンク") -------------------------------------------------------------------------------- 埋め込みドキュメントを定義することで、ドキュメント内の特定のプロパティーのパスに エンティティークラスを添付することができます。これは、親ドキュメント内のドキュメントに 独自の振る舞いを提供することができます。たとえば、あなたが記事に埋め込まれたコメントは、 特定のアプリケーション固有のメソッドを持っている場合があります。あなたが埋め込みドキュメントを 定義するために `embedOne` と `embedMany` を使用することができます。 // in src/Model/Type/ArticlesType.php namespace App\\Model\\Type; use Cake\\ElasticSearch\\Type; class ArticlesType extends Type { public function initialize() { $this\->embedOne('User'); $this\->embedMany('Comments', \[\ 'entityClass' \=> 'MyComment'\ \]); } } 上記の `Article` ドキュメント上の2つの埋め込みドキュメントを作成します。 `User` 埋め込みは `App\Model\Document\User` のインスタンスに `user` プロパティーを変換します。 プロパティー名と一致していないクラス名を使用する埋め込みコメントを得るためには、カスタムクラス名を 設定するための `entityClass` オプションを使用することができます。 埋め込みドキュメントをセットアップしたら、 `find()` と `get` の結果は 正しい埋め込みドキュメントクラスのオブジェクトを返します。 $article \= $this\->Articles\->get($id); // App\\Model\\Document\\User のインスタンス $article\->user; // App\\Model\\Document\\Comment インスタンスの配列 $article\->comments; Type インスタンスの取得[¶](https://book.cakephp.org/elasticsearch/3/ja/#type "この見出しへのパーマリンク") ------------------------------------------------------------------------------------- ORM と同様に、ElasticSearch プラグインは `Type` のインスタンスを取得するための ファクトリー/レジストリーを提供します。 use Cake\\ElasticSearch\\TypeRegistry; $articles \= TypeRegistry::get('Articles'); ### レジストリーのフラッシュ[¶](https://book.cakephp.org/elasticsearch/3/ja/#id10 "この見出しへのパーマリンク") テストケースの中で、レジストリーをフラッシュすることができます。 そうすることでモックオブジェクトを使用したり、Type の依存関係を変更する際に便利です。 TypeRegistry::flush(); テストフィクスチャー[¶](https://book.cakephp.org/elasticsearch/3/ja/#id11 "この見出しへのパーマリンク") --------------------------------------------------------------------------------- ElasticSearch プラグインは、シームレスなテストスイートの統合を提供します。ちょうどデータベースの フィクスチャーのように、elasticsearch のためのテストフィクスチャーを作成することができます。 次のように Articles タイプのテストフィクスチャーを定義することができます。 namespace App\\Test\\Fixture; use Cake\\ElasticSearch\\TestSuite\\TestFixture; /\*\* \* Articles fixture \*/ class ArticlesFixture extends TestFixture { /\*\* \* The table/type for this fixture. \* \* @var string \*/ public $table \= 'articles'; /\*\* \* The mapping data. \* \* @var array \*/ public $schema \= \[\ 'id' \=> \['type' \=> 'integer'\],\ 'user' \=> \[\ 'type' \=> 'nested',\ 'properties' \=> \[\ 'username' \=> \['type' \=> 'string'\],\ \]\ \],\ 'title' \=> \['type' \=> 'string'\],\ 'body' \=> \['type' \=> 'string'\],\ \]; public $records \= \[\ \[\ 'user' \=> \[\ 'username' \=> 'billy'\ \],\ 'title' \=> 'First Post',\ 'body' \=> 'Some content'\ \]\ \]; } `schema` プロパティーは [ネイティブ elasticsearch マッピングフォーマット](https://www.elastic.co/guide/en/elasticsearch/reference/1.5/mapping.html) を使用します。 安全にタイプ名およびトップレベルの `properties` キーを省略することができます。 フィクスチャーが作成されたら、あなたのテストの `fixtures` プロパティーに含めることによって、 あなたのテストケースで使用することができます。 public $fixtures \= \['app.Articles'\]; [](https://phpc.social/@cakephp "Mastodon") [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://slack-invite.cakephp.org/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") --- # Chronos - 1.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/chronos/edit/1.x/docs/ja/index.rst) [](https://book.cakephp.org/chronos/1/ja/#page-contents) ### Page Contents * [Chronos](https://book.cakephp.org/chronos/1/ja/#) * [インストール](https://book.cakephp.org/chronos/1/ja/#id1) * [概要](https://book.cakephp.org/chronos/1/ja/#id2) * [インスタンスの作成](https://book.cakephp.org/chronos/1/ja/#id3) * [イミュータブルオブジェクトの動作](https://book.cakephp.org/chronos/1/ja/#id4) * [日付オブジェクト](https://book.cakephp.org/chronos/1/ja/#id5) * [変更メソッド](https://book.cakephp.org/chronos/1/ja/#id6) * [比較メソッド](https://book.cakephp.org/chronos/1/ja/#id7) * [差の生成](https://book.cakephp.org/chronos/1/ja/#id8) * [フォーマットの設定](https://book.cakephp.org/chronos/1/ja/#id9) * [日付要素の抽出](https://book.cakephp.org/chronos/1/ja/#id10) * [テストの支援](https://book.cakephp.org/chronos/1/ja/#id11) Chronos[¶](https://book.cakephp.org/chronos/1/ja/#chronos "このヘッドラインへのパーマリンク") ============================================================================== Chronos (クロノス) は、 `DateTime` オブジェクトへの拡張の依存関係の無いコレクションを提供します。 便利なメソッドに加えて、Chronos は以下を提供します。 * カレンダー日付のための `Date` オブジェクト * イミュータブルな日付と日時オブジェクト * プラグインのような翻訳システム。ライブラリーは英語のみの翻訳を含んでいます。 しかし、全ての言語サポートのために、 `cakephp/i18n` を使うことができます。 インストール[¶](https://book.cakephp.org/chronos/1/ja/#id1 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------- Chronos をインストールするためには、 `composer` を利用することができます。 アプリケーションの ROOT ディレクトリー(composer.json ファイルのある場所) で以下のように実行します。 php composer.phar require cakephp/chronos "@stable" 概要[¶](https://book.cakephp.org/chronos/1/ja/#id2 "このヘッドラインへのパーマリンク") --------------------------------------------------------------------- Chronos は PHP が提供する DateTime オブジェクトのいくつかの拡張を提供します。 Chronos は `DateInterval` の拡張機能および、ミュータブル(変更可能)と イミュータブル(変更不可)な 日付/時刻 の派生系をカバーする5つのクラスを提供します。 * `Cake\Chronos\Chronos` はイミュータブルな _日付と時刻_ オブジェクト。 * `Cake\Chronos\Date` はイミュータブルな _日付_ オブジェクト。 * `Cake\Chronos\MutableDateTime` はミュータブルな _日付と時刻_ オブジェクト。 * `Cake\Chronos\MutableDate` はミュータブルな _日付_ オブジェクト。 * `Cake\Chronos\ChronosInterval` は `DateInterval` の拡張機能。 最後に、もしあなたが Chronos が提供する 日付/時刻 のオブジェクトに対して型宣言を行ないたい場合、 `Cake\Chronos\ChronosInterface` を使用することができます。 全ての日付と時間のオブジェクトはこのインターフェイスを実装しています。 インスタンスの作成[¶](https://book.cakephp.org/chronos/1/ja/#id3 "このヘッドラインへのパーマリンク") ---------------------------------------------------------------------------- Chronos または Date のインスタンスを取得するためには、多くの方法があります。 異なる引数セットで動作する多くのファクトリーメソッドがあります。 use Cake\\Chronos\\Chronos; $now \= Chronos::now(); $today \= Chronos::today(); $yesterday \= Chronos::yesterday(); $tomorrow \= Chronos::tomorrow(); // 相対式のパース $date \= Chronos::parse('+2 days, +3 hours'); // 日付と時間の整数値 $date \= Chronos::create(2015, 12, 25, 4, 32, 58); // 日付または時間の整数値 $date \= Chronos::createFromDate(2015, 12, 25); $date \= Chronos::createFromTime(11, 45, 10); // 整形した値にパース $date \= Chronos::createFromFormat('m/d/Y', '06/15/2015'); イミュータブルオブジェクトの動作[¶](https://book.cakephp.org/chronos/1/ja/#id4 "このヘッドラインへのパーマリンク") ----------------------------------------------------------------------------------- もしあなたが、PHP の `DateTime` オブジェクトを使用したことがあるなら、 _ミュータブル_ オブジェクトは簡単に使用できます。 Chronos はミュータブルオブジェクトを提供しますが、これは _イミュータブル_ オブジェクトにもなります。 イミュータブルオブジェクトはオブジェクトが変更されるたびにオブジェクトのコピーを作ります。 なぜなら、日時周りの変更メソッドは必ずしも透明でないため、データが誤って、 または開発者が知らない内に変更してしまうからです。 イミュータブルオブジェクトはデータが誤って変更されることを防止し、 順序ベースの依存関係の問題の無いコードを作ります。 不変性は、変更時に忘れずに変数を置き換える必要があることを意味しています。 // このコードはイミュータブルオブジェクトでは動作しません $time\->addDay(1); doSomething($time); return $time // このコードは期待通りに動作します $time \= $time\->addDay(1); $time \= doSomething($time); return $time 各修正の戻り値をキャプチャーすることによって、コードは期待通りに動作します。 イミュータブルオブジェクトを持っていて、ミュータブルオブジェクトを作りたい場合、 `toMutable()` が使用できます。 $inplace \= $time\->toMutable(); 日付オブジェクト[¶](https://book.cakephp.org/chronos/1/ja/#id5 "このヘッドラインへのパーマリンク") --------------------------------------------------------------------------- PHP は単純な DateTime オブジェクトだけを提供します。このクラスのカレンダー日付の表現で、 タイムゾーンおよび、本当に「日」の概念に属していないタイムコンポーネントを含むと、 少し厄介な可能性があります。 Chronos は日時表現のための `Date` オブジェクトを提供します。 これらのオブジェクトの時間とタイムゾーンは常に `00:00:00 UTC` に固定されており、 全ての書式/差分のメソッドは一日単位で動作します。 use Cake\\Chronos\\Date; $today \= Date::today(); // 時間/タイムゾーンの変更は無視されます $today\->modify('+1 hours'); // 出力 '2015-12-20' echo $today; 変更メソッド[¶](https://book.cakephp.org/chronos/1/ja/#id6 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------- Chronos オブジェクトは細やかに値を変更できるメソッドを提供します。 // 日時の値のコンポーネントを設定 $halloween \= Chronos::create() \->year(2015) \->month(10) \->day(31) \->hour(20) \->minute(30); また、日時の部分を相対的に変更することもできます。 $future \= Chronos::create() \->addYear(1) \->subMonth(2) \->addDays(15) \->addHours(20) \->subMinutes(2); また、ある時間の中で、定義された時点に飛ぶことも可能です。 $time \= Chronos::create(); $time\->startOfDay(); $time\->endOfDay(); $time\->startOfMonth(); $time\->endOfMonth(); $time\->startOfYear(); $time\->endOfYear(); $time\->startOfWeek(); $time\->endOfWeek(); また、1週間中の特定の日にも飛べます。 $time\->next(ChronosInterface::TUESDAY); $time\->previous(ChronosInterface::MONDAY); DST の遷移の前後で日付/時間を変更すると、 あなたの操作で時間が増減するかもしれませんが、その結果、意図しない時間の値になります。 これらの問題を回避するには、最初にタイムゾーンを `UTC` に変更し、時間を変更します。 // 余分な時間が追加されました $time \= new Chronos('2014-03-30 00:00:00', 'Europe/London'); debug($time\->modify('+24 hours')); // 2014-03-31 01:00:00 // 最初に UTC に切り替え、そして更新 $time \= $time\->setTimezone('UTC') \->modify('+24 hours'); 時間を変更すると、元のタイムゾーンを追加してローカライズされた時間を取得することができます。 比較メソッド[¶](https://book.cakephp.org/chronos/1/ja/#id7 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------- Chronos の日付/時間オブジェクトの2つのインスタンスを様々な方法で比較することができます。 // 比較のフルセットが存在します // ne, gt, lt, lte. $first\->eq($second); $first\->gte($second); // カレントオブジェクトが2つのオブジェクトの間にあるかどうかを確認します。 $now\->between($start, $end); // どちらの引数が最も近い (closest) か、または最も遠い (farthest) かを見つけます。 $now\->closest($june, $november); $now\->farthest($june, $november); また、与えられた値のカレンダーに当たる場所について問い合わせできます。 $now\->isToday(); $now\->isYesterday(); $now\->isFuture(); $now\->isPast(); // 曜日をチェック $now\->isWeekend(); // 他の曜日のメソッドも全て存在します。 $now\->isMonday(); また、値が相対的な期間内にあったかどうかを見つけることができます。 $time\->wasWithinLast('3 days'); $time\->isWithinNext('3 hours'); 差の生成[¶](https://book.cakephp.org/chronos/1/ja/#id8 "このヘッドラインへのパーマリンク") ----------------------------------------------------------------------- 日時比較に加えて、2つの値の差や変化の計算は一般的なタスクです。 // 差をあらわす DateInterval を取得 $first\->diff($second); // 特定の単位での差を取得 $first\->diffInHours($second); $first\->diffInDays($second); $first\->diffInWeeks($second); $first\->diffInYears($second); フィードやタイムラインで使用するのに適した、人が読める形式の差を生成することができます。 // 現在からの差 echo $date\->diffForHumans(); // 別の時点からの差 echo $date\->diffForHumans($other); // 1時間前; フォーマットの設定[¶](https://book.cakephp.org/chronos/1/ja/#id9 "このヘッドラインへのパーマリンク") ---------------------------------------------------------------------------- Chronos は、出力した日時オブジェクトを表示するための多くのメソッドを提供します。 // setToStringFormat() が制御するフォーマットを使用します echo $date; // 別の標準フォーマット echo $time\->toAtomString(); // 1975-12-25T14:15:16-05:00 echo $time\->toCookieString(); // Thursday, 25-Dec-1975 14:15:16 EST echo $time\->toIso8601String(); // 1975-12-25T14:15:16-05:00 echo $time\->toRfc822String(); // Thu, 25 Dec 75 14:15:16 -0500 echo $time\->toRfc850String(); // Thursday, 25-Dec-75 14:15:16 EST echo $time\->toRfc1036String(); // Thu, 25 Dec 75 14:15:16 -0500 echo $time\->toRfc1123String(); // Thu, 25 Dec 1975 14:15:16 -0500 echo $time\->toRfc2822String(); // Thu, 25 Dec 1975 14:15:16 -0500 echo $time\->toRfc3339String(); // 1975-12-25T14:15:16-05:00 echo $time\->toRssString(); // Thu, 25 Dec 1975 14:15:16 -0500 echo $time\->toW3cString(); // 1975-12-25T14:15:16-05:00 // クォーター/週数を取得 echo $time\->toQuarter(); // 4; echo $time\->toWeek(); // 52 // 一般的なフォーマット echo $time\->toTimeString(); // 14:15:16 echo $time\->toDateString(); // 1975-12-25 echo $time\->toDateTimeString(); // 1975-12-25 14:15:16 echo $time\->toFormattedDateString(); // Dec 25, 1975 echo $time\->toDayDateTimeString(); // Thu, Dec 25, 1975 2:15 PM 日付要素の抽出[¶](https://book.cakephp.org/chronos/1/ja/#id10 "このヘッドラインへのパーマリンク") --------------------------------------------------------------------------- 日付オブジェクトのプロパティーに直接アクセスして要素を取得することができます。 $time \= new Chronos('2015-12-31 23:59:58'); $time\->year; // 2015 $time\->month; // 12 $time\->day; // 31 $time\->hour // 23 $time\->minute // 59 $time\->second // 58 以下のプロパティーにもアクセスできます。 : * timezone * timezoneName * micro * dayOfWeek * dayOfMonth * dayOfYear * daysInMonth * timestamp * quarter テストの支援[¶](https://book.cakephp.org/chronos/1/ja/#id11 "このヘッドラインへのパーマリンク") -------------------------------------------------------------------------- 単体テストを書いている時、現在時刻を固定すると便利です。Chronos は、 各クラスの現在時刻を修正することができます。 テストスイートの bootstrap 処理に以下を含めることができます。 Chronos::setTestNow(Chronos::now()); MutableDateTime::setTestNow(MutableDateTime::now()); Date::setTestNow(Date::now()); MutableDate::setTestNow(MutableDate::now()); これでテストスイートが開始された時点で全てのオブジェクトの現在時刻を修正します。 例えば、 `Chronos` を過去のある瞬間に固定した場合、新たな `Chronos` のインスタンスが生成する `now` または相対時刻の文字列は、 固定された時刻の相対を返却します。 Chronos::setTestNow(new Chronos('1975-12-25 00:00:00')); $time \= new Chronos(); // 1975-12-25 00:00:00 $time \= new Chronos('1 hour ago'); // 1975-12-24 23:00:00 固定をリセットするには、 `setTestNow()` をパラメーター無し、または `null` を設定して 再び呼び出してください。 [](https://phpc.social/@cakephp "Mastodon") [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://slack-invite.cakephp.org/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") --- # ElasticSearch - 2.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/elastic-search/edit/master/docs/ja/index.rst) [](https://book.cakephp.org/elasticsearch/2/ja/#page-contents) ### Page Contents * [ElasticSearch](https://book.cakephp.org/elasticsearch/2/ja/#) * [インストール](https://book.cakephp.org/elasticsearch/2/ja/#id2) * [概要](https://book.cakephp.org/elasticsearch/2/ja/#id3) * [Document オブジェクト](https://book.cakephp.org/elasticsearch/2/ja/#document) * [インデックス付きドキュメントの検索](https://book.cakephp.org/elasticsearch/2/ja/#id4) * [データのバリデーションとアプリケーションルールの使用](https://book.cakephp.org/elasticsearch/2/ja/#id5) * [新しいドキュメントの保存](https://book.cakephp.org/elasticsearch/2/ja/#id6) * [既存ドキュメントの更新](https://book.cakephp.org/elasticsearch/2/ja/#id7) * [ドキュメントの削除](https://book.cakephp.org/elasticsearch/2/ja/#id8) * [埋め込みドキュメント](https://book.cakephp.org/elasticsearch/2/ja/#id9) * [Type インスタンスの取得](https://book.cakephp.org/elasticsearch/2/ja/#type) * [レジストリーのフラッシュ](https://book.cakephp.org/elasticsearch/2/ja/#id10) * [テストフィクスチャー](https://book.cakephp.org/elasticsearch/2/ja/#id11) ElasticSearch[¶](https://book.cakephp.org/elasticsearch/2/ja/#elasticsearch "このヘッドラインへのパーマリンク") ================================================================================================ ElasticSearch プラグインは、[elasticsearch](https://www.elastic.co/products/elasticsearch) の上に ORM のような抽象化を提供します。そのプラグインは、テストの作成、 ドキュメントのインデックス作成、インデックスをより簡単に検索などの機能を提供します。 インストール[¶](https://book.cakephp.org/elasticsearch/2/ja/#id2 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------------- ElasticSearch プラグインをインストールするには、 `composer` が利用できます。(composer.json ファイルが置かれている) アプリケーションの ROOT ディレクトリーから次のコマンドを実行します。 php composer.phar require cakephp/elastic\-search "^2.0" 以下の1行をあなたのアプリケーションの **src/Application.php** ファイルに追加する必要があります。 $this\->addPlugin('Cake/ElasticSearch', \['bootstrap' \=> true\]); // 3.6.0 より前は、Plugin::load() を使用する必要があります 追加で 'elastic' のデータソースの接続を **config/app.php** ファイルに設定する必要があります。 設定例は以下のようになります。 // config/app.php の中で 'Datasources' \=> \[\ // 他のデータソース\ 'elastic' \=> \[\ 'className' \=> 'Cake\\ElasticSearch\\Datasource\\Connection',\ 'driver' \=> 'Cake\\ElasticSearch\\Datasource\\Connection',\ 'host' \=> '127.0.0.1',\ 'port' \=> 9200,\ 'index' \=> 'my\_apps\_index',\ \],\ \] 概要[¶](https://book.cakephp.org/elasticsearch/2/ja/#id3 "このヘッドラインへのパーマリンク") --------------------------------------------------------------------------- ElasticSearch プラグインは elasticsearch インデックスと作用することを簡単にし、 [ORM](https://book.cakephp.org/3/ja/orm.html) に似たインタフェースを提供します。まず最初に `Type` オブジェクトを 作成しなければいけません。 `Type` オブジェクトは elasticsearch 内では "Repository" もしくは Table のようなクラスです。 // src/Model/Type/ArticlesType.php の中で namespace App\\Model\\Type; use Cake\\ElasticSearch\\Type; class ArticlesType extends Type { } コントローラーで Type クラスを利用できます。 public function beforeFilter(Event $event) { parent::beforeFilter($event); // 'Elastic' プロバイダーを利用して Type を読み込む $this\->loadModel('Articles', 'Elastic'); } public function add() { $article \= $this\->Articles\->newEntity(); if ($this\->request\->is('post')) { $article \= $this\->Articles\->patchEntity($article, $this\->request\->getData()); if ($this\->Articles\->save($article)) { $this\->Flash\->success('It saved'); } } $this\->set(compact('article')); } インデックスされた articles の基本的なビューを作成する必要があります。 // src/Template/Articles/add.ctp の中で Form\->create($article) ?> Form\->control('title') ?> Form\->control('body') ?> Form\->button('Save') ?> Form\->end() ?> これで、フォームの送信が可能になり、新しいドキュメントが elasticsearch に追加されました。 Document オブジェクト[¶](https://book.cakephp.org/elasticsearch/2/ja/#document "このヘッドラインへのパーマリンク") --------------------------------------------------------------------------------------------- ORM と同様に、Elasticsearch ODM は [エンティティー](https://book.cakephp.org/3.0/ja/orm/entities.html) のようなクラスを使用しています。 継承しなければならない基底クラスは `Cake\ElasticSearch\Document` です。 Document クラスは、アプリケーションやプラグイン内の `Model\Document` 名前空間に配置します。 namespace App\\Model\\Document; use Cake\\ElasticSearch\\Document; class Article extends Document { } elasticsearch からのデータで Document を動作させるコンストラクターロジックの外側、 インターフェイスと `Document` によって提供される機能は、 [Entities](https://book.cakephp.org/3.0/ja/orm/entities.html) 内にあるものと同じです。 インデックス付きドキュメントの検索[¶](https://book.cakephp.org/elasticsearch/2/ja/#id4 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------------------------ いくつかのドキュメントをインデックスに登録した後、あなたはそれらを検索したいと思うでしょう。 ElasticSearch プラグインを使用すると、検索クエリーを構築するためのクエリービルダーを提供します。 $query \= $this\->Articles\->find() \->where(\[\ 'title' \=> 'special',\ 'or' \=> \[\ 'tags in' \=> \['cake', 'php'\],\ 'tags not in' \=> \['c#', 'java'\]\ \]\ \]); foreach ($query as $article) { echo $article\->title; } フィルタリング条件を追加するために `QueryBuilder` を使用することができます。 $query\->where(function ($builder) { return $builder\->and( $builder\->gt('views', 99), $builder\->term('author.name', 'sally') ); }); [QueryBuilder のソース](https://github.com/cakephp/elastic-search/blob/master/src/QueryBuilder.php) は、多くの一般的に使用されるメソッドの例となるメソッドの完全なリストを持っています。 データのバリデーションとアプリケーションルールの使用[¶](https://book.cakephp.org/elasticsearch/2/ja/#id5 "このヘッドラインへのパーマリンク") --------------------------------------------------------------------------------------------------- ORMと同様に、ElasticSearch プラグインは、ドキュメントをマーシャリングするときに データを検証することができます。リクエストデータのバリデート、およびアプリケーションルールの 適用は、リレーショナルORMと同じ動作をします。詳細については、 [エンティティー構築前のデータ検証](https://book.cakephp.org/3.0/ja/orm/validation.html#validating-request-data) と [条件付き/動的なエラーメッセージ](https://book.cakephp.org/3.0/ja/orm/validation.html#id17) のセクションをご覧ください。 新しいドキュメントの保存[¶](https://book.cakephp.org/elasticsearch/2/ja/#id6 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------------------- elasticsearch にいくつかのデータをインデックスする準備ができたら、最初にインデックスが付けられる `Document` にデータを変換する必要があります。 $article \= $this\->Articles\->newEntity($data); if ($this\->Articles\->save($article)) { // Document はインデックスされました } ドキュメントをマーシャリングするとき、 `associated` キーを使用してマーシャリングしたい 埋め込みドキュメントを指定することができます。 $article \= $this\->Articles\->newEntity($data, \['associated' \=> \['Comments'\]\]); ドキュメントを保存すると、次のイベントがトリガーされます: * `Model.beforeSave` - ドキュメントが保存される前に発生します。 このイベントを停止することによって保存操作を防ぐことができます。 * `Model.buildRules` - ルールチェッカーが最初に構築されているときに発生します。 * `Model.afterSave` - ドキュメントが保存された後に発生します。 注釈 親ドキュメントとすべての埋め込みドキュメントを1つの操作で保存するため、 埋め込みドキュメントのためのイベントはありません。 既存ドキュメントの更新[¶](https://book.cakephp.org/elasticsearch/2/ja/#id7 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------------------ データの再インデックスが必要な場合、既存のエンティティーにパッチを適用すると再保存できます。 $query \= $this\->Articles\->find()\->where(\['user.name' \=> 'jill'\]); foreach ($query as $doc) { $doc\->set($newProperties); $this\->Articles\->save($doc); } ドキュメントの削除[¶](https://book.cakephp.org/elasticsearch/2/ja/#id8 "このヘッドラインへのパーマリンク") ---------------------------------------------------------------------------------- ドキュメントを検索した後、それを削除することができます。 $doc \= $this\->Articles\->get($id); $this\->Articles\->delete($doc); また、特定の条件に一致するドキュメントを削除することができます。 $this\->Articles\->deleteAll(\['user.name' \=> 'bob'\]); 埋め込みドキュメント[¶](https://book.cakephp.org/elasticsearch/2/ja/#id9 "このヘッドラインへのパーマリンク") ----------------------------------------------------------------------------------- 埋め込みドキュメントを定義することで、ドキュメント内の特定のプロパティーのパスに エンティティークラスを添付することができます。これは、親ドキュメント内のドキュメントに 独自の振る舞いを提供することができます。たとえば、あなたが記事に埋め込まれたコメントは、 特定のアプリケーション固有のメソッドを持っている場合があります。あなたが埋め込みドキュメントを 定義するために `embedOne` と `embedMany` を使用することができます。 // in src/Model/Type/ArticlesType.php namespace App\\Model\\Type; use Cake\\ElasticSearch\\Type; class ArticlesType extends Type { public function initialize() { $this\->embedOne('User'); $this\->embedMany('Comments', \[\ 'entityClass' \=> 'MyComment'\ \]); } } 上記の `Article` ドキュメント上の2つの埋め込みドキュメントを作成します。 `User` 埋め込みは `App\Model\Document\User` のインスタンスに `user` プロパティーを変換します。 プロパティー名と一致していないクラス名を使用する埋め込みコメントを得るためには、カスタムクラス名を 設定するための `entityClass` オプションを使用することができます。 埋め込みドキュメントをセットアップしたら、 `find()` と `get` の結果は 正しい埋め込みドキュメントクラスのオブジェクトを返します。 $article \= $this\->Articles\->get($id); // App\\Model\\Document\\User のインスタンス $article\->user; // App\\Model\\Document\\Comment インスタンスの配列 $article\->comments; Type インスタンスの取得[¶](https://book.cakephp.org/elasticsearch/2/ja/#type "このヘッドラインへのパーマリンク") ---------------------------------------------------------------------------------------- ORM と同様に、ElasticSearch プラグインは `Type` のインスタンスを取得するための ファクトリー/レジストリーを提供します。 use Cake\\ElasticSearch\\TypeRegistry; $articles \= TypeRegistry::get('Articles'); ### レジストリーのフラッシュ[¶](https://book.cakephp.org/elasticsearch/2/ja/#id10 "このヘッドラインへのパーマリンク") テストケースの中で、レジストリーをフラッシュすることができます。 そうすることでモックオブジェクトを使用したり、Type の依存関係を変更する際に便利です。 TypeRegistry::flush(); テストフィクスチャー[¶](https://book.cakephp.org/elasticsearch/2/ja/#id11 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------------------ ElasticSearch プラグインは、シームレスなテストスイートの統合を提供します。ちょうどデータベースの フィクスチャーのように、elasticsearch のためのテストフィクスチャーを作成することができます。 次のように Articles タイプのテストフィクスチャーを定義することができます。 namespace App\\Test\\Fixture; use Cake\\ElasticSearch\\TestSuite\\TestFixture; /\*\* \* Articles fixture \*/ class ArticlesFixture extends TestFixture { /\*\* \* The table/type for this fixture. \* \* @var string \*/ public $table \= 'articles'; /\*\* \* The mapping data. \* \* @var array \*/ public $schema \= \[\ 'id' \=> \['type' \=> 'integer'\],\ 'user' \=> \[\ 'type' \=> 'nested',\ 'properties' \=> \[\ 'username' \=> \['type' \=> 'string'\],\ \]\ \],\ 'title' \=> \['type' \=> 'string'\],\ 'body' \=> \['type' \=> 'string'\],\ \]; public $records \= \[\ \[\ 'user' \=> \[\ 'username' \=> 'billy'\ \],\ 'title' \=> 'First Post',\ 'body' \=> 'Some content'\ \]\ \]; } `schema` プロパティーは [ネイティブ elasticsearch マッピングフォーマット](https://www.elastic.co/guide/en/elasticsearch/reference/1.5/mapping.html) を使用します。 安全にタイプ名およびトップレベルの `properties` キーを省略することができます。 フィクスチャーが作成されたら、あなたのテストの `fixtures` プロパティーに含めることによって、 あなたのテストケースで使用することができます。 public $fixtures \= \['app.Articles'\]; [](https://phpc.social/@cakephp "Mastodon") [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://slack-invite.cakephp.org/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") --- # Bake コンソール - 1.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/bake/edit/1.x/docs/ja/index.rst) [](https://book.cakephp.org/bake/1/ja/#page-contents) ### Page Contents * [Bake コンソール](https://book.cakephp.org/bake/1/ja/#) * [インストール手順](https://book.cakephp.org/bake/1/ja/#id1) Bake コンソール[¶](https://book.cakephp.org/bake/1/ja/#bake "このヘッドラインへのパーマリンク") =========================================================================== CakePHP の bake コンソールは、迅速に CakePHP を動作させるまでを支援します。 bake コンソールは、CakePHP の基本的な素材(モデル、ビヘイビアー、ビュー、ヘルパー、 コントローラー、コンポーネント、テストケース、フィクスチャー、プラグイン)を作成できます。 その為のスケルトンクラスについては、ここでは省略しますが、 bake は数分で完全に機能するアプリケーションを作成できます。 要するに、bake は足場の組まれたアプリケーションをいっぺんに手に入れるためにうってつけの方法です。 インストール手順[¶](https://book.cakephp.org/bake/1/ja/#id1 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------ bake を使用したり拡張する前に、アプリケーションに bake をインストールしておいてください。 bake は Composer を使ってインストールするプラグインとして提供されています。 composer require \--dev cakephp/bake:~1.0 上記のコマンドは、bake を開発環境で使用するパッケージとしてインストールします。 この入れ方の場合、本番環境としてデプロイする際には、 bake はインストールされません。 Twig テンプレートを使用する場合、 `WyriHaximus/TwigView` プラグインをブートストラップとともに 読み込んでいることを確認してください。それを完全に省略して、 Bake プラグインにこのプラグインを読み込ませることもできます。 [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://cakesf.herokuapp.com/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") [#IRC](https://webchat.freenode.net/?channels=cakephp "IRC") --- # Migrations - 3.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/migrations/edit/3.x/docs/ja/index.rst) [](https://book.cakephp.org/migrations/3/ja/#page-contents) ### Page Contents * [Migrations](https://book.cakephp.org/migrations/3/ja/#) * [インストール](https://book.cakephp.org/migrations/3/ja/#id1) * [概要](https://book.cakephp.org/migrations/3/ja/#id2) * [マイグレーションファイルの作成](https://book.cakephp.org/migrations/3/ja/#id3) * [シンタックス](https://book.cakephp.org/migrations/3/ja/#id5) * [マイグレーションファイル名](https://book.cakephp.org/migrations/3/ja/#id6) * [カラムの定義](https://book.cakephp.org/migrations/3/ja/#id8) * [テーブルの作成](https://book.cakephp.org/migrations/3/ja/#id9) * [既存のテーブルにカラムを追加](https://book.cakephp.org/migrations/3/ja/#id10) * [テーブルにインデックスとしてカラムを追加](https://book.cakephp.org/migrations/3/ja/#id11) * [フィールド長を指定](https://book.cakephp.org/migrations/3/ja/#id12) * [テーブルから列を変更する](https://book.cakephp.org/migrations/3/ja/#id13) * [テーブルからカラムを削除](https://book.cakephp.org/migrations/3/ja/#id14) * [既存のデータベースからマイグレーションファイルを作成する](https://book.cakephp.org/migrations/3/ja/#id15) * [2つのデータベース間の状態の差分を生成する](https://book.cakephp.org/migrations/3/ja/#id16) * [コマンド](https://book.cakephp.org/migrations/3/ja/#id17) * [`migrate` : マイグレーションを適用する](https://book.cakephp.org/migrations/3/ja/#migrate) * [`rollback` : マイグレーションを戻す](https://book.cakephp.org/migrations/3/ja/#rollback) * [`status` : マイグレーションのステータス](https://book.cakephp.org/migrations/3/ja/#status) * [`mark_migrated` : マイグレーション済みとしてマーキングする](https://book.cakephp.org/migrations/3/ja/#mark-migrated) * [`seed` : データベースの初期データ投入](https://book.cakephp.org/migrations/3/ja/#seed) * [シーダーから別のシーダーの呼び出し](https://book.cakephp.org/migrations/3/ja/#id18) * [`dump` : 差分を bake する機能のためのダンプファイルの生成](https://book.cakephp.org/migrations/3/ja/#dump-bake) * [プラグイン内のマイグレーションファイルを使う](https://book.cakephp.org/migrations/3/ja/#id19) * [非シェルの環境でマイグレーションを実行する](https://book.cakephp.org/migrations/3/ja/#id20) * [小技と裏技](https://book.cakephp.org/migrations/3/ja/#id21) * [主キーをカスタマイズする](https://book.cakephp.org/migrations/3/ja/#id22) * [照合順序](https://book.cakephp.org/migrations/3/ja/#id23) * [カラム名の更新と Table オブジェクトの使用](https://book.cakephp.org/migrations/3/ja/#table) * [マイグレーションとデプロイメント](https://book.cakephp.org/migrations/3/ja/#id24) * [テーブルのリネーム](https://book.cakephp.org/migrations/3/ja/#id25) * [`schema.lock` ファイル生成のスキップ](https://book.cakephp.org/migrations/3/ja/#schema-lock) Migrations[¶](https://book.cakephp.org/migrations/3/ja/#migrations "この見出しへのパーマリンク") ==================================================================================== マイグレーションは、バージョン管理システムを使用して追跡することができる PHP ファイルを 記述することによって、あなたのデータベースのスキーマ変更を行うための、コアチームによって サポートされているプラグインです。 それはあなたが時間をかけてあなたのデータベーステーブルを進化させることができます。 スキーマ変更の SQL を書く代わりに、このプラグインでは、直観的にデータベースの変更を 実現するための手段を使用することができます。 このプラグインは、データベースマイグレーションライブラリーの [Phinx](https://phinx.org/) のラッパーです。 インストール[¶](https://book.cakephp.org/migrations/3/ja/#id1 "この見出しへのパーマリンク") ------------------------------------------------------------------------- 初期状態で Migrations は、デフォルトのアプリケーションの雛形と一緒にインストールされます。 もしあなたがそれを削除して再インストールしたい場合は、(composer.json ファイルが 配置されている)アプリケーションルートディレクトリーから次のコマンドを実行します。 php composer.phar require cakephp/migrations "@stable" \# また、composer がグローバルにインストールされていた場合は、 composer require cakephp/migrations "@stable" このプラグインを使用するためには、あなたは、アプリケーションの **config/bootstrap.php** ファイルでロードする必要があります。あなたの **config/bootstrap.php** からプラグインを ロード・アンロードするために [CakePHP の Plugin シェル](https://book.cakephp.org/3.0/ja/console-and-shells/plugin-shell.html) が利用できます。 : bin/cake plugin load Migrations もしくは、あなたの **src/Application.php** ファイルを編集し、次の行を追加することで ロードすることができます。 $this\->addPlugin('Migrations'); // 3.6.0 より前は Plugin::load() を使用する必要があります また、 [データベース設定](https://book.cakephp.org/3.0/en/orm/database-basics.html#database-configuration) の項で説明したように、 あなたの **config/app.php** ファイル内のデフォルトのデータベース構成を設定する必要が あります。 概要[¶](https://book.cakephp.org/migrations/3/ja/#id2 "この見出しへのパーマリンク") --------------------------------------------------------------------- マイグレーションは、基本的にはデータベースの変更の操作を PHP ファイルで表します。 マイグレーションファイルはテーブルを作成し、カラムの追加や削除、インデックスの作成や データの作成さえ可能です。 ここにマイグレーションの例があります。 table('products'); $table\->addColumn('name', 'string', \[\ 'default' \=> null,\ 'limit' \=> 255,\ 'null' \=> false,\ \]); $table\->addColumn('description', 'text', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->addColumn('created', 'datetime', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->addColumn('modified', 'datetime', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->create(); } } マイグレーションは、データベースに `products` という名前のテーブルを追加します。 以下のカラムが定義します。 * `id` カラムの型は、主キーの `integer` * `name` カラムの型は `string` * `description` カラムの型は `text` * `created` カラムの型は `datetime` * `modified` カラムの型は `datetime` Tip 主キーのカラム名 `id` は、 **暗黙のうちに** 追加されます。 注釈 このファイルは変更を **適用後** にデータベースがどのようになるかを記述していることに 注意してください。この時点でデータベースに `products` テーブルは存在せず、 `products` テーブルを作って項目を追加することができるのと同様に、マイグレーションを `rollback` すればテーブルが消えてしまいます。 マイグレーションファイルを **config/Migrations** フォルダーに作成したら、下記の `migrations` コマンドを実行することでデータベースにテーブルを作成することがでます。 : bin/cake migrations migrate 以下の `migrations` コマンドは、 `rollback` を実行するとあなたのデータベースから テーブルが削除されます。 bin/cake migrations rollback マイグレーションファイルの作成[¶](https://book.cakephp.org/migrations/3/ja/#id3 "この見出しへのパーマリンク") ---------------------------------------------------------------------------------- マイグレーションファイルは、あなたのアプリケーションの **config/Migration** ディレクトリーに配置します。マイグレーションファイルの名前には、先頭に **YYYYMMDDHHMMSS\_MigrationName.php** というように作成した日付を付けます。 以下がマイグレーションファイルの例です。 * 20160121163850\_CreateProducts.php * 20160210133047\_AddRatingToProducts.php マイグレーションファイルを作成する最も簡単な方法は `bake` CLI コマンドを使用することです。 マイグレーションファイルに記述可能なメソッドの一覧については、オフィシャルの [Phinx ドキュメント](https://book.cakephp.org/phinx/0/en/migrations.html) をご覧ください。 注釈 `bake` オプションを使用する場合、もし望むなら実行する前にマイグレーションを修正できます。 ### シンタックス[¶](https://book.cakephp.org/migrations/3/ja/#id5 "この見出しへのパーマリンク") 以下の `bake` コマンドは、 `products` テーブルを追加するためのマイグレーションファイルを 作成します。 : bin/cake bake migration CreateProducts name:string description:text created modified あなたのデータベースにテーブルの作成、カラムの追加などをするために `bake` を使用する場合、 一般に以下の2点を指定します。 * あなたが生成するマイグレーションの名前 (例えば、 `CreateProducts`) * マイグレーションで追加や削除を行うテーブルのカラム (例えば、 `name:string description:text created modified`) 規約のために、すべてのスキーマの変更がこれらのシェルコマンドで動作するわけではありません。 さらに、実行内容を完全に制御したいのであれば、空のマイグレーションファイルを 作る事ができます。 bin/cake migrations create MyCustomMigration #### マイグレーションファイル名[¶](https://book.cakephp.org/migrations/3/ja/#id6 "この見出しへのパーマリンク") マイグレーション名は下記のパターンに従うことができます。 * (`/^(Create)(.*)/`) 指定したテーブルを作成します。 * (`/^(Drop)(.*)/`) 指定したテーブルを削除します。フィールドの指定は無視されます。 * (`/^(Add).*(?:To)(.*)/`) 指定したテーブルにカラム追加します。 * (`/^(Remove).*(?:From)(.*)/`) 指定のテーブルのカラムを削除します。 * (`/^(Alter)(.*)/`) 指定したテーブルを変更します。 CreateTable と AddField の別名。 * (`/^(Alter).*(?:On)(.*)/`) 指定されたテーブルのフィールドを変更します。 マイグレーションの名前に `アンダースコアー_形式` を使用できます。例: create\_products バージョン cakephp/migrations で追加: 1.5.2 マイグレーションファイル名のキャメルケースへの変換は [migrations プラグイン](https://github.com/cakephp/migrations/) の v1.5.2 に含まれます。 このプラグインのバージョンは、 CakePHP 3.1 以上のリリースで利用できます。 このプラグインのバージョン以前では、マイグレーション名はアンダースコアー形式です。 例: 20160121164955\_create\_products.php 警告 マイグレーション名は、マイグレーションのクラス名として使われます。そして、 クラス名はユニークでない場合、他のマイグレーションと衝突するかもしれません。この場合、後日、 名前を手動で上書きするか、単純にあなたが指定した名前に変更する必要があるかもしれません。 #### カラムの定義[¶](https://book.cakephp.org/migrations/3/ja/#id8 "この見出しへのパーマリンク") コマンドラインでカラムを使用する場合には、次のようなパターンに従っている事を 覚えておくと便利です。 fieldName:fieldType?\[length\]:indexType:indexName 例えば、以下はメールアドレスのカラムを指定する方法です。 * `email:string?` * `email:string:unique` * `email:string?[50]` * `email:string:unique:EMAIL_INDEX` * `email:string[120]:unique:EMAIL_INDEX` fieldType の後のクエスチョンマークは、ヌルを許可するカラムを作成します。 `fieldType` のための `length` パラメーターは任意です。カッコの中に記述します。 フィールド名が `created` と `modified` 、それに `_at` サフィックス付きの 任意のフィールドなら、自動的に `datetime` 型が設定されます。 `Phinx` で一般的に利用可能なフィールドの型は次の通り: * string * text * integer * biginteger * float * decimal * datetime * timestamp * time * date * binary * boolean * uuid 未確定で無効な値のままのフィールド型を選ぶためのいくつかの発見的手法があります。 デフォルトのフィールド型は `string` です。 * id: integer * created, modified, updated: datetime ### テーブルの作成[¶](https://book.cakephp.org/migrations/3/ja/#id9 "この見出しへのパーマリンク") テーブルを作成するために `bake` が使えます。 : bin/cake bake migration CreateProducts name:string description:text created modified 上記のコマンドラインは、よく似たマイグレーションファイルを生成します。 table('products'); $table\->addColumn('name', 'string', \[\ 'default' \=> null,\ 'limit' \=> 255,\ 'null' \=> false,\ \]); $table\->addColumn('description', 'text', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->addColumn('created', 'datetime', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->addColumn('modified', 'datetime', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->create(); } } ### 既存のテーブルにカラムを追加[¶](https://book.cakephp.org/migrations/3/ja/#id10 "この見出しへのパーマリンク") もしコマンドラインのマイグレーション名が "AddXXXToYYY" といった 書式で、その後にカラム名と型が続けば、カラムの追加を行うコードを含んだ マイグレーションファイルが生成されます。 : bin/cake bake migration AddPriceToProducts price:decimal コマンドラインを実行すると下記のようなファイルが生成されます。 table('products'); $table\->addColumn('price', 'decimal') \->update(); } } ### テーブルにインデックスとしてカラムを追加[¶](https://book.cakephp.org/migrations/3/ja/#id11 "この見出しへのパーマリンク") カラムにインデックスを追加することも可能です。 : bin/cake bake migration AddNameIndexToProducts name:string:index このようなファイルが生成されます。 table('products'); $table\->addColumn('name', 'string') \->addIndex(\['name'\]) \->update(); } } ### フィールド長を指定[¶](https://book.cakephp.org/migrations/3/ja/#id12 "この見出しへのパーマリンク") バージョン cakephp/migrations で追加: 1.4 もし、フィールド長を指定する必要がある場合、フィールドタイプにカギ括弧の中で指定できます。例: bin/cake bake migration AddFullDescriptionToProducts full\_description:string\[60\] 上記のコマンドラインを実行すると生成されます。 table('products'); $table\->addColumn('full\_description', 'string', \[\ 'default' \=> null,\ 'limit' \=> 60,\ 'null' \=> false,\ \]) \->update(); } } 長さが未指定の場合、いくつかのカラム型の長さは初期値が設定されます。 * string: 255 * integer: 11 * biginteger: 20 ### テーブルから列を変更する[¶](https://book.cakephp.org/migrations/3/ja/#id13 "この見出しへのパーマリンク") 同様に、移行名が「AlterXXXOnYYY」の形式の場合、コマンドラインを使用して、列を変更する移行を生成できます。 bin/cake bake migration AlterPriceOnProducts name:float 生成されます: table('products'); $table\->changeColumn('name', 'float'); $table\->update(); } } ### テーブルからカラムを削除[¶](https://book.cakephp.org/migrations/3/ja/#id14 "この見出しへのパーマリンク") もしマイグレーション名が "RemoveXXXFromYYY" であるなら、同様にコマンドラインを使用して、 カラム削除のマイグレーションファイルを生成することができます。 : bin/cake bake migration RemovePriceFromProducts price このようなファイルが生成されます。 table('products'); $table\->removeColumn('price') \->save(); } } 注釈 removeColumn は不可逆ですので、 up メソッドの中で呼び出してください。 それに対する addColumn の呼び出しは、 down メソッドに追加してください。 ### 既存のデータベースからマイグレーションファイルを作成する[¶](https://book.cakephp.org/migrations/3/ja/#id15 "この見出しへのパーマリンク") もしあなたが既存のデータベースで、マイグレーションの使用を始めたい場合や、 あなたのアプリケーションのデータベースで初期状態のスキーマのバージョン管理を 行いたい場合、 `migration_snapshot` コマンドを実行します。 : bin/cake bake migration\_snapshot Initial これはデータベース内のすべてのテーブルの create 文を含んだ **YYYYMMDDHHMMSS\_Initial.php** と呼ばれるマイグレーションファイルを生成します。 デフォルトで、スナップショットは、 `default` 接続設定で定義されたデータベースに 接続することによって作成されます。 もし、異なるデータベースからスナップショットを bake する必要があるなら、 `--connection` オプションが使用できます。 : bin/cake bake migration\_snapshot Initial \--connection my\_other\_connection `--require-table` フラグを使用することによって対応するモデルクラスを定義したテーブルだけを 含まれることを確認することができます。 : bin/cake bake migration\_snapshot Initial \--require-table `--require-table` フラグを使用した時、シェルは、あなたのアプリケーションを通して `Table` クラスを見つけて、スナップショットのモデルテーブルのみ追加します。 プラグインのためのスナップショットを bake したい場合、同じロジックが暗黙的に適用されます。 そうするために、 `--plugin` オプションを使用する必要があります。 : bin/cake bake migration\_snapshot Initial \--plugin MyPlugin 定義された `Table` オブジェクトモデルを持つテーブルだけプラグインのスナップショットに 追加されます。 注釈 プラグインのためのスナップショットを bake した時、マイグレーションファイルは、 あなたのプラグインの **config/Migrations** ディレクトリーに作成されます。 スナップショットを bake した時、phinx のログテーブルに自動的に追加されることに注意してください。 2つのデータベース間の状態の差分を生成する[¶](https://book.cakephp.org/migrations/3/ja/#id16 "この見出しへのパーマリンク") ----------------------------------------------------------------------------------------- バージョン cakephp/migrations で追加: 1.6.0 `migration_diff` の bake テンプレートを使用して2つのデータベースの状態の すべての差分をまとめたマイグレーションファイルを生成することができます。 そのためには、以下のコマンドを使用します。 : bin/cake bake migration\_diff NameOfTheMigrations 現在のデータベースの状態からの比較のポイントを保持するために、migrations シェルは、 `migrate` もしくは `rollback` が呼ばれた後に "dump" ファイルを生成します。 ダンプファイルは、取得した時点でのあなたのデータベースの全スキーマの状態を含むファイルです。 一度ダンプファイルが生成されると、あなたのデータベース管理システムに直接行ったすべての変更は、 `bake migration_diff` コマンドが呼ばれた時に生成されたマイグレーションファイルに追加されます。 デフォルトでは、 `default` 接続設定に定義されたデータベースに接続することによって 差分が作成されます。もし、あなたが異なるデータソースから差分を bake する必要がある場合、 `--connection` オプションを使用できます。 : bin/cake bake migration\_diff NameOfTheMigrations \--connection my\_other\_connection もし、すでにマイグレーションの履歴を持つアプリケーション上で diff 機能を使用したい場合、 マニュアルで比較に使用するダンプファイルを作成する必要があります。 : bin/cake migrations dump データベースの状態は、あなたがダンプファイルを作成する前にマイグレーションを全て実行した状態と 同じでなければなりません。一度ダンプファイルが生成されると、あなたのデータベースの変更を始めて、 都合の良い時に `bake migration_diff` コマンドを使用することができます。 注釈 migrations シェルは、カラム名の変更は検知できません。 コマンド[¶](https://book.cakephp.org/migrations/3/ja/#id17 "この見出しへのパーマリンク") ------------------------------------------------------------------------ ### `migrate` : マイグレーションを適用する[¶](https://book.cakephp.org/migrations/3/ja/#migrate "この見出しへのパーマリンク") マイグレーションファイルを生成したり記述したら、以下のコマンドを実行して 変更をデータベースに適用しましょう。 : \# マイグレーションをすべて実行 bin/cake migrations migrate \# 特定のバージョンに移行するためには、 \`\`--target\`\` オプション \# (省略形は \`\`-t\`\` )を使用します。 \# これはマイグレーションファイル名の前に付加されるタイムスタンプに対応しています。 bin/cake migrations migrate \-t 20150103081132 \# デフォルトで、マイグレーションファイルは、 \*\*config/Migrations\*\* ディレクトリーに \# あります。 \`\`--source\`\` オプション (省略形は \`\`-s\`\`) を使用することで、 \# ディレクトリーを指定できます。 \# 次の例は、 \*\*config/Alternate\*\* ディレクトリー内でマイグレーションを実行します。 bin/cake migrations migrate \-s Alternate \# \`\`--connection\`\` オプション (省略形は \`\`-c\`\`) を使用することで \# \`\`default\`\` とは異なる接続でマイグレーションを実行できます。 bin/cake migrations migrate \-c my\_custom\_connection \# マイグレーションは、プラグインのためにも実行できます。 \`\`--plugin\`\` オプション \# (省略形は \`\`-p\`\`) を使用します。 bin/cake migrations migrate \-p MyAwesomePlugin ### `rollback` : マイグレーションを戻す[¶](https://book.cakephp.org/migrations/3/ja/#rollback "この見出しへのパーマリンク") ロールバックコマンドは、このプラグインを実行する前の状態に戻すために使われます。 これは `migrate` コマンドの逆向きの動作をします。 : \# あなたは \`\`rollback\`\` コマンドを使って以前のマイグレーション状態に戻すことができます。 bin/cake migrations rollback \# また、特定のバージョンに戻すために、マイグレーションバージョン番号を引き渡すこともできます。 bin/cake migrations rollback \-t 20150103081132 `migrate` コマンドのように `--source` 、 `--connection` そして `--plugin` オプションが使用できます。 ### `status` : マイグレーションのステータス[¶](https://book.cakephp.org/migrations/3/ja/#status "この見出しへのパーマリンク") Status コマンドは、現在の状況とすべてのマイグレーションのリストを出力します。 あなたはマイグレーションが実行されたかを判断するために、このコマンドを使用することができます。 : bin/cake migrations status `--format` (省略形は `-f`) オプションを使用することで JSON 形式の文字列として結果を出力できます。 : bin/cake migrations status \--format json `migrate` コマンドのように `--source` 、 `--connection` そして `--plugin` オプションが使用できます。 ### `mark_migrated` : マイグレーション済みとしてマーキングする[¶](https://book.cakephp.org/migrations/3/ja/#mark-migrated "この見出しへのパーマリンク") バージョン 1.4.0 で追加. 時には、実際にはマイグレーションを実行せずにマークだけすることが便利な事もあります。 これを実行するためには、 `mark_migrated` コマンドを使用します。 コマンドは、他のコマンドとしてシームレスに動作します。 このコマンドを使用して、すべてのマイグレーションをマイグレーション済みとして マークすることができます。 : bin/cake migrations mark\_migrated また、 `--target` オプションを使用して、指定したバージョンに対して、 すべてマイグレーション済みとしてマークすることができます。 : bin/cake migrations mark\_migrated \--target\=20151016204000 もし、指定したマイグレーションを処理中にマーク済みにしたくない場合、 `--exclude` フラグをつけて使用することができます。 : bin/cake migrations mark\_migrated \--target\=20151016204000 \--exclude 最後に、指定したマイグレーションだけをマイグレーション済みとしてマークしたい場合、 `--only` フラグを使用できます。 : bin/cake migrations mark\_migrated \--target\=20151016204000 \--only `migrate` コマンドのように `--source` 、 `--connection` そして `--plugin` オプションが使用できます。 注釈 あなたが `cake bake migration_snapshot` コマンドでスナップショットを作成したとき、 自動的にマイグレーション済みとしてマーキングされてマイグレーションが作成されます。 バージョン 1.4.0 で非推奨: 以下のコマンドの使用方法は非推奨になりました。もし、あなたが 1.4.0 より前のバージョンの プラグインの場合のみに使用してください。 このコマンドは、引数としてマイグレーションバージョン番号を想定しています。 : bin/cake migrations mark\_migrated 20150420082532 もし、すべてのマイグレーションをマイグレーション済みとしてマークしたい場合、 特別な値 `all` を使用できます。もし使用した場合、すべての見つかったマイグレーションを マイグレーション済みとしてマークします。 : bin/cake migrations mark\_migrated all ### `seed` : データベースの初期データ投入[¶](https://book.cakephp.org/migrations/3/ja/#seed "この見出しへのパーマリンク") 1.5.5 より、データベースの初期データ投入のために `migrations` シェルが使用できます。 これは、 [Phinx ライブラリーの seed 機能](https://book.cakephp.org/phinx/0/en/seeding.html) を利用しています。デフォルトで、seed ファイルは、あなたのアプリケーションの `config/Seeds` ディレクトリーの中に置かれます。 [seed ファイル作成のための Phinx の命令](https://book.cakephp.org/phinx/0/en/seeding.html#creating-a-new-seed-class) を確認してください。 マイグレーションに関して、 seed ファイルのための `bake` インターフェースが提供されます。 : \# これは、あなたのアプリケーションの config/Seeds ディレクトリー内に ArticlesSeed.php を作成します。 \# デフォルトでは、変換対象の seed は、 "tableized" バージョンの seed ファイル名です。 bin/cake bake seed Articles \# \`\`--table\`\` オプションを使用することで seed ファイルに変換するテーブル名を指定します。 bin/cake bake seed Articles \--table my\_articles\_table \# bake するプラグインを指定できます。 bin/cake bake seed Articles \--plugin PluginName \# シーダーの生成時に別の接続を指定できます。 bin/cake bake seed Articles \--connection connection バージョン cakephp/migrations で追加: 1.6.4 オプションの `--data`, `--limit` そして `--fields` は、 データベースからデータをエクスポートするために追加されました。 1.6.4 から、 `bake seed` コマンドは、 `--data` フラグを使用することによって、 データベースからエクスポートされたデータを元に seed ファイルを作成することができます。 : bin/cake bake seed \--data Articles デフォルトでは、テーブル内にある行を全てエクスポートします。 `--limit` オプションを 使用することによって、エクスポートされる行の数を制限できます。 : \# 10 行のみエクスポート bin/cake bake seed \--data \--limit 10 Articles もし、seed ファイルの中にテーブルから選択したフィールドのみを含めたい場合、 `--fields` オプションが使用できます。そのオプションは、 フィールドのリストをカンマ区切りの値の文字列として含めます。 : \# \`id\`, \`title\` そして \`excerpt\` フィールドのみをエクスポート bin/cake bake seed \--data \--fields id,title,excerpt Articles Tip もちろん、同じコマンド呼び出し中に `--limit` と `--fields` オプションの両方が利用できます。 データベースの初期データ投入のために、 `seed` サブコマンドが使用できます。 : \# パラメーターなしの seed サブコマンドは、対象のディレクトリーのアルファベット順で、 \# すべての利用可能なシーダーを実行します。 bin/cake migrations seed \# \`--seed\` オプションを使用して実行するための一つだけシーダーを指定できます。 bin/cake migrations seed \--seed ArticlesSeed \# 別のディレクトリーでシーダーを実行できます。 bin/cake migrations seed \--source AlternativeSeeds \# プラグインのシーダーを実行できます bin/cake migrations seed \--plugin PluginName \# 指定したコネクションでシーダーを実行できます bin/cake migrations seed \--connection connection マイグレーションとは対照的にシーダーは追跡されないことに注意してください。 それは、同じシーダーは、複数回適用することができることを意味します。 #### シーダーから別のシーダーの呼び出し[¶](https://book.cakephp.org/migrations/3/ja/#id18 "この見出しへのパーマリンク") バージョン cakephp/migrations で追加: 1.6.2 たいてい初期データ投入時は、データの挿入する順番は、規約違反しないように遵守しなければなりません。 デフォルトでは、アルファベット順でシーダーが実行されますが、独自にシーダーの実行順を定義するために `\Migrations\AbstractSeed::call()` メソッドが利用できます。 use Migrations\\AbstractSeed; class DatabaseSeed extends AbstractSeed { public function run(): void { $this\->call('AnotherSeed'); $this\->call('YetAnotherSeed'); // プラグインからシーダーを呼ぶためにプラグインドット記法が使えます $this\->call('PluginName.FromPluginSeed'); } } 注釈 もし、 `call()` メソッドを使いたい場合、Migrations プラグインの `AbstractSeed` クラスを継承していることを確認してください。このクラスは、リリース 1.6.2 で追加されました。 ### `dump` : 差分を bake する機能のためのダンプファイルの生成[¶](https://book.cakephp.org/migrations/3/ja/#dump-bake "この見出しへのパーマリンク") dump コマンドは、 `migration_diff` の bake テンプレートで使用するファイルを作成します。 : bin/cake migrations dump 各生成されたダンプファイルは、生成元の接続固有のものです(そして、そのようにサフィックスされます)。 これは、アプリケーションが、異なるデータベースベンダーの複数のデータベースを扱う場合、 `bake migration_diff` コマンドで正しく差分を算出することができます。 ダンプファイルは、マイグレーションファイルと同じディレクトリーに作成されます。 `migrate` コマンドのように `--source` 、 `--connection` そして `--plugin` オプションが使用できます。 プラグイン内のマイグレーションファイルを使う[¶](https://book.cakephp.org/migrations/3/ja/#id19 "この見出しへのパーマリンク") ------------------------------------------------------------------------------------------ プラグインはマイグレーションファイルも提供することができます。 これはプラグインの移植性とインストールの容易さを高め、配布しやすくなるように意図されています。 Migrations プラグインの全てのコマンドは、プラグイン関連のマイグレーションを行うための `--plugin` か `-p` オプションをサポートしています。 : bin/cake migrations status \-p PluginName bin/cake migrations migrate \-p PluginName 非シェルの環境でマイグレーションを実行する[¶](https://book.cakephp.org/migrations/3/ja/#id20 "この見出しへのパーマリンク") ----------------------------------------------------------------------------------------- バージョン cakephp/migrations で追加: 1.2.0 migrations プラグインのバージョン 1.2 から、非シェル環境でも app から直接 `Migrations` クラスを使ってマイグレーションを実行できるようになりました。 これは CMS のプラグインインストーラーを作る時などに便利です。 `Migrations` クラスを使用すると、マイグレーションシェルから下記のコマンドを 実行することができます。: * migrate * rollback * markMigrated * status * seed それぞれのコマンドは `Migrations` クラスのメソッドとして実装されています。 使い方は以下の通りです。 use Migrations\\Migrations; $migrations \= new Migrations(); // 全てのマイグレーションバージョンとそのステータスの配列を返します。 $status \= $migrations\->status(); // 成功した場合、 true を返し、エラーが発生した場合、例外が投げられます。 $migrate \= $migrations\->migrate(); // 成功した場合、 true を返し、エラーが発生した場合、例外が投げられます。 $rollback \= $migrations\->rollback(); // 成功した場合、 true を返し、エラーが発生した場合、例外が投げられます。 $markMigrated \= $migrations\->markMigrated(20150804222900); // 成功した場合、 true を返し、エラーが発生した場合、例外が投げられます。 $seeded \= $migrations\->seed(); メソッドはコマンドラインのオプションと同じパラメーター配列を受け取ります。 use Migrations\\Migrations; $migrations \= new Migrations(); // 全てのマイグレーションバージョンとそのステータスの配列を返す $status \= $migrations\->status(\['connection' \=> 'custom', 'source' \=> 'MyMigrationsFolder'\]); あなたはシェルコマンドのように任意のオプションを引き渡すことができます。 唯一の例外は `markMigrated` コマンドで、第1引数にはマイグレーション済みとして マーキングしたいマイグレーションバージョン番号を渡し、第2引数にパラメーターの配列を 渡します。 必要に応じて、クラスのコンストラクターでこれらのパラメーターを引き渡すことができます。 それはデフォルトとして使用され、それぞれのメソッド呼び出しの時に引き渡されることを 防止します。 use Migrations\\Migrations; $migrations \= new Migrations(\['connection' \=> 'custom', 'source' \=> 'MyMigrationsFolder'\]); // 以下のすべての呼び出しは、マイグレーションクラスのコンストラクターに渡されたパラメーターを使用して行われます $status \= $migrations\->status(); $migrate \= $migrations\->migrate(); 個別の呼び出しでデフォルトのパラメーターを上書きしたい場合は、メソッド呼び出し時に引き渡します。 use Migrations\\Migrations; $migrations \= new Migrations(\['connection' \=> 'custom', 'source' \=> 'MyMigrationsFolder'\]); // この呼び出しでは "custom" コネクションを使用します。 $status \= $migrations\->status(); // こちらでは "default" コネクションを使用します。 $migrate \= $migrations\->migrate(\['connection' \=> 'default'\]); 小技と裏技[¶](https://book.cakephp.org/migrations/3/ja/#id21 "この見出しへのパーマリンク") ------------------------------------------------------------------------- ### 主キーをカスタマイズする[¶](https://book.cakephp.org/migrations/3/ja/#id22 "この見出しへのパーマリンク") あなたがデータベースに新しいテーブルを作成する時、 `id` を主キーとして 自動生成したくない場合、 `table()` メソッドの第2引数を使うことができます。 table('products', \['id' \=> false, 'primary\_key' \=> \['id'\]\]); $table \->addColumn('id', 'uuid') \->addColumn('name', 'string') \->addColumn('description', 'text') \->create(); } } 上記の例では、 `CHAR(36)` の `id` というカラムを主キーとして作成します。 注釈 独自の主キーをコマンドラインで指定した時、id フィールドの中の主キーとして注意してください。 そうしなければ、id フィールドが重複してエラーになります。例: bin/cake bake migration CreateProducts id:uuid:primary name:string description:text created modified さらに、Migrations 1.3 以降では 主キーに対処するための新しい方法が導入されました。 これを行うには、あなたのマイグレーションクラスは新しい `Migrations\AbstractMigration` クラスを継承する必要があります。 あなたは Migration クラスの `autoId` プロパティーに `false` を設定することで、 自動的な `id` カラムの生成をオフにすることができます。 あなたは手動で主キーカラムを作成し、テーブル宣言に追加する必要があります。 table('products'); $table \->addColumn('id', 'integer', \[\ 'autoIncrement' \=> true,\ 'limit' \=> 11\ \]) \->addPrimaryKey('id') \->addColumn('name', 'string') \->addColumn('description', 'text') \->create(); } } 主キーを扱うこれまでの方法と比較すると、この方法は、unsigned や not や limit や comment など さらに多くの主キーの定義を操作することができるようになっています。 Bake で生成されたマイグレーションファイルとスナップショットは、この新しい方法を 必要に応じて使用します。 警告 主キーの操作ができるのは、テーブル作成時のみです。これはプラグインがサポートしている いくつかのデータベースサーバーの制限によるものです。 ### 照合順序[¶](https://book.cakephp.org/migrations/3/ja/#id23 "この見出しへのパーマリンク") もしデータベースのデフォルトとは別の照合順序を持つテーブルを作成する必要がある場合は、 `table()` メソッドのオプションとして定義することができます。: table('categories', \[\ 'collation' \=> 'latin1\_german1\_ci'\ \]) \->addColumn('title', 'string', \[\ 'default' \=> null,\ 'limit' \=> 255,\ 'null' \=> false,\ \]) \->create(); } } ですが、これはテーブル作成時にしかできず、既存のテーブルに対してカラムを追加する時に テーブルやデータベースと異なる照合順序を指定する方法がないことに注意してください。 ただ `MySQL` と `SqlServer` だけはこの設定キーをサポートしています。 ### カラム名の更新と Table オブジェクトの使用[¶](https://book.cakephp.org/migrations/3/ja/#table "この見出しへのパーマリンク") カラムのリネームや移動とともに、あなたのデータベースから値を操作するために CakePHP ORM Table オブジェクトを使用している場合、 `update()` を呼んだ後に Table オブジェクトの新しいインスタンスを作成できることを確かめてください。 インスタンス上の Table オブジェクトに反映し保存されたスキーマをリフレッシュするために Table オブジェクトのレジストリーは、 `update()` が呼ばれた後にクリアされます。 ### マイグレーションとデプロイメント[¶](https://book.cakephp.org/migrations/3/ja/#id24 "この見出しへのパーマリンク") もし、アプリケーションをデプロイする時にプラグインを使用する場合、 テーブルのカラムメタデータを更新するように、必ず ORM キャッシュをクリアしてください。 そうしなければ、それらの新しいカラムの操作を実行する時に、カラムが存在しないエラーになります。 CakePHP コアは、この操作を行うために使用できる [スキーマキャッシュシェル](https://book.cakephp.org/3.0/ja/console-and-shells/schema-cache.html) を含みます。 : // 3.6.0 より前の場合、orm\_cache を使用 bin/cake schema\_cache clear このシェルについてもっと知りたい場合、クックブックの [スキーマキャッシュシェル](https://book.cakephp.org/3.0/ja/console-and-shells/schema-cache.html) セクションをご覧ください。 ### テーブルのリネーム[¶](https://book.cakephp.org/migrations/3/ja/#id25 "この見出しへのパーマリンク") プラグインは、 `rename()` メソッドを使用することでテーブルのリネームができます。 あなたのマイグレーションファイルの中で、以下のように記述できます。 public function up() { $this\->table('old\_table\_name') \->rename('new\_table\_name') \->save(); } ### `schema.lock` ファイル生成のスキップ[¶](https://book.cakephp.org/migrations/3/ja/#schema-lock "この見出しへのパーマリンク") バージョン cakephp/migrations で追加: 1.6.5 diff 機能を動作させるために、 **.lock** ファイルは、migrate、rollback または スナップショットの bake の度に生成され、指定された時点でのデータベーススキーマの状態を追跡します。 例えば本番環境上にデプロイするときなど、前述のコマンドに `--no-lock` オプションを使用することによって、このファイルの生成をスキップすることができます。 : bin/cake migrations migrate \--no-lock bin/cake migrations rollback \--no-lock bin/cake bake migration\_snapshot MyMigration \--no-lock [](https://phpc.social/@cakephp "Mastodon") [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://slack-invite.cakephp.org/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") --- # Migrations - 2.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/migrations/edit/2.x/docs/ja/index.rst) [](https://book.cakephp.org/migrations/2/ja/#page-contents) ### Page Contents * [Migrations](https://book.cakephp.org/migrations/2/ja/#) * [インストール](https://book.cakephp.org/migrations/2/ja/#id1) * [概要](https://book.cakephp.org/migrations/2/ja/#id2) * [マイグレーションファイルの作成](https://book.cakephp.org/migrations/2/ja/#id3) * [シンタックス](https://book.cakephp.org/migrations/2/ja/#id5) * [マイグレーションファイル名](https://book.cakephp.org/migrations/2/ja/#id6) * [カラムの定義](https://book.cakephp.org/migrations/2/ja/#id8) * [テーブルの作成](https://book.cakephp.org/migrations/2/ja/#id9) * [既存のテーブルにカラムを追加](https://book.cakephp.org/migrations/2/ja/#id10) * [テーブルにインデックスとしてカラムを追加](https://book.cakephp.org/migrations/2/ja/#id11) * [フィールド長を指定](https://book.cakephp.org/migrations/2/ja/#id12) * [テーブルから列を変更する](https://book.cakephp.org/migrations/2/ja/#id13) * [テーブルからカラムを削除](https://book.cakephp.org/migrations/2/ja/#id14) * [既存のデータベースからマイグレーションファイルを作成する](https://book.cakephp.org/migrations/2/ja/#id15) * [2つのデータベース間の状態の差分を生成する](https://book.cakephp.org/migrations/2/ja/#id16) * [コマンド](https://book.cakephp.org/migrations/2/ja/#id17) * [`migrate` : マイグレーションを適用する](https://book.cakephp.org/migrations/2/ja/#migrate) * [`rollback` : マイグレーションを戻す](https://book.cakephp.org/migrations/2/ja/#rollback) * [`status` : マイグレーションのステータス](https://book.cakephp.org/migrations/2/ja/#status) * [`mark_migrated` : マイグレーション済みとしてマーキングする](https://book.cakephp.org/migrations/2/ja/#mark-migrated) * [`seed` : データベースの初期データ投入](https://book.cakephp.org/migrations/2/ja/#seed) * [シーダーから別のシーダーの呼び出し](https://book.cakephp.org/migrations/2/ja/#id18) * [`dump` : 差分を bake する機能のためのダンプファイルの生成](https://book.cakephp.org/migrations/2/ja/#dump-bake) * [プラグイン内のマイグレーションファイルを使う](https://book.cakephp.org/migrations/2/ja/#id19) * [非シェルの環境でマイグレーションを実行する](https://book.cakephp.org/migrations/2/ja/#id20) * [小技と裏技](https://book.cakephp.org/migrations/2/ja/#id21) * [主キーをカスタマイズする](https://book.cakephp.org/migrations/2/ja/#id22) * [照合順序](https://book.cakephp.org/migrations/2/ja/#id23) * [カラム名の更新と Table オブジェクトの使用](https://book.cakephp.org/migrations/2/ja/#table) * [マイグレーションとデプロイメント](https://book.cakephp.org/migrations/2/ja/#id24) * [テーブルのリネーム](https://book.cakephp.org/migrations/2/ja/#id25) * [`schema.lock` ファイル生成のスキップ](https://book.cakephp.org/migrations/2/ja/#schema-lock) Migrations[¶](https://book.cakephp.org/migrations/2/ja/#migrations "このヘッドラインへのパーマリンク") ======================================================================================= マイグレーションは、バージョン管理システムを使用して追跡することができる PHP ファイルを 記述することによって、あなたのデータベースのスキーマ変更を行うための、コアチームによって サポートされているプラグインです。 それはあなたが時間をかけてあなたのデータベーステーブルを進化させることができます。 スキーマ変更の SQL を書く代わりに、このプラグインでは、直観的にデータベースの変更を 実現するための手段を使用することができます。 このプラグインは、データベースマイグレーションライブラリーの [Phinx](https://phinx.org/) のラッパーです。 インストール[¶](https://book.cakephp.org/migrations/2/ja/#id1 "このヘッドラインへのパーマリンク") ---------------------------------------------------------------------------- 初期状態で Migrations は、デフォルトのアプリケーションの雛形と一緒にインストールされます。 もしあなたがそれを削除して再インストールしたい場合は、(composer.json ファイルが 配置されている)アプリケーションルートディレクトリーから次のコマンドを実行します。 php composer.phar require cakephp/migrations "@stable" \# また、composer がグローバルにインストールされていた場合は、 composer require cakephp/migrations "@stable" このプラグインを使用するためには、あなたは、アプリケーションの **config/bootstrap.php** ファイルでロードする必要があります。あなたの **config/bootstrap.php** からプラグインを ロード・アンロードするために [CakePHP の Plugin シェル](https://book.cakephp.org/3.0/ja/console-and-shells/plugin-shell.html) が利用できます。 : bin/cake plugin load Migrations もしくは、あなたの **src/Application.php** ファイルを編集し、次の行を追加することで ロードすることができます。 $this\->addPlugin('Migrations'); // 3.6.0 より前は Plugin::load() を使用する必要があります また、 [データベース設定](https://book.cakephp.org/3.0/en/orm/database-basics.html#database-configuration) の項で説明したように、 あなたの **config/app.php** ファイル内のデフォルトのデータベース構成を設定する必要が あります。 概要[¶](https://book.cakephp.org/migrations/2/ja/#id2 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------ マイグレーションは、基本的にはデータベースの変更の操作を PHP ファイルで表します。 マイグレーションファイルはテーブルを作成し、カラムの追加や削除、インデックスの作成や データの作成さえ可能です。 ここにマイグレーションの例があります。 table('products'); $table\->addColumn('name', 'string', \[\ 'default' \=> null,\ 'limit' \=> 255,\ 'null' \=> false,\ \]); $table\->addColumn('description', 'text', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->addColumn('created', 'datetime', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->addColumn('modified', 'datetime', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->create(); } } マイグレーションは、データベースに `products` という名前のテーブルを追加します。 以下のカラムが定義します。 * `id` カラムの型は、主キーの `integer` * `name` カラムの型は `string` * `description` カラムの型は `text` * `created` カラムの型は `datetime` * `modified` カラムの型は `datetime` ちなみに 主キーのカラム名 `id` は、 **暗黙のうちに** 追加されます。 注釈 このファイルは変更を **適用後** にデータベースがどのようになるかを記述していることに 注意してください。この時点でデータベースに `products` テーブルは存在せず、 `products` テーブルを作って項目を追加することができるのと同様に、マイグレーションを `rollback` すればテーブルが消えてしまいます。 マイグレーションファイルを **config/Migrations** フォルダーに作成したら、下記の `migrations` コマンドを実行することでデータベースにテーブルを作成することがでます。 : bin/cake migrations migrate 以下の `migrations` コマンドは、 `rollback` を実行するとあなたのデータベースから テーブルが削除されます。 : bin/cake migrations rollback マイグレーションファイルの作成[¶](https://book.cakephp.org/migrations/2/ja/#id3 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------------------- マイグレーションファイルは、あなたのアプリケーションの **config/Migration** ディレクトリーに配置します。マイグレーションファイルの名前には、先頭に **YYYYMMDDHHMMSS\_MigrationName.php** というように作成した日付を付けます。 以下がマイグレーションファイルの例です。 * 20160121163850\_CreateProducts.php * 20160210133047\_AddRatingToProducts.php マイグレーションファイルを作成する最も簡単な方法は `bake` CLI コマンドを使用することです。 マイグレーションファイルに記述可能なメソッドの一覧については、オフィシャルの [Phinx ドキュメント](https://book.cakephp.org/phinx/0/en/migrations.html) をご覧ください。 注釈 `bake` オプションを使用する場合、もし望むなら実行する前にマイグレーションを修正できます。 ### シンタックス[¶](https://book.cakephp.org/migrations/2/ja/#id5 "このヘッドラインへのパーマリンク") 以下の `bake` コマンドは、 `products` テーブルを追加するためのマイグレーションファイルを 作成します。 : bin/cake bake migration CreateProducts name:string description:text created modified あなたのデータベースにテーブルの作成、カラムの追加などをするために `bake` を使用する場合、 一般に以下の2点を指定します。 * あなたが生成するマイグレーションの名前 (例えば、 `CreateProducts`) * マイグレーションで追加や削除を行うテーブルのカラム (例えば、 `name:string description:text created modified`) 規約のために、すべてのスキーマの変更がこれらのシェルコマンドで動作するわけではありません。 さらに、実行内容を完全に制御したいのであれば、空のマイグレーションファイルを 作る事ができます。 .. code\-block:: bash > bin/cake migrations create MyCustomMigration #### マイグレーションファイル名[¶](https://book.cakephp.org/migrations/2/ja/#id6 "このヘッドラインへのパーマリンク") マイグレーション名は下記のパターンに従うことができます。 * (`/^(Create)(.*)/`) 指定したテーブルを作成します。 * (`/^(Drop)(.*)/`) 指定したテーブルを削除します。フィールドの指定は無視されます。 * (`/^(Add).*(?:To)(.*)/`) 指定したテーブルにカラム追加します。 * (`/^(Remove).*(?:From)(.*)/`) 指定のテーブルのカラムを削除します。 * (`/^(Alter)(.*)/`) 指定したテーブルを変更します。 CreateTable と AddField の別名。 * (`/^(Alter).*(?:On)(.*)/`) 指定されたテーブルのフィールドを変更します。 マイグレーションの名前に `アンダースコアー_形式` を使用できます。例: create\_products バージョン cakephp/migrations で追加: 1.5.2 マイグレーションファイル名のキャメルケースへの変換は [migrations プラグイン](https://github.com/cakephp/migrations/) の v1.5.2 に含まれます。 このプラグインのバージョンは、 CakePHP 3.1 以上のリリースで利用できます。 このプラグインのバージョン以前では、マイグレーション名はアンダースコアー形式です。 例: 20160121164955\_create\_products.php 警告 マイグレーション名は、マイグレーションのクラス名として使われます。そして、 クラス名はユニークでない場合、他のマイグレーションと衝突するかもしれません。この場合、後日、 名前を手動で上書きするか、単純にあなたが指定した名前に変更する必要があるかもしれません。 #### カラムの定義[¶](https://book.cakephp.org/migrations/2/ja/#id8 "このヘッドラインへのパーマリンク") コマンドラインでカラムを使用する場合には、次のようなパターンに従っている事を 覚えておくと便利です。 fieldName:fieldType?\[length\]:indexType:indexName 例えば、以下はメールアドレスのカラムを指定する方法です。 * `email:string?` * `email:string:unique` * `email:string?[50]` * `email:string:unique:EMAIL_INDEX` * `email:string[120]:unique:EMAIL_INDEX` fieldType の後のクエスチョンマークは、ヌルを許可するカラムを作成します。 `fieldType` のための `length` パラメーターは任意です。カッコの中に記述します。 フィールド名が `created` と `modified` 、それに `_at` サフィックス付きの 任意のフィールドなら、自動的に `datetime` 型が設定されます。 `Phinx` で一般的に利用可能なフィールドの型は次の通り: * string * text * integer * biginteger * float * decimal * datetime * timestamp * time * date * binary * boolean * uuid 未確定で無効な値のままのフィールド型を選ぶためのいくつかの発見的手法があります。 デフォルトのフィールド型は `string` です。 * id: integer * created, modified, updated: datetime ### テーブルの作成[¶](https://book.cakephp.org/migrations/2/ja/#id9 "このヘッドラインへのパーマリンク") テーブルを作成するために `bake` が使えます。 : bin/cake bake migration CreateProducts name:string description:text created modified 上記のコマンドラインは、よく似たマイグレーションファイルを生成します。 table('products'); $table\->addColumn('name', 'string', \[\ 'default' \=> null,\ 'limit' \=> 255,\ 'null' \=> false,\ \]); $table\->addColumn('description', 'text', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->addColumn('created', 'datetime', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->addColumn('modified', 'datetime', \[\ 'default' \=> null,\ 'null' \=> false,\ \]); $table\->create(); } } ### 既存のテーブルにカラムを追加[¶](https://book.cakephp.org/migrations/2/ja/#id10 "このヘッドラインへのパーマリンク") もしコマンドラインのマイグレーション名が "AddXXXToYYY" といった 書式で、その後にカラム名と型が続けば、カラムの追加を行うコードを含んだ マイグレーションファイルが生成されます。 : bin/cake bake migration AddPriceToProducts price:decimal コマンドラインを実行すると下記のようなファイルが生成されます。 table('products'); $table\->addColumn('price', 'decimal') \->update(); } } ### テーブルにインデックスとしてカラムを追加[¶](https://book.cakephp.org/migrations/2/ja/#id11 "このヘッドラインへのパーマリンク") カラムにインデックスを追加することも可能です。 : bin/cake bake migration AddNameIndexToProducts name:string:index このようなファイルが生成されます。 table('products'); $table\->addColumn('name', 'string') \->addIndex(\['name'\]) \->update(); } } ### フィールド長を指定[¶](https://book.cakephp.org/migrations/2/ja/#id12 "このヘッドラインへのパーマリンク") バージョン cakephp/migrations で追加: 1.4 もし、フィールド長を指定する必要がある場合、フィールドタイプにカギ括弧の中で指定できます。例: bin/cake bake migration AddFullDescriptionToProducts full\_description:string\[60\] 上記のコマンドラインを実行すると生成されます。 table('products'); $table\->addColumn('full\_description', 'string', \[\ 'default' \=> null,\ 'limit' \=> 60,\ 'null' \=> false,\ \]) \->update(); } } 長さが未指定の場合、いくつかのカラム型の長さは初期値が設定されます。 * string: 255 * integer: 11 * biginteger: 20 ### テーブルから列を変更する[¶](https://book.cakephp.org/migrations/2/ja/#id13 "このヘッドラインへのパーマリンク") 同様に、移行名が「AlterXXXOnYYY」の形式の場合、コマンドラインを使用して、列を変更する移行を生成できます。 bin/cake bake migration AlterPriceOnProducts name:float 生成されます: table('products'); $table\->changeColumn('name', 'float'); $table\->update(); } } ### テーブルからカラムを削除[¶](https://book.cakephp.org/migrations/2/ja/#id14 "このヘッドラインへのパーマリンク") もしマイグレーション名が "RemoveXXXFromYYY" であるなら、同様にコマンドラインを使用して、 カラム削除のマイグレーションファイルを生成することができます。 : bin/cake bake migration RemovePriceFromProducts price このようなファイルが生成されます。 table('products'); $table\->removeColumn('price') \->save(); } } 注釈 removeColumn は不可逆ですので、 up メソッドの中で呼び出してください。 それに対する addColumn の呼び出しは、 down メソッドに追加してください。 ### 既存のデータベースからマイグレーションファイルを作成する[¶](https://book.cakephp.org/migrations/2/ja/#id15 "このヘッドラインへのパーマリンク") もしあなたが既存のデータベースで、マイグレーションの使用を始めたい場合や、 あなたのアプリケーションのデータベースで初期状態のスキーマのバージョン管理を 行いたい場合、 `migration_snapshot` コマンドを実行します。 : bin/cake bake migration\_snapshot Initial これはデータベース内のすべてのテーブルの create 文を含んだ **YYYYMMDDHHMMSS\_Initial.php** と呼ばれるマイグレーションファイルを生成します。 デフォルトで、スナップショットは、 `default` 接続設定で定義されたデータベースに 接続することによって作成されます。 もし、異なるデータベースからスナップショットを bake する必要があるなら、 `--connection` オプションが使用できます。 : bin/cake bake migration\_snapshot Initial --connection my\_other\_connection `--require-table` フラグを使用することによって対応するモデルクラスを定義したテーブルだけを 含まれることを確認することができます。 : bin/cake bake migration\_snapshot Initial --require-table `--require-table` フラグを使用した時、シェルは、あなたのアプリケーションを通して `Table` クラスを見つけて、スナップショットのモデルテーブルのみ追加します。 プラグインのためのスナップショットを bake したい場合、同じロジックが暗黙的に適用されます。 そうするために、 `--plugin` オプションを使用する必要があります。 : bin/cake bake migration\_snapshot Initial --plugin MyPlugin 定義された `Table` オブジェクトモデルを持つテーブルだけプラグインのスナップショットに 追加されます。 注釈 プラグインのためのスナップショットを bake した時、マイグレーションファイルは、 あなたのプラグインの **config/Migrations** ディレクトリーに作成されます。 スナップショットを bake した時、phinx のログテーブルに自動的に追加されることに注意してください。 2つのデータベース間の状態の差分を生成する[¶](https://book.cakephp.org/migrations/2/ja/#id16 "このヘッドラインへのパーマリンク") -------------------------------------------------------------------------------------------- バージョン cakephp/migrations で追加: 1.6.0 `migration_diff` の bake テンプレートを使用して2つのデータベースの状態の すべての差分をまとめたマイグレーションファイルを生成することができます。 そのためには、以下のコマンドを使用します。 : bin/cake bake migration\_diff NameOfTheMigrations 現在のデータベースの状態からの比較のポイントを保持するために、migrations シェルは、 `migrate` もしくは `rollback` が呼ばれた後に "dump" ファイルを生成します。 ダンプファイルは、取得した時点でのあなたのデータベースの全スキーマの状態を含むファイルです。 一度ダンプファイルが生成されると、あなたのデータベース管理システムに直接行ったすべての変更は、 `bake migration_diff` コマンドが呼ばれた時に生成されたマイグレーションファイルに追加されます。 デフォルトでは、 `default` 接続設定に定義されたデータベースに接続することによって 差分が作成されます。もし、あなたが異なるデータソースから差分を bake する必要がある場合、 `--connection` オプションを使用できます。 : bin/cake bake migration\_diff NameOfTheMigrations --connection my\_other\_connection もし、すでにマイグレーションの履歴を持つアプリケーション上で diff 機能を使用したい場合、 マニュアルで比較に使用するダンプファイルを作成する必要があります。 : bin/cake migrations dump データベースの状態は、あなたがダンプファイルを作成する前にマイグレーションを全て実行した状態と 同じでなければなりません。一度ダンプファイルが生成されると、あなたのデータベースの変更を始めて、 都合の良い時に `bake migration_diff` コマンドを使用することができます。 注釈 migrations シェルは、カラム名の変更は検知できません。 コマンド[¶](https://book.cakephp.org/migrations/2/ja/#id17 "このヘッドラインへのパーマリンク") --------------------------------------------------------------------------- ### `migrate` : マイグレーションを適用する[¶](https://book.cakephp.org/migrations/2/ja/#migrate "このヘッドラインへのパーマリンク") マイグレーションファイルを生成したり記述したら、以下のコマンドを実行して 変更をデータベースに適用しましょう。 : \# マイグレーションをすべて実行 bin/cake migrations migrate \# 特定のバージョンに移行するためには、 \`\`--target\`\` オプション \# (省略形は \`\`-t\`\` )を使用します。 \# これはマイグレーションファイル名の前に付加されるタイムスタンプに対応しています。 bin/cake migrations migrate -t 20150103081132 \# デフォルトで、マイグレーションファイルは、 \*\*config/Migrations\*\* ディレクトリーに \# あります。 \`\`--source\`\` オプション (省略形は \`\`-s\`\`) を使用することで、 \# ディレクトリーを指定できます。 \# 次の例は、 \*\*config/Alternate\*\* ディレクトリー内でマイグレーションを実行します。 bin/cake migrations migrate -s Alternate \# \`\`--connection\`\` オプション (省略形は \`\`-c\`\`) を使用することで \# \`\`default\`\` とは異なる接続でマイグレーションを実行できます。 bin/cake migrations migrate -c my\_custom\_connection \# マイグレーションは、プラグインのためにも実行できます。 \`\`--plugin\`\` オプション \# (省略形は \`\`-p\`\`) を使用します。 bin/cake migrations migrate -p MyAwesomePlugin ### `rollback` : マイグレーションを戻す[¶](https://book.cakephp.org/migrations/2/ja/#rollback "このヘッドラインへのパーマリンク") ロールバックコマンドは、このプラグインを実行する前の状態に戻すために使われます。 これは `migrate` コマンドの逆向きの動作をします。 : \# あなたは \`\`rollback\`\` コマンドを使って以前のマイグレーション状態に戻すことができます。 bin/cake migrations rollback \# また、特定のバージョンに戻すために、マイグレーションバージョン番号を引き渡すこともできます。 bin/cake migrations rollback -t 20150103081132 `migrate` コマンドのように `--source` 、 `--connection` そして `--plugin` オプションが使用できます。 ### `status` : マイグレーションのステータス[¶](https://book.cakephp.org/migrations/2/ja/#status "このヘッドラインへのパーマリンク") Status コマンドは、現在の状況とすべてのマイグレーションのリストを出力します。 あなたはマイグレーションが実行されたかを判断するために、このコマンドを使用することができます。 : bin/cake migrations status `--format` (省略形は `-f`) オプションを使用することで JSON 形式の文字列として結果を出力できます。 : bin/cake migrations status --format json `migrate` コマンドのように `--source` 、 `--connection` そして `--plugin` オプションが使用できます。 ### `mark_migrated` : マイグレーション済みとしてマーキングする[¶](https://book.cakephp.org/migrations/2/ja/#mark-migrated "このヘッドラインへのパーマリンク") バージョン 1.4.0 で追加. 時には、実際にはマイグレーションを実行せずにマークだけすることが便利な事もあります。 これを実行するためには、 `mark_migrated` コマンドを使用します。 コマンドは、他のコマンドとしてシームレスに動作します。 このコマンドを使用して、すべてのマイグレーションをマイグレーション済みとして マークすることができます。 : bin/cake migrations mark\_migrated また、 `--target` オプションを使用して、指定したバージョンに対して、 すべてマイグレーション済みとしてマークすることができます。 : bin/cake migrations mark\_migrated --target\=20151016204000 もし、指定したマイグレーションを処理中にマーク済みにしたくない場合、 `--exclude` フラグをつけて使用することができます。 : bin/cake migrations mark\_migrated --target\=20151016204000 --exclude 最後に、指定したマイグレーションだけをマイグレーション済みとしてマークしたい場合、 `--only` フラグを使用できます。 : bin/cake migrations mark\_migrated --target\=20151016204000 --only `migrate` コマンドのように `--source` 、 `--connection` そして `--plugin` オプションが使用できます。 注釈 あなたが `cake bake migration_snapshot` コマンドでスナップショットを作成したとき、 自動的にマイグレーション済みとしてマーキングされてマイグレーションが作成されます。 バージョン 1.4.0 で非推奨: 以下のコマンドの使用方法は非推奨になりました。もし、あなたが 1.4.0 より前のバージョンの プラグインの場合のみに使用してください。 このコマンドは、引数としてマイグレーションバージョン番号を想定しています。 : bin/cake migrations mark\_migrated 20150420082532 もし、すべてのマイグレーションをマイグレーション済みとしてマークしたい場合、 特別な値 `all` を使用できます。もし使用した場合、すべての見つかったマイグレーションを マイグレーション済みとしてマークします。 : bin/cake migrations mark\_migrated all ### `seed` : データベースの初期データ投入[¶](https://book.cakephp.org/migrations/2/ja/#seed "このヘッドラインへのパーマリンク") 1.5.5 より、データベースの初期データ投入のために `migrations` シェルが使用できます。 これは、 [Phinx ライブラリーの seed 機能](https://book.cakephp.org/phinx/0/en/seeding.html) を利用しています。デフォルトで、seed ファイルは、あなたのアプリケーションの `config/Seeds` ディレクトリーの中に置かれます。 [seed ファイル作成のための Phinx の命令](https://book.cakephp.org/phinx/0/en/seeding.html#creating-a-new-seed-class) を確認してください。 マイグレーションに関して、 seed ファイルのための `bake` インターフェースが提供されます。 : \# これは、あなたのアプリケーションの config/Seeds ディレクトリー内に ArticlesSeed.php を作成します。 \# デフォルトでは、変換対象の seed は、 "tableized" バージョンの seed ファイル名です。 bin/cake bake seed Articles \# \`\`--table\`\` オプションを使用することで seed ファイルに変換するテーブル名を指定します。 bin/cake bake seed Articles --table my\_articles\_table \# bake するプラグインを指定できます。 bin/cake bake seed Articles --plugin PluginName \# シーダーの生成時に別の接続を指定できます。 bin/cake bake seed Articles --connection connection バージョン cakephp/migrations で追加: 1.6.4 オプションの `--data`, `--limit` そして `--fields` は、 データベースからデータをエクスポートするために追加されました。 1.6.4 から、 `bake seed` コマンドは、 `--data` フラグを使用することによって、 データベースからエクスポートされたデータを元に seed ファイルを作成することができます。 : bin/cake bake seed --data Articles デフォルトでは、テーブル内にある行を全てエクスポートします。 `--limit` オプションを 使用することによって、エクスポートされる行の数を制限できます。 : \# 10 行のみエクスポート bin/cake bake seed --data --limit 10 Articles もし、seed ファイルの中にテーブルから選択したフィールドのみを含めたい場合、 `--fields` オプションが使用できます。そのオプションは、 フィールドのリストをカンマ区切りの値の文字列として含めます。 : \# \`id\`, \`title\` そして \`excerpt\` フィールドのみをエクスポート bin/cake bake seed --data --fields id,title,excerpt Articles ちなみに もちろん、同じコマンド呼び出し中に `--limit` と `--fields` オプションの両方が利用できます。 データベースの初期データ投入のために、 `seed` サブコマンドが使用できます。 : \# パラメーターなしの seed サブコマンドは、対象のディレクトリーのアルファベット順で、 \# すべての利用可能なシーダーを実行します。 bin/cake migrations seed \# \`--seed\` オプションを使用して実行するための一つだけシーダーを指定できます。 bin/cake migrations seed --seed ArticlesSeed \# 別のディレクトリーでシーダーを実行できます。 bin/cake migrations seed --source AlternativeSeeds \# プラグインのシーダーを実行できます bin/cake migrations seed --plugin PluginName \# 指定したコネクションでシーダーを実行できます bin/cake migrations seed --connection connection マイグレーションとは対照的にシーダーは追跡されないことに注意してください。 それは、同じシーダーは、複数回適用することができることを意味します。 #### シーダーから別のシーダーの呼び出し[¶](https://book.cakephp.org/migrations/2/ja/#id18 "このヘッドラインへのパーマリンク") バージョン cakephp/migrations で追加: 1.6.2 たいてい初期データ投入時は、データの挿入する順番は、規約違反しないように遵守しなければなりません。 デフォルトでは、アルファベット順でシーダーが実行されますが、独自にシーダーの実行順を定義するために `\Migrations\AbstractSeed::call()` メソッドが利用できます。 use Migrations\\AbstractSeed; class DatabaseSeed extends AbstractSeed { public function run() { $this\->call('AnotherSeed'); $this\->call('YetAnotherSeed'); // プラグインからシーダーを呼ぶためにプラグインドット記法が使えます $this\->call('PluginName.FromPluginSeed'); } } 注釈 もし、 `call()` メソッドを使いたい場合、Migrations プラグインの `AbstractSeed` クラスを継承していることを確認してください。このクラスは、リリース 1.6.2 で追加されました。 ### `dump` : 差分を bake する機能のためのダンプファイルの生成[¶](https://book.cakephp.org/migrations/2/ja/#dump-bake "このヘッドラインへのパーマリンク") dump コマンドは、 `migration_diff` の bake テンプレートで使用するファイルを作成します。 : bin/cake migrations dump 各生成されたダンプファイルは、生成元の接続固有のものです(そして、そのようにサフィックスされます)。 これは、アプリケーションが、異なるデータベースベンダーの複数のデータベースを扱う場合、 `bake migration_diff` コマンドで正しく差分を算出することができます。 ダンプファイルは、マイグレーションファイルと同じディレクトリーに作成されます。 `migrate` コマンドのように `--source` 、 `--connection` そして `--plugin` オプションが使用できます。 プラグイン内のマイグレーションファイルを使う[¶](https://book.cakephp.org/migrations/2/ja/#id19 "このヘッドラインへのパーマリンク") --------------------------------------------------------------------------------------------- プラグインはマイグレーションファイルも提供することができます。 これはプラグインの移植性とインストールの容易さを高め、配布しやすくなるように意図されています。 Migrations プラグインの全てのコマンドは、プラグイン関連のマイグレーションを行うための `--plugin` か `-p` オプションをサポートしています。 : bin/cake migrations status -p PluginName bin/cake migrations migrate -p PluginName 非シェルの環境でマイグレーションを実行する[¶](https://book.cakephp.org/migrations/2/ja/#id20 "このヘッドラインへのパーマリンク") -------------------------------------------------------------------------------------------- バージョン cakephp/migrations で追加: 1.2.0 migrations プラグインのバージョン 1.2 から、非シェル環境でも app から直接 `Migrations` クラスを使ってマイグレーションを実行できるようになりました。 これは CMS のプラグインインストーラーを作る時などに便利です。 `Migrations` クラスを使用すると、マイグレーションシェルから下記のコマンドを 実行することができます。: * migrate * rollback * markMigrated * status * seed それぞれのコマンドは `Migrations` クラスのメソッドとして実装されています。 使い方は以下の通りです。 use Migrations\\Migrations; $migrations \= new Migrations(); // 全てのマイグレーションバージョンとそのステータスの配列を返します。 $status \= $migrations\->status(); // 成功した場合、 true を返し、エラーが発生した場合、例外が投げられます。 $migrate \= $migrations\->migrate(); // 成功した場合、 true を返し、エラーが発生した場合、例外が投げられます。 $rollback \= $migrations\->rollback(); // 成功した場合、 true を返し、エラーが発生した場合、例外が投げられます。 $markMigrated \= $migrations\->markMigrated(20150804222900); // 成功した場合、 true を返し、エラーが発生した場合、例外が投げられます。 $seeded \= $migrations\->seed(); メソッドはコマンドラインのオプションと同じパラメーター配列を受け取ります。 use Migrations\\Migrations; $migrations \= new Migrations(); // 全てのマイグレーションバージョンとそのステータスの配列を返す $status \= $migrations\->status(\['connection' \=> 'custom', 'source' \=> 'MyMigrationsFolder'\]); あなたはシェルコマンドのように任意のオプションを引き渡すことができます。 唯一の例外は `markMigrated` コマンドで、第1引数にはマイグレーション済みとして マーキングしたいマイグレーションバージョン番号を渡し、第2引数にパラメーターの配列を 渡します。 必要に応じて、クラスのコンストラクターでこれらのパラメーターを引き渡すことができます。 それはデフォルトとして使用され、それぞれのメソッド呼び出しの時に引き渡されることを 防止します。 use Migrations\\Migrations; $migrations \= new Migrations(\['connection' \=> 'custom', 'source' \=> 'MyMigrationsFolder'\]); // 以下のすべての呼び出しは、マイグレーションクラスのコンストラクターに渡されたパラメーターを使用して行われます $status \= $migrations\->status(); $migrate \= $migrations\->migrate(); 個別の呼び出しでデフォルトのパラメーターを上書きしたい場合は、メソッド呼び出し時に引き渡します。 use Migrations\\Migrations; $migrations \= new Migrations(\['connection' \=> 'custom', 'source' \=> 'MyMigrationsFolder'\]); // この呼び出しでは "custom" コネクションを使用します。 $status \= $migrations\->status(); // こちらでは "default" コネクションを使用します。 $migrate \= $migrations\->migrate(\['connection' \=> 'default'\]); 小技と裏技[¶](https://book.cakephp.org/migrations/2/ja/#id21 "このヘッドラインへのパーマリンク") ---------------------------------------------------------------------------- ### 主キーをカスタマイズする[¶](https://book.cakephp.org/migrations/2/ja/#id22 "このヘッドラインへのパーマリンク") あなたがデータベースに新しいテーブルを作成する時、 `id` を主キーとして 自動生成したくない場合、 `table()` メソッドの第2引数を使うことができます。 table('products', \['id' \=> false, 'primary\_key' \=> \['id'\]\]); $table \->addColumn('id', 'uuid') \->addColumn('name', 'string') \->addColumn('description', 'text') \->create(); } } 上記の例では、 `CHAR(36)` の `id` というカラムを主キーとして作成します。 注釈 独自の主キーをコマンドラインで指定した時、id フィールドの中の主キーとして注意してください。 そうしなければ、id フィールドが重複してエラーになります。例: bin/cake bake migration CreateProducts id:uuid:primary name:string description:text created modified さらに、Migrations 1.3 以降では 主キーに対処するための新しい方法が導入されました。 これを行うには、あなたのマイグレーションクラスは新しい `Migrations\AbstractMigration` クラスを継承する必要があります。 あなたは Migration クラスの `autoId` プロパティーに `false` を設定することで、 自動的な `id` カラムの生成をオフにすることができます。 あなたは手動で主キーカラムを作成し、テーブル宣言に追加する必要があります。 table('products'); $table \->addColumn('id', 'integer', \[\ 'autoIncrement' \=> true,\ 'limit' \=> 11\ \]) \->addPrimaryKey('id') \->addColumn('name', 'string') \->addColumn('description', 'text') \->create(); } } 主キーを扱うこれまでの方法と比較すると、この方法は、unsigned や not や limit や comment など さらに多くの主キーの定義を操作することができるようになっています。 Bake で生成されたマイグレーションファイルとスナップショットは、この新しい方法を 必要に応じて使用します。 警告 主キーの操作ができるのは、テーブル作成時のみです。これはプラグインがサポートしている いくつかのデータベースサーバーの制限によるものです。 ### 照合順序[¶](https://book.cakephp.org/migrations/2/ja/#id23 "このヘッドラインへのパーマリンク") もしデータベースのデフォルトとは別の照合順序を持つテーブルを作成する必要がある場合は、 `table()` メソッドのオプションとして定義することができます。: table('categories', \[\ 'collation' \=> 'latin1\_german1\_ci'\ \]) \->addColumn('title', 'string', \[\ 'default' \=> null,\ 'limit' \=> 255,\ 'null' \=> false,\ \]) \->create(); } } ですが、これはテーブル作成時にしかできず、既存のテーブルに対してカラムを追加する時に テーブルやデータベースと異なる照合順序を指定する方法がないことに注意してください。 ただ `MySQL` と `SqlServer` だけはこの設定キーをサポートしています。 ### カラム名の更新と Table オブジェクトの使用[¶](https://book.cakephp.org/migrations/2/ja/#table "このヘッドラインへのパーマリンク") カラムのリネームや移動とともに、あなたのデータベースから値を操作するために CakePHP ORM Table オブジェクトを使用している場合、 `update()` を呼んだ後に Table オブジェクトの新しいインスタンスを作成できることを確かめてください。 インスタンス上の Table オブジェクトに反映し保存されたスキーマをリフレッシュするために Table オブジェクトのレジストリーは、 `update()` が呼ばれた後にクリアされます。 ### マイグレーションとデプロイメント[¶](https://book.cakephp.org/migrations/2/ja/#id24 "このヘッドラインへのパーマリンク") もし、アプリケーションをデプロイする時にプラグインを使用する場合、 テーブルのカラムメタデータを更新するように、必ず ORM キャッシュをクリアしてください。 そうしなければ、それらの新しいカラムの操作を実行する時に、カラムが存在しないエラーになります。 CakePHP コアは、この操作を行うために使用できる [スキーマキャッシュシェル](https://book.cakephp.org/3.0/ja/console-and-shells/schema-cache.html) を含みます。 : // 3.6.0 より前の場合、orm\_cache を使用 bin/cake schema\_cache clear このシェルについてもっと知りたい場合、クックブックの [スキーマキャッシュシェル](https://book.cakephp.org/3.0/ja/console-and-shells/schema-cache.html) セクションをご覧ください。 ### テーブルのリネーム[¶](https://book.cakephp.org/migrations/2/ja/#id25 "このヘッドラインへのパーマリンク") プラグインは、 `rename()` メソッドを使用することでテーブルのリネームができます。 あなたのマイグレーションファイルの中で、以下のように記述できます。 public function up() { $this\->table('old\_table\_name') \->rename('new\_table\_name') \->save(); } ### `schema.lock` ファイル生成のスキップ[¶](https://book.cakephp.org/migrations/2/ja/#schema-lock "このヘッドラインへのパーマリンク") バージョン cakephp/migrations で追加: 1.6.5 diff 機能を動作させるために、 **.lock** ファイルは、migrate、rollback または スナップショットの bake の度に生成され、指定された時点でのデータベーススキーマの状態を追跡します。 例えば本番環境上にデプロイするときなど、前述のコマンドに `--no-lock` オプションを使用することによって、このファイルの生成をスキップすることができます。 : bin/cake migrations migrate --no-lock bin/cake migrations rollback --no-lock bin/cake bake migration\_snapshot MyMigration --no-lock [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://cakesf.herokuapp.com/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") [#IRC](https://webchat.freenode.net/?channels=cakephp "IRC") --- # Debug Kit - 3.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/debug_kit/edit/3.x/docs/ja/index.rst) [](https://book.cakephp.org/debugkit/3/ja/#page-contents) ### Page Contents * [Debug Kit](https://book.cakephp.org/debugkit/3/ja/#) * [インストール](https://book.cakephp.org/debugkit/3/ja/#id1) * [設定](https://book.cakephp.org/debugkit/3/ja/#id2) * [データベース設定](https://book.cakephp.org/debugkit/3/ja/#id3) * [ツールバーの使い方](https://book.cakephp.org/debugkit/3/ja/#id4) * [履歴パネルを使用する](https://book.cakephp.org/debugkit/3/ja/#id5) * [メールパネルを使用](https://book.cakephp.org/debugkit/3/ja/#id6) * [プレビュークラスの作成](https://book.cakephp.org/debugkit/3/ja/#id7) * [独自のパネルを開発する](https://book.cakephp.org/debugkit/3/ja/#id8) * [パネルクラスを作成する](https://book.cakephp.org/debugkit/3/ja/#id9) * [コールバック](https://book.cakephp.org/debugkit/3/ja/#id10) * [パネルの構成要素](https://book.cakephp.org/debugkit/3/ja/#id11) * [カスタムのタイトルとエレメント](https://book.cakephp.org/debugkit/3/ja/#id12) * [パネルフックメソッド](https://book.cakephp.org/debugkit/3/ja/#id13) * [他のプラグインのパネル](https://book.cakephp.org/debugkit/3/ja/#id14) * [ヘルパー関数](https://book.cakephp.org/debugkit/3/ja/#id15) Debug Kit[¶](https://book.cakephp.org/debugkit/3/ja/#debug-kit "このヘッドラインへのパーマリンク") =================================================================================== DebugKit は、CakePHP アプリケーション用のデバッグツールバーと拡張デバッグツールを提供します。 アプリケーションの設定データ、ログメッセージ、SQL クエリー、およびタイミングデータをすばやく 確認できます。 警告 DebugKit は、シングルユーザーのローカル開発環境での使用を目的としています。 共有開発環境、ステージング環境、または設定データと環境変数を隠しておく必要がある環境では、 DebugKit を使用しないでください。 インストール[¶](https://book.cakephp.org/debugkit/3/ja/#id1 "このヘッドラインへのパーマリンク") -------------------------------------------------------------------------- デフォルトで、DebugKit はデフォルトのアプリケーションスケルトンにインストールされています。 もし削除してしまって再インストールしたい場合は、以下のコマンドをアプリケーションの ルートディレクトリー (composer.json ファイルのある場所) で実行してください。 php composer.phar require \--dev cakephp/debug\_kit "~3.0" そして以下のコマンドでプラグインを有効化する必要があります。 bin/cake plugin load DebugKit 設定[¶](https://book.cakephp.org/debugkit/3/ja/#id2 "このヘッドラインへのパーマリンク") ---------------------------------------------------------------------- * `DebugKit.panels` - DebugKit のパネルを有効化または無効化します。 次のようにして、任意の標準パネルを無効にすることができます。 // DebugKit をロードする前に Configure::write('DebugKit.panels', \['DebugKit.Packages' \=> false\]); * `DebugKit.includeSchemaReflection` - スキーマリフレクションクエリーの ロギングを有効にするには、true に設定します。デフォルトは無効になっています。 * `DebugKit.safeTld` - ローカル開発用のトップレベルドメインのホワイトリストを設定します。 これにより安全でないと判断したホスト上で DebugKit を表示できるようになります。 // 例: http://foo.bar.dev または http://my-shop.local のドメインはローカルとして許可する Configure::write('DebugKit.safeTld', \['dev', 'local', 'example'\]); * `DebugKit.forceEnable` - DebugKit を強制的に表示します。これを使うときは注意してください。 通常は単純にローカルのトップレベルドメインをホワイトリストに追加したほうが安全です。 使用例: // DebugKit をロードする前に Configure::write('DebugKit.forceEnable', true); ### データベース設定[¶](https://book.cakephp.org/debugkit/3/ja/#id3 "このヘッドラインへのパーマリンク") デフォルトでは DebugKit はアプリケーションの `/tmp` 内の SQLite データベースに パネルデータを保持します。もし pdo\_sqlite をインストールできない場合は、 **config/app.php** ファイル に `debug_kit` コネクションを定義すると DebugKit が異なるデータベースを使用するように設定できます。例: /\*\* \* debug\_kit コネクションは DebugKit のメタデータを格納します。 \*/ 'debug\_kit' \=> \[\ 'className' \=> 'Cake\\Database\\Connection',\ 'driver' \=> 'Cake\\Database\\Driver\\Mysql',\ 'persistent' \=> false,\ 'host' \=> 'localhost',\ //'port' => 'nonstandard\_port\_number',\ 'username' \=> 'dbusername', // Your DB username here\ 'password' \=> 'dbpassword', // Your DB password here\ 'database' \=> 'debug\_kit',\ 'encoding' \=> 'utf8',\ 'timezone' \=> 'UTC',\ 'cacheMetadata' \=> true,\ 'quoteIdentifiers' \=> false,\ //'init' => \['SET GLOBAL innodb\_stats\_on\_metadata = 0'\],\ \], **tmp/debug\_kit.sqlite** ファイルは、いつでも削除することができます。 DebugKit は、必要に応じて、それを再生成します。 ツールバーの使い方[¶](https://book.cakephp.org/debugkit/3/ja/#id4 "このヘッドラインへのパーマリンク") ----------------------------------------------------------------------------- DebugKit ツールバーは、いくつかのパネルで構成されています。これらのパネルは、 DebugKit をインストールしてロードした後、ブラウザーの右下隅にある CakePHP アイコンをクリックすると表示されます。各パネルは、パネルクラスとビューエレメントで構成されています。 一般的に、パネルは単一の種類の情報のコレクションの処理やログやリクエスト情報の表示を行います。 ツールバーからパネルを表示したり、独自のカスタムパネルを追加することを選択できます。 各パネルはアプリケーションの様々な側面を見せてくれます。 * **Cache** リクエスト中のキャッシュの使用状況の確認とキャッシュのクリアー。 * **Environment** PHP 及び CakePHP に関連する環境変数の表示。 * **History** 以前のリクエストの一覧の表示と、以前のリクエストのツールバーデータの読み込みと表示。 * **Include** タイプごとにグループ化されたインクルードファイルを表示。 * **Log** このリクエスト中にログファイルに加えられたすべてのエントリーを表示。 * **Packages** 現在のバージョンのパッケージの依存関係の一覧を表示し、 古いパッケージをチェックすることができます。 * **Mail** このリクエスト中の全てのメール送信を表示し、 送信せずに開発中のメールのプレビューができます。 * **Request** 現在のリクエスト、GET、POST、Cake パラメーター、現在のルート情報、クッキー情報の表示。 * **Session** 現在のセッション情報の表示。 * **Sql Logs** 各データベースコネクションの SQL ログの表示。 * **Timer** リクエスト中に `DebugKit\DebugTimer` で設定されたすべてのタイマーと、 `DebugKit\DebugMemory` で収集されたメモリー使用状況の表示。 * **Variables** コントローラーでセットされたビュー変数の表示。 履歴パネルを使用する[¶](https://book.cakephp.org/debugkit/3/ja/#id5 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------------ 履歴パネルは DebugKit で最も勘違いされやすい機能の一つです。 エラーやリダイレクトを含む以前のリクエストのツールバーのデータを表示することができます。 ![Screenshot of the history panel in debug kit.](https://book.cakephp.org/debugkit/3/_static/history-panel.png) ご覧のようにパネルにはリクエストの一覧が含まれます。左側にドットがついているのがアクティブな リクエストです。どれかのリクエストをクリックするとそのリクエストのデータが読み込まれます。 履歴データがロードされると代替のデータが読み込まれたことを示すようにパネルのタイトルが遷移します。 Video of history panel in action. メールパネルを使用[¶](https://book.cakephp.org/debugkit/3/ja/#id6 "このヘッドラインへのパーマリンク") ----------------------------------------------------------------------------- メールパネルは、リクエストの間に送信された全てのメールを追跡することができます。 Video of mail panel in action メーラープレビューは、開発中のメールを簡単にプレビューすることができます。 Video of mail panel in action ### プレビュークラスの作成[¶](https://book.cakephp.org/debugkit/3/ja/#id7 "このヘッドラインへのパーマリンク") メールを送信する前にプレビューするには、受信者と mailer メソッドに必要なテンプレート変数を 定義するプレビュークラスを作成する必要があります。 // src/Mailer/MailPreview/WelcomePreview.php の中で namespace App\\Mailer\\Preview; use DebugKit\\Mailer\\MailPreview; class WelcomePreview extends MailPreview { public function welcome() { $mailer \= $this\->getMailer('Welcome'); // メーラーのテンプレート変数受信者を設定します。 return $mailer; } } MailPreview クラスは、 アプリケーションまたはプラグインの `Mailer\Preview` 名前空間に存在し、 `Preview` を使用する必要があります。 独自のパネルを開発する[¶](https://book.cakephp.org/debugkit/3/ja/#id8 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------------- アプリケーションのデバッグを補助するための DebugKit の独自のカスタムパネルを 作成することができます。 ### パネルクラスを作成する[¶](https://book.cakephp.org/debugkit/3/ja/#id9 "このヘッドラインへのパーマリンク") パネルクラスは単に **src/Panel** ディレクトリーに設置してください。ファイル名はクラス名と 一致する必要があります。 つまり `MyCustomPanel` クラスは **src/Panel/MyCustomPanel.php** というファイル名であることを想定しています。 namespace App\\Panel; use DebugKit\\DebugPanel; /\*\* \* My Custom Panel \*/ class MyCustomPanel extends DebugPanel { ... } カスタムパネルは `DebugPanel` クラスを拡張する必要があることに注意してください。 ### コールバック[¶](https://book.cakephp.org/debugkit/3/ja/#id10 "このヘッドラインへのパーマリンク") デフォルトではパネルオブジェクトには、現在のリクエストをフックすることができる 2つのコールバックがあります。パネルは `Controller.initialize` と `Controller.shutdown` のイベントを取得します。もしパネルが追加のイベントを 取得したい場合は、 `implementedEvents()` メソッドを使用し、 パネルが必要とするすべてのイベントを定義できます。 どのようにパネルを構築するかについてのいくつかの例として、ビルトインのパネルを参照してください。 ### パネルの構成要素[¶](https://book.cakephp.org/debugkit/3/ja/#id11 "このヘッドラインへのパーマリンク") 各パネルはパネルのコンテンツを描画するためのビューエレメントがあることを想定しています。 エレメント名はアンダースコアー区切りのクラス名である必要があります。 たとえば、 `SessionPanel` は **session\_panel.ctp** という名前のエレメントを持ちます。 また、SqllogPanelは **sqllog\_panel.ctp** という名前のエレメントを持ちます。 これらのエレメントは **src/Template/Element** ディレクトリーのルートに設置する必要があります。 ### カスタムのタイトルとエレメント[¶](https://book.cakephp.org/debugkit/3/ja/#id12 "このヘッドラインへのパーマリンク") パネルは慣例を元にそのタイトルとエレメント名を補足します。もしカスタムのタイトルやエレメント名を 付けたい場合は、パネルの振る舞いをカスタムするメソッドを定義することができます。 * `title()` - ツールバー上に表示されるタイトルを設定します * `elementName()` - 与えられたパネルがどのエレメントを使用するかを設定します ### パネルフックメソッド[¶](https://book.cakephp.org/debugkit/3/ja/#id13 "このヘッドラインへのパーマリンク") また、パネルの動作や表示方法をカスタムするために以下のフックメソッドを実装することができます。 * `shutdown(Event $event)` このメソッドは通常はパネルのデータの収集と準備を行います。 * `summary()` パネルが折りたたまれている時に表示されるサマリーデータの文字列を 返すことができます。多くの場合、これは件数や短いサマリー情報です。 * `data()` エレメントのコンテキストで使用されるパネルのデータを返します。 このフックメソッドは `shutdown()` で収集されるデータを更に操作することができます。 このメソッドはシリアライズ化可能なデータを **必ず** 返す必要があります。 ### 他のプラグインのパネル[¶](https://book.cakephp.org/debugkit/3/ja/#id14 "このヘッドラインへのパーマリンク") パネルはひとつの小さな違いを除き、[plugins](https://book.cakephp.org/3.0/ja/plugins.html) とほぼ同じ動作を提供します。レンダリング時にパネルのエレメントを配置できるように、 `public $plugin` にプラグインディレクトリーの名前を必ずセットする必要があります。 namespace MyPlugin\\Panel; use DebugKit\\DebugPanel; class MyCustomPanel extends DebugPanel { public $plugin \= 'MyPlugin'; ... } プラグインやアプリケーションパネルを使用するには、アプリケーションの DebugKit の設定を 更新します。 // src/Application.php の bootstrap() メソッドの中に追加 Configure::write('DebugKit.panels', \['App', 'MyPlugin.MyCustom'\]); $this\->addPlugin('DebugKit', \['bootstrap' \=> true\]); 上記は、すべてのデフォルトのパネルと同じように `AppPanel` と `MyPlugin` の `MyCustomPanel` パネルを読みこみます。 ヘルパー関数[¶](https://book.cakephp.org/debugkit/3/ja/#id15 "このヘッドラインへのパーマリンク") --------------------------------------------------------------------------- * `sql()` ORM クエリーから SQL をダンプします。 * `sqld()` ORM クエリーから SQL をダンプして終了します。 [](https://phpc.social/@cakephp "Mastodon") [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://slack-invite.cakephp.org/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") --- # ビュー | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/views.html#VPContent) Return to top ビュー [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC) ========================================================================================= `class` Cake\\View\\**View** ビュー (View) は MVC の **V** です。ビューはリクエストに対する出力を生成する役割を担います。 大抵の場合、これは HTML フォームや XML、JSON などですが、ファイルのストリーミングや、 ユーザーがダウンロード可能な PDF の生成もビューレイヤーの役割となります。 CakePHP では下記の典型的な描画シナリオに対応するためのいくつかの組み込みのビュークラスを 用意しています。 * XML や JSON ウェブサービスを作成するには [JSON と XML ビュー](https://book.cakephp.org/3.x/ja/views/json-and-xml-views.html) を利用できます。 * 保護されたファイルや動的に生成されたファイルを提供するには [Cake Response File](https://book.cakephp.org/3.x/ja/controllers/request-response.html#cake-response-file) を利用できます。 * 複数テーマのビューを作成するには [テーマ](https://book.cakephp.org/3.x/ja/views/themes.html) を利用できます。 App ビュー [​](https://book.cakephp.org/3.x/ja/views.html#app-%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC) ------------------------------------------------------------------------------------------------- `AppView` はアプリケーションの既定のビュークラスです。 `AppView` は自身が CakePHP に含まれる `Cake\View\View` クラスを継承していて、 **src/View/AppView.php** の中で次のように定義されています。 loadHelper('MyUtils'); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ビューテンプレート [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E3%83%86%E3%83%B3%E3%83%95%E3%82%9A%E3%83%AC%E3%83%BC%E3%83%88) -------------------------------------------------------------------------------------------------------------------------------------------------------------- CakePHP のビューレイヤーは、どのようにユーザーに伝えるかです。ほとんどの場合、ビューは HTML/XHTML ドキュメントをブラウザーに返しますが、JSON を介して リモートアプリケーションに返答したり、CSV ファイルを出力する必要もあるかもしれません。 CakePHP のテンプレートファイルは既定の拡張子を **.ctp** (CakePHP Template) としており、 制御構造や出力のために [PHP 別の構文](https://php.net/manual/ja/control-structures.alternative-syntax.php) を利用することができます。 これらのファイルにはコントローラーから受け取ったデータを、 閲覧者のために用意した表示形式に整形するのに必要なロジックを入れます。 ### 別の echo [​](https://book.cakephp.org/3.x/ja/views.html#%E5%88%A5%E3%81%AE-echo) テンプレート中の変数を echo または print します。 : 1 短いタグにも対応しています。 : 1 ### 別の制御構文 [​](https://book.cakephp.org/3.x/ja/views.html#%E5%88%A5%E3%81%AE%E5%88%B6%E5%BE%A1%E6%A7%8B%E6%96%87) `if` 、 `for` 、 `foreach` 、 `switch` 、そして `while` のような制御構文は単純な形式で書くことができます。括弧は必要ないことに注意してください。 代わりに、 `foreach` の閉じ括弧は `endforeach` に置き換えられています。 上記の各制御構造は `endif` 、 `endfor` 、 `endforeach` 、 `endwhile` のような閉じ構文を持っています。各制御構造の後(最後の一つを除いて)に `セミコロン (;)` ではなく、 `コロン (:)` があることにも注意してください。 以下は `foreach` の使用例です。
    1 2 3 4 5 別の例として、 if/elseif/else の用法です。コロンに注意してください。

    やあ、Sally

    やあ、Joe

    やあ、知らない人

    1 2 3 4 5 6 7 もしも、 [Twig](https://twig.sensiolabs.org/) のようなテンプレート言語を使いたいのであれば、 ビューのサブクラスがテンプレート言語と CakePHP の橋渡しをしてくれるでしょう。 テンプレートファイルは **/src/Template/** の中の、ファイルを使用するコントローラーにちなんで 名付けられたフォルダーに置かれ、その対応するアクション名にちなんで名付けられます。 例えば、 `Products` コントローラーの `view()` アクションのビューファイルは通常、 **/src/Template/Products/view.ctp** となります。 CakePHP のビューレイヤーはいくつかの異なるパーツによって作り上げられています。 各パーツは異なる役割を持っており、この章で説明していきます。 * **テンプレート**: テンプレートは実行中のアクション固有のページの一部分です。 アプリケーションの応答の中心となります。 * **エレメント**: 小さな、再利用可能なちょっとしたコードです。エレメントは通常、 ビューの中で描画されます。 * **レイアウト**: アプリケーションの多くのインターフェイスをくるむ表示コードを入れる テンプレートファイルです。ほとんどのビューはレイアウトの中に描画されます。 * **ヘルパー**: これらのクラスはビューレイヤーの様々な場所で必要とされるロジックを カプセル化します。とりわけ、CakePHP のヘルパーはフォームの構築や AJAX 機能の構築、 モデルデータのページ切替、RSS フィードの提供などの手助けをしてくれます。 * **cells**: これらのクラスは、自己完結型のUI部品を作成する 小さなコントローラー風の機能を提供します。 より詳しい情報は [ビューセル](https://book.cakephp.org/3.x/ja/views/cells.html) を参照してください。 ### ビュー変数 [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E5%A4%89%E6%95%B0) コントローラーの中で `set()` で設定した変数は、 アクションが描画するビューやレイアウトの双方で使用可能です。 加えて、設定した変数はエレメントの中でも使用可能です。 もしも、追加の変数をビューからレイアウトに渡す必要があれば、 ビューテンプレートの中から `set()` を呼ぶか、 [View Blocks](https://book.cakephp.org/3.x/ja/views.html#view-blocks) が利用できます。 CakePHP は自動では出力をエスケープしませんので、ユーザーデータを出力する前には **いつも** エスケープしなければならないことを覚えておいてください。 `h()` 関数でユーザーコンテンツをエスケープできます。 : bio); ?> 1 ### ビュー変数の設定 [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E5%A4%89%E6%95%B0%E3%81%AE%E8%A8%AD%E5%AE%9A) `method` Cake\\View\\View::**set**(string $var, mixed $value) ビューにはコントローラーオブジェクトの `set()` と類似の `set()` メソッドがあります。 ビューファイルから set() を使うと後で描画されるレイアウトやエレメントに変数を追加できます。 `set()` の使い方のより詳しい情報は [Setting View Variables](https://book.cakephp.org/3.x/ja/controllers.html#setting-view-variables) を参照してください。 ビューファイルでは、次のように記述できます。 : $this->set('activeMenuButton', 'posts'); 1 そしてレイアウトでは、 `$activeMenuButton` 変数が使用でき、 'posts' という値を持ちます。 ### ビューの継承 [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E3%81%AE%E7%B6%99%E6%89%BF) ビューの継承によって、あるビューを他のビューでくるむことができるようになります。 [ビューブロック](https://book.cakephp.org/3.x/ja/views.html#view-blocks) と組み合わせることでビューを `DRY` に保つための 強力な方法が得られます。例えば、あなたが作成しているアプリケーションの特定のビューで、 サイドバーの描画を変える必要があるとします。共通のビューファイルを継承することで、 サイドバーのマークアップの繰り返しを避けられ、そしてただ変化する場所を定義するだけです。

    fetch('title') ?>

    fetch('content') ?>

    関連アクション

      fetch('sidebar') ?>
    1 2 3 4 5 6 7 8 9 10 上記のビューファイルを親ビューとして使うことができます。これは `sidebar` と `title` ブロックを定義しているビューが継承することを期待しています。 `content` ブロックは CakePHP が作る特別なブロックで、継承しているビューの捕捉されなかったすべての内容が入ります。 ビューファイルに投稿のデータが格納されている `$post` という変数があるとすれば、 ビューは次のようになります。 extend('/Common/view'); $this->assign('title', $post->title); $this->start('sidebar'); ?>
  • Html->link('edit', [\ 'action' => 'edit',\ $post->id\ ]); ?>
  • end(); ?> // 残りの内容は親ビューの 'content' ブロックとして使用可能です。 body) ?> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 上記の例はどのようにビューを継承できるかを示しており、ブロック一式を生成しています。 定義されたブロックの中に入っていないあらゆるコンテンツは捕捉され、 `content` という特別な名前のブロックに配置されます。ビューに `extend()` の呼び出しがある場合、 現在のビューファイルは最後まで実行されます。実行完了後、継承されたビューが描画されます。 一つのビューファイルで二回以上 `extend()` が呼び出される場合、 次に処理される親ビューを上書きします。 : $this->extend('/Common/view'); $this->extend('/Common/index'); 1 2 上記は `/Common/index.ctp` が現在のビューの親ビューとして描画される結果になります。 継承されたビューは好きなだけ入れ子にすることができます。必要に応じて 各ビューは他のビューを継承することができます。各親ビューは一つ前のビューの内容を `content` ブロックとして取得できます。 NOTE `content` をブロック名として使うことは避けるべきです。 CakePHP は継承されたビューの中で捕捉されていないコンテンツとして扱ってしまいます。 `blocks()` メソッドを使って、存在するブロックを列挙することができます。 : $list = $this->blocks(); 1 ビューブロックの使用 [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E3%83%95%E3%82%99%E3%83%AD%E3%83%83%E3%82%AF%E3%81%AE%E4%BD%BF%E7%94%A8) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ビューブロックはビュー/レイアウトの中のどこかで定義されるであろう、スロットやブロックを 定義できるようにする柔軟な API を提供します。例えばブロックは、サイドバーや、 レイアウトの末尾や先頭のアセット読込領域の実装に理想的です。 ブロックを実装するには二つの方法があります。捕捉するブロックとするか、直接割り当てるかです。 `start()` 、 `append()` 、 `prepend()` 、 `assign()` 、 `fetch()` 、 そして `end()` メソッドは捕捉するブロックと共に動作します。 : // sidebar ブロックを作成する。 $this->start('sidebar'); echo $this->element('sidebar/recent_topics'); echo $this->element('sidebar/recent_comments'); $this->end(); // sidebar の末尾に追加する。 $this->start('sidebar'); echo $this->fetch('sidebar'); echo $this->element('sidebar/popular_topics'); $this->end(); 1 2 3 4 5 6 7 8 9 10 11 `append()` を使ってブロックに追記することもできます。 : $this->append('sidebar'); echo $this->element('sidebar/popular_topics'); $this->end(); // 上と同じです。 $this->append('sidebar', $this->element('sidebar/popular_topics')); 1 2 3 4 5 6 もしあるブロックを消去または上書きする必要がある場合、二つほど選択肢があります。 `reset()` メソッドはいつでもブロックを消去または上書きします。 空文字での `assign()` メソッドも特定のブロックを消去するために使えます。 : // sidebar ブロックの以前の中身を消去します。 $this->reset('sidebar'); // 空文字を代入も sidebar ブロックを消去します。. $this->assign('sidebar', ''); 1 2 3 4 5 Added in version 3.2 3.2 で View::reset() が追加されました ブロックのコンテンツへの代入は、ビュー変数をブロックに変換したい時にしばしば役に立ちます。 例えば、ページタイトルのためにブロックを使いたいかもしれませんし、 時にはコントローラーの中で、ビュー変数としてタイトルを代入するかもしれません。 : // ビューやレイアウトの中で $this->fetch('title') に $this->assign('title', $title); 1 2 `prepend()` メソッドは既存のブロックの先頭にコンテンツを追記することができます。 : // sidebar に前置します $this->prepend('sidebar', 'このコンテンツはサイドバーの先頭に来ます'); 1 2 ### ブロックの表示 [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%95%E3%82%99%E3%83%AD%E3%83%83%E3%82%AF%E3%81%AE%E8%A1%A8%E7%A4%BA) ブロックの表示には `fetch()` メソッドを使います。`fetch()` は もしもブロックが存在しなかった場合に '' を返してブロックを出力します。 : fetch('sidebar') ?> 1 fetch を使うとブロックが存在するかどうかによってブロックに囲まれたコンテンツの表示を 切り替えることができます。これはレイアウトや継承されたビューで 見出しや他のマークアップ表示を切り替えたい場合に役に立ちます。 // src/Template/Layout/default.ctp の中で fetch('menu')): ?> 1 2 3 4 5 6 7 ブロックが存在しない場合の既定の値を指定することもできます。 これによって、ブロックが存在しない場合のプレースホルダーを追加することでききます。 既定値は第二引数で指定します。

    買い物かご

    fetch('cart', '買い物かごが空です') ?>
    1 2 3 4 ### スクリプトと CSS ファイルのためのブロック使用 [​](https://book.cakephp.org/3.x/ja/views.html#%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%95%E3%82%9A%E3%83%88%E3%81%A8-css-%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%95%E3%82%99%E3%83%AD%E3%83%83%E3%82%AF%E4%BD%BF%E7%94%A8) `HtmlHelper` はビューブロックと結び付いており、その `script()` 、 `css()` 、そして `meta()` メソッドは `block = true` のオプションで使われると 同名のブロックをそれぞれ更新します。 Html->script('carousel', ['block' => true]); $this->Html->css('carousel', ['block' => true]); ?> // レイアウトファイルの中で <?= $this->fetch('title') ?> fetch('script') ?> fetch('css') ?> // 残りのレイアウトが続きます 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 `Cake\View\Helper\HtmlHelper` はスクリプトや CSS が入るブロックを 制御することもできます。 : // ビューファイルの中で $this->Html->script('carousel', ['block' => 'scriptBottom']); // レイアウトの中で fetch('scriptBottom') ?> 1 2 3 4 5 レイアウト [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88) ---------------------------------------------------------------------------------------------------- レイアウトにはビューをくるむ表示コードが入ります。すべてのビューから見えて欲しいものは レイアウトに配置されるべきです。 CakePHP の既定のレイアウトは **src/Template/Layout/default.ctp** に置かれます。 もし、アプリケーションの見栄え全体を変更したい場合、これが手始めとなり、 なぜならページが描画される時には、コントローラーによって描画されるビューのコードは、 既定のレイアウトの中に置かれるからです。 他のレイアウトファイルは **src/Template/Layout** に配置されるべきです。 レイアウトを作るとき、ビューの出力がどこに配置されるかを CakePHP に伝える必要があります。 そのために、レイアウトには `$this->fetch('content')` を入れるようにしてください。 これは既定のレイアウトがどのようなものかの一例です。 <?= h($this->fetch('title')) ?> fetch('meta'); echo $this->fetch('css'); echo $this->fetch('script'); ?> fetch('content') ?> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 `script` 、 `css` 、 `meta` ブロックには、組み込みの HTML ヘルパーを使って ビューで定義されたすべての内容が入ります。 ビューからの JavaScript と CSS ファイルを読み込むのに便利です。 NOTE `HtmlHelper::css()` や `HtmlHelper::script()` を テンプレートファイルで使うとき、HTML ソースを同じ名前でブロックの中に配置するには `'block' => true` を指定してください。 (詳しい使い方は API を参照してください) `content` ブロックは描画されたビューの内容が入ります。 `title` ブロックの内容をビューファイルから設定することができます。 : $this->assign('title', 'アクティブユーザー表示'); 1 `title` ブロックが空の値の場合、自動的に `'Admin/Articles'` のような 現在のテンプレートパスの表現に置き換えられます。 好きなだけレイアウトを作ることができます。 **src/Template/Layout** ディレクトリーに置いて、 コントローラーのアクションの中か、ビューの `$layout` プロパティーで切り替えるだけです。 : // コントローラーから public function view() { // レイアウトの設定 $this->viewBuilder()->setLayout('admin'); // 3.4 以前 $this->viewBuilder()->layout('admin'); // 3.1 以前 $this->layout = 'admin'; } // ビューファイルから $this->layout = 'loggedin'; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 例えば、サイトに小さな広告バナー枠があるとすれば、小さな広告枠のある新しいレイアウトを作って、 以下のように全コントローラーのアクションで指定するかもしれません。 : namespace App\Controller; class UsersController extends AppController { public function viewActive() { $this->set('title', 'アクティブユーザー表示'); $this->viewBuilder()->setLayout('default_small_ad'); // あるいは 3.4 以前では以下 $this->viewBuilder()->layout('default_small_ad'); // あるいは 3.1 以前では以下 $this->layout = 'default_small_ad'; } public function viewImage() { $this->viewBuilder()->setLayout('image'); // ユーザー画像の出力 } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 既定のレイアウトの他に CakePHP の公式スケルトン app は 'ajax' レイアウトも持っています。 Ajax レイアウトは AJAX のレスポンスを組み立てるのに便利で、これは空のレイアウトです。 (ほとんどの AJAX 呼び出しは、完全に描画されたインターフェイスというよりも、 返却にちょっとしたマークアップを必要とするだけです。) スケルトン app は RSS を生成するのを手助けする既定のレイアウトも持っています。 ### プラグインのレイアウト使用 [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E4%BD%BF%E7%94%A8) もしプラグインに存在するレイアウトを使いたい場合、 `プラグイン記法` を使うことが出来ます。例えば、 Contacts プラグインの contact レイアウトを使うには 次のようにします。 : namespace App\Controller; class UsersController extends AppController { public function viewActive() { $this->viewBuilder()->setLayout('Contacts.contact'); // あるいは 3.4 以前では以下 $this->viewBuilder()->layout('Contacts.contact'); // あるいは 3.1 以前では以下 $this->layout = 'Contacts.contact'; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 エレメント [​](https://book.cakephp.org/3.x/ja/views.html#%E3%82%A8%E3%83%AC%E3%83%A1%E3%83%B3%E3%83%88) ---------------------------------------------------------------------------------------------------- `method` Cake\\View\\View::**element**(string $elementPath, array $data, array $options = \[\]) 多くのアプリケーションは、様々なページで、時には異なるレイアウトのページで、 繰り返し必要とされる表示コードの小さなブロックを持っています。CakePHP は再利用が必要な ウェブサイトのパーツを繰り返し使う手助けをします。この再利用可能なパーツはエレメントと 呼ばれます。広告、ヘルプボックス、ナビゲーションコントロール、追加のメニュー、 ログインフォーム、吹き出しは CakePHP ではしばしばエレメントとして実装されます。 エレメントは基本的に他のビュー、レイアウト、そして他のエレメントにさえも入れることができる 小さなビューです。エレメントは、繰り返し使う要素の描画を個別のファイルに収めるので、 ビューの可読性を高めるのに使えます。 アプリケーション内のコンテンツの一部を再利用する手助けにもなります。 エレメントは **src/Template/Element/** フォルダーの中に .ctp の拡張子を持つ名前で配置されます。 次の例はビューの element メソッドを使って出力しています。 : echo $this->element('helpbox'); 1 ### エレメントに変数を渡す [​](https://book.cakephp.org/3.x/ja/views.html#%E3%82%A8%E3%83%AC%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AB%E5%A4%89%E6%95%B0%E3%82%92%E6%B8%A1%E3%81%99) element メソッドの第二引数を通してエレメントにデータを渡すことができます。 : echo $this->element('helpbox', [\ "helptext" => "おお、このテキストはとても役に立つ。"\ ]); 1 2 3 エレメントファイルの内部では、引数で渡されたすべての変数を パラメーター配列のメンバーとして利用できます。(テンプレートファイルにおけるコントローラーの `Controller::set()` メソッドと同様の動作です。) 上記の例では **src/Template/Element/helpbox.ctp** の中で `$helptext` 変数が使えます。 : // src/Template/Element/helpbox.ctp の中で echo $helptext; // 出力 "おお、このテキストはとても役に立つ。" 1 2 `View::element()` メソッドは、エレメントのためのオプションもサポートしています。 サポートされるオプションは、 'cache' と 'callbacks' です。例えば: echo $this->element('helpbox', [\ "helptext" => "これはエレメントに $helptext として渡されます",\ "foobar" => "これはエレメントに $foobar として渡されます",\ ], [\ // "long_view" のキャッシュ設定を使います\ "cache" => "long_view",\ // エレメントから before/afterRender が呼び出されるには true に設定してください\ "callbacks" => true\ ] ); 1 2 3 4 5 6 7 8 9 10 11 エレメントは `Cache` クラスを通じてキャッシュされます。 設定済みのキャッシュのいずれかにエレメントが保存されるように設定できます。 その結果、何処にいつまでエレメントを保存しておくのかを非常に柔軟に制御することができます。 あるアプリケーションの中で同じエレメントの異なるバージョンをキャッシュするためには、 次の書式を使って一意のキャッシュキーを提供してください。 : $this->element('helpbox', [], [\ "cache" => ['config' => 'short', 'key' => 'unique value']\ ] ); 1 2 3 4 もしもエレメント中で、データソースからの動的なデータのような、さらなるロジックが必要であれば、 エレメントの代わりにビューセルを使用することを検討してください。 詳細は [ビューセルについて](https://book.cakephp.org/3.x/ja/views/cells.html) 参照してください。 ### エレメントのキャッシュ [​](https://book.cakephp.org/3.x/ja/views.html#%E3%82%A8%E3%83%AC%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AE%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5) キャッシュパラメーターを渡すだけで CakePHP のビューキャッシュの恩恵を得られます。 `true` を渡した場合、 'default' のキャッシュ設定に基づいてエレメントがキャッシュされます。 あるいは、どのキャッシュ設定を使うかを設定することができます。 `Cache` の設定についての詳細は [キャッシュ](https://book.cakephp.org/3.x/ja/core-libraries/caching.html) を参照してください。 エレメントキャッシュの単純な例は以下のようになります。 : echo $this->element('helpbox', [], ['cache' => true]); 1 あるビューの中で同じエレメントを二回以上描画し、かつキャッシュが有効であれば、 毎回異なる名前の 'key' パラメーターを設定するようにしてください。 後続の呼び出しが、その前の `element()` の呼び出しでキャッシュされた結果を 上書してしまうのを避けることができるでしょう。例えば: echo $this->element( 'helpbox', ['var' => $var], ['cache' => ['key' => 'first_use', 'config' => 'view_long']] ); echo $this->element( 'helpbox', ['var' => $differenVar], ['cache' => ['key' => 'second_use', 'config' => 'view_long']] ); 1 2 3 4 5 6 7 8 9 10 11 上の例は、双方の element() の結果が別々にキャッシュされるようにします。 もしすべてのエレメントのキャッシュで同じ設定を使いたい場合、 `View::$elementCache` を設定することで繰り返しを避けられます。 CakePHP は element() に何も渡されなかった場合、この設定を使います。 ### プラグインのエレメントの要求 [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E3%82%A8%E3%83%AC%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AE%E8%A6%81%E6%B1%82) もしプラグインを使っていて、そのプラグインのエレメントを使いたければ、慣れ親しんだ `プラグイン記法` を使うだけでよいです。もしもビューが プラグインのコントローラー/アクションで描画される場合、他のプラグイン名が渡されなければ、 使用されるすべてのエレメントに対して自動的にそのプラグイン名が接頭されます。 もしエレメントがプラグインに存在しない場合、メインの APP フォルダーの中を探します。 : echo $this->element('Contacts.helpbox'); 1 もしビューがプラグインの一部であれば、プラグイン名を省略できます。 例えば、Contacts プラグインの `ContactsController` の中にいる場合、次の: echo $this->element('helpbox'); // と echo $this->element('Contacts.helpbox'); 1 2 3 は等価で、描画されるエレメントは同じになります。 プラグインのサブフォルダー中のエレメント (例: **plugins/Contacts/Template/Element/sidebar/helpbox.ctp**) については、 以下を使ってください。 : echo $this->element('Contacts.sidebar/helpbox'); 1 ### ルーティングプレフィックスとエレメント [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%AF%E3%82%99%E3%83%95%E3%82%9A%E3%83%AC%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E3%82%B9%E3%81%A8%E3%82%A8%E3%83%AC%E3%83%A1%E3%83%B3%E3%83%88) Added in version 3.0.1 ルーティングプレフィックスを設定している場合、レイアウトやビューがそうであるように、 エレメントのパスの解決は、プレフィックスの場所に切り替わります。 "Admin" プレフィックスが設定されていて、次のように呼ぶとすれば: echo $this->element('my_element'); 1 エレメントはまず **src/Template/Admin/Element/** から探されます。 もしもファイルが存在しなければ、既定の場所から探されます。 ### ビューの断片のキャッシュ [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E3%81%AE%E6%96%AD%E7%89%87%E3%81%AE%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5) `method` Cake\\View\\View::**cache**(callable $block, array $options = \[\]) 時には、ビュー出力の断片を生成するのに時間がかかることがあります。 たとえば、 [ビューセル](https://book.cakephp.org/3.x/ja/views/cells.html) の描画や、時間のかかるヘルパーの操作など。 アプリケーションの実行を速くする手助けのために、 CakePHP はビューの断片をキャッシュする方法を提供します。 : // ローカル変数を想定しています echo $this->cache(function () use ($user, $article) { echo $this->cell('UserProfile', [$user]); echo $this->cell('ArticleFull', [$article]); }, ['key' => 'my_view_key']); 1 2 3 4 5 既定ではキャッシュされたビューの内容は `View::$elementCache` のキャッシュ設定になりますが、 これを変更するために `config` オプションを使用できます。 ビューイベント [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E3%82%A4%E3%83%98%E3%82%99%E3%83%B3%E3%83%88) ------------------------------------------------------------------------------------------------------------------------------------------ コントローラーと同様、ビューは、描画のライフサイクル回りのロジックを入れるために、 いくつかのイベント/コールバックを呼び出すことができます。 ### イベント一覧 [​](https://book.cakephp.org/3.x/ja/views.html#%E3%82%A4%E3%83%98%E3%82%99%E3%83%B3%E3%83%88%E4%B8%80%E8%A6%A7) * `View.beforeRender` * `View.beforeRenderFile` * `View.afterRenderFile` * `View.afterRender` * `View.beforeLayout` * `View.afterLayout` アプリケーションの [イベントリスナー](https://book.cakephp.org/3.x/ja/core-libraries/events.html) をこれらのイベントに アタッチする、または [ヘルパーコールバック](https://book.cakephp.org/3.x/ja/views/helpers.html#helper-api) を使うことができます。 独自のビュークラス作成 [​](https://book.cakephp.org/3.x/ja/views.html#%E7%8B%AC%E8%87%AA%E3%81%AE%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E3%82%AF%E3%83%A9%E3%82%B9%E4%BD%9C%E6%88%90) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- データビューの新しいタイプを有効にしたり、 付加的なカスタムのビュー描画ロジックをアプリケーションに追加するために、 カスタムビュークラスを作成する必要があるかもしれません。 CakePHP のほとんどの構成要素と同様に、ビュークラスにはいくつかの規約があります。 * ビュークラスは **src/View** に配置してください。例: **src/View/PdfView.php** * ビュークラス名には `View` をサフィックスとしてつけてください。 例: `PdfView` * ビュークラス名を参照するときは `View` サフィックスを省略する必要があります。 例: `$this->viewBuilder()->setClassName('Pdf');`. また、正しく動作するように、 `View` を継承しましょう。 : // src/View/PdfView.php の中で namespace App\View; use Cake\View\View; class PdfView extends View { public function render($view = null, $layout = null) { // カスタムロジックをここに。 } } 1 2 3 4 5 6 7 8 9 10 11 12 render メソッドを置き換えると、コンテンツがレンダリングされる方法を完全に制御できます。 ビューのより詳細 [​](https://book.cakephp.org/3.x/ja/views.html#%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E3%81%AE%E3%82%88%E3%82%8A%E8%A9%B3%E7%B4%B0) ------------------------------------------------------------------------------------------------------------------------------------------- * [ビューセル](https://book.cakephp.org/3.x/ja/views/cells.html) * [テーマ](https://book.cakephp.org/3.x/ja/views/themes.html) * [JSON と XML ビュー](https://book.cakephp.org/3.x/ja/views/json-and-xml-views.html) * [ヘルパー](https://book.cakephp.org/3.x/ja/views/helpers.html) --- # コンテンツ管理チュートリアル | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/installation.html#VPContent) Return to top コンテンツ管理チュートリアル [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/installation.html#%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84%E7%AE%A1%E7%90%86%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB) ================================================================================================================================================================================================================================ このチュートリアルは簡単な `CMS (Content Management System)` アプリケーションを作ります。 はじめに CakePHP のインストールを行い、データベースの作成、 そしてアプリケーションを素早く仕上げるための CakePHP が提供するツールを使います。 必要なもの: 1. データベースサーバー。このチュートリアルでは MySQL サーバーを使います。 データベースを作成するための SQL の知識が必要です。CakePHP は、それを前提としています。 MySQL を使用するとき、 PHP で `pdo_mysql` が有効になっていることを確認してください。 2. 基礎的な PHP の知識。 始める前に、最新の PHP バージョンであることを確認してください。 php -v 1 最低でも PHP _5.6_ (CLI) 以上をインストールしてください。 あなたのウェブサーバーの PHP バージョンもまた、 _5.6_ 以上でなければなりません。 そして、コマンドラインインターフェイス (CLI) の PHP バージョンと同じバージョンにしてください。 CakePHP の取得 [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/installation.html#cakephp-%E3%81%AE%E5%8F%96%E5%BE%97) ---------------------------------------------------------------------------------------------------------------------------------- 最も簡単な CakePHP のインストール方法は Composer を使う方法です。Composer は、 ターミナルやコマンドラインプロンプトから CakePHP をインストールのシンプルな方法です。 まだ準備ができていない場合、最初に Composer をダウンロードとインストールが必要です。 cURL がインストールされていたら、次のように実行するのが簡単です。 curl -s https://getcomposer.org/installer | php 1 もしくは [Composer のウェブサイト](https://getcomposer.org/download/) から `composer.phar` をダウンロードすることができます。 そして、インストールディレクトリーからターミナルに次の行を入力するだけで、現在の作業ディレクトリーの **cms** ディレクトリーに CakePHP アプリケーションのスケルトンをインストールすることができます。 php composer.phar create-project --prefer-dist cakephp/app:^3.8 cms 1 [Composer Windows Installer](https://getcomposer.org/Composer-Setup.exe) をダウンロードして実行した場合、インストールディレクトリー (例えば、 C:\\wamp\\www\\dev\\cakephp3) からターミナルに次の行を入力してください。 composer self-update && composer create-project --prefer-dist cakephp/app:^3.8 cms 1 Composer を使うメリットは、 正しいファイルパーミッションの設定や、 **config/app.php** ファイルの作成などのように、自動的に完全なセットアップをしてくれることです。 CakePHP をインストールする他の方法があります。 Composer を使いたくない場合、 [インストール](https://book.cakephp.org/3.x/ja/installation.html) セクションをご覧ください。 CakePHP のダウンロードやインストール方法にかかわらず、いったんセットアップが完了すると、 ディレクトリー構成は次のようになります。 : /cms /bin /config /logs /plugins /src /tests /tmp /vendor /webroot .editorconfig .gitignore .htaccess .travis.yml composer.json index.php phpunit.xml.dist README.md CakePHP のディレクトリー構造がどのように働くかを学ぶのにいい機会かもしれません。 [CakePHP のフォルダー構成](https://book.cakephp.org/3.x/ja/intro/cakephp-folder-structure.html) セクションをご覧ください。 このチュートリアルで迷ったら、 [GitHub](https://github.com/cakephp/cms-tutorial) で完成した結果を見ることができます。 インストールの確認 [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/installation.html#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%AE%E7%A2%BA%E8%AA%8D) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ デフォルトホームページを確認することで、インストールが正しいことをざっと確かめることができます。 その前に、開発用サーバーを起動する必要があります。 cd /path/to/our/app bin/cake server 1 2 3 NOTE Windows では、このコマンドは `bin\cake server` (バックスラッシュ) です。 これで、 8765 ポートで PHP のビルトインウェブサーバーが起動します。ウェルカムページを見るために **[http://localhost:8765](http://localhost:8765/) ** をウェブブラウザーで開いてください。CakePHP がデータベース接続が 可能かどうか以外は、すべての確認事項が緑色のコック帽になるべきです。そうでなければ、PHP 拡張の 追加のインストールやディレクトリーのパーミッション設定が必要かもしれません。 次に、 [データベースの構築と最初のモデルの作成](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/database.html) をします。 --- # クイック スタート - 3.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/authorization/edit/3.x/docs/ja/index.rst) [](https://book.cakephp.org/authorization/3/ja/index.html#page-contents) ### Page Contents * [クイック スタート](https://book.cakephp.org/authorization/3/ja/index.html#) * [インストール](https://book.cakephp.org/authorization/3/ja/index.html#id2) * [はじめに](https://book.cakephp.org/authorization/3/ja/index.html#id3) * [より詳しく](https://book.cakephp.org/authorization/3/ja/index.html#id4) クイック スタート[¶](https://book.cakephp.org/authorization/3/ja/index.html#id1 "この見出しへのパーマリンク") ========================================================================================= インストール[¶](https://book.cakephp.org/authorization/3/ja/index.html#id2 "この見出しへのパーマリンク") -------------------------------------------------------------------------------------- プラグインをインストールするには、CakePHPから [composer](https://getcomposer.org/) を プロジェクトのルートディレクトリ (**composer.json** がある場所) で使用します。 php composer.phar require "cakephp/authorization:^2.0" Authorization Plugin(認可プラグイン)のバージョン2はCakePHP4に対応しています。 プラグインを読み込むにはApplication.phpに下記の一業を追加します。 `src/Application.php` $this\->addPlugin('Authorization'); はじめに[¶](https://book.cakephp.org/authorization/3/ja/index.html#id3 "この見出しへのパーマリンク") ------------------------------------------------------------------------------------ Authorization pluginは、ミドルウェア層としてアプリケーションに組み込まれ、 オプションのコンポーネントで認可の確認を容易に行え行えます。 はじめに **src/Application.php** に以下のクラス使用を明示してください。: use Authorization\\AuthorizationService; use Authorization\\AuthorizationServiceInterface; use Authorization\\AuthorizationServiceProviderInterface; use Authorization\\Middleware\\AuthorizationMiddleware; use Authorization\\Policy\\OrmResolver; use Psr\\Http\\Message\\ResponseInterface; use Psr\\Http\\Message\\ServerRequestInterface; Applicationに `AuthorizationServiceProviderInterface` を追加してください: class Application extends BaseApplication implements AuthorizationServiceProviderInterface そして、Applicationの `middleware()` を以下のようにします(AuthorizationMiddlewareを加える): public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue { // Middleware provided by CakePHP $middlewareQueue\->add(new ErrorHandlerMiddleware(Configure::read('Error'))) \->add(new AssetMiddleware()) \->add(new RoutingMiddleware($this)) \->add(new BodyParserMiddleware()) // If you are using Authentication it should be \*before\* Authorization. \->add(new AuthenticationMiddleware($this)); // Add the AuthorizationMiddleware \*after\* routing, body parser // and authentication middleware. \->add(new AuthorizationMiddleware($this)); return $middlewareQueue(); } `AuthorizationMiddleware` は `AuthenticationMiddleware` の **後** に置く必要があります。 これにより、認可の確認で使用する `identity` が使用できるようになります。 `AuthorizationMiddleware` はリクエスト処理が開始した際に、フックメソッドを呼び出します。 このフックメソッドで、使用したい `AuthorizationService` を定義できます。 以下のメソッドを **src/Application.php** に追加してください。: public function getAuthorizationService(ServerRequestInterface $request): AuthorizationServiceInterface { $resolver \= new OrmResolver(); return new AuthorizationService($resolver); } これは、ORMエンティティとPolicyクラスをマッチングする、基本的な [ポリシーリゾルバー](https://book.cakephp.org/authorization/3/ja/policy-resolvers.html) を設定するものです。 次に、 `AppController` に `AuthorizationComponent` を加えます。 **src/Controller/AppController.php** の `initialize()` に下記を追加してください。: $this\->loadComponent('Authorization.Authorization'); [AuthorizationComponent](https://book.cakephp.org/authorization/3/ja/component.html) を読み込むことで、以下のような認可チェックを行うことができます。 > public function edit($id = null) { > > > $article = $this->Article->get($id); $this->Authorization->authorize($article, 'update'); > > > > // Rest of action > > } `authorize` を呼び出すことで、 [Policies](https://book.cakephp.org/authorization/3/ja/policies.html) を使用して、アクセス制御ルールを強制することができます。 [identity stored in the request](https://book.cakephp.org/authorization/3/ja/checking-authorization.html) を使えばどこでも権限を確認することができます。 より詳しく[¶](https://book.cakephp.org/authorization/3/ja/index.html#id4 "この見出しへのパーマリンク") ------------------------------------------------------------------------------------- * [Policies](https://book.cakephp.org/authorization/3/ja/policies.html) * [ポリシーリゾルバー](https://book.cakephp.org/authorization/3/ja/policy-resolvers.html) * [認可ミドルウェア](https://book.cakephp.org/authorization/3/ja/middleware.html) * [AuthorizationComponent](https://book.cakephp.org/authorization/3/ja/component.html) * [認可の確認](https://book.cakephp.org/authorization/3/ja/checking-authorization.html) * [リクエスト認証ミドルウェア](https://book.cakephp.org/authorization/3/ja/request-authorization-middleware.html) [](https://phpc.social/@cakephp "Mastodon") [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://slack-invite.cakephp.org/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") --- # Quick Start - 3.x **Nav** **Table of Contents** [###### Improve This Doc](https://github.com/cakephp/authentication/edit/3.x/docs/ja/index.rst) [](https://book.cakephp.org/authentication/3/ja/index.html#page-contents) ### Page Contents * [Quick Start](https://book.cakephp.org/authentication/3/ja/index.html#) * [はじめに](https://book.cakephp.org/authentication/3/ja/index.html#id1) * [ログインアクションの構成](https://book.cakephp.org/authentication/3/ja/index.html#id3) * [Further Reading](https://book.cakephp.org/authentication/3/ja/index.html#further-reading) Quick Start[¶](https://book.cakephp.org/authentication/3/ja/index.html#quick-start "このヘッドラインへのパーマリンク") ======================================================================================================= CakePHPから [composer](https://getcomposer.org/) でプラグインをインストールします。 プロジェクトのルートディレクトリ( **composer.json** ファイルが置かれている場所です) php composer.phar require "cakephp/authentication:^2.0" プロジェクトの `src/Application.php` に以下の文を追加してプラグインをロードしてください。 public function bootstrap(): void { parent::bootstrap(); $this\->addPlugin('Authentication'); } はじめに[¶](https://book.cakephp.org/authentication/3/ja/index.html#id1 "このヘッドラインへのパーマリンク") ---------------------------------------------------------------------------------------- 認証プラグインは、ミドルウェアとしてアプリケーションと統合します。 [middleware](https://book.cakephp.org/4/en/controllers/middleware.html) また、認証されていないアクセスをより簡単にするためのコンポーネントとして使用することもできます。 まずはミドルウェアを適用してみましょう。 **src/Application.php** に以下のクラスを追加します。 インポート: use Authentication\\AuthenticationService; use Authentication\\AuthenticationServiceInterface; use Authentication\\AuthenticationServiceProviderInterface; use Authentication\\Identifier\\AbstractIdentifier; use Authentication\\Middleware\\AuthenticationMiddleware; use Cake\\Http\\MiddlewareQueue; use Psr\\Http\\Message\\ServerRequestInterface; 次に、アプリケーションに実装されたインターフェースに `AuthenticationProviderInterface` を追加します。: class Application extends BaseApplication implements AuthenticationServiceProviderInterface 次に、 `middleware()` メソッドに以下の AuthenticationMiddleware を追加します。: $middleware\->add(new AuthenticationMiddleware($this)); 注釈 両方ある場合は `AuthenticationMiddleware` の前に `AuthorizationMiddleware` を追加するようにしてください。 リクエストの処理を開始すると、 `AuthenticationMiddleware` はフックメソッドを呼び出します。 このフックメソッドにより、アプリケーションが使用したい `AuthenticationService` を定義することができます。 以下のメソッドを **src/Application.php** に記述します。: /\*\* \* サービスプロバイダのインスタンスを返します。 \* \* @param \\Psr\\Http\\Message\\ServerRequestInterface $request Request \* @return \\Authentication\\AuthenticationServiceInterface \*/ public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface { $service \= new AuthenticationService(); // 認証されていない場合にユーザーがどこにリダイレクトするかを定義します。 $service\->setConfig(\[\ 'unauthenticatedRedirect' \=> '/users/login',\ 'queryParam' \=> 'redirect',\ \]); $fields \= \[\ AbstractIdentifier::CREDENTIAL\_USERNAME \=> 'email',\ AbstractIdentifier::CREDENTIAL\_PASSWORD \=> 'password'\ \]; // 認証者を読み込みます。セッションを優先してください。 $service\->loadAuthenticator('Authentication.Session'); $service\->loadAuthenticator('Authentication.Form', \[\ 'fields' \=> $fields,\ 'loginUrl' \=> '/users/login'\ \]); // 識別子を読み込みます。 $service\->loadIdentifier('Authentication.Password', compact('fields')); return $service; } まず、ユーザーが認証されていない場合にどうするかを設定します。 次に、アプリケーションがユーザーを認証するための仕組みを定義する `Session` と `Form` [認証機能](https://book.cakephp.org/authentication/3/ja/authenticators.html) をアタッチします。 `Session` はセッション内のデータに基づいてユーザを識別し、 `Form` はログインフォームを `loginUrl` で扱うことを可能にします。 最後に、ログインしたユーザーを表す [identifier](https://book.cakephp.org/authentication/3/ja/identifiers.html) に変換するための [identity](https://book.cakephp.org/authentication/3/ja/identity-object.html) をアタッチします。 認証が確認できた場合、ミドルウェアは認証サービスを [属性](https://www.php-fig.org/psr/psr-7/) . としてリクエストオブジェクトに追加します。 次に、 `AppController` に [認証 Component](https://book.cakephp.org/authentication/3/ja/authentication-component.html) を呼び出します。: // in src/Controller/AppController.php public function initialize() { parent::initialize(); $this\->loadComponent('Authentication.Authentication'); } デフォルトでコンポーネントは、 **全て** のアクションに認証済みのユーザーを必要とします。 特定のコントローラでこの動作を無効にするには、 `allowUnauthenticated()` を使用してください。: // コントローラの beforeFilter か initialize で、 // ログインしている必要のないview()とindex()を作成します。 $this\->Authentication\->allowUnauthenticated(\['view', 'index'\]); ログインアクションの構成[¶](https://book.cakephp.org/authentication/3/ja/index.html#id3 "このヘッドラインへのパーマリンク") ------------------------------------------------------------------------------------------------ アプリケーションにミドルウェアを適用したら、ユーザーがログインするための方法が必要になります。 基本的に次のように `UsersController` にloginアクションと追加します。: public function login() { $result \= $this\->Authentication\->getResult(); // ユーザーがログインしている場合は、そのユーザーを送り出してください。 if ($result\->isValid()) { $target \= $this\->Authentication\->getLoginRedirect() ?? '/home'; return $this\->redirect($target); } if ($this\->request\->is('post')) { $this\->Flash\->error('ユーザー名とパスワードが無効です'); } } 前のセクションで述べたように、コントローラの `beforeFilter()` コールバックで `login` アクションにアクセスできるようにして、 認証されていないユーザがアクセスできるようにしてください。: public function beforeFilter(\\Cake\\Event\\EventInterface $event) { parent::beforeFilter($event); $this\->Authentication\->allowUnauthenticated(\['login'\]); } シンプルなlogoutアクションの追加: public function logout() { $this\->Authentication\->logout(); return $this\->redirect(\['controller' \=> 'Users', 'action' \=> 'login'\]); } ログインするためには、ユーザーはハッシュ化されたパスワードを持つ必要があります。以下のようなことができます。 ユーザーがエンティティを使用してパスワードを更新すると、自動的にパスワードをハッシュ化します。: // in src/Model/Entity/User.php use Authentication\\PasswordHasher\\DefaultPasswordHasher; class User extends Entity { // ... other methods // Automatically hash passwords when they are changed. protected function \_setPassword(string $password) { $hasher \= new DefaultPasswordHasher(); return $hasher\->hash($password); } } Further Reading[¶](https://book.cakephp.org/authentication/3/ja/index.html#further-reading "このヘッドラインへのパーマリンク") --------------------------------------------------------------------------------------------------------------- * [認証機能](https://book.cakephp.org/authentication/3/ja/authenticators.html) * [Identifiers](https://book.cakephp.org/authentication/3/ja/identifiers.html) * [Password Hashers](https://book.cakephp.org/authentication/3/ja/password-hashers.html) * [Identity Objects](https://book.cakephp.org/authentication/3/ja/identity-object.html) * [認証 Component](https://book.cakephp.org/authentication/3/ja/authentication-component.html) * [認証コンポーネントから移行](https://book.cakephp.org/authentication/3/ja/migration-from-the-authcomponent.html) * [URL チェッカー](https://book.cakephp.org/authentication/3/ja/url-checkers.html) * [認証によるテスト](https://book.cakephp.org/authentication/3/ja/testing.html) * [View Helper](https://book.cakephp.org/authentication/3/ja/view-helper.html) [](https://phpc.social/@cakephp "Mastodon") [](https://twitter.com/cakephp "Twitter") [](https://www.facebook.com/groups/cake.community "Facebook") [](https://www.youtube.com/user/CakePHP "Youtube") [](https://www.linkedin.com/groups/4623165/profile "Linkedin") [](https://github.com/cakephp "Github") [](https://slack-invite.cakephp.org/ "Slack") [](https://stackoverflow.com/tags/cakephp "Stack Overflow") --- # アップグレードツール | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/upgrade-tool.html#VPContent) Return to top アップグレードツール [​](https://book.cakephp.org/3.x/ja/upgrade-tool.html#%E3%82%A2%E3%83%83%E3%83%95%E3%82%9A%E3%82%AF%E3%82%99%E3%83%AC%E3%83%BC%E3%83%88%E3%82%99%E3%83%84%E3%83%BC%E3%83%AB) ======================================================================================================================================================================================== CakePHP 2.x から CakePHP 3 にアップグレードするためには、多くの変換が必要となります。 それは、名前空間を追加するなど、自動化することができます。これらの機械的な変換を容易に 作成することを支援するために、CakePHP は CLI ベースのアップグレードツールを提供します。 インストール [​](https://book.cakephp.org/3.x/ja/upgrade-tool.html#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB) --------------------------------------------------------------------------------------------------------------------- アップグレードツールは、スタンドアロンアプリケーションとしてインストールされています。 アップグレードツールを git clone して、composer で依存関係をインストールする必要があります。 : git clone https://github.com/cakephp/upgrade.git cd upgrade php ../composer.phar install この時点で、アップグレードツールのヘルプを確認することができます。 : cd upgrade bin/cake upgrade --help 上記の出力は次のようになります。 : Welcome to CakePHP v3.0.8 Console --------------------------------------------------------------- App : src Path: /Users/markstory/Sites/cake_plugins/upgrade/src/ --------------------------------------------------------------- A shell to help automate upgrading from CakePHP 2.x to 3.x. Be sure to have a backup of your application before running these commands. Usage: cake upgrade [subcommand] [-h] [-v] [-q] Subcommands: locations Move files/directories around. Run this *before* adding namespaces with the namespaces command. namespaces Add namespaces to files based on their file path. Only run this *after* you have moved files. app_uses Replace App::uses() with use statements rename_classes Rename classes that have been moved/renamed. Run after replacing App::uses() with use statements. rename_collections Rename HelperCollection, ComponentCollection, and TaskCollection. Will also rename component constructor arguments and _Collection properties on all objects. method_names Update many of the methods that were renamed during 2.x -> 3.0 method_signatures Update many of the method signatures that were changed during 2.x -> 3.0 fixtures Update fixtures to use new index/constraint features. This is necessary before running tests. tests Update test cases regarding fixtures. i18n Update translation functions regarding placeholders. skeleton Add basic skeleton files and folders from the "app" repository. prefixed_templates Move view templates for prefixed actions. all Run all tasks except for skeleton. That task should only be run manually, and only for apps (not plugins). To see help on a subcommand use `cake upgrade [subcommand] --help` Options: --help, -h Display this help. --verbose, -v Enable verbose output. --quiet, -q Enable quiet output. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 使用法 [​](https://book.cakephp.org/3.x/ja/upgrade-tool.html#%E4%BD%BF%E7%94%A8%E6%B3%95) --------------------------------------------------------------------------------------- アップグレードツールを正しくインストールしたら、2.x のアプリケーションに対して 使用を開始する準備ができています。 WARNING アプリケーションのコードのバックアップやバージョン管理していることを確認してください。 各サブコマンドの後にバックアップやコミットすることも良いアイデアです。 `locations` コマンドの実行を開始するには: # コマンドのオプションを表示 bin/cake upgrade locations --help # dry run モードでコマンドを実行 bin/cake upgrade locations --dry-run /path/to/app 1 2 3 4 5 上記は、何が起こるかの予行演習の出力が得られます。実際にコマンドを実行する準備ができたら、 `--dry-run` フラグを削除します。 `--git` フラグを使用することにより、 アップグレードツールは git の内のファイルの移動を自動化することができます。 ファイルの場所が更新されたら、 `namespaces` コマンドを使用してコードに名前空間を 追加することができます。 : # コマンドのオプションを表示 bin/cake upgrade namespaces --help # dry run モードでコマンドを実行 bin/cake upgrade namespaces --dry-run /path/to/app # 実際にコマンドを実行 bin/cake upgrade namespaces /path/to/app 1 2 3 4 5 6 7 8 この2つのコマンドの後、任意の順序で残りのサブコマンドを実行することができます。 --- # セキュリティ | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/security.html#VPContent) Return to top セキュリティ [​](https://book.cakephp.org/3.x/ja/security.html#%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3) ================================================================================================================= CakePHP はあなたのアプリケーションをセキュアにする幾つかのツールを提供します。 以下のセクションにこれらのツールを記載します。 * [セキュリティユーティリティ](https://book.cakephp.org/3.x/ja/core-libraries/security.html) * [クロスサイトリクエストフォージェリ](https://book.cakephp.org/3.x/ja/controllers/components/csrf.html) * [Security コンポーネント](https://book.cakephp.org/3.x/ja/controllers/components/security.html) --- # CMS チュートリアル - 認証 | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/authentication.html#VPContent) Return to top CMS チュートリアル - 認証 [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/authentication.html#cms-%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB-%E8%AA%8D%E8%A8%BC) ============================================================================================================================================================================================ CMS にはユーザーがいますので、ログインできるようにし、 記事の作成と編集の経験に基本的なアクセス制御を適用する必要があります。 パスワードハッシュ化の追加 [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/authentication.html#%E3%83%8F%E3%82%9A%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%88%E3%82%99%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E5%8C%96%E3%81%AE%E8%BF%BD%E5%8A%A0) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ もしこの時点でユーザーを作成・更新していたとしたら、パスワードが平文で保存されることに気付いたかもしれません。 これは、セキュリティの観点から本当に悪いことですので、修正しましょう。 これはまた、CakePHP のモデル層について話す良い時期です。CakePHP では、 オブジェクトのコレクションに対して操作するメソッドと、単一のオブジェクトを別のクラスに分けています。 エンティティーのコレクションに対して操作するメソッドは `Table` クラスにあり、 一方、単一のレコードに属する機能は `Entity` クラスにあります。 例えば、パスワードのハッシュ化は個々のレコードで行われるため、 この動作をエンティティーオブジェクトに実装します。パスワードが設定されるたびにパスワードを ハッシュ化したいので、ミューテーター/セッターメソッドを使用します。CakePHP は、 エンティティーの1つにプロパティーが設定されているときはいつでも、規約に基づいたセッターメソッドを呼び出します。 パスワードのセッターを追加しましょう。 **src/Model/Entity/User.php** の中に次を追加してください。 : hash($value); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ここで、ブラウザーで **[http://localhost:8765/users](http://localhost:8765/users) ** にアクセスしてユーザーのリストを 見てください。 [インストール](https://book.cakephp.org/3.x/ja/installation.html) 中に作成されたデフォルトユーザーを 編集することができます。ユーザーのパスワードを変更すると、リストやビューページでは 元の値の代わりにハッシュ化されたパスワードが表示されます。CakePHP は、デフォルトでは [bcrypt](https://codahale.com/how-to-safely-store-a-password/) を使って パスワードをハッシュ化します。既存のデータベースを使用している場合は SHA-1 または MD5 を 使用することもできますが、すべての新しいアプリケーションに対して bcrypt を推奨します。 ### ログインの追加 [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/authentication.html#%E3%83%AD%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E8%BF%BD%E5%8A%A0) CakePHP での認証は、 [コンポーネント](https://book.cakephp.org/3.x/ja/controllers/components.html) によって処理されます。コンポーネントは、 特定の機能やコンセプトに関連するコントローラーコードの再利用可能なかたまりを作成する方法と 考えることができます。コンポーネントは、コントローラーのイベントライフサイクルにフックし、 その方法でアプリケーションとやりとりすることができます。まず、 [AuthComponent](https://book.cakephp.org/3.x/ja/controllers/components/authentication.html) をアプリケーションに追加します。 create、update、delete メソッドで認証が必要なので、AuthComponent を AppController に追加します。 : // src/Controller/AppController.php の中で namespace App\Controller; use Cake\Controller\Controller; class AppController extends Controller { public function initialize() { // 既存のコード $this->loadComponent('Auth', [\ 'authenticate' => [\ 'Form' => [\ 'fields' => [\ 'username' => 'email',\ 'password' => 'password'\ ]\ ]\ ],\ 'loginAction' => [\ 'controller' => 'Users',\ 'action' => 'login'\ ],\ // コントローラーで isAuthorized を使用します\ 'authorize' => ['Controller'],\ // 未認証の場合、直前のページに戻します\ 'unauthorizedRedirect' => $this->referer()\ ]); // display アクションを許可して、PagesController が引き続き // 動作するようにします。また、読み取り専用のアクションを有効にします。 $this->Auth->allow(['display', 'view', 'index']); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 CakePHP に `Auth` コンポーネントをロードするように指示しました。users テーブルは ユーザー名として `email` を使用するので、AuthComponent の設定をカスタマイズしました。 今、 `/articles/add` のような保護された URL に行くと、 **/users/login** に リダイレクトされます。これはまだコードを書いていないので、エラーページを表示します。 login アクションを作成しましょう。 : // src/Controller/UsersController.php の中で public function login() { if ($this->request->is('post')) { $user = $this->Auth->identify(); if ($user) { $this->Auth->setUser($user); return $this->redirect($this->Auth->redirectUrl()); } $this->Flash->error('ユーザー名またはパスワードが不正です。'); } } 1 2 3 4 5 6 7 8 9 10 11 12 そして **src/Template/Users/login.ctp** に次を追加してください。 :

    ログイン

    Form->create() ?> Form->control('email') ?> Form->control('password') ?> Form->button('ログイン') ?> Form->end() ?> 1 2 3 4 5 6 シンプルなログインフォームが完成したので、ハッシュ化されたパスワードを持つユーザーで ログインできるはずです。 NOTE もし、ハッシュ化されたパスワードを持つユーザーがいない場合、 `loadComponent('Auth')` ブロックと `$this->Auth->allow()` 呼び出しを コメントにしてください。その後、ユーザーのパスワードを保存して編集します。 ユーザーの新しいパスワードを保存した後、一時的にコメントした行を元に戻してください。 さぁやってみましょう!ログインする前に `/articles/add` にアクセスしてください。 この操作は許可されていないため、ログインページにリダイレクトされます。 ログインに成功すると、CakePHP は自動的に `/articles/add` にリダイレクトします。 ### ログアウトの追加 [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/authentication.html#%E3%83%AD%E3%82%AF%E3%82%99%E3%82%A2%E3%82%A6%E3%83%88%E3%81%AE%E8%BF%BD%E5%8A%A0) ユーザーがログインできるようになったので、おそらくログアウトする方法を提供したいと思うでしょう。 もう一度、 `UsersController` に次のコードを追加してください。 : public function initialize() { parent::initialize(); $this->Auth->allow(['logout']); } public function logout() { $this->Flash->success('ログアウトしました。'); return $this->redirect($this->Auth->logout()); } 1 2 3 4 5 6 7 8 9 10 11 このコードは、認証を必要としないアクションのリストに `logout` アクションを追加し、 logout メソッドを実装します。ログアウトのために `/users/logout` にアクセスできます。 その時、ログインページへ送られます。 ### ユーザー登録の有効化 [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/authentication.html#%E3%83%A6%E3%83%BC%E3%82%B5%E3%82%99%E3%83%BC%E7%99%BB%E9%8C%B2%E3%81%AE%E6%9C%89%E5%8A%B9%E5%8C%96) ログインせずに **/users/add** にアクセスしようとすると、ログインページにリダイレクトされます。 人々がアプリケーションにサインアップできるようにしたいので、修正する必要があります。 `UsersController` に以下を追加してください。 : public function initialize() { parent::initialize(); // 許可アクションリストに 'add' アクションを追加 $this->Auth->allow(['logout', 'add']); } 1 2 3 4 5 6 上記の例は、 `AuthComponent` に、 `UsersController` の `add()` アクションが 認証や認可を必要と _しない_ ことを伝えています。 **Users/add.ctp** をクリーンアップし、 誤解を招くリンクを削除することに時間をかけたり、次のセクションに進みたいでしょう。 このチュートリアルでは、ユーザーの編集、表示、リスト作成は行いませんが、それはあなた自身で 行うことができる練習です。 ### 記事へのアクセスの制限 [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/authentication.html#%E8%A8%98%E4%BA%8B%E3%81%B8%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%AE%E5%88%B6%E9%99%90) ユーザーはログインできるようになったので、作成した記事のみを編集するようにユーザーを 制限したいと考えています。 'authorization' アダプターを使用してこれを行います。 私たちの要件は基本的なものなので、 `ArticlesController` にコントローラーフックメソッドを 使うことができます。しかし、これを行う前に、アプリケーションがアクションを許可する方法を 「AuthComponent」に伝えたいと思うでしょう。 `AppController` を更新して次を追加してください。 : public function isAuthorized($user) { // デフォルトでは、アクセスを拒否します。 return false; } 1 2 3 4 5 次に、 `AuthComponent` にコントローラーのフックメソッドを使用して認可を行いたいことを伝えます。 `AppController::initialize()` メソッドは次のようになります。 : public function initialize() { // 既存のコード $this->loadComponent('Flash'); $this->loadComponent('Auth', [\ // この行を追加しました\ 'authorize'=> 'Controller',\ 'authenticate' => [\ 'Form' => [\ 'fields' => [\ 'username' => 'email',\ 'password' => 'password'\ ]\ ]\ ],\ 'loginAction' => [\ 'controller' => 'Users',\ 'action' => 'login'\ ],\ // 未認証の場合、直前のページに戻します\ 'unauthorizedRedirect' => $this->referer()\ ]); // display アクションを許可して、PagesController が引き続き // 動作するようにします。また、読み取り専用のアクションを有効にします。 $this->Auth->allow(['display', 'view', 'index']); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 デフォルトではアクセスを拒否し、意味のある場所で段階的にアクセスを許可します。 まず、記事の認可ロジックを追加します。 `ArticlesController` に以下を追加してください。 : public function isAuthorized($user) { $action = $this->request->getParam('action'); // add および tags アクションは、常にログインしているユーザーに許可されます。 if (in_array($action, ['add', 'tags'])) { return true; } // 他のすべてのアクションにはスラッグが必要です。 $slug = $this->request->getParam('pass.0'); if (!$slug) { return false; } // 記事が現在のユーザーに属していることを確認します。 $article = $this->Articles->findBySlug($slug)->first(); return $article->user_id === $user['id']; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 あなたに属していない記事を編集または削除しようとすると、元のページにリダイレクトされるはずです。 エラーメッセージが表示されない場合は、レイアウトに以下を追加します。 : // src/Template/Layout/default.ctp の中で Flash->render() ?> 1 2 次に、 **src/Controller/ArticlesController.php** の `initialize()` に以下を追加して、 未認証のユーザーに許可されたアクションに `tags` アクションを追加してください。 : $this->Auth->allow(['tags']); 1 上記は非常に単純ですが、柔軟性のある認証ロジックを構築するために、現在のユーザーと リクエストデータを組み合わせたより複雑なロジックを構築する方法を示しています。 ### add と edit アクションの修正 [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/authentication.html#add-%E3%81%A8-edit-%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BF%AE%E6%AD%A3) edit アクションへのアクセスをブロックしていますが、編集中の記事の `user_id` 属性を変更することはできます。次に、これらの問題を解決します。 最初は `add` アクションです。 記事を作成するときに、 `user_id` を現在ログインしているユーザーに修正したいと考えています。 add アクションを次のように置き換えます。 : // src/Controller/ArticlesController.php の中で public function add() { $article = $this->Articles->newEntity(); if ($this->request->is('post')) { $article = $this->Articles->patchEntity($article, $this->request->getData()); // 変更: セッションから user_id をセット $article->user_id = $this->Auth->user('id'); if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to add your article.')); } $this->set('article', $article); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 次は `edit` アクションを更新します。edit メソッドを次のように置き換えます。 : // src/Controller/ArticlesController.php の中で public function edit($slug) { $article = $this->Articles ->findBySlug($slug) ->contain('Tags') // 関連づけられた Tags を読み込む ->firstOrFail(); if ($this->request->is(['post', 'put'])) { $this->Articles->patchEntity($article, $this->request->getData(), [\ // 追加: user_id の更新を無効化\ 'accessibleFields' => ['user_id' => false]\ ]); if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been updated.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to update your article.')); } $this->set('article', $article); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ここでは、 `patchEntity()` のオプションを使って、どのプロパティーを一括代入できるかを変更しています。 詳しい情報は、 [Changing Accessible Fields](https://book.cakephp.org/3.x/ja/orm/saving-data.html#changing-accessible-fields) セクションをご覧ください。 **src/Templates/Articles/edit.ctp** から必要のなくなった `user_id` コントロールを 削除してください。 ### できあがり [​](https://book.cakephp.org/3.x/ja/tutorials-and-examples/cms/authentication.html#%E3%81%A6%E3%82%99%E3%81%8D%E3%81%82%E3%81%8B%E3%82%99%E3%82%8A) ユーザーがログインしたり、記事を投稿したり、タグ付けしたり、投稿された記事をタグで検索したり、 記事への基本的なアクセス制御を適用したりできるシンプルな CMS アプリケーションを構築しました。 また、FormHelper と ORM の機能を活用して、UX のいくつかの改良点を追加しました。 CakePHP の探検にお時間をいただきありがとうございます。 次は、 [データベースアクセス & ORM](https://book.cakephp.org/3.x/ja/orm.html) についてもっと学んだり、 [CakePHP の利用](https://book.cakephp.org/3.x/ja/topics.html) を調べてみてください。 --- # Flash | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/helpers/flash.html#VPContent) Return to top Flash [​](https://book.cakephp.org/3.x/views/helpers/flash.html#flash) ======================================================================= `class` Cake\\View\\Helper\\**FlashHelper**(View $view, array $config = \[\]) FlashHelper provides a way to render flash messages that were set in `$_SESSION` by [FlashComponent](https://book.cakephp.org/3.x/controllers/components/flash.html) . [FlashComponent](https://book.cakephp.org/3.x/controllers/components/flash.html) and FlashHelper primarily use elements to render flash messages. Flash elements are found under the **src/Template/Element/Flash** directory. You'll notice that CakePHP's App template comes with three flash elements: **success.ctp**, **default.ctp**, and **error.ctp**. Rendering Flash Messages [​](https://book.cakephp.org/3.x/views/helpers/flash.html#rendering-flash-messages) ------------------------------------------------------------------------------------------------------------- To render a flash message, you can simply use FlashHelper's `render()` method in your template file: Flash->render() ?> 1 By default, CakePHP uses a "flash" key for flash messages in a session. But, if you've specified a key when setting the flash message in [FlashComponent](https://book.cakephp.org/3.x/controllers/components/flash.html) , you can specify which flash key to render: Flash->render('other') ?> 1 You can also override any of the options that were set in FlashComponent: // In your Controller $this->Flash->set('The user has been saved.', [\ 'element' => 'success'\ ]); // In your template file: Will use great_success.ctp instead of succcess.ctp Flash->render('flash', [\ 'element' => 'great_success'\ ]); 1 2 3 4 5 6 7 8 9 NOTE When building custom flash message templates, be sure to properly HTML encode any user data. CakePHP won't escape flash message parameters for you. Added in version 3.1 The [FlashComponent](https://book.cakephp.org/3.x/controllers/components/flash.html) now stacks messages. If you set multiple flash messages, when you call `render()`, each message will be rendered in its own elements, in the order they were set. For more information about the available array options, please refer to the [FlashComponent](https://book.cakephp.org/3.x/controllers/components/flash.html) section. Routing Prefix and Flash Messages [​](https://book.cakephp.org/3.x/views/helpers/flash.html#routing-prefix-and-flash-messages) ------------------------------------------------------------------------------------------------------------------------------- Added in version 3.0.1 If you have a Routing prefix configured, you can now have your Flash elements stored in **src/Template/{Prefix}/Element/Flash**. This way, you can have specific messages layouts for each part of your application. For instance, using different layouts for your front-end and admin section. Flash Messages and Themes [​](https://book.cakephp.org/3.x/views/helpers/flash.html#flash-messages-and-themes) --------------------------------------------------------------------------------------------------------------- The FlashHelper uses normal elements to render the messages and will therefore obey any theme you might have specified. So when your theme has a **src/Template/Element/Flash/error.ctp** file it will be used, just as with any Elements and Views. --- # Themes | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/themes.html#VPContent) Return to top Themes [​](https://book.cakephp.org/3.x/views/themes.html#themes) ================================================================== Themes in CakePHP are simply plugins that focus on providing template files. See the section on [Plugin Create Your Own](https://book.cakephp.org/3.x/plugins.html#plugin-create-your-own) . You can take advantage of themes, making it easy to switch the look and feel of your page quickly. In addition to template files, they can also provide helpers and cells if your theming requires that. When using cells and helpers from your theme, you will need to continue using the `plugin syntax`. To use themes, set the theme name in your controller's action or `beforeRender()` callback: class ExamplesController extends AppController { // For CakePHP before 3.1 public $theme = 'Modern'; public function beforeRender(\Cake\Event\Event $event) { $this->viewBuilder()->setTheme('Modern'); // For CakePHP before 3.5 $this->viewBuilder()->theme('Modern'); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 Theme template files need to be within a plugin with the same name. For example, the above theme would be found in **plugins/Modern/src/Template**. It's important to remember that CakePHP expects PascalCase plugin/theme names. Beyond that, the folder structure within the **plugins/Modern/src/Template** folder is exactly the same as **src/Template/**. For example, the view file for an edit action of a Posts controller would reside at **plugins/Modern/src/Template/Posts/edit.ctp**. Layout files would reside in **plugins/Modern/src/Template/Layout/**. You can provide customized templates for plugins with a theme as well. If you had a plugin named 'Cms', that contained a TagsController, the Modern theme could provide **plugins/Modern/src/Template/Plugin/Cms/Tags/edit.ctp** to replace the edit template in the plugin. If a view file can't be found in the theme, CakePHP will try to locate the view file in the **src/Template/** folder. This way, you can create master template files and simply override them on a case-by-case basis within your theme folder. If your theme also acts as a plugin, don't forget to ensure it is loaded in your application's `bootstrap` method. For example: // Load our plugin theme residing in the folder /plugins/Modern $this->addPlugin('Modern'); 1 2 Theme Assets [​](https://book.cakephp.org/3.x/views/themes.html#theme-assets) ------------------------------------------------------------------------------ Because themes are standard CakePHP plugins, they can include any necessary assets in their webroot directory. This allows for easy packaging and distribution of themes. Whilst in development, requests for theme assets will be handled by `Cake\Routing\Dispatcher`. To improve performance for production environments, it's recommended that you [Symlink Assets](https://book.cakephp.org/3.x/deployment.html#symlink-assets) . All of CakePHP's built-in helpers are aware of themes and will create the correct paths automatically. Like template files, if a file isn't in the theme folder, it will default to the main webroot folder: // When in a theme with the name of 'purple_cupcake' $this->Html->css('main.css'); // creates a path like /purple_cupcake/css/main.css // and links to plugins/PurpleCupcake/webroot/css/main.css 1 2 3 4 5 6 7 8 --- # データの検証 | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/orm/validation.html#VPContent) Return to top データの検証 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%83%86%E3%82%99%E3%83%BC%E3%82%BF%E3%81%AE%E6%A4%9C%E8%A8%BC) ================================================================================================================================ [データを保存する](https://book.cakephp.org/3.x/ja/orm/saving-data.html) 前におそらくそのデータが正しく 矛盾がないことを保証したいはずです。 CakePHP ではデータの検証には二つの段階があります: 1. リクエストデータがエンティティーにコンバートされる前、 データ型や書式まわりのバリデーションルールが適用されます。 2. データが保存される前、ドメインまたはアプリケーションルールが適用されます。 これらのルールはアプリケーションのデータの一貫性の保証に役立ちます。 エンティティー構築前のデータ検証 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3%E3%83%BC%E6%A7%8B%E7%AF%89%E5%89%8D%E3%81%AE%E3%83%86%E3%82%99%E3%83%BC%E3%82%BF%E6%A4%9C%E8%A8%BC) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ データからエンティティーを構築する時、データの検証 (バリデーション) ができます。 データのバリデーションではデータの型、形状およびサイズなどを確認することができます。 既定ではリクエストデータがエンティティーに変換される前に検証が行われます。 もしも何らかのバリデーションルールが通らなかった場合、 返されたエンティティーはエラーを含んだ状態になります。 エラーのあるフィールドは返されたエンティティーには含まれません。 : $article = $articles->newEntity($this->request->getData()); if ($article->errors()) { // エンティティー検証失敗。 } 1 2 3 4 Added in version 3.4.0 `getErrors()` 関数は追加されました。 バリデーションが有効になっている状態でエンティティーを構築すると、次のことが起こります: 1. バリデータオブジェクトが作成されます。 2. `table` および `default` バリデーションプロバイダーが追加されます。 3. 命名に沿ったバリデーションメソッドが呼び出されます。たとえば `validationDefault` 。 4. `Model.buildValidator` イベントが発動します。 5. リクエストデータが検証されます。 6. リクエストデータがそのカラム型に対応する型に変換されます。 7. エラーがエンティティーにセットされます。 8. 正しいデータはエンティティーに設定されますが、 検証を通らなかったフィールドは除外されます。 もしもリクエストデータを変換する時にバリデーションを無効にしたければ、 `validate` オプションに偽を指定してください。 : $article = $articles->newEntity( $this->request->getData(), ['validate' => false] ); 1 2 3 4 `patchEntity()` メソッドについても同じことが言えます。 : $article = $articles->patchEntity($article, $newData, [\ 'validate' => false\ ]); 1 2 3 既定のバリデーションセットの作成 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E6%97%A2%E5%AE%9A%E3%81%AE%E3%83%8F%E3%82%99%E3%83%AA%E3%83%86%E3%82%99%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%BB%E3%83%83%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- バリデーションルールは規約ではテーブルクラス中で定義されます。 何のデータが検証されるかとあわせてどこで保存されるかも定義します。 テーブル中で既定のバリデーションオブジェクトを作るには、 `validationDefault()` 関数を作成します。 : use Cake\ORM\Table; use Cake\Validation\Validator; class ArticlesTable extends Table { public function validationDefault(Validator $validator) { $validator ->requirePresence('title', 'create') ->notEmpty('title'); $validator ->allowEmpty('link') ->add('link', 'valid-url', ['rule' => 'url']); ... return $validator; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 有効なバリデーションメソッドやルールは `Validator` クラスによって提供され [Creating Validators](https://book.cakephp.org/3.x/ja/core-libraries/validation.html#creating-validators) の節に記載されています。 NOTE バリデーションオブジェクトは主にユーザー入力の検証用に意図されています。 たとえば、フォームやその他の投稿されたリクエストデータです。 異なるバリデーションセットの使用 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E7%95%B0%E3%81%AA%E3%82%8B%E3%83%8F%E3%82%99%E3%83%AA%E3%83%86%E3%82%99%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%BB%E3%83%83%E3%83%88%E3%81%AE%E4%BD%BF%E7%94%A8) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- バリデーションを無効にすることに加えて 適用させたいバリデーションルールを選ぶこともできます。 : $article = $articles->newEntity( $this->request->getData(), ['validate' => 'update'] ); 1 2 3 4 上記は必要なルールを構築するために、そのテーブルインスタンスの `validationUpdate()` メソッドを呼び出します。既定では `validationDefault()` メソッドが使用されます。 記事テーブル用のバリデータの一例はこのようになります。 : class ArticlesTable extends Table { public function validationUpdate($validator) { $validator ->add('title', 'notEmpty', [\ 'rule' => 'notEmpty',\ 'message' => __('タイトルを設定してください'),\ ]) ->add('body', 'notEmpty', [\ 'rule' => 'notEmpty',\ 'message' => __('本文は必須です')\ ]); return $validator; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 必要に応じていくつものバリデーションセットを設けることができます。 バリデーションルールセットの構築についてのより多くの情報は [バリデーション](https://book.cakephp.org/3.x/ja/core-libraries/validation.html) を参照してください。 ### アソシエーションに異なるバリデーションセットを使用 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%82%A2%E3%82%BD%E3%82%B7%E3%82%A8%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AB%E7%95%B0%E3%81%AA%E3%82%8B%E3%83%8F%E3%82%99%E3%83%AA%E3%83%86%E3%82%99%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%BB%E3%83%83%E3%83%88%E3%82%92%E4%BD%BF%E7%94%A8) バリデーションセットはアソシエーションごとに定義することもできます。 `newEntity()` または `patchEntity()` メソッドを使用する時、 変換されるアソシエーション各々に追加のオプションを渡すことができます。 : $data = [\ 'title' => '私の肩書き',\ 'body' => 'テキスト',\ 'user_id' => 1,\ 'user' => [\ 'username' => 'マーク'\ ],\ 'comments' => [\ ['body' => '一番目のコメント'],\ ['body' => '二番目のコメント'],\ ]\ ]; $article = $articles->patchEntity($article, $data, [\ 'validate' => 'update',\ 'associated' => [\ 'Users' => ['validate' => 'signup'],\ 'Comments' => ['validate' => 'custom']\ ]\ ]); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 バリデータの組み合わせ [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%83%8F%E3%82%99%E3%83%AA%E3%83%86%E3%82%99%E3%83%BC%E3%82%BF%E3%81%AE%E7%B5%84%E3%81%BF%E5%90%88%E3%82%8F%E3%81%9B) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- バリデータオブジェクトはこのように構築されるので、 その構築過程を複数の手順に分割することは簡単です。 : // UsersTable.php public function validationDefault(Validator $validator) { $validator->notEmpty('username'); $validator->notEmpty('password'); $validator->add('email', 'valid-email', ['rule' => 'email']); ... return $validator; } public function validationHardened(Validator $validator) { $validator = $this->validationDefault($validator); $validator->add('password', 'length', ['rule' => ['lengthBetween', 8, 100]]); return $validator; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 上の手順では、 `hardened` バリデーションセットを使う時には `default` セット中で定義されているバリデーションルールも含むことになります。 バリデーションプロバイダー [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%83%8F%E3%82%99%E3%83%AA%E3%83%86%E3%82%99%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%95%E3%82%9A%E3%83%AD%E3%83%8F%E3%82%99%E3%82%A4%E3%82%BF%E3%82%99%E3%83%BC) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ バリデーションルールは既知のあらゆるプロバイダーで定義されている関数を使うことができます。 既定では CakePHP はいくつかのプロバイダーを設定します: 1. `table` プロバイダーではテーブルクラスまたはそのビヘイビアーのメソッドが有効です。 2. コアの `Cake\Validation\Validation` クラスが `default` プロバイダーとしてセットアップされます。 バリデーションルールを作る時に、そのルールのプロバイダー名を指定できます。 たとえば、もしあなたのテーブルが `isValidRole` メソッドを持っているとすれば それをバリデーションルールとして使うことができます。 : use Cake\ORM\Table; use Cake\Validation\Validator; class UsersTable extends Table { public function validationDefault(Validator $validator) { $validator ->add('role', 'validRole', [\ 'rule' => 'isValidRole',\ 'message' => __('有効な権限を指定する必要があります'),\ 'provider' => 'table',\ ]); return $validator; } public function isValidRole($value, array $context) { return in_array($value, ['admin', 'editor', 'author'], true); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 バリデーションルールにはクロージャも使うことができます。 : $validator->add('name', 'myRule', [\ 'rule' => function ($data, $provider) {\ if ($data > 1) {\ return true;\ }\ return '適切な値ではありません。';\ }\ ]); 1 2 3 4 5 6 7 8 バリデーションメソッドは通らない時にエラーメッセージを返すことができます。 これは渡された値に動的に基づくエラーメッセージを作るための簡単な方法です。 テーブルからのバリデータ取得 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%83%86%E3%83%BC%E3%83%95%E3%82%99%E3%83%AB%E3%81%8B%E3%82%89%E3%81%AE%E3%83%8F%E3%82%99%E3%83%AA%E3%83%86%E3%82%99%E3%83%BC%E3%82%BF%E5%8F%96%E5%BE%97) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- テーブルクラスにバリデーションセットを作成した後は、 名前を指定して結果のオブジェクトを取得できるようになります。 : $defaultValidator = $usersTable->validator('default'); $hardenedValidator = $usersTable->validator('hardened'); 1 2 3 Deprecated in version 3.5.0 `validator()` は非推奨です。代わりに `getValidator()` を使用してください。 既定のバリデータクラス [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E6%97%A2%E5%AE%9A%E3%81%AE%E3%83%8F%E3%82%99%E3%83%AA%E3%83%86%E3%82%99%E3%83%BC%E3%82%BF%E3%82%AF%E3%83%A9%E3%82%B9) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 上述の通り、既定ではバリデーションメソッドは `Cake\Validation\Validator` のインスタンスを受け取ります。 そうではなくて、カスタムバリデータのインスタンスが毎回ほしいのであれば、 テーブルの `$_validatorClass` プロパティーを使うことができます。 : // あなたのテーブルクラスの中で public function initialize(array $config) { $this->_validatorClass = '\FullyNamespaced\Custom\Validator'; } 1 2 3 4 5 アプリケーションルールの適用 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%82%A2%E3%83%95%E3%82%9A%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%AE%E9%81%A9%E7%94%A8) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [リクエストデータがエンティティーに変換される](https://book.cakephp.org/3.x/ja/orm/validation.html#validating-request-data) 時、 基本的なデータ検証が行われますが、多くのアプリケーションは 基本的な検証が完了した後にのみ適用されるもっと複雑な検証も設けています。 バリデーションはデータの形式や構文が正しいことを保証する一方、 ルールは あなたのアプリケーションやネットワークの既存の状態に対してデータを比較することに 焦点を当てます。 この種のルールはしばしば「ドメインルール」や「アプリケーションルール」と言われます。 CakePHP は、エンティティーが保存される前に適用される「ルールチェッカー」を通して これを行います。いくつかのドメインルールの例は次のようになります: * メールアドレスの一意性の保証。 * ステータス遷移や業務フローの手順 (たとえば、請求書のステータス更新)。 * 論理削除されたアイテムの更新の抑制。 * 使用量/料金の上限の強制。 ドメインルールは `save()` および `delete()` メソッドを呼ぶとチェックされます。 ### ルールチェッカーの作成 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%83%AB%E3%83%BC%E3%83%AB%E3%83%81%E3%82%A7%E3%83%83%E3%82%AB%E3%83%BC%E3%81%AE%E4%BD%9C%E6%88%90) ルールチェッカークラスは一般にテーブルクラスの `buildRules()` メソッドで定義されます。ビヘイビアーや他のイベントの受け手は 与えられたテーブルクラスのルールチェッカーを受け取るために `Model.buildRules` イベントを使うことができます。 : use Cake\ORM\RulesChecker; // テーブルクラスの中で public function buildRules(RulesChecker $rules) { // 作成および更新操作に提供されるルールを追加 $rules->add(function ($entity, $options) { // 失敗/成功を示す真偽値を返す }, 'ruleName'); // 作成のルールを追加 $rules->addCreate(function ($entity, $options) { // 失敗/成功を示す真偽値を返す }, 'ruleName'); // 更新のルールを追加 $rules->addUpdate(function ($entity, $options) { // 失敗/成功を示す真偽値を返す }, 'ruleName'); // 削除のルールを追加 $rules->addDelete(function ($entity, $options) { // 失敗/成功を示す真偽値を返す }, 'ruleName'); return $rules; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 ルールの関数はチェックされるエンティティーとオプションの配列を期待します。 オプションの配列は `errorField` 、 `message` 、そして `repository` を含みます。 `repository` オプションはルールが追加されるテーブルクラスを含みます。 ルールはあらゆる `callable` を受け取るので、インスタンス関数を使うこともできます。 : $rules->addCreate([$this, 'uniqueEmail'], 'uniqueEmail'); 1 または呼び出し可能なクラスも使えます。 : $rules->addCreate(new IsUnique(['email']), 'uniqueEmail'); 1 ルールを追加する時、任意でルールが適用されるフィールドやエラーメッセージ を定義することができます。 : $rules->add([$this, 'isValidState'], 'validState', [\ 'errorField' => 'status',\ 'message' => 'この請求書はそのステータスに遷移できません。'\ ]); 1 2 3 4 エンティティーの `errors()` メソッドを呼ぶとエラーを確認できます。 : $entity->errors(); // ドメインルールのエラーメッセージを含んでいます 1 ### 一意フィールドルールの作成 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E4%B8%80%E6%84%8F%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%88%E3%82%99%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) 一意ルールは極めて一般的なので、CakePHP は一意フィールドの組み合わせを定義できる 単純なルールクラスを内包しています。 : use Cake\ORM\Rule\IsUnique; // 一つのフィールド $rules->add($rules->isUnique(['email'])); // フィールドのリスト $rules->add($rules->isUnique( ['username', 'account_id'], 'この username と account_id の組み合わせはすでに使用されています。' )); 1 2 3 4 5 6 7 8 9 10 外部キーフィールドのルールを設定する時には、 ルールでは列挙したフィールドのみが使われるのを覚えておくことが重要です。 これは `$user->account->id` を変更しても上記のルールは発動しないことを意味します。 ### 外部キールール [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E5%A4%96%E9%83%A8%E3%82%AD%E3%83%BC%E3%83%AB%E3%83%BC%E3%83%AB) 制約を強制するためにデータベースエラーに頼ることもできますが、 ルールのコードはより良いユーザーエクスペリエンスを提供するのに役立ちます。 このために CakePHP は `ExistsIn` ルールクラスを内包しています。 : // 一つのフィールド $rules->add($rules->existsIn('article_id', 'Articles')); // 複数キー。複合主キーに役立ちます。 $rules->add($rules->existsIn(['site_id', 'article_id'], 'Articles')); 1 2 3 4 5 存在をチェックするための関連テーブルのフィールドは主キーの一部でなければなりません。 複合外部キーの null が可能な部分が null の時、 `existsIn` が通るように強制することができます。 : // 例: NodesTable の複合主キーは (id, site_id) です。 // Node は、親 Node を参照しますが、必須ではありません。参照しない場合、parent_id が null になります。 // たとえ null が可能なフィールド (parent_id のような) が null であっても、このルールが通ることを許可します。 $rules->add($rules->existsIn( ['parent_id', 'site_id'], // Schema: parent_id NULL, site_id NOT NULL 'ParentNodes', ['allowNullableNulls' => true] )); // それに加えて Node は、常に Site を参照してください。 $rules->add($rules->existsIn(['site_id'], 'Sites')); 1 2 3 4 5 6 7 8 9 10 11 大部分の SQL データベースでは、複数カラムの `UNIQUE` インデックスは、 `NULL` は、それ自身と等しくないため、複数の null 値が存在することを許可します。 複数の null 値を許可することは、CakePHP のデフォルトの振る舞いですが、 `allowMultipleNulls` を使用することでユニークチェックに null 値を含むことができます。 : // null 値は `parent_id` と `site_id` の中に1つだけで存在できます。 $rules->add($rules->existsIn( ['parent_id', 'site_id'], 'ParentNodes', ['allowMultipleNulls' => false] )); 1 2 3 4 5 6 Added in version 3.3.0 `allowNullableNulls` と `allowMultipleNulls` オプションが追加されました。 ### アソシエーションカウントルール [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%82%A2%E3%82%BD%E3%82%B7%E3%82%A8%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%83%AB%E3%83%BC%E3%83%AB) プロパティーやアソシエーションが正しい件数かどうかの検証が必要な場合、 `validCount()` ルールが利用できます。 : // ArticlesTable.php ファイルの中で // 記事にタグは5つ以内。 $rules->add($rules->validCount('tags', 5, '<=', 'タグは 5 つまで持てます')); 1 2 3 ルールに基づく件数を定義する際、第3引数は、比較演算子を定義します。 比較には `==`, `>=`, `<=`, `>`, `<`, そして `!=` が使えます。 プロパティーの件数が範囲内であることを保証するために、2つのルールを使用してください。 : // ArticlesTable.php ファイルの中で // タグは3つ以上、5つ以内 $rules->add($rules->validCount('tags', 3, '>=', 'タグは 3 つ以上必要です')); $rules->add($rules->validCount('tags', 5, '<=', 'タグは 5 つ以下です')); 1 2 3 4 もしプロパティーが数えられない場合や存在しない場合、 `validCount` は `false` を返すことに注意してください。 : // もし tags が null の場合、保存操作は失敗します。 $rules->add($rules->validCount('tags', 0, '<=', 'タグを持つことはできません')); 1 2 Added in version 3.3.0 `validCount()` メソッドは、3.3.0 で追加されました。 ### エンティティーメソッドをルールとして使用 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3%E3%83%BC%E3%83%A1%E3%82%BD%E3%83%83%E3%83%88%E3%82%99%E3%82%92%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%A8%E3%81%97%E3%81%A6%E4%BD%BF%E7%94%A8) ドメインルールとしてエンティティーのメソッドを使いたいかもしれません。 : $rules->add(function ($entity, $options) { return $entity->isOkLooking(); }, 'ruleName'); 1 2 3 ### 条件付きルールの使用 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E6%9D%A1%E4%BB%B6%E4%BB%98%E3%81%8D%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%BF%E7%94%A8) エンティティーデータに基づいて条件付きでルールを適用することができます。 : $rules->add(function ($entity, $options) use($rules) { if ($entity->role == 'admin') { $rule = $rules->existsIn('user_id', 'Admins'); return $rule($entity, $options); } if ($entity->role == 'user') { $rule = $rules->existsIn('user_id', 'Users'); return $rule($entity, $options); } return false; }, 'userExists'); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ### 条件付き/動的なエラーメッセージ [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E6%9D%A1%E4%BB%B6%E4%BB%98%E3%81%8D-%E5%8B%95%E7%9A%84%E3%81%AA%E3%82%A8%E3%83%A9%E3%83%BC%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B7%E3%82%99) ルールは、 [カスタムコールバック](https://book.cakephp.org/3.x/ja/orm/validation.html#creating-a-rules-checker) または [ルールオブジェクト](https://book.cakephp.org/3.x/ja/orm/validation.html#creating-custom-rule-objects) であり、 パスするかどうかを示すブーリアン型を返すか、検証がパスしなかったことを意味する文字列を返すことができ、 返された文字列はエラーメッセージとして使用されます。 `message` オプションで定義された既存のエラーメッセージは、 ルールから返されたエラーメッセージによって上書きされます。 : $rules->add( function ($entity, $options) { if (!$entity->length) { return false; } if ($entity->length < 10) { return '値が 10 より小さい場合のエラーメッセージ'; } if ($entity->length > 20) { return '値が 20 より大きい場合のエラーメッセージ'; } return true; }, 'ruleName', [\ 'errorField' => 'length',\ 'message' => '`false` が返された時に使われる一般的なエラーメッセージ'\ ] ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 NOTE 返されたメッセージを実際に使用するためには、 `errorField` オプションも _指定しなければならない_ ことに注意してください。そうしなければ、ルールは単にパスしないだけで、 エンティティーにエラーメッセージが設定されません。 ### 再利用可能なカスタムルールの作成 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E5%86%8D%E5%88%A9%E7%94%A8%E5%8F%AF%E8%83%BD%E3%81%AA%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90) カスタムドメインルールを再利用したい事もあるでしょう。それには、 独自の呼び出し可能なルールを作成することによって行います。 : use App\ORM\Rule\IsUniqueWithNulls; // ... public function buildRules(RulesChecker $rules) { $rules->add(new IsUniqueWithNulls(['parent_id', 'instance_id', 'name']), 'uniqueNamePerParent', [\ 'errorField' => 'name',\ 'message' => 'Name must be unique per parent.'\ ]); return $rules; } 1 2 3 4 5 6 7 8 9 10 そのようなルールを作成する方法の例として、コアのルールを確認してください。 ### カスタムルールオブジェクト作成 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%AA%E3%83%95%E3%82%99%E3%82%B7%E3%82%99%E3%82%A7%E3%82%AF%E3%83%88%E4%BD%9C%E6%88%90) もしもアプリケーションがよく再利用されるルールを持っているのであれば、 再利用可能なクラスにそうしたルールをまとめると役に立ちます。 : // src/Model/Rule/CustomRule.php の中で namespace App\Model\Rule; use Cake\Datasource\EntityInterface; class CustomRule { public function __invoke(EntityInterface $entity, array $options) { // 何かする return false; } } // カスタムルールの追加 use App\Model\Rule\CustomRule; $rules->add(new CustomRule(...), 'ruleName'); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 カスタムルールクラスを作ることでコードを _重複がない状態_ (訳注:DRY = Don't Repeat Yourself の訳) に保つことができ、またドメインルールを簡単にテストできるようになります。 ### ルールの無効化 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%AE%E7%84%A1%E5%8A%B9%E5%8C%96) エンティティーを保存する時、必要であればルールを無効にできます。 : $articles->save($article, ['checkRules' => false]); 1 バリデーション対アプリケーションルール [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%83%8F%E3%82%99%E3%83%AA%E3%83%86%E3%82%99%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E5%AF%BE%E3%82%A2%E3%83%95%E3%82%9A%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%AB%E3%83%BC%E3%83%AB) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ CakePHP の ORM は検証に二層のアプローチを使う点がユニークです。 一層目はバリデーションです。バリデーションルールは、ステートレスな方法の操作を意図しています。 それらは、形状、データ型、データの書式が正しいことを保証するために最もよく作用します。 二層目は、アプリケーションルールです。アプリケーションルールは、あなたのエンティティーの ステートフルなプロパティーのチェックに最もよく作用します。例えば、バリデーションルールは、 メールアドレスが有効なことを保証することができますが、アプリケーションルールは、 メールアドレスがユニークであることを保証できます。 すでに見てきた通りに、一層目は `newEntity()` か `patchEntity()` を呼ぶ時に `Validator` オブジェクトを通して行われます。 : $validatedEntity = $articlesTable->newEntity( $unsafeData, ['validate' => 'customName'] ); $validatedEntity = $articlesTable->patchEntity( $entity, $unsafeData, ['validate' => 'customName'] ); 1 2 3 4 5 6 7 8 9 上記の例では、 `validationCustomName()` メソッドを使って定義される 「カスタム」バリデータを使用します。 : public function validationCustomName($validator) { $validator->add(...); return $validator; } 1 2 3 4 5 バリデーションは文字列や配列を渡されることを想定しています。 それらがリクエストから得られるものですので: // src/Model/Table/UsersTable.php の中で public function validatePasswords($validator) { $validator->add('confirm_password', 'no-misspelling', [\ 'rule' => ['compareWith', 'password'],\ 'message' => 'パスワードが一致しません',\ ]); ... return $validator; } 1 2 3 4 5 6 7 8 9 10 11 バリデーションはエンティティーのプロパティーを直接設定した時には起動 **しません** 。 : $userEntity->email = 'not an email!!'; $usersTable->save($userEntity); 1 2 上記の例では、バリデーションは `newEntity()` と `patchEntity()` メソッドのためにのみ起動されるので、エンティティーは保存されてしまうことになります。 検証の第二層がこの状況に対処します。 アプリケーションルールは上で説明したように `save()` か `delete()` が呼ばれるといつでもチェックされます。 : // src/Model/Table/UsersTable.php の中で public function buildRules(RulesChecker $rules) { $rules->add($rules->isUnique('email')); return $rules; } // アプリケーションのコード中のどこかで $userEntity->email = '[email protected]'; $usersTable->save($userEntity); // 偽を返します 1 2 3 4 5 6 7 8 9 10 バリデーションは直接のユーザー入力を意図しており、アプリケーションルールは アプリケーション中で生成されたデータの変更に特化しています。 : // src/Model/Table/OrdersTable.php の中で public function buildRules(RulesChecker $rules) { $check = function($order) { if($order->shipping_mode !== 'free'){ return true; } return $order->price >= 100; }; $rules->add($check, [\ 'errorField' => 'shipping_mode',\ 'message' => '100ドル以下の注文を送料無料にはできません!'\ ]); return $rules; } // アプリケーションのコード中のどこかで $order->price = 50; $order->shipping_mode = 'free'; $ordersTable->save($order); // 偽を返します 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ### バリデーションをアプリケーションルールとして使用 [​](https://book.cakephp.org/3.x/ja/orm/validation.html#%E3%83%8F%E3%82%99%E3%83%AA%E3%83%86%E3%82%99%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E3%82%A2%E3%83%95%E3%82%9A%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%A8%E3%81%97%E3%81%A6%E4%BD%BF%E7%94%A8) ある状況ではユーザーあるいはアプリケーションによって生成されたデータの 両方に対して同じ検証の処理を走らせたいかもしれません。 これは、エンティティーのプロパティーを直接設定するような CLI スクリプトを走らせる時に起こり得るでしょう。 : // src/Model/Table/UsersTable.php の中で public function validationDefault(Validator $validator) { $validator->add('email', 'valid', [\ 'rule' => 'email',\ 'message' => '無効なメールアドレスです'\ ]); ... return $validator; } public function buildRules(RulesChecker $rules) { // アプリケーションルールの追加 $rules->add(function($entity) { $data = $entity->extract($this->schema()->columns(), true); $validator = $this->validator('default'); // Prior to 3.9 use $validator->errors() $errors = $validator->validate($data, $entity->isNew()); $entity->errors($errors); return empty($errors); }); ... return $rules; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 保存が実行されると、追加された新しいアプリケーションのおかげで失敗します。 : $userEntity->email = 'not an email!!!'; $usersTable->save($userEntity); $userEntity->errors('email'); // 無効なメールアドレスです 1 2 3 同じ結果が `newEntity()` や `patchEntity()` を使う時にも期待できます。 : $userEntity = $usersTable->newEntity(['email' => 'not an email!!']); $userEntity->errors('email'); // 無効なメールアドレスです 1 2 --- # プラグイン | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/plugins.html#VPContent) Return to top プラグイン [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3) ======================================================================================================================== CakePHP では、コントローラー・モデル・ビューの組み合わせを設定し、 他の CakePHP アプリケーションで使用できるよう事前にパッケージ化された アプリケーションプラグインとしてリリースできます。あなたのアプリケーションの1つに、 素敵なユーザー管理モジュールやシンプルなブログやウェブサービスモジュールを作成したら、 CakePHP プラグインとしてパッケージ化してみませんか?そうすれば、他のアプリケーションで 再利用したり、コミュニティーで共有したりすることができます! CakePHP プラグインは、ホストアプリケーション自身とは基本的に分離されており、 一般的にきちんとパッケージ化され、他のアプリケーションではほとんど手間をかけずに 再利用できる明確な機能を提供します。アプリケーションとプラグインは、それぞれの空間で動作しますが、 アプリケーションの設定によって定義・共有される、アプリケーション固有のプロパティー (データベース接続パラメーターなど)を共有します。 CakePHP 3.0 では、それぞれのプラグインごとに最上位の名前空間 (例えば `DebugKit` と いったように) を定義します。規約により、プラグインはそのパッケージ名が名前空間の名前と なります。 もし別の名前空間名を使いたいなら、プラグインをロードする時に設定することが可能です。 Composer を使ったプラグインのインストール [​](https://book.cakephp.org/3.x/ja/plugins.html#composer-%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- [Packagist](https://packagist.org/) には多くのプラグインがあり、 `Composer` を 使ってインストールが可能です。DebugKit をインストールには、下記のコマンドを実行します。 php composer.phar require cakephp/debug_kit 1 これによって最新の DebugKit をインストールして、あなたの **composer.json**, **composer.lock** ファイルを更新し、 **vendor/cakephp-plugins.php** とオートローダーも更新します。 プラグインの手動インストール [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E6%89%8B%E5%8B%95%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ もしあなたがインストールしたいプラグインが packagist.org になければ、プラグインのコードを **plugins** ディレクトリーにコピーすることもできます。 例えば 'ContactManager' という名前のプラグインをインストールするなら、 `plugins` フォルダーの中に 'ContactManager' という名前のフォルダーを作り、この下にプラグインの src, tests といった フォルダーを作ります。 ### プラグインクラスを手動で自動読み込み [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%92%E6%89%8B%E5%8B%95%E3%81%A6%E3%82%99%E8%87%AA%E5%8B%95%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF) `composer` や `bake` を使ってプラグインをインストールするなら、 プラグインのためにクラスの自動読み込みの設定をする必要はありません。 一方、 `MyPlugin` という名前のプラグインを手動でインストールした場合、 アプリケーションの **composer.json** ファイルを次の情報を含むように更新する必要があります。 { "autoload": { "psr-4": { "MyPlugin\\": "plugins/MyPlugin/src/" } }, "autoload-dev": { "psr-4": { "MyPlugin\\Test\\": "plugins/MyPlugin/tests/" } } } 1 2 3 4 5 6 7 8 9 10 11 12 あなたのプラグインがベンダーの名前空間を使うなら、パスマッピングの名前空間は下記のように なるでしょう。 { "autoload": { "psr-4": { "AcmeCorp\\Users\\": "plugins/AcmeCorp/Users/src/", "AcmeCorp\\Users\\Test\\": "plugins/AcmeCorp/Users/tests/" } } } 1 2 3 4 5 6 7 8 そして、 Composer の自動読み込みキャッシュを初期化する必要があります。 php composer.phar dumpautoload 1 もしあなたが何らかの理由で Composer を使う事ができないのなら、 `Plugin` を使って 自動読み込みを行うこともできます。 : Plugin::load('ContactManager', ['autoload' => true]); 1 Deprecated in version 3.7.0 Plugin::load() と `autoload` オプションは非推奨です。 NOTE 重要: `autoload` オプションは `addPlugin()` では使用できません。代わりに `composer dumpautoload` を使用してください。 プラグインの読み込み [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- もし、プラグインのルート、コンソールコマンド、ミドルウェア、またはイベントリスナーが欲しい場合、 プラグインを読み込む必要があります。プラグインは、アプリケーションの `bootstrap()` 関数の中で 読み込まれます。 : // src/Application.php の中。3.6.0 以上が必要。 use Cake\Http\BaseApplication; use ContactManager\Plugin as ContactManagerPlugin; class Application extends BaseApplication { public function bootstrap() { parent::bootstrap(); // クラス名で contact manager プラグインを読み込み $this->addPlugin(ContactManagerPlugin::class); // '短縮名' でベンダーの名前空間付きプラグインを読み込み $this->addPlugin('AcmeCorp/ContactManager'); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 単にプラグインのヘルパー、ビヘイビアー、またはコンポーネントが欲しいだけの場合、 プラグインを読み込む必要はありません。 3.6.0 より前の場合、 `Plugin::load()` を使ってください。 : // config/bootstrap.php の中で // 特定のプラグインを読み込みます。 Plugin::load('ContactManager'); // ベンダーの名前空間の特定のプラグインを読み込みます。 Plugin::load('AcmeCorp/ContactManager'); 1 2 3 4 5 6 7 また、プラグインを有効にする便利なシェルコマンドがあります。次の行を実行してください。 bin/cake plugin load ContactManager 1 これは、アプリケーションの bootstrap メソッドを更新、 または `$this->addPlugin('ContactManager');` を bootstrap に書き込みます。 Added in version 3.6.0 `addPlugin()` が追加されました。 プラグインフックの設定 [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%83%95%E3%83%83%E3%82%AF%E3%81%AE%E8%A8%AD%E5%AE%9A) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ プラグインは、プラグインがアプリケーションの適切な部分に自分自身を注入できるようにする いくつかのフックを提供します。 フックは以下の通りです。 * `bootstrap` プラグインのデフォルト設定ファイルの読み込み、 定数やその他のグローバル関数の定義に使用されます。 * `routes` プラグインのルートをロードするために使用されます。 アプリケーションのルートがロードされた後に呼ばれます。 * `middleware` プラグインのミドルウェアをアプリケーションの ミドルウェアキューに追加するために使用されます。 * `console` アプリケーションのコマンドコレクションにコンソールコマンドを 追加するために使用されます。 プラグインをロードするとき、有効にするフックを設定できます。 デフォルトでは、 [Plugin Objects](https://book.cakephp.org/3.x/ja/plugins.html#plugin-objects) のないプラグインはすべてのフックを無効にします。 新しいスタイルのプラグインを使用すると、プラグイン作成者はデフォルトを設定できます。 これを利用者はアプリケーション中で変更可能です。 : // Application::bootstrap() の中で use ContactManager\Plugin as ContactManagerPlugin; // ContactManager プラグインのルートを無効化 $this->addPlugin(ContactManagerPlugin::class, ['routes' => false]); 1 2 3 4 5 フックを配列オプションで設定することも、 Plugin クラスで提供されるメソッドで設定することもできます。 : // Application::bootstrap() の中で use ContactManager\Plugin as ContactManagerPlugin; // フックを設定するために disable/enable を使用 $plugin = new ContactManagerPlugin(); $plugin->disable('bootstrap'); $plugin->enable('routes'); $this->addPlugin($plugin); 1 2 3 4 5 6 7 8 9 Plugin オブジェクトは、名前とパス情報も知っています。 : $plugin = new ContactManagerPlugin(); // プラグイン名を取得 $name = $plugin->getName(); // プラグインルートへのパスとその他のパス $path = $plugin->getPath(); $path = $plugin->getConfigPath(); $path = $plugin->getClassPath(); 1 2 3 4 5 6 7 8 9 ### 古いスタイルのプラグイン [​](https://book.cakephp.org/3.x/ja/plugins.html#%E5%8F%A4%E3%81%84%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3) 3.6.0 より前は、 `bootstrap` と `routs` フックを有効にする必要があります。 古いスタイルのプラグインは、 `middleware` と `console` フックはサポートしません。 : // config/bootstrap.php の中、 // または Application::bootstrap() の中で // loadAll() を使用 Plugin::loadAll([\ 'Blog' => ['routes' => true],\ 'ContactManager' => ['bootstrap' => true],\ 'WebmasterTools' => ['bootstrap' => true, 'routes' => true],\ ]); 1 2 3 4 5 6 7 8 9 また、プラグインを個別に読み込むことができます。 : // blog を読み込み、routes をインクルード Plugin::load('Blog', ['routes' => true]); // 設定と初期化を行う bootstrap をインクルード Plugin::load('ContactManager', ['bootstrap' => true]); 1 2 3 4 5 この設定スタイルは、プラグインの設定やルートを手動で `include()` や `require()` する必要がなく、自動で正しい時間と正しい場所で読み込まれます。 特定の設定を持たない全てのプラグインを読み込むデフォルトの `loadAll()` を設定できます。 次の例は、全てのプラグインの bootstrap を読み込み、 それに加えて Blog プラグインの routes を読み込みます。 : Plugin::loadAll([\ ['bootstrap' => true],\ 'Blog' => ['routes' => true]\ ]); 1 2 3 4 プラグインで指定された全てのファイルが実際に存在しないと、PHP が読み込めないファイルごとに 警告を出します。この潜在的な警告は、 `ignoreMissing` オプションを使用して避けることができます。 : Plugin::loadAll([\ ['ignoreMissing' => true, 'bootstrap' => true],\ 'Blog' => ['routes' => true]\ ]); 1 2 3 4 プラグインを読み込むとき、プラグイン名は名前空間名と一致すべきです。 例えば、最上位の名前空間が `Users` のプラグインがあるなら、このように読み込みます。 : Plugin::load('User'); 1 もしあなたが `AcmeCorp/Users` といったように、ベンダー名を最上位の名前空間名に したいのなら、このようにプラグインを読み込みます。 : Plugin::load('AcmeCorp/Users'); 1 クラス名は `プラグイン記法` を使うことで、適切に解決されるでしょう。 ほとんどのプラグインで、設定するための正確な手続きとデータベースのセットアップするための方法が、 ドキュメントに書かれています。他よりセットアップが必要なものもあります。 Deprecated in version 3.7.0 Plugin::load() と Plugin::loadAll() は非推奨です。 プラグインの利用 [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E5%88%A9%E7%94%A8) ------------------------------------------------------------------------------------------------------------------------------------------------------ クラス名の前にプラグイン名を付けることで、プラグインのコントローラー、 モデル、コンポーネント、ビヘイビアーとヘルパーを参照できます。 例えば、あなたの画面で整形された連絡先情報を表示するために、 ContactManager プラグインの ContactInfoHelper を使いたいとしましょう。この場合、あなたのコントローラーの `$helpers` 配列にこのように記述します。 : public $helpers = ['ContactManager.ContactInfo']; 1 NOTE このドット区切りのクラス名は、 `プラグイン記法` と呼ばれます。 すると、あなたが作った他のヘルパー同様に、 `ContactInfoHelper` に アクセスできるようになります。 : echo $this->ContactInfo->address($contact); 1 独自プラグインの作成 [​](https://book.cakephp.org/3.x/ja/plugins.html#%E7%8B%AC%E8%87%AA%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E4%BD%9C%E6%88%90) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 動作サンプルとして、上記を参考に ContactManager を作りましょう。 まず始めに、プラグインの基本ディレクトリー構成を準備します。 それはこのようになります。 : /src /plugins /ContactManager /config /src /Plugin.php /Controller /Component /Model /Table /Entity /Behavior /View /Helper /Template /Layout /tests /TestCase /Fixture /webroot プラグインフォルダーの名前が '\*\*ContactManager\*\*' になっています。このフォルダーが プラグインと同じ名前になる事が大切です。 プラグインフォルダーの中は CakePHP アプリケーションと同じような構成であることに気づく 思いますが、それが基本的な構成です。使わないフォルダーは作る必要はありません。 コンポーネントとビヘイビアーだけで定義されるプラグインもあれば、 'Template' ディレクトリーが 完全に省略されるプラグインもあります。 プラグインは、アプリケーションが持つ Config, Console, webroot 等といったディレクトリーも 設置できます。 ### Bake を使ってプラグインを作成 [​](https://book.cakephp.org/3.x/ja/plugins.html#bake-%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%82%92%E4%BD%9C%E6%88%90) プラグイン制作の過程は、Bake shell を使えば非常に簡単です。 プラグインを bake するのは以下のコマンドになります。 bin/cake bake plugin ContactManager 1 Bake を使用して、プラグインのクラスを作成できます。 例えばプラグインのコントローラーを bake するには bin/cake bake controller --plugin ContactManager Contacts 1 もしコマンドラインで問題があれば、 [Bake でコード生成](https://book.cakephp.org/3.x/ja/bake/usage.html) の章を参照してください。 また、プラグインを作ったら必ずオートローダーを再作成してください。 php composer.phar dumpautoload 1 Plugin オブジェクト [​](https://book.cakephp.org/3.x/ja/plugins.html#plugin-%E3%82%AA%E3%83%95%E3%82%99%E3%82%B7%E3%82%99%E3%82%A7%E3%82%AF%E3%83%88) ------------------------------------------------------------------------------------------------------------------------------------------------ Plugin オブジェクトを使用すると、プラグイン作成者は設定ロジックを定義し、 デフォルトのフックを定義し、ルート、ミドルウェア、およびコンソールコマンドをロードできます。 Plugin オブジェクトは、 **src/Plugin.php** にあります。 ContactManager プラグイン の場合、 Plugin クラスは、次のようになります。 : namespace ContactManager; use Cake\Core\BasePlugin; use Cake\Core\PluginApplicationInterface; class Plugin extends BasePlugin { public function middleware($middleware) { // ここにミドルウェアを追加。 return $middleware; } public function console($commands) { // ここにコンソールコマンドを追加。 return $commands; } public function bootstrap(PluginApplicationInterface $app) { // 定数を追加。デフォルトの設定をロード。 // デフォルトでは、プラグインの中の `config/bootstrap.php` をロードします。 parent::bootstrap($app); } public function routes($routes) { // ルートの追加。 // デフォルトでは、プラグインの中の `config/routes.php` をロードします。 parent::routes($routes); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 Added in version 3.6.0 Plugin オブジェクトは 3.6.0 で追加されました。 プラグインのルート [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%88) ---------------------------------------------------------------------------------------------------------------------------------------------------------------- プラグインは、ルートを含むルートファイルを提供できます。各プラグインは、 **config/routes.php** ファイルを含むことができます。このルートファイルは、 プラグインが追加された時、またはアプリケーションのルートファイルの中で ロードすることができます。ContactManager プラグインのルートを作成するためには、 **plugins/ContactManager/config/routes.php** の中に以下を記述してください。 : '/contact-manager'], function ($routes) { $routes->get('/contacts', ['controller' => 'Contacts']); $routes->get('/contacts/:id', ['controller' => 'Contacts', 'action' => 'view']); $routes->put('/contacts/:id', ['controller' => 'Contacts', 'action' => 'update']); } ); 1 2 3 4 5 6 7 8 9 10 11 12 13 上記のようにすれば、プラグインのデフォルトルートに接続できるでしょう。 このファイルをカスタマイズすることで、後から個別のルートを設定することができます。 コントローラーにアクセスする前に、プラグインがロードされ、ルートがロードされる必要があります。 **src/Application.php** に下記を追加してください。 : $this->addPlugin('ContactManager', ['routes' => true]); 1 アプリケーションのルート一覧の中で、プラグインのルートをロードすることもできます。 これにより、プラグインのルートをロードする方法をより詳細に制御し、 追加のスコープやプレフィックスでプラグインのルートをラップすることができます。 : Router::scope('/', function ($routes) { // 他のルートに接続。 $routes->scope('/backend', function ($routes) { $routes->loadPlugin('ContactManager'); }); }); 1 2 3 4 5 6 上記の結果は、 `/backend/contact-manager/contacts` のような URL になります。 Added in version 3.5.0 `RouteBuilder::loadPlugin()` は 3.5.0 で追加されました。 プラグインのコントローラー [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%83%BC) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ContactManager プラグインのコントローラーは、 **plugins/ContactManager/src/Controller/** に設置されます。主にやりたい事は contacts の管理ですので、このプラグインには ContactsController が必要です。 そこで ContactsController を **plugins/ContactManager/src/Controller** に設置し、 このように書きます。 : // plugins/ContactManager/src/Controller/ContactsController.php namespace ContactManager\Controller; use ContactManager\Controller\AppController; class ContactsController extends AppController { public function index() { //... } } 1 2 3 4 5 6 7 8 9 10 11 12 まだ作っていないなら、 `AppController` も作りましょう。 : // plugins/ContactManager/src/Controller/AppController.php namespace ContactManager\Controller; use App\Controller\AppController as BaseController; class AppController extends BaseController { } 1 2 3 4 5 6 7 8 プラグインの `AppController` は、プラグイン内の全コントローラー共通のロジックを 持ちますが、使わないようでしたら作らなくても構いません。 これまでのところでアクセスするなら、 `/contact-manager/contacts` にアクセスして みてください。 "Missing Model" エラーが表示されるでしょうが、これはまだ Contact モデルが定義されていないためです。 もしあなたのアプリケーションが、CakePHP の提供するデフォルトルーティングを含むなら、 あなたのプラグインコントローラーへは下記のような URL でアクセスできます。 : // プラグインコントローラーの index にアクセスする /contact-manager/contacts // プラグインコントローラーのそれぞれのアクションにアクセスする /contact-manager/contacts/view/1 1 2 3 4 5 もしあなたのアプリケーションでルーティングプレフィックスを定義しているなら、 CakePHP のデフォルトルーティングは下記の書式でルーティングします。 : /:prefix/:plugin/:controller /:prefix/:plugin/:controller/:action 特定ファイルにルーティングするようなプラグインの読み込み方法については、 [Plugin Configuration](https://book.cakephp.org/3.x/ja/plugins.html#plugin-configuration) のセクションをご覧ください。 bake で作っていないプラグインなら、クラスを自動的に読み込むために **composer.json** ファイルを編集して、あなたのプラグインを追加する必要があります。 これは [Autoloading Plugin Classes](https://book.cakephp.org/3.x/ja/plugins.html#autoloading-plugin-classes) に従って行うことができます。 プラグインのモデル [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E3%83%A2%E3%83%86%E3%82%99%E3%83%AB) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- プラグインのモデルは **plugins/ContactManager/src/Model** に設置されます。 既にこのプラグインの ContactsController は定義してありますから、このコントローラーの ためのテーブルとエンティティーを作成しましょう。 : // plugins/ContactManager/src/Model/Entity/Contact.php: namespace ContactManager\Model\Entity; use Cake\ORM\Entity; class Contact extends Entity { } // plugins/ContactManager/src/Model/Table/ContactsTable.php: namespace ContactManager\Model\Table; use Cake\ORM\Table; class ContactsTable extends Table { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 エンティティークラスを作った時や関連付けを行いたい時など、あなたのプラグイン内のモデルを 参照したい場合には、プラグイン名とクラス名をドットで区切る必要があります。例えば: // plugins/ContactManager/src/Model/Table/ContactsTable.php: namespace ContactManager\Model\Table; use Cake\ORM\Table; class ContactsTable extends Table { public function initialize(array $config) { $this->hasMany('ContactManager.AltName'); } } 1 2 3 4 5 6 7 8 9 10 11 12 もし関連付け配列のキーにプラグインの接頭語をつけたくないのなら、代わりにこのような 構文が使えます。 : // plugins/ContactManager/src/Model/Table/ContactsTable.php: namespace ContactManager\Model\Table; use Cake\ORM\Table; class ContactsTable extends Table { public function initialize(array $config) { $this->hasMany('AltName', [\ 'className' => 'ContactManager.AltName',\ ]); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 おなじみの `プラグイン記法` を使う事で、プラグインのテーブルを 読み込むために `TableRegistry` を使用することができます。 : use Cake\ORM\TableRegistry; // Prior to 3.6 use TableRegistry::get('ContactManager.Contacts') $contacts = TableRegistry::getTableLocator()->get('ContactManager.Contacts'); 1 2 3 4 あるいは、コントローラーの処理の中で以下のように使用できます。 : $this->loadModel('ContactsMangager.Contacts'); 1 プラグインのビュー [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ビューは通常のアプリケーション内と同じように動作します。 `plugins/[PluginName]/src/Template/` フォルダーの中の正しいフォルダー内に配置するだけです。 我々の ContactManager プラグインでは `ContactsController::index()` アクションに ビューが必要ですから、このような内容になります。 : // plugins/ContactManager/src/Template/Contacts/index.ctp:

    連絡先

    ソート可能なあなたの連絡先一覧は次のとおりです

    1 2 3 4 プラグインは独自のレイアウトを提供することができます。 プラグインレイアウトを追加するためには、テンプレートファイルを `plugins/[PluginName]/src/Template/Layout` に配置します。 プラグインレイアウトをコントローラーで使用するには、下記のようにします。 : public $layout = 'ContactManager.admin'; 1 プラグインのプレフィックスを省略した場合は、レイアウトやビューファイルは通常のものを使用します。 NOTE プラグインからのエレメントの使い方については、 [View Elements](https://book.cakephp.org/3.x/ja/views.html#view-elements) を参照してください。 ### アプリケーション内からプラグインのテンプレートを上書き [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%82%A2%E3%83%95%E3%82%9A%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E5%86%85%E3%81%8B%E3%82%89%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E3%83%86%E3%83%B3%E3%83%95%E3%82%9A%E3%83%AC%E3%83%BC%E3%83%88%E3%82%92%E4%B8%8A%E6%9B%B8%E3%81%8D) プラグインのビューはあるパスを使って上書きできます。 仮にあなたが 'ContactManager' という名前のプラグインを持っているとして、 **src/Template/Plugin/\[Plugin\]/\[Controller\]/\[view\].ctp** というファイルを作って そこにビューロジックを書いておけば、プラグインのテンプレートファイルを上書きすることができます。 Contacts コントローラーなら、次のようなファイルを作成します。 : src/Template/Plugin/ContactManager/Contacts/index.ctp このファイルを作成すると、 **plugins/ContactManager/src/Template/Contacts/index.ctp** を上書きします。 もし、あなたのプラグインが composer の依存関係の中にある場合 (例えば 'Company/ContactManager')、 Custom コントローラーの 'index' ビューへのパスは、次の通りです。 : src/Template/Plugin/ContactManager/Contacts/index.ctp このファイルを作成すると、 **vendor/Company/ContactManager/src/Template/Contacts/index.ctp** を上書きします。 プラグインがルーティングプレフィックスを実装する場合、上書きする アプリケーションテンプレートのパスにルーティングプレフィックスが含まなければなりません。 例えば、 'ContactManager' プラグインが 'admin' プレフィックスを実装する場合、 上書きするパスは、次の通りです。 : src/Template/Plugin/Company/ContactManager/Admin/Contact/index.ctp プラグインのアセット [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E3%82%A2%E3%82%BB%E3%83%83%E3%83%88) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- プラグインのウェブアセット (PHP 以外のファイル) は、メインアプリケーションのアセットと 同様にプラグインの `webroot` ディレクトリーを介して配信されます。 : /plugins/ContactManager/webroot/ css/ js/ img/ flash/ pdf/ 通常の webroot と同じようにどのディレクトリーにどんなファイルでも置くことができます。 WARNING ディスパッチャーを介して静的アセット (画像や JavaScript や CSS ファイル) を取り扱うことは 非常に非効率です。 詳細は [アプリケーションのパフォーマンスの向上](https://book.cakephp.org/3.x/ja/deployment.html#symlink-assets) をご覧ください。 ### プラグイン内のアセットへのリンク [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E5%86%85%E3%81%AE%E3%82%A2%E3%82%BB%E3%83%83%E3%83%88%E3%81%B8%E3%81%AE%E3%83%AA%E3%83%B3%E3%82%AF) `Cake\View\Helper\HtmlHelper` の script, image, css メソッドを使って プラグイン内のアセットへのリンクを作りたい場合、 `プラグイン記法` が使えます。 : // /contact_manager/css/styles.css への URL を生成します echo $this->Html->css('ContactManager.styles'); // /contact_manager/js/widget.js への URL を生成します echo $this->Html->script('ContactManager.widget'); // /contact_manager/img/logo.jpg への URL を生成します echo $this->Html->image('ContactManager.logo'); 1 2 3 4 5 6 7 8 プラグインのアセットは、デフォルトで `AssetMiddleware` ミドルウェアを 使用して提供されます。これは開発時のみ使用することが推奨されます。 本番環境ではパフォーマンスを向上させるために、 [プラグインのアセットをシンボリックリンク化](https://book.cakephp.org/3.x/ja/deployment.html#symlink-assets) すべきです。 もしあなたがヘルパーを使わないなら、プラグインのアセットを提供するためには URL の先頭に プラグイン名を付加します。 '/contact\_manager/js/some\_file.js' へのリンクで、 **plugins/ContactManager/webroot/js/some\_file.js** というアセットを提供します。 コンポーネント、ヘルパーとビヘイビアー [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%82%B3%E3%83%B3%E3%83%9B%E3%82%9A%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%80%81%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC%E3%81%A8%E3%83%92%E3%82%99%E3%83%98%E3%82%A4%E3%83%92%E3%82%99%E3%82%A2%E3%83%BC) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- プラグインには通常の CakePHP アプリケーションと同じように、コンポーネント、ヘルパー、 ビヘイビアーを持つ事ができます。あなたはコンポーネント、ヘルパー、ビヘイビアーだけからなる プラグインを作る事もできます。これはコンポーネントを他のプロジェクトに簡単に導入すれば 再利用可能となるような素晴らしい方法です。 このようなコンポーネントを作る事は、実際、通常のアプリケーションとして作る事と同じであり、 特別な命名規則もありません。 プラグインの内部や外部からコンポーネントを参照する方法は、コンポーネント名の前に プラグイン名を付けるだけです。例えば: // 'ContactManager' プラグインのコンポーネントとして定義 namespace ContactManager\Controller\Component; use Cake\Controller\Component; class ExampleComponent extends Component { } // コントローラーの中で public function initialize() { parent::initialize(); $this->loadComponent('ContactManager.Example'); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 同じテクニックはヘルパーとビヘイビアーにも使えます。 コマンド [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%88%E3%82%99) ----------------------------------------------------------------------------------------------------- プラグインは、 `console()` フックの中で、コマンドを登録することができます。 デフォルトでは、プラグイン内のすべてのシェルとコマンドが自動検出され、 アプリケーションのコマンドリストに追加されます。 プラグインコマンドの先頭にはプラグイン名が付いています。例えば、 `ContactManager` プラグインによって提供される `UserCommand` は、 `contact_manager.user` と `user` の両方として登録されます。プレフィックスのない名前は、 アプリケーションや他のプラグインで使用されていないプラグインでのみ使用されます。 プラグインで各コマンドを定義することによって、コマンド名をカスタマイズすることができます。 : public function console($commands) { // ネストされたコマンドを作成 $commands->add('bake model', ModelCommand::class); $commands->add('bake controller', ControllerCommand::class); return $commands; } 1 2 3 4 5 6 7 8 プラグインのテスト [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E3%83%86%E3%82%B9%E3%83%88) ---------------------------------------------------------------------------------------------------------------------------------------------------------------- コントローラーやURLの生成をテストする場合、プラグインがルート `tests/bootstrap.php` に接続していることを確認してください。 詳細は [testing plugins](https://book.cakephp.org/3.x/ja/development/testing.html) ページを確認してください。 プラグインの公開 [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E5%85%AC%E9%96%8B) ------------------------------------------------------------------------------------------------------------------------------------------------------ CakePHP のプラグインは [the packagist](https://packagist.org/) に公開しましょう。 こちらでは、他の人々は composer の依存関係として使用することができます。 [awesome-cakephp list](https://github.com/FriendsOfCake/awesome-cakephp) に申し込みできます。 パッケージ名にセマンティックな意味のある名前を選んでください。これは、理想を言えば、 "cakephp" をフレームワークとして依存関係を設定するべきです。 ベンダー名は、通常あなたの GitHub ユーザー名になります。 CakePHP 名前空間 (cakephp) を **使用しない** でください。 これは、CakePHP 自身のプラグインのために予約されています。 小文字と区切り文字のダッシュを使用することが決まりです。 もし、あなたの GitHub アカウントが "FooBar" で "Logging" プラグインを作成する場合、 foo-bar/cakephp-logging と名付けるといいでしょう。 そして、CakePHP 自身の "Localized" プラグンは、 cakephp/localized で見つけられます。 vendor/cakephp-plugins.php プラグイン マップ ファイル [​](https://book.cakephp.org/3.x/ja/plugins.html#%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3-%E3%83%9E%E3%83%83%E3%83%95%E3%82%9A-%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Composer 経由でインストールすると、 `vendor/cakephp-plugins.php` というファイルが 作られることに気付くかもしれません。この設定ファイルにはプラグイン名とファイルシステム上の 配置場所の情報が含まれています。これによって、プラグインを通常の検索パスの外の、標準の vendor ディレクトリーにインストールすることが可能になります。 `Plugin` クラスは `load()` や `loadAll()` でプラグインをロードする時に、このファイルを使って 場所を特定します。通常あなたはこのファイルを手動で編集する必要はなく、 Composer や `plugin-installer` パッケージが管理してくれます。 Mixer を使用したプラグインの管理 [​](https://book.cakephp.org/3.x/ja/plugins.html#mixer-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F%E3%83%95%E3%82%9A%E3%83%A9%E3%82%AF%E3%82%99%E3%82%A4%E3%83%B3%E3%81%AE%E7%AE%A1%E7%90%86) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- CakePHP アプリケーションでプラグインを発見して管理する別の方法は、 [Mixer](https://github.com/CakeDC/mixer) です。これは Packagist からプラグインをインストールするのに 便利な CakePHP のプラグインです。また、既存のプラグインを管理するのにも役立ちます。 NOTE 重要: 本番環境でこれを使用しないでください。 --- # JSON and XML views | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/json-and-xml-views.html#VPContent) Return to top JSON and XML views [​](https://book.cakephp.org/3.x/views/json-and-xml-views.html#json-and-xml-views) ====================================================================================================== The `JsonView` and `XmlView` let you create JSON and XML responses, and integrate with the `Cake\Controller\Component\RequestHandlerComponent`. By enabling `RequestHandlerComponent` in your application, and enabling support for the `json` and/or `xml` extensions, you can automatically leverage the new view classes. `JsonView` and `XmlView` will be referred to as data views for the rest of this page. There are two ways you can generate data views. The first is by using the `_serialize` key, and the second is by creating normal template files. Enabling Data Views in Your Application [​](https://book.cakephp.org/3.x/views/json-and-xml-views.html#enabling-data-views-in-your-application) ------------------------------------------------------------------------------------------------------------------------------------------------ Before you can use the data view classes, you'll first need to load the `Cake\Controller\Component\RequestHandlerComponent` in your controller: public function initialize() { ... $this->loadComponent('RequestHandler'); } 1 2 3 4 5 This can be done in your `AppController` and will enable automatic view class switching on content types. You can also set the component up with the `viewClassMap` setting, to map types to your custom classes and/or map other data types. You can optionally enable the json and/or xml extensions with [File Extensions](https://book.cakephp.org/3.x/development/routing.html#file-extensions) . This will allow you to access the `JSON`, `XML` or any other special format views by using a custom URL ending with the name of the response type as a file extension such as `http://example.com/articles.json`. By default, when not enabling [File Extensions](https://book.cakephp.org/3.x/development/routing.html#file-extensions) , the request, the `Accept` header is used for, selecting which type of format should be rendered to the user. An example `Accept` format that is used to render `JSON` responses is `application/json`. Using Data Views with the Serialize Key [​](https://book.cakephp.org/3.x/views/json-and-xml-views.html#using-data-views-with-the-serialize-key) ------------------------------------------------------------------------------------------------------------------------------------------------ The `_serialize` key is a special view variable that indicates which other view variable(s) should be serialized when using a data view. This lets you skip defining template files for your controller actions if you don't need to do any custom formatting before your data is converted into json/xml. If you need to do any formatting or manipulation of your view variables before generating the response, you should use template files. The value of `_serialize` can be either a string or an array of view variables to serialize: namespace App\Controller; class ArticlesController extends AppController { public function initialize() { parent::initialize(); $this->loadComponent('RequestHandler'); } public function index() { // Set the view vars that have to be serialized. $this->set('articles', $this->paginate()); // Specify which view vars JsonView should serialize. $this->set('_serialize', 'articles'); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 You can also define `_serialize` as an array of view variables to combine: namespace App\Controller; class ArticlesController extends AppController { public function initialize() { parent::initialize(); $this->loadComponent('RequestHandler'); } public function index() { // Some code that created $articles and $comments // Set the view vars that have to be serialized. $this->set(compact('articles', 'comments')); // Specify which view vars JsonView should serialize. $this->set('_serialize', ['articles', 'comments']); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Defining `_serialize` as an array has added the benefit of automatically appending a top-level `` element when using `XmlView`. If you use a string value for `_serialize` and XmlView, make sure that your view variable has a single top-level element. Without a single top-level element the Xml will fail to generate. Using a Data View with Template Files [​](https://book.cakephp.org/3.x/views/json-and-xml-views.html#using-a-data-view-with-template-files) -------------------------------------------------------------------------------------------------------------------------------------------- You should use template files if you need to do some manipulation of your view content before creating the final output. For example if we had articles, that had a field containing generated HTML, we would probably want to omit that from a JSON response. This is a situation where a view file would be useful: // Controller code class ArticlesController extends AppController { public function index() { $articles = $this->paginate('Articles'); $this->set(compact('articles')); } } // View code - src/Template/Articles/json/index.ctp foreach ($articles as &$article) { unset($article->generated_html); } echo json_encode(compact('articles')); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 You can do more complex manipulations, or use helpers to do formatting as well. The data view classes don't support layouts. They assume that the view file will output the serialized content. NOTE As of 3.1.0 until 3.5.0, AppController in the application skeleton automatically added `'_serialize' => true` to all XML/JSON requests. You will need to remove this code from the beforeRender callback or set `'_serialize' => false` in your controller's action if you want to use view files. Creating XML Views [​](https://book.cakephp.org/3.x/views/json-and-xml-views.html#creating-xml-views) ------------------------------------------------------------------------------------------------------ `class` **XmlView** By default when using `_serialize` the XmlView will wrap your serialized view variables with a `` node. You can set a custom name for this node using the `_rootNode` view variable. The XmlView class supports the `_xmlOptions` variable that allows you to customize the options used to generate XML, e.g. `tags` vs `attributes`. An example of using `XmlView` would be to generate a [sitemap.xml](https://www.sitemaps.org/protocol.html) . This document type requires that you change `_rootNode` and set attributes. Attributes are defined using the `@` prefix: public function sitemap() { $pages = $this->Pages->find(); $urls = []; foreach ($pages as $page) { $urls[] = [\ 'loc' => Router::url(['controller' => 'Pages', 'action' => 'view', $page->slug, '_full' => true]),\ 'lastmod' => $page->modified->format('Y-m-d'),\ 'changefreq' => 'daily',\ 'priority' => '0.5'\ ]; } // Define a custom root node in the generated document. $this->set('_rootNode', 'urlset'); $this->set([\ // Define an attribute on the root node.\ '@xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9',\ 'url' => $urls\ ]); $this->set('_serialize', ['@xmlns', 'url']); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Creating JSON Views [​](https://book.cakephp.org/3.x/views/json-and-xml-views.html#creating-json-views) -------------------------------------------------------------------------------------------------------- `class` **JsonView** The JsonView class supports the `_jsonOptions` variable that allows you to customize the bit-mask used to generate JSON. See the [json\_encode](https://php.net/json_encode) documentation for the valid values of this option. For example, to serialize validation error output of CakePHP entities in a consistent form of JSON do: // In your controller's action when saving failed $this->set('errors', $articles->errors()); $this->set('_jsonOptions', JSON_FORCE_OBJECT); $this->set('_serialize', ['errors']); 1 2 3 4 ### JSONP Responses [​](https://book.cakephp.org/3.x/views/json-and-xml-views.html#jsonp-responses) When using `JsonView` you can use the special view variable `_jsonp` to enable returning a JSONP response. Setting it to `true` makes the view class check if query string parameter named "callback" is set and if so wrap the json response in the function name provided. If you want to use a custom query string parameter name instead of "callback" set `_jsonp` to required name instead of `true`. Example Usage [​](https://book.cakephp.org/3.x/views/json-and-xml-views.html#example-usage) -------------------------------------------------------------------------------------------- While the [RequestHandlerComponent](https://book.cakephp.org/3.x/controllers/components/request-handling.html) can automatically set the view based on the request content-type or extension, you could also handle view mappings in your controller: // src/Controller/VideosController.php namespace App\Controller; use App\Controller\AppController; // Prior to 3.6 use Cake\Network\Exception\NotFoundException use Cake\Http\Exception\NotFoundException; class VideosController extends AppController { public function export($format = '') { $format = strtolower($format); // Format to view mapping $formats = [\ 'xml' => 'Xml',\ 'json' => 'Json',\ ]; // Error on unknown type if (!isset($formats[$format])) { throw new NotFoundException(__('Unknown format.')); } // Set Out Format View $this->viewBuilder()->className($formats[$format]); // Get data $videos = $this->Videos->find('latest'); // Set Data View $this->set(compact('videos')); $this->set('_serialize', ['videos']); // Set Force Download // Prior to 3.4.0 // $this->response->download('report-' . date('YmdHis') . '.' . $format); return $this->response->withDownload('report-' . date('YmdHis') . '.' . $format); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 --- # View Cells | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/cells.html#VPContent) Return to top View Cells [​](https://book.cakephp.org/3.x/views/cells.html#view-cells) ========================================================================= View cells are small mini-controllers that can invoke view logic and render out templates. The idea of cells is borrowed from [cells in Ruby](https://github.com/trailblazer/cells) , where they fulfill a similar role and purpose. When to use Cells [​](https://book.cakephp.org/3.x/views/cells.html#when-to-use-cells) --------------------------------------------------------------------------------------- Cells are ideal for building reusable page components that require interaction with models, view logic, and rendering logic. A simple example would be the cart in an online store, or a data-driven navigation menu in a CMS. Creating a Cell [​](https://book.cakephp.org/3.x/views/cells.html#creating-a-cell) ----------------------------------------------------------------------------------- To create a cell, define a class in **src/View/Cell** and a template in **src/Template/Cell/**. In this example, we'll be making a cell to display the number of messages in a user's notification inbox. First, create the class file. Its contents should look like: namespace App\View\Cell; use Cake\View\Cell; class InboxCell extends Cell { public function display() { } } 1 2 3 4 5 6 7 8 9 10 Save this file into **src/View/Cell/InboxCell.php**. As you can see, like other classes in CakePHP, Cells have a few conventions: * Cells live in the `App\View\Cell` namespace. If you are making a cell in a plugin, the namespace would be `PluginName\View\Cell`. * Class names should end in Cell. * Classes should inherit from `Cake\View\Cell`. We added an empty `display()` method to our cell; this is the conventional default method when rendering a cell. We'll cover how to use other methods later in the docs. Now, create the file **src/Template/Cell/Inbox/display.ctp**. This will be our template for our new cell. You can generate this stub code quickly using `bake`: bin/cake bake cell Inbox Would generate the code we created above. Implementing the Cell [​](https://book.cakephp.org/3.x/views/cells.html#implementing-the-cell) ----------------------------------------------------------------------------------------------- Assume that we are working on an application that allows users to send messages to each other. We have a `Messages` model, and we want to show the count of unread messages without having to pollute AppController. This is a perfect use case for a cell. In the class we just made, add the following: namespace App\View\Cell; use Cake\View\Cell; class InboxCell extends Cell { public function display() { $this->loadModel('Messages'); $unread = $this->Messages->find('unread'); $this->set('unread_count', $unread->count()); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 Because Cells use the `ModelAwareTrait` and `ViewVarsTrait`, they behave very much like a controller would. We can use the `loadModel()` and `set()` methods just like we would in a controller. In our template file, add the following:
    You have unread messages.
    1 2 3 4 NOTE Cell templates have an isolated scope that does not share the same View instance as the one used to render template and layout for the current controller action or other cells. Hence they are unaware of any helper calls made or blocks set in the action's template / layout and vice versa. Loading Cells [​](https://book.cakephp.org/3.x/views/cells.html#loading-cells) ------------------------------------------------------------------------------- Cells can be loaded from views using the `cell()` method and works the same in both contexts: // Load an application cell $cell = $this->cell('Inbox'); // Load a plugin cell $cell = $this->cell('Messaging.Inbox'); 1 2 3 4 5 The above will load the named cell class and execute the `display()` method. You can execute other methods using the following: // Run the expanded() method on the Inbox cell $cell = $this->cell('Inbox::expanded'); 1 2 If you need controller logic to decide which cells to load in a request, you can use the `CellTrait` in your controller to enable the `cell()` method there: namespace App\Controller; use App\Controller\AppController; use Cake\View\CellTrait; class DashboardsController extends AppController { use CellTrait; // More code. } 1 2 3 4 5 6 7 8 9 10 11 Passing Arguments to a Cell [​](https://book.cakephp.org/3.x/views/cells.html#passing-arguments-to-a-cell) ----------------------------------------------------------------------------------------------------------- You will often want to parameterize cell methods to make cells more flexible. By using the second and third arguments of `cell()`, you can pass action parameters and additional options to your cell classes, as an indexed array: $cell = $this->cell('Inbox::recent', ['-3 days']); 1 The above would match the following function signature: public function recent($since) { } 1 2 3 Rendering a Cell [​](https://book.cakephp.org/3.x/views/cells.html#rendering-a-cell) ------------------------------------------------------------------------------------- Once a cell has been loaded and executed, you'll probably want to render it. The easiest way to render a cell is to echo it: 1 This will render the template matching the lowercased and underscored version of our action name, e.g. **display.ctp**. Because cells use `View` to render templates, you can load additional cells within a cell template if required. NOTE Echoing a cell uses the PHP `__toString()` magic method which prevents PHP from showing the filename and line number for any fatal errors raised. To obtain a meanful error message, it is recommended to use the `Cell::render()` method, for example `render() ?>`. ### Rendering Alternate Templates [​](https://book.cakephp.org/3.x/views/cells.html#rendering-alternate-templates) By convention cells render templates that match the action they are executing. If you need to render a different view template, you can specify the template to use when rendering the cell: // Calling render() explicitly echo $this->cell('Inbox::recent', ['-3 days'])->render('messages'); // Set template before echoing the cell. $cell = $this->cell('Inbox'); $cell->viewBuilder()->setTemplate('messages'); // Before 3.4 $cell->viewBuilder()->template('messages'); // Before 3.1 $cell->template = 'messages'; echo $cell; 1 2 3 4 5 6 7 8 9 10 11 ### Caching Cell Output [​](https://book.cakephp.org/3.x/views/cells.html#caching-cell-output) When rendering a cell you may want to cache the rendered output if the contents don't change often or to help improve performance of your application. You can define the `cache` option when creating a cell to enable & configure caching: // Cache using the default config and a generated key $cell = $this->cell('Inbox', [], ['cache' => true]); // Cache to a specific cache config and a generated key $cell = $this->cell('Inbox', [], ['cache' => ['config' => 'cell_cache']]); // Specify the key and config to use. $cell = $this->cell('Inbox', [], [\ 'cache' => ['config' => 'cell_cache', 'key' => 'inbox_' . $user->id]\ ]); 1 2 3 4 5 6 7 8 9 10 If a key is generated the underscored version of the cell class and template name will be used. NOTE A new `View` instance is used to render each cell and these new objects do not share context with the main template / layout. Each cell is self-contained and only has access to variables passed as arguments to the `View::cell()` call. Paginating Data inside a Cell [​](https://book.cakephp.org/3.x/views/cells.html#paginating-data-inside-a-cell) --------------------------------------------------------------------------------------------------------------- Creating a cell that renders a paginated result set can be done by leveraging the `Paginator` class of the ORM. An example of paginating a user's favorite messages could look like: namespace App\View\Cell; use Cake\View\Cell; use Cake\Datasource\Paginator; class FavoritesCell extends Cell { public function display($user) { $this->loadModel('Messages'); // Create a paginator $paginator = new Paginator(); // Paginate the model $results = $paginator->paginate( $this->Messages, $this->request->getQueryParams(), [\ // Use a parameterized custom finder.\ 'finder' => ['favorites' => [$user]],\ \ // Use scoped query string parameters.\ 'scope' => 'favorites',\ ] ); $paging = $paginator->getPagingParams() + (array)$this->request->getParam('paging'); $this->request = $this->request->withParam('paging', $paging); $this->set('favorites', $results); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 The above cell would paginate the `Messages` model using [scoped pagination parameters](https://book.cakephp.org/3.x/controllers/components/pagination.html#paginating-multiple-queries) . Added in version 3.5.0 `Cake\Datasource\Paginator` was added in 3.5.0. Cell Options [​](https://book.cakephp.org/3.x/views/cells.html#cell-options) ----------------------------------------------------------------------------- Cells can declare constructor options that are converted into properties when creating a cell object: namespace App\View\Cell; use Cake\View\Cell; use Cake\Datasource\Paginator; class FavoritesCell extends Cell { protected $_validCellOptions = ['limit']; protected $limit = 3; public function display($userId) { $this->loadModel('Users'); $result = $this->Users->find('friends', ['for' => $userId]); $this->set('favorites', $result); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Here we have defined a `$limit` property and add `limit` as a cell option. This will allow us to define the option when creating the cell: $cell = $this->cell('Favorites', [$user->id], ['limit' => 10]) 1 Cell options are handy when you want data available as properties allowing you to override default values. --- # CMS Tutorial - Creating the Database | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples/cms/database.html#VPContent) Return to top CMS Tutorial - Creating the Database [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/database.html#cms-tutorial-creating-the-database) =================================================================================================================================================== Now that we have CakePHP installed, let's set up the database for our `CMS (Content Management System)` application. If you haven't already done so, create an empty database for use in this tutorial, with a name of your choice, e.g. `cake_cms`. You can execute the following SQL to create the necessary tables: USE cake_cms; CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, email VARCHAR(255) NOT NULL, password VARCHAR(255) NOT NULL, created DATETIME, modified DATETIME ); CREATE TABLE articles ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, title VARCHAR(255) NOT NULL, slug VARCHAR(191) NOT NULL, body TEXT, published BOOLEAN DEFAULT FALSE, created DATETIME, modified DATETIME, UNIQUE KEY (slug), FOREIGN KEY user_key (user_id) REFERENCES users(id) ) CHARSET=utf8mb4; CREATE TABLE tags ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(191), created DATETIME, modified DATETIME, UNIQUE KEY (title) ) CHARSET=utf8mb4; CREATE TABLE articles_tags ( article_id INT NOT NULL, tag_id INT NOT NULL, PRIMARY KEY (article_id, tag_id), FOREIGN KEY tag_key(tag_id) REFERENCES tags(id), FOREIGN KEY article_key(article_id) REFERENCES articles(id) ); INSERT INTO users (email, password, created, modified) VALUES ('[email protected]', 'secret', NOW(), NOW()); INSERT INTO articles (user_id, title, slug, body, published, created, modified) VALUES (1, 'First Post', 'first-post', 'This is the first post.', 1, now(), now()); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 You may have noticed that the `articles_tags` table used a composite primary key. CakePHP supports composite primary keys almost everywhere allowing you to have simpler schemas that don't require additional `id` columns. The table and column names we used were not arbitrary. By using CakePHP's [naming conventions](https://book.cakephp.org/3.x/intro/conventions.html) , we can leverage CakePHP more effectively and avoid needing to configure the framework. While CakePHP is flexible enough to accommodate almost any database schema, adhering to the conventions will save you time as you can leverage the convention based defaults CakePHP provides. Database Configuration [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/database.html#database-configuration) ------------------------------------------------------------------------------------------------------------------------- Next, let's tell CakePHP where our database is and how to connect to it. Replace the values in the `Datasources.default` array in your **config/app\_local.php** file with those that apply to your setup. A sample completed configuration array might look something like the following: [\ 'default' => [\ 'className' => 'Cake\Database\Connection',\ 'driver' => 'Cake\Database\Driver\Mysql',\ 'persistent' => false,\ 'host' => 'localhost',\ 'username' => 'cakephp',\ 'password' => 'AngelF00dC4k3~',\ 'database' => 'cake_cms',\ 'encoding' => 'utf8mb4',\ 'timezone' => 'UTC',\ 'cacheMetadata' => true,\ ],\ ],\ // More configuration below.\ ]; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Once you've saved your **config/app\_local.php** file, you should see that 'CakePHP is able to connect to the database' section have a green chef hat. NOTE A copy of CakePHP's default configuration file is found in **config/app.default.php**. Creating our First Model [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/database.html#creating-our-first-model) ----------------------------------------------------------------------------------------------------------------------------- Models are the heart of a CakePHP applications. They enable us to read and modify our data. They allow us to build relations between our data, validate data, and apply application rules. Models build the foundations necessary to build our controller actions and templates. CakePHP's models are composed of `Table` and `Entity` objects. `Table` objects provide access to the collection of entities stored in a specific table. They are stored in **src/Model/Table**. The file we'll be creating will be saved to **src/Model/Table/ArticlesTable.php**. The completed file should look like this: addBehavior('Timestamp'); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 We've attached the [Timestamp](https://book.cakephp.org/3.x/orm/behaviors/timestamp.html) behavior which will automatically populate the `created` and `modified` columns of our table. By naming our Table object `ArticlesTable`, CakePHP can use naming conventions to know that our model uses the `articles` table. CakePHP also uses conventions to know that the `id` column is our table's primary key. NOTE CakePHP will dynamically create a model object for you if it cannot find a corresponding file in **src/Model/Table**. This also means that if you accidentally name your file wrong (i.e. articlestable.php or ArticleTable.php), CakePHP will not recognize any of your settings and will use the generated model instead. We'll also create an Entity class for our Articles. Entities represent a single record in the database, and provide row level behavior for our data. Our entity will be saved to **src/Model/Entity/Article.php**. The completed file should look like this: true,\ 'id' => false,\ 'slug' => false,\ ]; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Our entity is quite slim right now, and we've only setup the `_accessible` property which controls how properties can be modified by [Entities Mass Assignment](https://book.cakephp.org/3.x/orm/entities.html#entities-mass-assignment) . We can't do much with our models right now, so next we'll create our first [Controller and Template](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html) to allow us to interact with our model. --- # Time | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/helpers/time.html#VPContent) Return to top Time [​](https://book.cakephp.org/3.x/views/helpers/time.html#time) ==================================================================== `class` Cake\\View\\Helper\\**TimeHelper**(View $view, array $config = \[\]) The TimeHelper allows for the quick processing of time related information. The TimeHelper has two main tasks that it can perform: 1. It can format time strings. 2. It can test time. Using the Helper [​](https://book.cakephp.org/3.x/views/helpers/time.html#using-the-helper) -------------------------------------------------------------------------------------------- A common use of the TimeHelper is to offset the date and time to match a user's time zone. Lets use a forum as an example. Your forum has many users who may post messages at any time from any part of the world. An easy way to manage the time is to save all dates and times as GMT+0 or UTC. Uncomment the line `date_default_timezone_set('UTC');` in **config/bootstrap.php** to ensure your application's time zone is set to GMT+0. Next add a time zone field to your users table and make the necessary modifications to allow your users to set their time zone. Now that we know the time zone of the logged in user we can correct the date and time on our posts using the TimeHelper: echo $this->Time->format( $post->created, \IntlDateFormatter::FULL, null, $user->time_zone ); // Will display 'Saturday, August 22, 2011 at 11:53:00 PM GMT' // for a user in GMT+0. While displaying, // 'Saturday, August 22, 2011 at 03:53 PM GMT-8:00' // for a user in GMT-8 1 2 3 4 5 6 7 8 9 10 Most of TimeHelper's features are intended as backwards compatible interfaces for applications that are upgrading from older versions of CakePHP. Because the ORM returns `Cake\I18n\Time` instances for every `timestamp` and `datetime` column, you can use the methods there to do most tasks. For example, to read about the accepted formatting strings take a look at the [Cake\\I18n\\Time::i18nFormat()](https://api.cakephp.org/3.x/class-Cake.I18n.Time.html#_i18nFormat) method. --- # Helpers | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/helpers.html#VPContent) Return to top Helpers [​](https://book.cakephp.org/3.x/views/helpers.html#helpers) ===================================================================== Helpers are the component-like classes for the presentation layer of your application. They contain presentational logic that is shared between many views, elements, or layouts. This chapter will show you how to configure helpers. How to load helpers and use those helpers, and outline the simple steps for creating your own custom helpers. CakePHP includes a number of helpers that aid in view creation. They assist in creating well-formed markup (including forms), aid in formatting text, times and numbers, and can even speed up AJAX functionality. For more information on the helpers included in CakePHP, check out the chapter for each helper: * [Breadcrumbs](https://book.cakephp.org/3.x/views/helpers/breadcrumbs.html) * [Flash](https://book.cakephp.org/3.x/views/helpers/flash.html) * [Form](https://book.cakephp.org/3.x/views/helpers/form.html) * [Html](https://book.cakephp.org/3.x/views/helpers/html.html) * [Number](https://book.cakephp.org/3.x/views/helpers/number.html) * [Paginator](https://book.cakephp.org/3.x/views/helpers/paginator.html) * [Rss](https://book.cakephp.org/3.x/views/helpers/rss.html) * [Session](https://book.cakephp.org/3.x/views/helpers/session.html) * [Text](https://book.cakephp.org/3.x/views/helpers/text.html) * [Time](https://book.cakephp.org/3.x/views/helpers/time.html) * [Url](https://book.cakephp.org/3.x/views/helpers/url.html) Configuring Helpers [​](https://book.cakephp.org/3.x/views/helpers.html#configuring-helpers) --------------------------------------------------------------------------------------------- You load helpers in CakePHP by declaring them in a view class. An `AppView` class comes with every CakePHP application and is the ideal place to load helpers: class AppView extends View { public function initialize() { parent::initialize(); $this->loadHelper('Html'); $this->loadHelper('Form'); $this->loadHelper('Flash'); } } 1 2 3 4 5 6 7 8 9 10 To load helpers from plugins use the `plugin syntax` used elsewhere in CakePHP: $this->loadHelper('Blog.Comment'); 1 You don't have to explicitly load Helpers that come from CakePHP or your application. These helpers can be lazily loaded upon first use. For example: // Loads the FormHelper if it has not already been loaded. $this->Form->create($article); 1 2 From within a plugin's views, plugin helpers can also be lazily loaded. For example, view templates in the 'Blog' plugin, can lazily load helpers from the same plugin. ### Conditionally Loading Helpers [​](https://book.cakephp.org/3.x/views/helpers.html#conditionally-loading-helpers) You can use the current action name to conditionally load helpers: class AppView extends View { public function initialize() { parent::initialize(); if ($this->request->getParam('action') === 'index') { $this->loadHelper('ListPage'); } } } 1 2 3 4 5 6 7 8 9 10 You can also use your controller's `beforeRender` method to load helpers: class ArticlesController extends AppController { public function beforeRender(Event $event) { parent::beforeRender($event); $this->viewBuilder()->helpers(['MyHelper']); } } 1 2 3 4 5 6 7 8 ### Configuration options [​](https://book.cakephp.org/3.x/views/helpers.html#configuration-options) You can pass configuration options to helpers. These options can be used to set attribute values or modify the behavior of a helper: namespace App\View\Helper; use Cake\View\Helper; use Cake\View\View; class AwesomeHelper extends Helper { // initialize() hook is available since 3.2. For prior versions you can // override the constructor if required. public function initialize(array $config) { debug($config); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Options can be specified when declaring helpers in controller as shown: namespace App\Controller; use App\Controller\AppController; class AwesomeController extends AppController { public $helpers = ['Awesome' => ['option1' => 'value1']]; } 1 2 3 4 5 6 7 8 By default all configuration options will be merged with the `$_defaultConfig` property. This property should define the default values of any configuration your helper requires. For example: namespace App\View\Helper; use Cake\View\Helper; use Cake\View\StringTemplateTrait; class AwesomeHelper extends Helper { use StringTemplateTrait; protected $_defaultConfig = [\ 'errorClass' => 'error',\ 'templates' => [\ 'label' => '',\ ],\ ]; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Any configuration provided to your helper's constructor will be merged with the default values during construction and the merged data will be set to `_config`. You can use the `config()` method to read runtime configuration: // Read the errorClass config option. $class = $this->Awesome->config('errorClass'); 1 2 Using helper configuration allows you to declaratively configure your helpers and keep configuration logic out of your controller actions. If you have configuration options that cannot be included as part of a class declaration, you can set those in your controller's beforeRender callback: class PostsController extends AppController { public function beforeRender(Event $event) { parent::beforeRender($event); $builder = $this->viewBuilder(); $builder->helpers([\ 'CustomStuff' => $this->_getCustomStuffConfig(),\ ]); } } 1 2 3 4 5 6 7 8 9 10 11 ### Aliasing Helpers [​](https://book.cakephp.org/3.x/views/helpers.html#aliasing-helpers) One common setting to use is the `className` option, which allows you to create aliased helpers in your views. This feature is useful when you want to replace `$this->Html` or another common Helper reference with a custom implementation: // src/View/AppView.php class AppView extends View { public function initialize() { $this->loadHelper('Html', [\ 'className' => 'MyHtml'\ ]); } } // src/View/Helper/MyHtmlHelper.php namespace App\View\Helper; use Cake\View\Helper\HtmlHelper; class MyHtmlHelper extends HtmlHelper { // Add your code to override the core HtmlHelper } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 The above would _alias_ `MyHtmlHelper` to `$this->Html` in your views. NOTE Aliasing a helper replaces that instance anywhere that helper is used, including inside other Helpers. Using Helpers [​](https://book.cakephp.org/3.x/views/helpers.html#using-helpers) --------------------------------------------------------------------------------- Once you've configured which helpers you want to use in your controller, each helper is exposed as a public property in the view. For example, if you were using the `HtmlHelper` you would be able to access it by doing the following: echo $this->Html->css('styles'); 1 The above would call the `css()` method on the HtmlHelper. You can access any loaded helper using `$this->{$helperName}`. ### Loading Helpers On The Fly [​](https://book.cakephp.org/3.x/views/helpers.html#loading-helpers-on-the-fly) There may be situations where you need to dynamically load a helper from inside a view. You can use the view's `Cake\View\HelperRegistry` to do this: // Either one works. $mediaHelper = $this->loadHelper('Media', $mediaConfig); $mediaHelper = $this->helpers()->load('Media', $mediaConfig); 1 2 3 The HelperRegistry is a [registry](https://book.cakephp.org/3.x/core-libraries/registry-objects.html) and supports the registry API used elsewhere in CakePHP. Callback Methods [​](https://book.cakephp.org/3.x/views/helpers.html#callback-methods) --------------------------------------------------------------------------------------- Helpers feature several callbacks that allow you to augment the view rendering process. See the [Helper Api](https://book.cakephp.org/3.x/views/helpers.html#helper-api) and the [Events System](https://book.cakephp.org/3.x/core-libraries/events.html) documentation for more information. Creating Helpers [​](https://book.cakephp.org/3.x/views/helpers.html#creating-helpers) --------------------------------------------------------------------------------------- You can create custom helper classes for use in your application or plugins. Like most components of CakePHP, helper classes have a few conventions: * Helper class files should be put in **src/View/Helper**. For example: **src/View/Helper/LinkHelper.php** * Helper classes should be suffixed with `Helper`. For example: `LinkHelper`. * When referencing helper class names you should omit the `Helper` suffix. For example: `$this->loadHelper('Link');`. You'll also want to extend `Helper` to ensure things work correctly: /* src/View/Helper/LinkHelper.php */ namespace App\View\Helper; use Cake\View\Helper; class LinkHelper extends Helper { public function makeEdit($title, $url) { // Logic to create specially formatted link goes here... } } 1 2 3 4 5 6 7 8 9 10 11 12 ### Including Other Helpers [​](https://book.cakephp.org/3.x/views/helpers.html#including-other-helpers) You may wish to use some functionality already existing in another helper. To do so, you can specify helpers you wish to use with a `$helpers` array, formatted just as you would in a controller: /* src/View/Helper/LinkHelper.php (using other helpers) */ namespace App\View\Helper; use Cake\View\Helper; class LinkHelper extends Helper { public $helpers = ['Html']; public function makeEdit($title, $url) { // Use the HTML helper to output // Formatted data: $link = $this->Html->link($title, $url, ['class' => 'edit']); return '
    ' . $link . '
    '; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ### Using Your Helper [​](https://book.cakephp.org/3.x/views/helpers.html#using-your-helper) Once you've created your helper and placed it in **src/View/Helper/**, you can load it in your views: class AppView extends View { public function initialize() { parent::initialize(); $this->loadHelper('Link'); } } 1 2 3 4 5 6 7 8 Once your helper has been loaded, you can use it in your views by accessing the matching view property: Link->makeEdit('Change this Recipe', '/recipes/edit/5') ?> 1 2 NOTE The `HelperRegistry` will attempt to lazy load any helpers not specifically identified in your `Controller`. ### Accessing View Variables Inside Your Helper [​](https://book.cakephp.org/3.x/views/helpers.html#accessing-view-variables-inside-your-helper) If you would like to access a View variable inside a helper, you can use `$this->_View->get()` like: class AwesomeHelper extends Helper { public $helpers = ['Html']; public function someMethod() { // set meta description echo $this->Html->meta( 'description', $this->_View->get('metaDescription'), ['block' => 'meta'] ); } } 1 2 3 4 5 6 7 8 9 10 11 12 ### Rendering A View Element Inside Your Helper [​](https://book.cakephp.org/3.x/views/helpers.html#rendering-a-view-element-inside-your-helper) If you would like to render an Element inside your Helper you can use `$this->_View->element()` like: class AwesomeHelper extends Helper { public function someFunction() { // output directly in your helper echo $this->_View->element( '/path/to/element', ['foo'=>'bar','bar'=>'foo'] ); // or return it to your view return $this->_View->element( '/path/to/element', ['foo'=>'bar','bar'=>'foo'] ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Helper Class [​](https://book.cakephp.org/3.x/views/helpers.html#helper-class) ------------------------------------------------------------------------------- `class` **Helper** ### Callbacks [​](https://book.cakephp.org/3.x/views/helpers.html#callbacks) By implementing a callback method in a helper, CakePHP will automatically subscribe your helper to the relevant event. Unlike previous versions of CakePHP you should _not_ call `parent` in your callbacks, as the base Helper class does not implement any of the callback methods. `method` Helper::**beforeRenderFile**(Event $event, $viewFile) `method` Helper::**afterRenderFile**(Event $event, $viewFile, $content) `method` Helper::**beforeRender**(Event $event, $viewFile) `method` Helper::**afterRender**(Event $event, $viewFile) `method` Helper::**beforeLayout**(Event $event, $layoutFile) `method` Helper::**afterLayout**(Event $event, $layoutFile) --- # Session | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/helpers/session.html#VPContent) Return to top Session [​](https://book.cakephp.org/3.x/views/helpers/session.html#session) ============================================================================= `class` Cake\\View\\Helper\\**SessionHelper**(View $view, array $config = \[\]) Deprecated in version 3.0.0 The SessionHelper is deprecated in 3.x. Instead you should use either the [FlashHelper](https://book.cakephp.org/3.x/views/helpers/flash.html) or [access the session via the request](https://book.cakephp.org/3.x/development/sessions.html#accessing-session-object) . As a natural counterpart to the Session object, the Session Helper replicates most of the object's functionality and makes it available in your view. The major difference between the SessionHelper and the Session object is that the helper does _not_ have the ability to write to the session. As with the session object, data is read by using `dot notation` array structures: ['User' => [\ 'username' => '[email protected]'\ ]]; 1 2 3 Given the previous array structure, the node would be accessed by `User.username`, with the dot indicating the nested array. This notation is used for all SessionHelper methods wherever a `$key` is used. `method` Cake\\View\\Helper\\SessionHelper::**read**(string $key) `method` Cake\\View\\Helper\\SessionHelper::**check**(string $key) --- # Rss | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/helpers/rss.html#VPContent) Return to top Rss [​](https://book.cakephp.org/3.x/views/helpers/rss.html#rss) ================================================================= `class` Cake\\View\\Helper\\**RssHelper**(View $view, array $config = \[\]) The RssHelper makes generating XML for [RSS feeds](https://en.wikipedia.org/wiki/RSS) easy. Deprecated in version 3.5.0 RssHelper is deprecated as of 3.5.0, and will be removed in 4.0.0 Creating an RSS Feed with the RssHelper [​](https://book.cakephp.org/3.x/views/helpers/rss.html#creating-an-rss-feed-with-the-rsshelper) ----------------------------------------------------------------------------------------------------------------------------------------- This example assumes you have a Articles Controller, Articles Table and an Article Entity already created and want to make an alternative view for RSS. Creating an XML/RSS version of your Articles index action is a snap with CakePHP. After a few simple steps you can simply append the desired extension .rss to `articles` making your URL `articles.rss`. This will work with the index action included as well so `articles/index` would become `articles/index.rss` Before we jump too far ahead trying to get our webservice up and running we need to do a few things. First extensions parsing needs to be activated, this is done in **config/routes.php**: Router::extensions('rss'); 1 In the call above we've activated the .rss extension. When using `Cake\Routing\Router::extensions()` you can pass a string or an array of extensions as first argument. This will activate each extension/content-type for use in your application. Now when the address `articles.rss` is requested you will get an XML version of your `articles` index action. However, first we need to edit the controller to add in the rss-specific code. ### Controller Code [​](https://book.cakephp.org/3.x/views/helpers/rss.html#controller-code) It is a good idea to add RequestHandler to your ArticlesController's `initialize()` method. This will allow a lot of automagic to occur: public function initialize() { parent::initialize(); $this->loadComponent('RequestHandler'); } 1 2 3 4 5 Before we can make an RSS version of our `articles` index action we need to get a few things in order. It may be tempting to put the channel metadata in the controller action and pass it to your view using the `Cake\Controller\Controller::set()` method but this is inappropriate. That information can also go in the view. That will come later though, for now if you have a different set of logic for the data used to make the RSS feed and the data for the HTML view you can use the `Cake\Controller\Component\RequestHandler::isRss()` method, otherwise your controller can stay the same: // Modify the Articles Controller action that corresponds to // the action which deliver the rss feed, which is the // Index action in our example. public function index() { if ($this->RequestHandler->isRss() ) { $articles = $this->Articles ->find() ->limit(20) ->order(['created' => 'desc']); $this->set(compact('articles')); } else { // this is not an Rss request, so deliver // data used by website's interface. $this->paginate = [\ 'order' => ['created' => 'desc'],\ 'limit' => 10\ ]; $this->set('articles', $this->paginate($this->Articles)); $this->set('_serialize', ['articles']); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 With all the View variables set we need to create an rss layout. ### Layout [​](https://book.cakephp.org/3.x/views/helpers/rss.html#layout) An Rss layout is very simple, put the following contents in **src/Template/Layout/rss/default.ctp**: if (!isset($documentData)) { $documentData = []; } if (!isset($channelData)) { $channelData = []; } if (!isset($channelData['title'])) { $channelData['title'] = $this->fetch('title'); } $channel = $this->Rss->channel([], $channelData, $this->fetch('content')); echo $this->Rss->document($documentData, $channel); 1 2 3 4 5 6 7 8 9 10 11 It doesn't look like much but thanks to the power in the `RssHelper` it's doing a lot of lifting for us. We haven't set `$documentData` or `$channelData` in the controller, however in CakePHP your views can pass variables back to the layout. Which is where our `$channelData` array will come from setting all of the meta data for our feed. Next up is view file for my articles index action. Much like the layout file we created, we need to create a **src/Template/Articles/rss/** directory and create a new **index.ctp** inside that folder. The contents of the file are below. ### View [​](https://book.cakephp.org/3.x/views/helpers/rss.html#view) Our view, located at **src/Template/Articles/rss/index.ctp**, begins by setting the `$documentData` and `$channelData` variables for the layout, these contain all the metadata for our RSS feed. This is done by using the `Cake\View\View::set()` method which is analogous to the `Cake\Controller\Controller::set()` method. Here though we are passing the channel's metadata back to the layout: $this->set('channelData', [\ 'title' => __("Most Recent Articles"),\ 'link' => $this->Url->build('/', true),\ 'description' => __("Most recent articles."),\ 'language' => 'en-us'\ ]); 1 2 3 4 5 6 The second part of the view generates the elements for the actual records of the feed. This is accomplished by looping through the data that has been passed to the view ($items) and using the `RssHelper::item()` method. The other method you can use, `RssHelper::items()` which takes a callback and an array of items for the feed. The callback method is usually called `transformRss()`. There is one downfall to this method, which is that you cannot use any of the other helper classes to prepare your data inside the callback method because the scope inside the method does not include anything that is not passed inside, thus not giving access to the TimeHelper or any other helper that you may need. The `RssHelper::item()` transforms the associative array into an element for each key value pair. NOTE You will need to modify the $link variable as appropriate to your application. You might also want to use a [virtual field](https://book.cakephp.org/3.x/orm/entities.html#entities-virtual-fields) in your Entity. foreach ($articles as $article) { $created = strtotime($article->created); $link = [\ 'controller' => 'Articles',\ 'action' => 'view',\ 'year' => date('Y', $created),\ 'month' => date('m', $created),\ 'day' => date('d', $created),\ 'slug' => $article->slug\ ]; // Remove & escape any HTML to make sure the feed content will validate. $body = h(strip_tags($article->body)); $body = $this->Text->truncate($body, 400, [\ 'ending' => '...',\ 'exact' => true,\ 'html' => true,\ ]); echo $this->Rss->item([], [\ 'title' => $article->title,\ 'link' => $link,\ 'guid' => ['url' => $link, 'isPermaLink' => 'true'],\ 'description' => $body,\ 'pubDate' => $article->created\ ]); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 You can see above that we can use the loop to prepare the data to be transformed into XML elements. It is important to filter out any non-plain text characters out of the description, especially if you are using a rich text editor for the body of your blog. In the code above we used `strip_tags()` and `h()` to remove/escape any XML special characters from the content, as they could cause validation errors. Once we have set up the data for the feed, we can then use the `RssHelper::item()` method to create the XML in RSS format. Once you have all this setup, you can test your RSS feed by going to your site `/articles.rss` and you will see your new feed. It is always important that you validate your RSS feed before making it live. This can be done by visiting sites that validate the XML such as Feed Validator or the w3c site at [https://validator.w3.org/feed/](https://validator.w3.org/feed/) . NOTE You may need to set the value of 'debug' in your core configuration to `false` to get a valid feed, because of the various debug information added automagically under higher debug settings that break XML syntax or feed validation rules. --- # Plugins | CakePHP [Skip to content](https://book.cakephp.org/3.x/plugins.html#VPContent) Return to top Plugins [​](https://book.cakephp.org/3.x/plugins.html#plugins) =============================================================== CakePHP allows you to set up a combination of controllers, models, and views and release them as a pre-packaged application plugin that others can use in their CakePHP applications. If you've created great user management, a simple blog, or web service adapters in one of your applications, why not package it as a CakePHP plugin? This way you can reuse it in your other applications, and share with the community! A CakePHP plugin is separate from the host application itself and generally provides some well-defined functionality that can be packaged up neatly, and reused with little effort in other applications. The application and the plugin operate in their own respective spaces, but share the application's configuration data (e.g. database connections, email transports) In CakePHP 3.0 each plugin defines its own top-level namespace. For example: `DebugKit`. By convention, plugins use their package name as their namespace. If you'd like to use a different namespace, you can configure the plugin namespace, when plugins are loaded. Installing a Plugin With Composer [​](https://book.cakephp.org/3.x/plugins.html#installing-a-plugin-with-composer) ------------------------------------------------------------------------------------------------------------------- Many plugins are available on [Packagist](https://packagist.org/) and can be installed with `Composer`. To install DebugKit, you would do the following: php composer.phar require cakephp/debug_kit 1 This would install the latest version of DebugKit and update your **composer.json**, **composer.lock** file, update **vendor/cakephp-plugins.php**, and update your autoloader. Manually Installing a Plugin [​](https://book.cakephp.org/3.x/plugins.html#manually-installing-a-plugin) --------------------------------------------------------------------------------------------------------- If the plugin you want to install is not available on packagist.org, you can clone or copy the plugin code into your **plugins** directory. Assuming you want to install a plugin named 'ContactManager', you should have a folder in **plugins** named 'ContactManager'. In this directory are the plugin's src, tests and any other directories. ### Manually Autoloading Plugin Classes [​](https://book.cakephp.org/3.x/plugins.html#manually-autoloading-plugin-classes) If you install your plugins via `composer` or `bake` you shouldn't need to configure class autoloading for your plugins. If we were installing a plugin named `MyPlugin` manually you would need to modify your application's **composer.json** file to contain the following information: { "autoload": { "psr-4": { "MyPlugin\\": "plugins/MyPlugin/src/" } }, "autoload-dev": { "psr-4": { "MyPlugin\\Test\\": "plugins/MyPlugin/tests/" } } } 1 2 3 4 5 6 7 8 9 10 11 12 If you are using vendor namespaces for your plugins, the namespace to path mapping should resemble the following: { "autoload": { "psr-4": { "AcmeCorp\\Users\\": "plugins/AcmeCorp/Users/src/", "AcmeCorp\\Users\\Test\\": "plugins/AcmeCorp/Users/tests/" } } } 1 2 3 4 5 6 7 8 Additionally, you will need to tell Composer to refresh its autoloading cache: php composer.phar dumpautoload 1 If you are unable to use Composer for any reason, you can also configure autoloading with `Plugin`: Plugin::load('ContactManager', ['autoload' => true]); 1 Deprecated in version 3.7.0 Plugin::load() and `autoload` option are deprecated. NOTE IMPORTANT: `autoload` option is not available on `addPlugin()`, you should use `composer dumpautoload` instead. Loading a Plugin [​](https://book.cakephp.org/3.x/plugins.html#loading-a-plugin) --------------------------------------------------------------------------------- If you want to use a plugin's routes, console commands, middleware, or event listeners you will need to load the plugin. Plugins are loaded in your application's `bootstrap()` function: // In src/Application.php. Requires at least 3.6.0 use Cake\Http\BaseApplication; use ContactManager\Plugin as ContactManagerPlugin; class Application extends BaseApplication { public function bootstrap() { parent::bootstrap(); // Load the contact manager plugin by class name $this->addPlugin(ContactManagerPlugin::class); // Load a plugin with a vendor namespace by 'short name' $this->addPlugin('AcmeCorp/ContactManager'); // Load a dev dependency that will not exist in production builds. $this->addOptionalPlugin('AcmeCorp/ContactManager'); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 If you just want to use helpers, behaviors or components from a plugin you do not need to load a plugin. Prior to 3.6.0, you should use `Plugin::load()`: // In config/bootstrap.php // Loads a single plugin Plugin::load('ContactManager'); // Loads a plugin with a vendor namespace at top level. Plugin::load('AcmeCorp/ContactManager'); 1 2 3 4 5 6 7 There is also a handy shell command to enable the plugin. Execute the following line: bin/cake plugin load ContactManager 1 This would update your application's bootstrap method, or put the `$this->addPlugin('ContactManager');` snippet in the bootstrap for you. Added in version 3.6.0 `addPlugin()` was added. Added in version 3.9.0 The `addOptionalPlugin()` method was added. Plugin Hook Configuration [​](https://book.cakephp.org/3.x/plugins.html#plugin-hook-configuration) --------------------------------------------------------------------------------------------------- Plugins offer several hooks that allow a plugin to inject itself into the appropriate parts of your application. The hooks are: * `bootstrap` Used to load plugin default configuration files, define constants and other global functions. * `routes` Used to load routes for a plugin. Fired after application routes are loaded. * `middleware` Used to add plugin middleware to an application's middleware queue. * `console` Used to add console commands to an application's command collection. When loading plugins you can configure which hooks are enabled. By default plugins without a [Plugin Objects](https://book.cakephp.org/3.x/plugins.html#plugin-objects) have all hooks disabled. New style plugins allow plugin authors to set defaults, which can be configured by you in your appliation: // In Application::bootstrap() use ContactManager\Plugin as ContactManagerPlugin; // Disable routes for the ContactManager plugin $this->addPlugin(ContactManagerPlugin::class, ['routes' => false]); 1 2 3 4 5 You can configure hooks with array options, or the methods provided by plugin classes: // In Application::bootstrap() use ContactManager\Plugin as ContactManagerPlugin; // Use the disable/enable to configure hooks. $plugin = new ContactManagerPlugin(); $plugin->disable('bootstrap'); $plugin->enable('routes'); $this->addPlugin($plugin); 1 2 3 4 5 6 7 8 9 Plugin objects also know their names and path information: $plugin = new ContactManagerPlugin(); // Get the plugin name. $name = $plugin->getName(); // Path to the plugin root, and other paths. $path = $plugin->getPath(); $path = $plugin->getConfigPath(); $path = $plugin->getClassPath(); 1 2 3 4 5 6 7 8 9 ### Old Style Plugins [​](https://book.cakephp.org/3.x/plugins.html#old-style-plugins) Prior to 3.6.0, you will need to enable the `bootstrap` and `routes` hooks. Old style plugins do not support `middleware` and `console` hooks: // In config/bootstrap.php, // or in Application::bootstrap() // Using loadAll() Plugin::loadAll([\ 'Blog' => ['routes' => true],\ 'ContactManager' => ['bootstrap' => true],\ 'WebmasterTools' => ['bootstrap' => true, 'routes' => true],\ ]); 1 2 3 4 5 6 7 8 9 Or you can load the plugins individually: // Loading just the blog and include routes Plugin::load('Blog', ['routes' => true]); // Include bootstrap configuration/initializer file. Plugin::load('ContactManager', ['bootstrap' => true]); 1 2 3 4 5 With either approach you no longer need to manually `include()` or `require()` a plugin's configuration or routes file -- it happens automatically at the right time and place. You can specify a set of defaults for `loadAll()` which will apply to every plugin that doesn't have a more specific configuration. The following example will load the bootstrap file from all plugins, and additionally the routes from the Blog plugin: Plugin::loadAll([\ ['bootstrap' => true],\ 'Blog' => ['routes' => true]\ ]); 1 2 3 4 Note that all files specified should actually exist in the configured plugin(s) or PHP will give warnings for each file it cannot load. You can avoid potential warnings by using the `ignoreMissing` option: Plugin::loadAll([\ ['ignoreMissing' => true, 'bootstrap' => true],\ 'Blog' => ['routes' => true]\ ]); 1 2 3 4 When loading plugins, the plugin name used should match the namespace. For example, if you have a plugin with top level namespace `Users` you would load it using: Plugin::load('User'); 1 If you prefer to have your vendor name as top level and have a namespace like `AcmeCorp/Users`, then you would load the plugin as: Plugin::load('AcmeCorp/Users'); 1 This will ensure that classnames are resolved properly when using `plugin syntax`. Most plugins will indicate the proper procedure for configuring them and setting up the database in their documentation. Deprecated in version 3.7.0 Plugin::load() and Plugin::loadAll() are deprecated. Using Plugin Classes [​](https://book.cakephp.org/3.x/plugins.html#using-plugin-classes) ----------------------------------------------------------------------------------------- You can reference a plugin's controllers, models, components, behaviors, and helpers by prefixing the name of the plugin. For example, say you wanted to use the ContactManager plugin's ContactInfoHelper to output formatted contact information in one of your views. In your controller, your `$helpers` array could look like this: public $helpers = ['ContactManager.ContactInfo']; 1 NOTE This dot separated class name is referred to as `plugin syntax`. You would then be able to access the `ContactInfoHelper` just like any other helper in your view, such as: echo $this->ContactInfo->address($contact); 1 Plugins can use the models, components, behaviors and helpers provided by the application, or other plugins if necessary: // Use an application component $this->loadComponent('AppFlash'); // Use another plugin's behavior $this->addBehavior('OtherPlugin.AuditLog'); 1 2 3 4 5 Creating Your Own Plugins [​](https://book.cakephp.org/3.x/plugins.html#creating-your-own-plugins) --------------------------------------------------------------------------------------------------- As a working example, let's begin to create the ContactManager plugin referenced above. To start out, we'll set up our plugin's basic directory structure. It should look like this: /src /plugins /ContactManager /config /src /Plugin.php /Controller /Component /Model /Table /Entity /Behavior /View /Helper /Template /Layout /tests /TestCase /Fixture /webroot Note the name of the plugin folder, '\*\*ContactManager\*\*'. It is important that this folder has the same name as the plugin. Inside the plugin folder, you'll notice it looks a lot like a CakePHP application, and that's basically what it is. You don't have to include any of the folders you are not using. Some plugins might only define a Component and a Behavior, and in that case they can completely omit the 'Template' directory. A plugin can also have basically any of the other directories that your application can, such as Config, Console, webroot, etc. ### Creating a Plugin Using Bake [​](https://book.cakephp.org/3.x/plugins.html#creating-a-plugin-using-bake) The process of creating plugins can be greatly simplified by using bake. In order to bake a plugin, use the following command: bin/cake bake plugin ContactManager 1 Bake can be used to create classes in your plugin. For example to generate a plugin controller you could run: bin/cake bake controller --plugin ContactManager Contacts 1 Please refer to the chapter [Code Generation with Bake](https://book.cakephp.org/3.x/bake/usage.html) if you have any problems with using the command line. Be sure to re-generate your autoloader once you've created your plugin: php composer.phar dumpautoload 1 Plugin Objects [​](https://book.cakephp.org/3.x/plugins.html#plugin-objects) ----------------------------------------------------------------------------- Plugin Objects allow a plugin author to define set-up logic, define default hooks, load routes, middleware and console commands. Plugin objects live in **src/Plugin.php**. For our ContactManager plugin, our plugin class could look like: namespace ContactManager; use Cake\Core\BasePlugin; use Cake\Core\PluginApplicationInterface; class Plugin extends BasePlugin { public function middleware($middleware) { // Add middleware here. $middleware = parent::middleware($middleware); return $middleware; } public function console($commands) { // Add console commands here. $commands = parent::console($commands); return $commands; } public function bootstrap(PluginApplicationInterface $app) { // Add constants, load configuration defaults. // By default will load `config/bootstrap.php` in the plugin. parent::bootstrap($app); // Load another plugin through this plugin $app->addPlugin(\My\Plugin::class); } public function routes($routes) { // Add routes. // By default will load `config/routes.php` in the plugin. parent::routes($routes); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 Added in version 3.6.0 Plugin Objects were added in 3.6.0 Plugin Routes [​](https://book.cakephp.org/3.x/plugins.html#plugin-routes) --------------------------------------------------------------------------- Plugins can provide routes files containing their routes. Each plugin can contain a **config/routes.php** file. This routes file can be loaded when the plugin is added, or in the application's routes file. To create the ContactManager plugin routes, put the following into **plugins/ContactManager/config/routes.php**: '/contact-manager'], function ($routes) { $routes->get('/contacts', ['controller' => 'Contacts']); $routes->get('/contacts/:id', ['controller' => 'Contacts', 'action' => 'view']); $routes->put('/contacts/:id', ['controller' => 'Contacts', 'action' => 'update']); } ); 1 2 3 4 5 6 7 8 9 10 11 12 13 The above will connect default routes for your plugin. You can customize this file with more specific routes later on. Before you can access your controllers, you'll need to ensure the plugin is loaded and the plugin routes are loaded. In your **src/Application.php** add the following: $this->addPlugin('ContactManager', ['routes' => true]); 1 You can also load plugin routes in your application's routes list. Doing this provides you more control on how plugin routes are loaded and allows you to wrap plugin routes in additional scopes or prefixes: Router::scope('/', function ($routes) { // Connect other routes. $routes->scope('/backend', function ($routes) { $routes->loadPlugin('ContactManager'); }); }); 1 2 3 4 5 6 The above would result in URLs like `/backend/contact-manager/contacts`. Added in version 3.5.0 `RouteBuilder::loadPlugin()` was added in 3.5.0 Plugin Controllers [​](https://book.cakephp.org/3.x/plugins.html#plugin-controllers) ------------------------------------------------------------------------------------- Controllers for our ContactManager plugin will be stored in **plugins/ContactManager/src/Controller/**. Since the main thing we'll be doing is managing contacts, we'll need a ContactsController for this plugin. So, we place our new ContactsController in **plugins/ContactManager/src/Controller** and it looks like so: // plugins/ContactManager/src/Controller/ContactsController.php namespace ContactManager\Controller; use ContactManager\Controller\AppController; class ContactsController extends AppController { public function index() { //... } } 1 2 3 4 5 6 7 8 9 10 11 12 Also make the `AppController` if you don't have one already: // plugins/ContactManager/src/Controller/AppController.php namespace ContactManager\Controller; use App\Controller\AppController as BaseController; class AppController extends BaseController { } 1 2 3 4 5 6 7 8 A plugin's `AppController` can hold controller logic common to all controllers in a plugin but is not required if you don't want to use one. If you want to access what we've got going thus far, visit `/contact-manager/contacts`. You should get a "Missing Model" error because we don't have a Contact model defined yet. If your application includes the default routing CakePHP provides you will be able to access your plugin controllers using URLs like: // Access the index route of a plugin controller. /contact-manager/contacts // Any action on a plugin controller. /contact-manager/contacts/view/1 1 2 3 4 5 If your application defines routing prefixes, CakePHP's default routing will also connect routes that use the following pattern: /:prefix/:plugin/:controller /:prefix/:plugin/:controller/:action See the section on [Plugin Configuration](https://book.cakephp.org/3.x/plugins.html#plugin-configuration) for information on how to load plugin specific route files. For plugins you did not create with bake, you will also need to edit the **composer.json** file to add your plugin to the autoload classes, this can be done as per the documentation [Autoloading Plugin Classes](https://book.cakephp.org/3.x/plugins.html#autoloading-plugin-classes) . Plugin Models [​](https://book.cakephp.org/3.x/plugins.html#plugin-models) --------------------------------------------------------------------------- Models for the plugin are stored in **plugins/ContactManager/src/Model**. We've already defined a ContactsController for this plugin, so let's create the table and entity for that controller: // plugins/ContactManager/src/Model/Entity/Contact.php: namespace ContactManager\Model\Entity; use Cake\ORM\Entity; class Contact extends Entity { } // plugins/ContactManager/src/Model/Table/ContactsTable.php: namespace ContactManager\Model\Table; use Cake\ORM\Table; class ContactsTable extends Table { } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 If you need to reference a model within your plugin when building associations or defining entity classes, you need to include the plugin name with the class name, separated with a dot. For example: // plugins/ContactManager/src/Model/Table/ContactsTable.php: namespace ContactManager\Model\Table; use Cake\ORM\Table; class ContactsTable extends Table { public function initialize(array $config) { $this->hasMany('ContactManager.AltName'); } } 1 2 3 4 5 6 7 8 9 10 11 12 If you would prefer that the array keys for the association not have the plugin prefix on them, use the alternative syntax: // plugins/ContactManager/src/Model/Table/ContactsTable.php: namespace ContactManager\Model\Table; use Cake\ORM\Table; class ContactsTable extends Table { public function initialize(array $config) { $this->hasMany('AltName', [\ 'className' => 'ContactManager.AltName',\ ]); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 You can use `TableRegistry` to load your plugin tables using the familiar `plugin syntax`: use Cake\ORM\TableRegistry; // Prior to 3.6 use TableRegistry::get('ContactManager.Contacts') $contacts = TableRegistry::getTableLocator()->get('ContactManager.Contacts'); 1 2 3 4 Alternatively, from a controller context, you can use: $this->loadModel('ContactsManager.Contacts'); 1 Plugin Templates [​](https://book.cakephp.org/3.x/plugins.html#plugin-templates) --------------------------------------------------------------------------------- Views behave exactly as they do in normal applications. Just place them in the right folder inside of the `plugins/[PluginName]/src/Template/` folder. For our ContactManager plugin, we'll need a view for our `ContactsController::index()` action, so let's include that as well: // plugins/ContactManager/src/Template/Contacts/index.ctp:

    Contacts

    Following is a sortable list of your contacts

    1 2 3 4 Plugins can provide their own layouts. To add plugin layouts, place your template files inside `plugins/[PluginName]/src/Template/Layout`. To use a plugin layout in your controller you can do the following: public $layout = 'ContactManager.admin'; 1 If the plugin prefix is omitted, the layout/view file will be located normally. NOTE For information on how to use elements from a plugin, look up [View Elements](https://book.cakephp.org/3.x/views.html#view-elements) ### Overriding Plugin Templates from Inside Your Application [​](https://book.cakephp.org/3.x/plugins.html#overriding-plugin-templates-from-inside-your-application) You can override any plugin views from inside your app using special paths. If you have a plugin called 'ContactManager' you can override the template files of the plugin with application specific view logic by creating files using the following template **src/Template/Plugin/\[Plugin\]/\[Controller\]/\[view\].ctp**. For the Contacts controller you could make the following file: src/Template/Plugin/ContactManager/Contacts/index.ctp Creating this file would allow you to override **plugins/ContactManager/src/Template/Contacts/index.ctp**. If your plugin is in a composer dependency (i.e. 'Company/ContactManager'), the path to the 'index' view of the Contacts controller will be: src/Template/Plugin/Company/ContactManager/Contacts/index.ctp Creating this file would allow you to override **vendor/Company/ContactManager/src/Template/Contacts/index.ctp**. If the plugin implements a routing prefix, you must include the routing prefix in your application template overrides. For example, if the 'ContactManager' plugin implemented an 'admin' prefix the overridng path would be: src/Template/Plugin/Company/ContactManager/Admin/Contact/index.ctp Plugin Assets [​](https://book.cakephp.org/3.x/plugins.html#plugin-assets) --------------------------------------------------------------------------- A plugin's web assets (but not PHP files) can be served through the plugin's `webroot` directory, just like the main application's assets: /plugins/ContactManager/webroot/ css/ js/ img/ flash/ pdf/ You may put any type of file in any directory, just like a regular webroot. WARNING Handling static assets (such as images, JavaScript and CSS files) through the Dispatcher is very inefficient. See [Symlink Assets](https://book.cakephp.org/3.x/deployment.html#symlink-assets) for more information. ### Linking to Assets in Plugins [​](https://book.cakephp.org/3.x/plugins.html#linking-to-assets-in-plugins) You can use the `plugin syntax` when linking to plugin assets using the `Cake\View\Helper\HtmlHelper`'s script, image, or css methods: // Generates a URL of /contact_manager/css/styles.css echo $this->Html->css('ContactManager.styles'); // Generates a URL of /contact_manager/js/widget.js echo $this->Html->script('ContactManager.widget'); // Generates a URL of /contact_manager/img/logo.jpg echo $this->Html->image('ContactManager.logo'); 1 2 3 4 5 6 7 8 Plugin assets are served using the `AssetMiddleware` middleware by default. This is only recommended for development. In production you should [symlink plugin assets](https://book.cakephp.org/3.x/deployment.html#symlink-assets) to improve performance. If you are not using the helpers, you can prepend /plugin\_name/ to the beginning of the URL for an asset within that plugin to serve it. Linking to '/contact\_manager/js/some\_file.js' would serve the asset **plugins/ContactManager/webroot/js/some\_file.js**. Components, Helpers and Behaviors [​](https://book.cakephp.org/3.x/plugins.html#components-helpers-and-behaviors) ------------------------------------------------------------------------------------------------------------------ A plugin can have Components, Helpers and Behaviors just like a CakePHP application. You can even create plugins that consist only of Components, Helpers or Behaviors which can be a great way to build reusable components that can be dropped into any project. Building these components is exactly the same as building it within a regular application, with no special naming convention. Referring to your component from inside or outside of your plugin requires only that you prefix the plugin name before the name of the component. For example: // Component defined in 'ContactManager' plugin namespace ContactManager\Controller\Component; use Cake\Controller\Component; class ExampleComponent extends Component { } // Within your controllers public function initialize() { parent::initialize(); $this->loadComponent('ContactManager.Example'); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 The same technique applies to Helpers and Behaviors. Commands [​](https://book.cakephp.org/3.x/plugins.html#commands) ----------------------------------------------------------------- Plugins can register their commands inside the `console()` hook. By default all shells and commands in the plugin are auto-discovered and added to the application's command list. Plugin commands are prefixed with the plugin name. For example, the `UserCommand` provided by the `ContactManager` plugin would be registered as both `contact_manager.user` and `user`. The un-prefixed name will only be taken by a plugin if it is not used by the application, or another plugin. You can customize the command names by defining each command in your plugin: public function console($commands) { // Create nested commands $commands->add('bake model', ModelCommand::class); $commands->add('bake controller', ControllerCommand::class); return $commands; } 1 2 3 4 5 6 7 8 Testing your Plugin [​](https://book.cakephp.org/3.x/plugins.html#testing-your-plugin) --------------------------------------------------------------------------------------- If you are testing controllers or generating URLs, make sure your plugin connects routes `tests/bootstrap.php`. For more information see [testing plugins](https://book.cakephp.org/3.x/development/testing.html) page. Publishing your Plugin [​](https://book.cakephp.org/3.x/plugins.html#publishing-your-plugin) --------------------------------------------------------------------------------------------- CakePHP plugins should be published to [the packagist](https://packagist.org/) . This way other people can use it as composer dependency. You can also propose your plugin to the [awesome-cakephp list](https://github.com/FriendsOfCake/awesome-cakephp) . Choose a semantically meaningful name for the package name. This should ideally be prefixed with the dependency, in this case "cakephp" as the framework. The vendor name will usually be your GitHub username. Do **not** use the CakePHP namespace (cakephp) as this is reserved to CakePHP owned plugins. The convention is to use lowercase letters and dashes as separator. So if you created a plugin "Logging" with your GitHub account "FooBar", a good name would be foo-bar/cakephp-logging. And the CakePHP owned "Localized" plugin can be found under cakephp/localized respectively. vendor/cakephp-plugins.php Plugin Map File [​](https://book.cakephp.org/3.x/plugins.html#plugin-map-file) ------------------------------------------------------------------------------- When installing plugins via Composer, you may notice that **vendor/cakephp-plugins.php** is created. This configuration file contains a map of plugin names and their paths on the filesystem. It makes it possible for plugins to be installed into the standard vendor directory which is outside of the normal search paths. The `Plugin` class will use this file to locate plugins when they are loaded with `load()` or `loadAll()`. You generally won't need to edit this file by hand, as Composer and the `plugin-installer` package will manage it for you. Manage Your Plugins using Mixer [​](https://book.cakephp.org/3.x/plugins.html#manage-your-plugins-using-mixer) --------------------------------------------------------------------------------------------------------------- Another way to discover and manage plugins into your CakePHP application is [Mixer](https://github.com/CakeDC/mixer) . It is a CakePHP plugin which helps you to install plugins from Packagist. It also helps you to manage your existing plugins. NOTE IMPORTANT: Do not use this in production environment. --- # Number | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/helpers/number.html#VPContent) Return to top Number [​](https://book.cakephp.org/3.x/views/helpers/number.html#number) ========================================================================== `class` Cake\\View\\Helper\\**NumberHelper**(View $view, array $config = \[\]) The NumberHelper contains convenient methods that enable display numbers in common formats in your views. These methods include ways to format currency, percentages, data sizes, format numbers to specific precisions and also to give you more flexibility with formatting numbers. All of these functions return the formatted number; they do not automatically echo the output into the view. Formatting Currency Values [​](https://book.cakephp.org/3.x/views/helpers/number.html#formatting-currency-values) ------------------------------------------------------------------------------------------------------------------ `method` Cake\\I18n\\Number::**currency**(mixed $value, string $currency = null, array $options = \[\]) This method is used to display a number in common currency formats (EUR, GBP, USD). Usage in a view looks like: // Called as NumberHelper echo $this->Number->currency($value, $currency); // Called as Number echo Number::currency($value, $currency); 1 2 3 4 5 The first parameter, `$value`, should be a floating point number that represents the amount of money you are expressing. The second parameter is a string used to choose a predefined currency formatting scheme: | $currency | 1234.56, formatted by currency type | | --- | --- | | EUR | €1.234,56 | | GBP | £1,234.56 | | USD | $1,234.56 | The third parameter is an array of options for further defining the output. The following options are available: | Option | Description | | --- | --- | | before | Text to display before the rendered number. | | after | Text to display after the rendered number. | | zero | The text to use for zero values; can be a string or a number. ie. 0, 'Free!'. | | places | Number of decimal places to use, ie. 2 | | precision | Maximal number of decimal places to use, ie. 2 | | locale | The locale name to use for formatting number, ie. "fr\_FR". | | fractionSymbol | String to use for fraction numbers, ie. ' cents'. | | fractionPosition | Either 'before' or 'after' to place the fraction symbol. | | pattern | An ICU number pattern to use for formatting the number ie. #,###.00 | | useIntlCode | Set to `true` to replace the currency symbol with the international currency code. | If `$currency` value is `null`, the default currency will be retrieved from `Cake\I18n\Number::defaultCurrency()`. To format currencies in an accounting format you should set the currency format: Number::setDefaultCurrencyFormat(Number::FORMAT_CURRENCY_ACCOUNTING); 1 Added in version 3.9.0 Formatting currency as accounting values was added. Setting the Default Currency [​](https://book.cakephp.org/3.x/views/helpers/number.html#setting-the-default-currency) ---------------------------------------------------------------------------------------------------------------------- `method` Cake\\I18n\\Number::**defaultCurrency**($currency) Setter/getter for the default currency. This removes the need to always pass the currency to `Cake\I18n\Number::currency()` and change all currency outputs by setting other default. If `$currency` is set to `false`, it will clear the currently stored value. By default, it will retrieve the `intl.default_locale` if set and 'en\_US' if not. Formatting Floating Point Numbers [​](https://book.cakephp.org/3.x/views/helpers/number.html#formatting-floating-point-numbers) -------------------------------------------------------------------------------------------------------------------------------- `method` Cake\\I18n\\Number::**precision**(float $value, int $precision = 3, array $options = \[\]) This method displays a number with the specified amount of precision (decimal places). It will round in order to maintain the level of precision defined. : // Called as NumberHelper echo $this->Number->precision(456.91873645, 2); // Outputs 456.92 // Called as Number echo Number::precision(456.91873645, 2); 1 2 3 4 5 6 7 8 Formatting Percentages [​](https://book.cakephp.org/3.x/views/helpers/number.html#formatting-percentages) ---------------------------------------------------------------------------------------------------------- `method` Cake\\I18n\\Number::**toPercentage**(mixed $value, int $precision = 2, array $options = \[\]) | Option | Description | | --- | --- | | multiply | Boolean to indicate whether the value has to be multiplied by 100. Useful for decimal percentages. | Like `Cake\I18n\Number::precision()`, this method formats a number according to the supplied precision (where numbers are rounded to meet the given precision). This method also expresses the number as a percentage and appends the output with a percent sign. : // Called as NumberHelper. Output: 45.69% echo $this->Number->toPercentage(45.691873645); // Called as Number. Output: 45.69% echo Number::toPercentage(45.691873645); // Called with multiply. Output: 45.7% echo Number::toPercentage(0.45691, 1, [\ 'multiply' => true\ ]); 1 2 3 4 5 6 7 8 9 10 Interacting with Human Readable Values [​](https://book.cakephp.org/3.x/views/helpers/number.html#interacting-with-human-readable-values) ------------------------------------------------------------------------------------------------------------------------------------------ `method` Cake\\I18n\\Number::**toReadableSize**(string $size) This method formats data sizes in human readable forms. It provides a shortcut way to convert bytes to KB, MB, GB, and TB. The size is displayed with a two-digit precision level, according to the size of data supplied (i.e. higher sizes are expressed in larger terms): // Called as NumberHelper echo $this->Number->toReadableSize(0); // 0 Byte echo $this->Number->toReadableSize(1024); // 1 KB echo $this->Number->toReadableSize(1321205.76); // 1.26 MB echo $this->Number->toReadableSize(5368709120); // 5 GB // Called as Number echo Number::toReadableSize(0); // 0 Byte echo Number::toReadableSize(1024); // 1 KB echo Number::toReadableSize(1321205.76); // 1.26 MB echo Number::toReadableSize(5368709120); // 5 GB 1 2 3 4 5 6 7 8 9 10 11 Formatting Numbers [​](https://book.cakephp.org/3.x/views/helpers/number.html#formatting-numbers) -------------------------------------------------------------------------------------------------- `method` Cake\\I18n\\Number::**format**(mixed $value, array $options = \[\]) This method gives you much more control over the formatting of numbers for use in your views (and is used as the main method by most of the other NumberHelper methods). Using this method might looks like: // Called as NumberHelper $this->Number->format($value, $options); // Called as Number Number::format($value, $options); 1 2 3 4 5 The `$value` parameter is the number that you are planning on formatting for output. With no `$options` supplied, the number 1236.334 would output as 1,236. Note that the default precision is zero decimal places. The `$options` parameter is where the real magic for this method resides. * If you pass an integer then this becomes the amount of precision or places for the function. * If you pass an associated array, you can use the following keys: | Option | Description | | --- | --- | | places | Number of decimal places to use, ie. 2 | | precision | Maximum number of decimal places to use, ie. 2 | | pattern | An ICU number pattern to use for formatting the number ie. #,###.00 | | locale | The locale name to use for formatting number, ie. "fr\_FR". | | before | Text to display before the rendered number. | | after | Text to display after the rendered number. | Example: // Called as NumberHelper echo $this->Number->format('123456.7890', [\ 'places' => 2,\ 'before' => '¥ ',\ 'after' => ' !'\ ]); // Output '¥ 123,456.79 !' echo $this->Number->format('123456.7890', [\ 'locale' => 'fr_FR'\ ]); // Output '123 456,79 !' // Called as Number echo Number::format('123456.7890', [\ 'places' => 2,\ 'before' => '¥ ',\ 'after' => ' !'\ ]); // Output '¥ 123,456.79 !' echo Number::format('123456.7890', [\ 'locale' => 'fr_FR'\ ]); // Output '123 456,79 !' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 `method` Cake\\I18n\\Number::**ordinal**(mixed $value, array $options = \[\]) This method will output an ordinal number. Examples: echo Number::ordinal(1); // Output '1st' echo Number::ordinal(2); // Output '2nd' echo Number::ordinal(2, [\ 'locale' => 'fr_FR'\ ]); // Output '2e' echo Number::ordinal(410); // Output '410th' 1 2 3 4 5 6 7 8 9 10 11 12 13 Format Differences [​](https://book.cakephp.org/3.x/views/helpers/number.html#format-differences) -------------------------------------------------------------------------------------------------- `method` Cake\\I18n\\Number::**formatDelta**(mixed $value, array $options = \[\]) This method displays differences in value as a signed number: // Called as NumberHelper $this->Number->formatDelta($value, $options); // Called as Number Number::formatDelta($value, $options); 1 2 3 4 5 The `$value` parameter is the number that you are planning on formatting for output. With no `$options` supplied, the number 1236.334 would output as 1,236. Note that the default precision is zero decimal places. The `$options` parameter takes the same keys as `Number::format()` itself: | Option | Description | | --- | --- | | places | Number of decimal places to use, ie. 2 | | precision | Maximum number of decimal places to use, ie. 2 | | locale | The locale name to use for formatting number, ie. "fr\_FR". | | before | Text to display before the rendered number. | | after | Text to display after the rendered number. | Example: // Called as NumberHelper echo $this->Number->formatDelta('123456.7890', [\ 'places' => 2,\ 'before' => '[',\ 'after' => ']'\ ]); // Output '[+123,456.79]' // Called as Number echo Number::formatDelta('123456.7890', [\ 'places' => 2,\ 'before' => '[',\ 'after' => ']'\ ]); // Output '[+123,456.79]' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 WARNING All symbols are UTF-8. --- # Text | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/helpers/text.html#VPContent) Return to top Text [​](https://book.cakephp.org/3.x/views/helpers/text.html#text) ==================================================================== `class` Cake\\View\\Helper\\**TextHelper**(View $view, array $config = \[\]) The TextHelper contains methods to make text more usable and friendly in your views. It aids in enabling links, formatting URLs, creating excerpts of text around chosen words or phrases, highlighting key words in blocks of text, and gracefully truncating long stretches of text. Linking Email addresses [​](https://book.cakephp.org/3.x/views/helpers/text.html#linking-email-addresses) ---------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\TextHelper::**autoLinkEmails**(string $text, array $options = \[\]) Adds links to the well-formed email addresses in $text, according to any options defined in `$options` (see `HtmlHelper::link()`). : $myText = 'For more information regarding our world-famous ' . 'pastries and desserts, contact [email protected]'; $linkedText = $this->Text->autoLinkEmails($myText); 1 2 3 Output: For more information regarding our world-famous pastries and desserts, contact
    [email protected] 1 2 This method automatically escapes its input. Use the `escape` option to disable this if necessary. Linking URLs [​](https://book.cakephp.org/3.x/views/helpers/text.html#linking-urls) ------------------------------------------------------------------------------------ `method` Cake\\View\\Helper\\TextHelper::**autoLinkUrls**(string $text, array $options = \[\]) Same as `autoLinkEmails()`, only this method searches for strings that start with https, http, ftp, or nntp and links them appropriately. This method automatically escapes its input. Use the `escape` option to disable this if necessary. Linking Both URLs and Email Addresses [​](https://book.cakephp.org/3.x/views/helpers/text.html#linking-both-urls-and-email-addresses) -------------------------------------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\TextHelper::**autoLink**(string $text, array $options = \[\]) Performs the functionality in both `autoLinkUrls()` and `autoLinkEmails()` on the supplied `$text`. All URLs and emails are linked appropriately given the supplied `$options`. This method automatically escapes its input. Use the `escape` option to disable this if necessary. Converting Text into Paragraphs [​](https://book.cakephp.org/3.x/views/helpers/text.html#converting-text-into-paragraphs) -------------------------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\TextHelper::**autoParagraph**(string $text) Adds proper

    around text where double-line returns are found, and
    where single-line returns are found. : $myText = 'For more information regarding our world-famous pastries and desserts. contact [email protected]'; $formattedText = $this->Text->autoParagraph($myText); 1 2 3 4 5 Output:

    For more information
    regarding our world-famous pastries and desserts.

    contact [email protected]

    1 2 3 Highlighting Substrings [​](https://book.cakephp.org/3.x/views/helpers/text.html#highlighting-substrings) ---------------------------------------------------------------------------------------------------------- `method` Cake\\Utility\\Text::**highlight**(string $haystack, string $needle, array $options = \[\] ) Highlights `$needle` in `$haystack` using the `$options['format']` string specified or a default string. Options: * `format` string - The piece of HTML with the phrase that will be highlighted * `html` bool - If `true`, will ignore any HTML tags, ensuring that only the correct text is highlighted Example: // Called as TextHelper echo $this->Text->highlight( $lastSentence, 'using', ['format' => '\1'] ); // Called as Text use Cake\Utility\Text; echo Text::highlight( $lastSentence, 'using', ['format' => '\1'] ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Output: Highlights $needle in $haystack using the $options['format'] string specified or a default string. Removing Links [​](https://book.cakephp.org/3.x/views/helpers/text.html#removing-links) ---------------------------------------------------------------------------------------- `method` Cake\\Utility\\Text::**stripLinks**($text) Strips the supplied `$text` of any HTML links. Truncating Text [​](https://book.cakephp.org/3.x/views/helpers/text.html#truncating-text) ------------------------------------------------------------------------------------------ `method` Cake\\Utility\\Text::**truncate**(string $text, int $length = 100, array $options) If `$text` is longer than `$length`, this method truncates it at `$length` and adds a suffix consisting of `'ellipsis'`, if defined. If `'exact'` is passed as `false`, the truncation will occur at the first whitespace after the point at which `$length` is exceeded. If `'html'` is passed as `true`, HTML tags will be respected and will not be cut off. `$options` is used to pass all extra parameters, and has the following possible keys by default, all of which are optional: [\ 'ellipsis' => '...',\ 'exact' => true,\ 'html' => false\ ] 1 2 3 4 5 Example: // Called as TextHelper echo $this->Text->truncate( 'The killer crept forward and tripped on the rug.', 22, [\ 'ellipsis' => '...',\ 'exact' => false\ ] ); // Called as Text use Cake\Utility\Text; echo Text::truncate( 'The killer crept forward and tripped on the rug.', 22, [\ 'ellipsis' => '...',\ 'exact' => false\ ] ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Output: The killer crept... Truncating the Tail of a String [​](https://book.cakephp.org/3.x/views/helpers/text.html#truncating-the-tail-of-a-string) -------------------------------------------------------------------------------------------------------------------------- `method` Cake\\Utility\\Text::**tail**(string $text, int $length = 100, array $options) If `$text` is longer than `$length`, this method removes an initial substring with length consisting of the difference and prepends a prefix consisting of `'ellipsis'`, if defined. If `'exact'` is passed as `false`, the truncation will occur at the first whitespace prior to the point at which truncation would otherwise take place. `$options` is used to pass all extra parameters, and has the following possible keys by default, all of which are optional: [\ 'ellipsis' => '...',\ 'exact' => true\ ] 1 2 3 4 Example: $sampleText = 'I packed my bag and in it I put a PSP, a PS3, a TV, ' . 'a C# program that can divide by zero, death metal t-shirts' // Called as TextHelper echo $this->Text->tail( $sampleText, 70, [\ 'ellipsis' => '...',\ 'exact' => false\ ] ); // Called as Text use Cake\Utility\Text; echo Text::tail( $sampleText, 70, [\ 'ellipsis' => '...',\ 'exact' => false\ ] ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Output: ...a TV, a C# program that can divide by zero, death metal t-shirts Extracting an Excerpt [​](https://book.cakephp.org/3.x/views/helpers/text.html#extracting-an-excerpt) ------------------------------------------------------------------------------------------------------ `method` Cake\\Utility\\Text::**excerpt**(string $haystack, string $needle, integer $radius=100, string $ellipsis="...") Extracts an excerpt from `$haystack` surrounding the `$needle` with a number of characters on each side determined by `$radius`, and prefix/suffix with `$ellipsis`. This method is especially handy for search results. The query string or keywords can be shown within the resulting document. : // Called as TextHelper echo $this->Text->excerpt($lastParagraph, 'method', 50, '...'); // Called as Text use Cake\Utility\Text; echo Text::excerpt($lastParagraph, 'method', 50, '...'); 1 2 3 4 5 6 7 Output: ... by $radius, and prefix/suffix with $ellipsis. This method is especially handy for search results. The query... Converting an Array to Sentence Form [​](https://book.cakephp.org/3.x/views/helpers/text.html#converting-an-array-to-sentence-form) ------------------------------------------------------------------------------------------------------------------------------------ `method` Cake\\Utility\\Text::**toList**(array $list, $and='and', $separator=', ') Creates a comma-separated list where the last two items are joined with 'and': $colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']; // Called as TextHelper echo $this->Text->toList($colors); // Called as Text use Cake\Utility\Text; echo Text::toList($colors); 1 2 3 4 5 6 7 8 9 Output: red, orange, yellow, green, blue, indigo and violet --- # CMS Tutorial - Creating the Articles Controller | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#VPContent) Return to top CMS Tutorial - Creating the Articles Controller [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#cms-tutorial-creating-the-articles-controller) ==================================================================================================================================================================================== With our model created, we need a controller for our articles. Controllers in CakePHP handle HTTP requests and execute business logic contained in model methods, to prepare the response. We'll place this new controller in a file called **ArticlesController.php** inside the **src/Controller** directory. Here's what the basic controller should look like: loadComponent('Paginator'); $articles = $this->Paginator->paginate($this->Articles->find()); $this->set(compact('articles')); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 By defining function `index()` in our `ArticlesController`, users can now access the logic there by requesting **www.example.com/articles/index**. Similarly, if we were to define a function called `foobar()`, users would be able to access that at **www.example.com/articles/foobar**. You may be tempted to name your controllers and actions in a way that allows you to obtain specific URLs. Resist that temptation. Instead, follow the [CakePHP Conventions](https://book.cakephp.org/3.x/intro/conventions.html) creating readable, meaningful action names. You can then use [Routing](https://book.cakephp.org/3.x/development/routing.html) to connect the URLs you want to the actions you've created. Our controller action is very simple. It fetches a paginated set of articles from the database, using the Articles Model that is automatically loaded via naming conventions. It then uses `set()` to pass the articles into the Template (which we'll create soon). CakePHP will automatically render the template after our controller action completes. Create the Article List Template [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#create-the-article-list-template) -------------------------------------------------------------------------------------------------------------------------------------------------------- Now that we have our controller pulling data from the model, and preparing our view context, let's create a view template for our index action. CakePHP view templates are presentation-flavored PHP code that is inserted inside the application's layout. While we'll be creating HTML here, Views can also generate JSON, CSV or even binary files like PDFs. A layout is presentation code that is wrapped around a view. Layout files contain common site elements like headers, footers and navigation elements. Your application can have multiple layouts, and you can switch between them, but for now, let's just use the default layout. CakePHP's template files are stored in **src/Template** inside a folder named after the controller they correspond to. So we'll have to create a folder named 'Articles' in this case. Add the following code to your application:

    Articles

    Title Created
    Html->link($article->title, ['action' => 'view', $article->slug]) ?> created->format(DATE_RFC850) ?>
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 In the last section we assigned the 'articles' variable to the view using `set()`. Variables passed into the view are available in the view templates as local variables which we used in the above code. You might have noticed the use of an object called `$this->Html`. This is an instance of the CakePHP [HtmlHelper](https://book.cakephp.org/3.x/views/helpers/html.html) . CakePHP comes with a set of view helpers that make tasks like creating links, forms, and pagination buttons easy. You can learn more about [Helpers](https://book.cakephp.org/3.x/views/helpers.html) in their chapter, but what's important to note here is that the `link()` method will generate an HTML link with the given link text (the first parameter) and URL (the second parameter). When specifying URLs in CakePHP, it is recommended that you use arrays or [named routes](https://book.cakephp.org/3.x/development/routing.html#named-routes) . These syntaxes allow you to leverage the reverse routing features CakePHP offers. At this point, you should be able to point your browser to **[http://localhost:8765/articles/index](http://localhost:8765/articles/index) **. You should see your list view, correctly formatted with the title and table listing of the articles. Create the View Action [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#create-the-view-action) ------------------------------------------------------------------------------------------------------------------------------------ If you were to click one of the 'view' links in our Articles list page, you'd see an error page saying that action hasn't been implemented. Lets fix that now: // Add to existing src/Controller/ArticlesController.php file public function view($slug = null) { $article = $this->Articles->findBySlug($slug)->firstOrFail(); $this->set(compact('article')); } 1 2 3 4 5 6 7 While this is a simple action, we've used some powerful CakePHP features. We start our action off by using `findBySlug()` which is a [Dynamic Finder](https://book.cakephp.org/3.x/orm/retrieving-data-and-resultsets.html#dynamic-finders) . This method allows us to create a basic query that finds articles by a given slug. We then use `firstOrFail()` to either fetch the first record, or throw a `NotFoundException`. Our action takes a `$slug` parameter, but where does that parameter come from? If a user requests `/articles/view/first-post`, then the value 'first-post' is passed as `$slug` by CakePHP's routing and dispatching layers. If we reload our browser with our new action saved, we'd see another CakePHP error page telling us we're missing a view template; let's fix that. Create the View Template [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#create-the-view-template) ---------------------------------------------------------------------------------------------------------------------------------------- Let's create the view for our new 'view' action and place it in **src/Template/Articles/view.ctp**

    title) ?>

    body) ?>

    Created: created->format(DATE_RFC850) ?>

    Html->link('Edit', ['action' => 'edit', $article->slug]) ?>

    1 2 3 4 5 6 You can verify that this is working by trying the links at `/articles/index` or manually requesting an article by accessing URLs like `/articles/view/first-post`. Adding Articles [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#adding-articles) ---------------------------------------------------------------------------------------------------------------------- With the basic read views created, we need to make it possible for new articles to be created. Start by creating an `add()` action in the `ArticlesController`. Our controller should now look like: // src/Controller/ArticlesController.php namespace App\Controller; use App\Controller\AppController; class ArticlesController extends AppController { public function initialize() { parent::initialize(); $this->loadComponent('Paginator'); $this->loadComponent('Flash'); // Include the FlashComponent } public function index() { $articles = $this->Paginator->paginate($this->Articles->find()); $this->set(compact('articles')); } public function view($slug) { $article = $this->Articles->findBySlug($slug)->firstOrFail(); $this->set(compact('article')); } public function add() { $article = $this->Articles->newEntity(); if ($this->request->is('post')) { $article = $this->Articles->patchEntity($article, $this->request->getData()); // Hardcoding the user_id is temporary, and will be removed later // when we build authentication out. $article->user_id = 1; if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to add your article.')); } $this->set('article', $article); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 NOTE You need to include the [Flash](https://book.cakephp.org/3.x/controllers/components/flash.html) component in any controller where you will use it. Often it makes sense to include it in your `AppController`. Here's what the `add()` action does: * If the HTTP method of the request was POST, try to save the data using the Articles model. * If for some reason it doesn't save, just render the view. This gives us a chance to show the user validation errors or other warnings. Every CakePHP request includes a request object which is accessible using `$this->request`. The request object contains information regarding the request that was just received. We use the `Cake\Http\ServerRequest::is()` method to check that the request is a HTTP POST request. Our POST data is available in `$this->request->getData()`. You can use the `pr()` or `debug()` functions to print it out if you want to see what it looks like. To save our data, we first 'marshal' the POST data into an Article Entity. The Entity is then persisted using the ArticlesTable we created earlier. After saving our new article we use FlashComponent's `success()` method to set a message into the session. The `success` method is provided using PHP's [magic method features](https://php.net/manual/en/language.oop5.overloading.php#object.call) . Flash messages will be displayed on the next page after redirecting. In our layout we have `Flash->render() ?>` which displays flash messages and clears the corresponding session variable. Finally, after saving is complete, we use `Cake\Controller\Controller::redirect` to send the user back to the articles list. The param `['action' => 'index']` translates to URL `/articles` i.e the index action of the `ArticlesController`. You can refer to `Cake\Routing\Router::url()` function on the [API](https://api.cakephp.org/) to see the formats in which you can specify a URL for various CakePHP functions. Create Add Template [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#create-add-template) ------------------------------------------------------------------------------------------------------------------------------ Here's our add view template:

    Add Article

    Form->create($article); // Hard code the user for now. echo $this->Form->control('user_id', ['type' => 'hidden', 'value' => 1]); echo $this->Form->control('title'); echo $this->Form->control('body', ['rows' => '3']); echo $this->Form->button(__('Save Article')); echo $this->Form->end(); ?> 1 2 3 4 5 6 7 8 9 10 11 12 We use the FormHelper to generate the opening tag for an HTML form. Here's the HTML that `$this->Form->create()` generates: 1 Because we called `create()` without a URL option, `FormHelper` assumes we want the form to submit back to the current action. The `$this->Form->control()` method is used to create form elements of the same name. The first parameter tells CakePHP which field they correspond to, and the second parameter allows you to specify a wide array of options - in this case, the number of rows for the textarea. There's a bit of introspection and conventions used here. The `control()` will output different form elements based on the model field specified, and use inflection to generate the label text. You can customize the label, the input or any other aspect of the form controls using options. The `$this->Form->end()` call closes the form. Now let's go back and update our **src/Template/Articles/index.ctp** view to include a new "Add Article" link. Before the ``, add the following line: Html->link('Add Article', ['action' => 'add']) ?> 1 Adding Simple Slug Generation [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#adding-simple-slug-generation) -------------------------------------------------------------------------------------------------------------------------------------------------- If we were to save an Article right now, saving would fail as we are not creating a slug attribute, and the column is `NOT NULL`. Slug values are typically a URL-safe version of an article's title. We can use the [beforeSave() callback](https://book.cakephp.org/3.x/orm/table-objects.html#table-callbacks) of the ORM to populate our slug: // in src/Model/Table/ArticlesTable.php namespace App\Model\Table; use Cake\ORM\Table; // the Text class use Cake\Utility\Text; // Add the following method. public function beforeSave($event, $entity, $options) { if ($entity->isNew() && !$entity->slug) { $sluggedTitle = Text::slug($entity->title); // trim slug to maximum length defined in schema $entity->slug = substr($sluggedTitle, 0, 191); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 This code is simple, and doesn't take into account duplicate slugs. But we'll fix that later on. Add Edit Action [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#add-edit-action) ---------------------------------------------------------------------------------------------------------------------- Our application can now save articles, but we can't edit them. Lets rectify that now. Add the following action to your `ArticlesController`: // in src/Controller/ArticlesController.php // Add the following method. public function edit($slug) { $article = $this->Articles->findBySlug($slug)->firstOrFail(); if ($this->request->is(['post', 'put'])) { $this->Articles->patchEntity($article, $this->request->getData()); if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been updated.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to update your article.')); } $this->set('article', $article); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 This action first ensures that the user has tried to access an existing record. If they haven't passed in an `$slug` parameter, or the article does not exist, a `NotFoundException` will be thrown, and the CakePHP ErrorHandler will render the appropriate error page. Next the action checks whether the request is either a POST or a PUT request. If it is, then we use the POST/PUT data to update our article entity by using the `patchEntity()` method. Finally, we call `save()` set the appropriate flash message and either redirect or display validation errors. Create Edit Template [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#create-edit-template) -------------------------------------------------------------------------------------------------------------------------------- The edit template should look like this:

    Edit Article

    Form->create($article); echo $this->Form->control('user_id', ['type' => 'hidden']); echo $this->Form->control('title'); echo $this->Form->control('body', ['rows' => '3']); echo $this->Form->button(__('Save Article')); echo $this->Form->end(); ?> 1 2 3 4 5 6 7 8 9 10 11 This template outputs the edit form (with the values populated), along with any necessary validation error messages. You can now update your index view with links to edit specific articles:

    Articles

    Html->link("Add Article", ['action' => 'add']) ?>

    Title Created Action
    Html->link($article->title, ['action' => 'view', $article->slug]) ?> created->format(DATE_RFC850) ?> Html->link('Edit', ['action' => 'edit', $article->slug]) ?>
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 Update Validation Rules for Articles [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#update-validation-rules-for-articles) ---------------------------------------------------------------------------------------------------------------------------------------------------------------- Up until this point our Articles had no input validation done. Lets fix that by using [a validator](https://book.cakephp.org/3.x/orm/validation.html#validating-request-data) : // src/Model/Table/ArticlesTable.php // add this use statement right below the namespace declaration to import // the Validator class use Cake\Validation\Validator; // Add the following method. public function validationDefault(Validator $validator) { $validator ->allowEmptyString('title', 'Title cannot be empty', false) ->minLength('title', 10) ->maxLength('title', 255); $validator ->allowEmptyString('body', 'Body cannot be empty', false) ->minLength('body', 10); return $validator; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 The `validationDefault()` method tells CakePHP how to validate your data when the `save()` method is called. Here, we've specified that both the title, and body fields must not be empty, and have certain length constraints. CakePHP's validation engine is powerful and flexible. It provides a suite of frequently used rules for tasks like email addresses, IP addresses etc. and the flexibility for adding your own validation rules. For more information on that setup, check the [Validation](https://book.cakephp.org/3.x/core-libraries/validation.html) documentation. Now that your validation rules are in place, use the app to try to add an article with an empty title or body to see how it works. Since we've used the `Cake\View\Helper\FormHelper::control()` method of the FormHelper to create our form elements, our validation error messages will be shown automatically. Add Delete Action [​](https://book.cakephp.org/3.x/tutorials-and-examples/cms/articles-controller.html#add-delete-action) -------------------------------------------------------------------------------------------------------------------------- Next, let's make a way for users to delete articles. Start with a `delete()` action in the `ArticlesController`: // src/Controller/ArticlesController.php public function delete($slug) { $this->request->allowMethod(['post', 'delete']); $article = $this->Articles->findBySlug($slug)->firstOrFail(); if ($this->Articles->delete($article)) { $this->Flash->success(__('The {0} article has been deleted.', $article->title)); return $this->redirect(['action' => 'index']); } } 1 2 3 4 5 6 7 8 9 10 11 12 This logic deletes the article specified by `$slug`, and uses `$this->Flash->success()` to show the user a confirmation message after redirecting them to `/articles`. If the user attempts to delete an article using a GET request, `allowMethod()` will throw an exception. Uncaught exceptions are captured by CakePHP's exception handler, and a nice error page is displayed. There are many built-in [Exceptions](https://book.cakephp.org/3.x/development/errors.html) that can be used to indicate the various HTTP errors your application might need to generate. WARNING Allowing content to be deleted using GET requests is _very_ dangerous, as web crawlers could accidentally delete all your content. That is why we used `allowMethod()` in our controller. Because we're only executing logic and redirecting to another action, this action has no template. You might want to update your index template with links that allow users to delete articles:

    Articles

    Html->link("Add Article", ['action' => 'add']) ?>

    Title Created Action
    Html->link($article->title, ['action' => 'view', $article->slug]) ?> created->format(DATE_RFC850) ?> Html->link('Edit', ['action' => 'edit', $article->slug]) ?> Form->postLink( 'Delete', ['action' => 'delete', $article->slug], ['confirm' => 'Are you sure?']) ?>
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 Using `Cake\View\Helper\FormHelper::postLink()` will create a link that uses JavaScript to do a POST request deleting our article. NOTE This view code also uses the `FormHelper` to prompt the user with a JavaScript confirmation dialog before they attempt to delete an article. With a basic articles management setup, we'll create the [basic actions for our Tags and Users tables](https://book.cakephp.org/3.x/tutorials-and-examples/cms/tags-and-users.html) . --- # Breadcrumbs | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/helpers/breadcrumbs.html#VPContent) Return to top `class` Cake\\View\\Helper\\**BreadcrumbsHelper**(View $view, array $config = \[\]) Added in version 3.3.6 BreadcrumbsHelper provides a way to easily deal with the creation and rendering of a breadcrumbs trail for your app. Creating a Breadcrumbs Trail [​](https://book.cakephp.org/3.x/views/helpers/breadcrumbs.html#creating-a-breadcrumbs-trail) --------------------------------------------------------------------------------------------------------------------------- You can add a crumb to the list using the `add()` method. It takes three arguments: * **title** The string to be displayed as a the title of the crumb * **url** A string or an array of parameters that will be given to the [Url](https://book.cakephp.org/3.x/views/helpers/url.html) * **options** An array of attributes for the `item` and `itemWithoutLink` templates. See the section about [defining attributes for the item](https://book.cakephp.org/3.x/views/helpers/breadcrumbs.html#defining-attributes-item) for more information. In addition to adding to the end of the trail, you can do a variety of operations: // Add at the end of the trail $this->Breadcrumbs->add( 'Products', ['controller' => 'products', 'action' => 'index'] ); // Add multiple crumbs at the end of the trail $this->Breadcrumbs->add([\ ['title' => 'Products', 'url' => ['controller' => 'products', 'action' => 'index']],\ ['title' => 'Product name', 'url' => ['controller' => 'products', 'action' => 'view', 1234]]\ ]); // Prepended crumbs will be put at the top of the list $this->Breadcrumbs->prepend( 'Products', ['controller' => 'products', 'action' => 'index'] ); // Prepend multiple crumbs at the top of the trail, in the order given $this->Breadcrumbs->prepend([\ ['title' => 'Products', 'url' => ['controller' => 'products', 'action' => 'index']],\ ['title' => 'Product name', 'url' => ['controller' => 'products', 'action' => 'view', 1234]]\ ]); // Insert in a specific slot. If the slot is out of // bounds, an exception will be raised. $this->Breadcrumbs->insertAt( 2, 'Products', ['controller' => 'products', 'action' => 'index'] ); // Insert before another crumb, based on the title. // If the named crumb title cannot be found, // an exception will be raised. $this->Breadcrumbs->insertBefore( 'A product name', // the title of the crumb to insert before 'Products', ['controller' => 'products', 'action' => 'index'] ); // Insert after another crumb, based on the title. // If the named crumb title cannot be found, // an exception will be raised. $this->Breadcrumbs->insertAfter( 'A product name', // the title of the crumb to insert after 'Products', ['controller' => 'products', 'action' => 'index'] ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 Using these methods gives you the ability to work with CakePHP's 2-step rendering process. Since templates and layouts are rendered from the inside out (meaning, included elements are rendered first), this allows you to define precisely where you want to add a breadcrumb. Rendering the Breadcrumbs Trail [​](https://book.cakephp.org/3.x/views/helpers/breadcrumbs.html#rendering-the-breadcrumbs-trail) --------------------------------------------------------------------------------------------------------------------------------- After adding crumbs to the trail, you can easily render it using the `render()` method. This method accepts two array arguments: * `$attributes` : An array of attributes that will applied to the `wrapper` template. This gives you the ability to add attributes to the HTML tag. It accepts the special `templateVars` key to allow the insertion of custom template variables in the template. * `$separator` : An array of attributes for the `separator` template. Possible properties are: * `separator` The string to be displayed as a separator * `innerAttrs` To provide attributes in case your separator is divided in two elements * `templateVars` Allows the insertion of custom template variable in the template All other properties will be converted as HTML attributes and will replace the `attrs` key in the template. If you use the default for this option (empty), it will not render a separator. Here is an example of how to render a trail: echo $this->Breadcrumbs->render( ['class' => 'breadcrumbs-trail'], ['separator' => ''] ); 1 2 3 4 ### Customizing the Output [​](https://book.cakephp.org/3.x/views/helpers/breadcrumbs.html#customizing-the-output) The BreadcrumbsHelper internally uses the `StringTemplateTrait`, which gives the ability to easily customize output of various HTML strings. It includes four templates, with the following default declaration: [\ 'wrapper' => '{{content}}',\ 'item' => '{{title}}{{separator}}',\ 'itemWithoutLink' => '{{title}}{{separator}}',\ 'separator' => '{{separator}}'\ ] 1 2 3 4 5 6 You can easily customize them using the `templates()` method from the `StringTemplateTrait`: $this->Breadcrumbs->templates([\ 'wrapper' => '',\ ]); 1 2 3 Since your templates will be rendered, the `templateVars` option allows you to add your own template variables in the various templates: $this->Breadcrumbs->templates([\ 'item' => '{{icon}}{{title}}{{separator}}'\ ]); 1 2 3 And to define the parameter, just specify it when adding the crumb to the trail: $this->Breadcrumbs->add( 'Products', ['controller' => 'products', 'action' => 'index'], [\ 'templateVars' => [\ 'icon' => ''\ ]\ ] ); 1 2 3 4 5 6 7 8 9 ### Defining Attributes for the Item [​](https://book.cakephp.org/3.x/views/helpers/breadcrumbs.html#defining-attributes-for-the-item) If you want to apply specific HTML attributes to both the item and its sub-item , you can leverage the `innerAttrs` key, which the `$options` argument provides. Everything except `innerAttrs` and `templateVars` will be rendered as HTML attributes: $this->Breadcrumbs->add( 'Products', ['controller' => 'products', 'action' => 'index'], [\ 'class' => 'products-crumb',\ 'data-foo' => 'bar',\ 'innerAttrs' => [\ 'class' => 'inner-products-crumb',\ 'id' => 'the-products-crumb'\ ]\ ] ); // Based on the default template, this will render the following HTML :
  • Products
  • 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Clearing the Breadcrumbs [​](https://book.cakephp.org/3.x/views/helpers/breadcrumbs.html#clearing-the-breadcrumbs) ------------------------------------------------------------------------------------------------------------------- You can clear the bread crumbs using the `reset()` method. This can be useful when you want to transform the crumbs and overwrite the list: $crumbs = $this->Breadcrumbs->getCrumbs(); $crumbs = collection($crumbs)->map(function ($crumb) { $crumb['options']['class'] = 'breadcrumb-item'; return $crumb; })->toArray(); $this->Breadcrumbs->reset()->add($crumbs); 1 2 3 4 5 6 7 Added in version 3.4.0 The `reset()` method was added in 3.4.0 --- # Blog Tutorial | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html#VPContent) Return to top Blog Tutorial [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html#blog-tutorial) ==================================================================================================== This tutorial will walk you through the creation of a simple blog application. We'll be installing CakePHP, creating a database, and creating enough application logic to list, add, edit, and delete blog articles. Here's what you'll need: 1. A running web server. We're going to assume you're using Apache, though the instructions for using other servers should be very similar. We might have to play a little with the server configuration, but most folks can get CakePHP up and running without any configuration at all. Make sure you have PHP _5.6_ or greater, and that the `mbstring` and `intl` extensions are enabled in PHP. 2. A database server. We're going to be using MySQL server in this tutorial. You'll need to know enough about SQL in order to create a database: CakePHP will be taking the reins from there. Since we're using MySQL, also make sure that you have `pdo_mysql` enabled in PHP. 3. Basic PHP knowledge. Let's get started! Getting CakePHP [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html#getting-cakephp) -------------------------------------------------------------------------------------------------------- The easiest way to install CakePHP is to use Composer. Composer is a simple way of installing CakePHP from your terminal or command line prompt. First, you'll need to download and install Composer if you haven't done so already. If you have cURL installed, it's as easy as running the following: curl -s https://getcomposer.org/installer | php Or, you can download `composer.phar` from the [Composer website](https://getcomposer.org/download/) . Then simply type the following line in your terminal from your installation directory to install the CakePHP application skeleton in the directory that you wish to use it with. For this example we will be using "blog" but feel free to change it to something else.: php composer.phar create-project --prefer-dist cakephp/app:"^3.10" blog In case you've already got composer installed globally, you may instead type: composer self-update && composer create-project --prefer-dist cakephp/app:"^3.10" blog The advantage to using Composer is that it will automatically complete some important set up tasks, such as setting the correct file permissions and creating your config/app.php file for you. There are other ways to install CakePHP. If you cannot or don't want to use Composer, check out the [Installation](https://book.cakephp.org/3.x/installation.html) section. Regardless of how you downloaded and installed CakePHP, once your set up is completed, your directory setup should look something like the following: /cake_install /bin /config /logs /plugins /src /tests /tmp /vendor /webroot .editorconfig .gitignore .htaccess .travis.yml composer.json index.php phpunit.xml.dist README.md Now might be a good time to learn a bit about how CakePHP's directory structure works: check out the [CakePHP Folder Structure](https://book.cakephp.org/3.x/intro/cakephp-folder-structure.html) section. Directory Permissions on tmp and logs [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html#directory-permissions-on-tmp-and-logs) ---------------------------------------------------------------------------------------------------------------------------------------------------- The `tmp` and `logs` directories need to have proper permissions to be writable by your webserver. If you used Composer for the install, this should have been done for you and confirmed with a "Permissions set on " message. If you instead got an error message or want to do it manually, the best way would be to find out what user your webserver runs as (````) and change the ownership of these two directories to that user. The final command you run (in \*nix) might look something like this: chown -R www-data tmp chown -R www-data logs If for some reason CakePHP can't write to these directories, you'll be informed by a warning while not in production mode. While not recommended, if you are unable to set the permissions to the same as your webserver, you can simply set write permissions on the folder by running a command such as: chmod -R 777 tmp chmod -R 777 logs Creating the Blog Database [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html#creating-the-blog-database) ------------------------------------------------------------------------------------------------------------------------------ Next, let's set up the underlying MySQL database for our blog. If you haven't already done so, create an empty database for use in this tutorial, with a name of your choice, e.g. `cake_blog`. Right now, we'll just create a single table to store our articles. We'll also throw in a few articles to use for testing purposes. Execute the following SQL statements into your database: # First, create our articles table CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, title VARCHAR(50), body TEXT, created DATETIME DEFAULT NULL, modified DATETIME DEFAULT NULL ); # Then insert some articles for testing: INSERT INTO articles (title,body,created) VALUES ('The title', 'This is the article body.', NOW()); INSERT INTO articles (title,body,created) VALUES ('A title once again', 'And the article body follows.', NOW()); INSERT INTO articles (title,body,created) VALUES ('Title strikes back', 'This is really exciting! Not.', NOW()); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 The choices on table and column names are not arbitrary. If you follow CakePHP's database naming conventions, and CakePHP's class naming conventions (both outlined in [CakePHP Conventions](https://book.cakephp.org/3.x/intro/conventions.html) ), you'll be able to take advantage of a lot of free functionality and avoid configuration. CakePHP is flexible enough to accommodate even inconsistent legacy database schemas, but adhering to the conventions will save you time. Check out [CakePHP Conventions](https://book.cakephp.org/3.x/intro/conventions.html) for more information, but it's suffice to say that naming our table 'articles' automatically hooks it to our Articles model, and having fields called 'modified' and 'created' will be automatically managed by CakePHP. Database Configuration [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html#database-configuration) ---------------------------------------------------------------------------------------------------------------------- Next, let's tell CakePHP where our database is and how to connect to it. For many, this will be the first and last time you will need to configure anything. The configuration should be pretty straightforward: just replace the values in the `Datasources.default` array in the **config/app.php** file with those that apply to your setup. A sample completed configuration array might look something like the following: return [\ // More configuration above.\ 'Datasources' => [\ 'default' => [\ 'className' => 'Cake\Database\Connection',\ 'driver' => 'Cake\Database\Driver\Mysql',\ 'persistent' => false,\ 'host' => 'localhost',\ 'username' => 'cake_blog',\ 'password' => 'AngelF00dC4k3~',\ 'database' => 'cake_blog',\ 'encoding' => 'utf8',\ 'timezone' => 'UTC'\ ],\ ],\ // More configuration below.\ ]; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Once you've saved your **config/app.php** file, you should be able to open your browser and see the CakePHP welcome page. It should also tell you that your database connection file was found, and that CakePHP can successfully connect to the database. NOTE A copy of CakePHP's default configuration file is found in **config/app.default.php**. Optional Configuration [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html#optional-configuration) ---------------------------------------------------------------------------------------------------------------------- There are a few other items that can be configured. Most developers complete these laundry-list items, but they're not required for this tutorial. One is defining a custom string (or "salt") for use in security hashes. The security salt is used for generating hashes. If you used Composer this too is taken care of for you during the install. Else you'd need to change the default salt value by editing **config/app.php**. It doesn't matter much what the new value is, as long as it's not guessable: 'Security' => [\ 'salt' => 'something long and containing lots of different values.',\ ], 1 2 3 A Note on mod\_rewrite [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/blog.html#a-note-on-mod-rewrite) --------------------------------------------------------------------------------------------------------------------- Occasionally new users will run into mod\_rewrite issues. For example if the CakePHP welcome page looks a little funny (no images or CSS styles). This probably means mod\_rewrite is not functioning on your system. Please refer to the [Url Rewriting](https://book.cakephp.org/3.x/installation.html#url-rewriting) section to help resolve any issues you are having. Now continue to [Blog Tutorial - Part 2](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-two.html) to start building your first CakePHP application. --- # Paginator | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/helpers/paginator.html#VPContent) Return to top Paginator [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#paginator) =================================================================================== `class` Cake\\View\\Helper\\**PaginatorHelper**(View $view, array $config = \[\]) The PaginatorHelper is used to output pagination controls such as page numbers and next/previous links. It works in tandem with `PaginatorComponent`. See also [Pagination](https://book.cakephp.org/3.x/controllers/components/pagination.html) for information on how to create paginated datasets and do paginated queries. PaginatorHelper Templates [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#paginatorhelper-templates) ------------------------------------------------------------------------------------------------------------------- Internally PaginatorHelper uses a series of simple HTML templates to generate markup. You can modify these templates to customize the HTML generated by the PaginatorHelper. Templates use style placeholders. It is important to not add any spaces around the or the replacements will not work. ### Loading Templates from a File [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#loading-templates-from-a-file) When adding the PaginatorHelper in your controller, you can define the 'templates' setting to define a template file to load. This allows you to customize multiple templates and keep your code DRY: // In your AppView.php public function initialize() { ... $this->loadHelper('Paginator', ['templates' => 'paginator-templates']); } 1 2 3 4 5 6 This will load the file located at **config/paginator-templates.php**. See the example below for how the file should look like. You can also load templates from a plugin using `plugin syntax`: // In your AppView.php public function initialize() { ... $this->loadHelper('Paginator', ['templates' => 'MyPlugin.paginator-templates']); } 1 2 3 4 5 6 Whether your templates are in the primary application or a plugin, your templates file should look something like: return [\ 'number' => '{{text}}',\ ]; 1 2 3 ### Changing Templates at Run-time [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#changing-templates-at-run-time) `method` Cake\\View\\Helper\\PaginatorHelper::**setTemplates**($templates) This method allows you to change the templates used by PaginatorHelper at runtime. This can be useful when you want to customize templates for a particular method call: // Read the current template value. $result = $this->Paginator->getTemplates('number'); // Prior to 3.4 $result = $this->Paginator->templates('number'); // Change a template $this->Paginator->setTemplates([\ 'number' => '{{text}}'\ ]); 1 2 3 4 5 6 7 8 9 WARNING Template strings containing a percentage sign (`%`) need special attention, you should prefix this character with another percentage so it looks like `%%`. The reason is that internally templates are compiled to be used with `sprintf()`. Example: '
    ' ### Template Names [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#template-names) PaginatorHelper uses the following templates: * `nextActive` The active state for a link generated by next(). * `nextDisabled` The disabled state for next(). * `prevActive` The active state for a link generated by prev(). * `prevDisabled` The disabled state for prev() * `counterRange` The template counter() uses when format == range. * `counterPages` The template counter() uses when format == pages. * `first` The template used for a link generated by first(). * `last` The template used for a link generated by last() * `number` The template used for a link generated by numbers(). * `current` The template used for the current page. * `ellipsis` The template used for ellipses generated by numbers(). * `sort` The template for a sort link with no direction. * `sortAsc` The template for a sort link with an ascending direction. * `sortDesc` The template for a sort link with a descending direction. Creating Sort Links [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#creating-sort-links) ------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\PaginatorHelper::**sort**($key, $title = null, $options = \[\]) Generates a sorting link. Sets querystring parameters for the sort and direction. Links will default to sorting by asc. After the first click, links generated with `sort()` will handle direction switching automatically. If the resultset is sorted 'asc' by the specified key the returned link will sort by 'desc'. Accepted keys for `$options`: * `escape` Whether you want the contents HTML entity encoded, defaults to `true`. * `model` The model to use, defaults to `PaginatorHelper::defaultModel()`. * `direction` The default direction to use when this link isn't active. * `lock` Lock direction. Will only use the default direction then, defaults to `false`. Assuming you are paginating some posts, and are on page one: echo $this->Paginator->sort('user_id'); 1 Output: User Id 1 You can use the title parameter to create custom text for your link: echo $this->Paginator->sort('user_id', 'User account'); 1 Output: User account 1 If you are using HTML like images in your links remember to set escaping off: echo $this->Paginator->sort( 'user_id', 'User account', ['escape' => false] ); 1 2 3 4 5 Output: User account 1 The direction option can be used to set the default direction for a link. Once a link is active, it will automatically switch directions like normal: echo $this->Paginator->sort('user_id', null, ['direction' => 'desc']); 1 Output: User Id 1 The lock option can be used to lock sorting into the specified direction: echo $this->Paginator->sort('user_id', null, ['direction' => 'asc', 'lock' => true]); 1 `method` Cake\\View\\Helper\\PaginatorHelper::**sortDir**(string $model = null, mixed $options = \[\]) `method` Cake\\View\\Helper\\PaginatorHelper::**sortKey**(string $model = null, mixed $options = \[\]) Creating Page Number Links [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#creating-page-number-links) --------------------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\PaginatorHelper::**numbers**($options = \[\]) Returns a set of numbers for the paged result set. Uses a modulus to decide how many numbers to show on each side of the current page By default 8 links on either side of the current page will be created if those pages exist. Links will not be generated for pages that do not exist. The current page is also not a link. Supported options are: * `before` Content to be inserted before the numbers. * `after` Content to be inserted after the numbers. * `model` Model to create numbers for, defaults to `PaginatorHelper::defaultModel()`. * `modulus` how many numbers to include on either side of the current page, defaults to 8. * `first` Whether you want first links generated, set to an integer to define the number of 'first' links to generate. Defaults to `false`. If a string is set a link to the first page will be generated with the value as the title: echo $this->Paginator->numbers(['first' => 'First page']); 1 * `last` Whether you want last links generated, set to an integer to define the number of 'last' links to generate. Defaults to `false`. Follows the same logic as the `first` option. There is a `~PaginatorHelper::last()` method to be used separately as well if you wish. While this method allows a lot of customization for its output. It is also ok to just call the method without any parameters. : echo $this->Paginator->numbers(); 1 Using the first and last options you can create links to the beginning and end of the page set. The following would create a set of page links that include links to the first 2 and last 2 pages in the paged results: echo $this->Paginator->numbers(['first' => 2, 'last' => 2]); 1 Creating Jump Links [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#creating-jump-links) ------------------------------------------------------------------------------------------------------- In addition to generating links that go directly to specific page numbers, you'll often want links that go to the previous and next links, first and last pages in the paged data set. `method` Cake\\View\\Helper\\PaginatorHelper::**prev**($title = '<< Previous', $options = \[\]) `method` Cake\\View\\Helper\\PaginatorHelper::**next**($title = 'Next >>', $options = \[\]) `method` Cake\\View\\Helper\\PaginatorHelper::**first**($first = '<< first', $options = \[\]) `method` Cake\\View\\Helper\\PaginatorHelper::**last**($last = 'last >>', $options = \[\]) Creating Header Link Tags [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#creating-header-link-tags) ------------------------------------------------------------------------------------------------------------------- PaginatorHelper can be used to create pagination link tags in your page `` elements: // Create next/prev links for the current model. echo $this->Paginator->meta(); // Create next/prev & first/last links for the current model. echo $this->Paginator->meta(['first' => true, 'last' => true]); 1 2 3 4 5 Added in version 3.4.0 The `first` and `last` options were added in 3.4.0 Checking the Pagination State [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#checking-the-pagination-state) --------------------------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\PaginatorHelper::**current**(string $model = null) `method` Cake\\View\\Helper\\PaginatorHelper::**hasNext**(string $model = null) `method` Cake\\View\\Helper\\PaginatorHelper::**hasPrev**(string $model = null) `method` Cake\\View\\Helper\\PaginatorHelper::**hasPage**(string $model = null, integer $page = 1) `method` Cake\\View\\Helper\\PaginatorHelper::**total**(string $model = null) Creating a Page Counter [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#creating-a-page-counter) --------------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\PaginatorHelper::**counter**($options = \[\]) Returns a counter string for the paged result set. Using a provided format string and a number of options you can create localized and application specific indicators of where a user is in the paged data set. There are a number of options for `counter()`. The supported ones are: * `format` Format of the counter. Supported formats are 'range', 'pages' and custom. Defaults to pages which would output like '1 of 10'. In the custom mode the supplied string is parsed and tokens are replaced with actual values. The available tokens are: * \- the current page displayed. * \- total number of pages. * \- current number of records being shown. * \- the total number of records in the result set. * \- number of the first record being displayed. * \- number of the last record being displayed. * \- The pluralized human form of the model name. If your model was 'RecipePage', would be 'recipe pages'. You could also supply only a string to the counter method using the tokens available. For example: echo $this->Paginator->counter( 'Page {{page}} of {{pages}}, showing {{current}} records out of {{count}} total, starting on record {{start}}, ending on {{end}}' ); 1 2 3 4 Setting 'format' to range would output like '1 - 3 of 13': echo $this->Paginator->counter([\ 'format' => 'range'\ ]); 1 2 3 * `model` The name of the model being paginated, defaults to `PaginatorHelper::defaultModel()`. This is used in conjunction with the custom string on 'format' option. Generating Pagination URLs [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#generating-pagination-urls) --------------------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\PaginatorHelper::**generateUrl**(array $options = \[\], $model = null, $full = false) By default returns a full pagination URL string for use in non-standard contexts (i.e. JavaScript). : echo $this->Paginator->generateUrl(['sort' => 'title']); 1 Creating a Limit Selectbox Control [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#creating-a-limit-selectbox-control) ------------------------------------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\PaginatorHelper::**limitControl**(array $limits = \[\], $default = null, array $options = \[\]) Create a dropdown control that changes the `limit` query parameter: // Use the defaults. echo $this->Paginator->limitControl(); // Define which limit options you want. echo $this->Paginator->limitControl([25 => 25, 50 => 50]); // Custom limits and set the selected option echo $this->Paginator->limitControl([25 => 25, 50 => 50], $user->perPage); 1 2 3 4 5 6 7 8 The generated form and control will automatically submit on change. Added in version 3.5.0 The `limitControl()` method was added in 3.5.0 Configuring Pagination Options [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#configuring-pagination-options) ----------------------------------------------------------------------------------------------------------------------------- `method` Cake\\View\\Helper\\PaginatorHelper::**options**($options = \[\]) Sets all the options for the PaginatorHelper. Supported options are: * `url` The URL of the paginating action. 'url' has a few sub options as well: * `sort` The key that the records are sorted by. * `direction` The direction of the sorting. Defaults to 'ASC'. * `page` The page number to display. The above mentioned options can be used to force particular pages/directions. You can also append additional URL content into all URLs generated in the helper: $this->Paginator->options([\ 'url' => [\ 'sort' => 'email',\ 'direction' => 'desc',\ 'page' => 6,\ 'lang' => 'en'\ ]\ ]); 1 2 3 4 5 6 7 8 The above adds the `en` route parameter to all links the helper will generate. It will also create links with specific sort, direction and page values. By default PaginatorHelper will merge in all of the current passed arguments and query string parameters. * `escape` Defines if the title field for links should be HTML escaped. Defaults to `true`. * `model` The name of the model being paginated, defaults to `PaginatorHelper::defaultModel()`. Example Usage [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#example-usage) ------------------------------------------------------------------------------------------- It's up to you to decide how to show records to the user, but most often this will be done inside HTML tables. The examples below assume a tabular layout, but the PaginatorHelper available in views doesn't always need to be restricted as such. See the details on [PaginatorHelper](https://api.cakephp.org/3.x/class-Cake.View.Helper.PaginatorHelper.html) in the API. As mentioned, the PaginatorHelper also offers sorting features which can be integrated into your table column headers:
    Paginator->sort('id', 'ID') ?> Paginator->sort('title', 'Title') ?>
    id ?> title) ?>
    1 2 3 4 5 6 7 8 9 10 11 12 13 The links output from the `sort()` method of the `PaginatorHelper` allow users to click on table headers to toggle the sorting of the data by a given field. It is also possible to sort a column based on associations:
    Paginator->sort('title', 'Title') ?> Paginator->sort('Authors.name', 'Author') ?>
    title) ?> author->name) ?>
    1 2 3 4 5 6 7 8 9 10 11 12 NOTE Sorting by columns in associated models requires setting these in the `PaginationComponent::paginate` property. Using the example above, the controller handling the pagination would need to set its `sortWhitelist` key as follows: $this->paginate = [\ 'sortWhitelist' => [\ 'Posts.title',\ 'Authors.name',\ ],\ ]; 1 2 3 4 5 6 For more information on using the `sortWhitelist` option, please see [Control Which Fields Used For Ordering](https://book.cakephp.org/3.x/controllers/components/pagination.html#control-which-fields-used-for-ordering) . The final ingredient to pagination display in views is the addition of page navigation, also supplied by the PaginationHelper: // Shows the page numbers Paginator->numbers() ?> // Shows the next and previous links Paginator->prev('« Previous') ?> Paginator->next('Next »') ?> // Prints X of Y, where X is current page and Y is number of pages Paginator->counter() ?> 1 2 3 4 5 6 7 8 9 The wording output by the counter() method can also be customized using special markers: Paginator->counter([\ 'format' => 'Page {{page}} of {{pages}}, showing {{current}} records out of\ {{count}} total, starting on record {{start}}, ending on {{end}}'\ ]) ?> 1 2 3 4 Paginating Multiple Results [​](https://book.cakephp.org/3.x/views/helpers/paginator.html#paginating-multiple-results) ----------------------------------------------------------------------------------------------------------------------- If you are [paginating multiple queries](https://book.cakephp.org/3.x/controllers/components/pagination.html#paginating-multiple-queries) you'll need to set the `model` option when generating pagination related elements. You can either use the `model` option on every method call you make to `PaginatorHelper`, or use `options()` to set the default model: // Pass the model option echo $this->Paginator->sort('title', ['model' => 'Articles']); // Set the default model. $this->Paginator->options(['model' => 'Articles']); echo $this->Paginator->sort('title'); 1 2 3 4 5 6 By using the `model` option, `PaginatorHelper` will automatically use the `scope` defined in when the query was paginated. Added in version 3.3.0 Multiple Pagination was added in 3.3.0 --- # ヘルパー | CakePHP [Skip to content](https://book.cakephp.org/3.x/ja/views/helpers.html#VPContent) Return to top ヘルパー [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC) =========================================================================================================== ヘルパーはアプリケーションのプレゼンテーション層のためのコンポーネントのようなクラスです。 多くのビューやエレメント、レイアウトで共有される表示ロジックを含んでいます。 この章では、ヘルパーを設定する方法を紹介します。ヘルパーの読み込み方法、 それらのヘルパーの使い方、独自のヘルパーを作成するための簡単な手順を概説します。 CakePHP にはビューの作成に役立つ多くのヘルパーがあります。それらは、整形式のマークアップ (フォーム含む)、テキスト、時間、数値の整形に役立ったり、 Ajax 機能 をスピードアップさせたりします。 CakePHP のヘルパーに関する詳細については、各ヘルパーの章をご覧ください。 * [Breadcrumbs (パンくず)](https://book.cakephp.org/3.x/ja/views/helpers/breadcrumbs.html) * [Flash](https://book.cakephp.org/3.x/ja/views/helpers/flash.html) * [Form](https://book.cakephp.org/3.x/ja/views/helpers/form.html) * [Html](https://book.cakephp.org/3.x/ja/views/helpers/html.html) * [Number](https://book.cakephp.org/3.x/ja/views/helpers/number.html) * [Paginator](https://book.cakephp.org/3.x/ja/views/helpers/paginator.html) * [Rss](https://book.cakephp.org/3.x/ja/views/helpers/rss.html) * [Session](https://book.cakephp.org/3.x/ja/views/helpers/session.html) * [Text](https://book.cakephp.org/3.x/ja/views/helpers/text.html) * [Time](https://book.cakephp.org/3.x/ja/views/helpers/time.html) * [Url](https://book.cakephp.org/3.x/ja/views/helpers/url.html) ヘルパーの設定 [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC%E3%81%AE%E8%A8%AD%E5%AE%9A) ----------------------------------------------------------------------------------------------------------------------------------------- CakePHP でヘルパーを読み込むには、ビュークラスでヘルパーを宣言します。 `AppView` クラスは、すべての CakePHP アプリケーションが付属し、 ヘルパーを読み込むための理想的な場所です。 : class AppView extends View { public function initialize() { parent::initialize(); $this->loadHelper('Html'); $this->loadHelper('Form'); $this->loadHelper('Flash'); } } 1 2 3 4 5 6 7 8 9 10 プラグインのヘルパーを読み込むには、CakePHP の他の場所でも使われている `プラグイン記法` を使います。 : $this->loadHelper('Blog.Comment'); 1 CakePHP やアプリケーションにあるヘルパーを明示的に読み込む必要はありません。 これらのヘルパーは、初回の使用時に遅延ロードされます。 例えば: // まだ読み込まれていなければ FormHelper を読み込みます。 $this->Form->create($article); 1 2 プラグインのビュー内から、プラグインヘルパーを遅延ロードすることもできます。 例えば、'Blog' プラグインのビューテンプレートは、同じプラグインからヘルパーを 遅延ロードすることができます。 ### 条件付きヘルパーの読み込み [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E6%9D%A1%E4%BB%B6%E4%BB%98%E3%81%8D%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF) 現在のアクション名を使用して、条件付きでヘルパーを読み込むことができます。 : class AppView extends View { public function initialize() { parent::initialize(); if ($this->request->getParam('action') === 'index') { $this->loadHelper('ListPage'); } } } 1 2 3 4 5 6 7 8 9 10 また、コントローラーの `beforeRender` メソッドを使用して、ヘルパーを読み込むことができます。 : class ArticlesController extends AppController { public function beforeRender(Event $event) { parent::beforeRender($event); $this->viewBuilder()->helpers(['MyHelper']); } } 1 2 3 4 5 6 7 8 ### 設定オプション [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E8%A8%AD%E5%AE%9A%E3%82%AA%E3%83%95%E3%82%9A%E3%82%B7%E3%83%A7%E3%83%B3) ヘルパーに設定オプションを渡すことができます。これらのオプションは、属性値を設定したり、 ヘルパーの振る舞いを変更するために使用することができます。 : namespace App\View\Helper; use Cake\View\Helper; use Cake\View\View; class AwesomeHelper extends Helper { // initialize() フックは 3.2 以降で使用可能です。前のバージョンで // 必要な場合は、コンストラクターをオーバーライドしてください。 public function initialize(array $config) { debug($config); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 次に示すように、コントローラーのヘルパーを宣言するときにオプションを指定することができます。 : namespace App\Controller; use App\Controller\AppController; class AwesomeController extends AppController { public $helpers = ['Awesome' => ['option1' => 'value1']]; } 1 2 3 4 5 6 7 8 デフォルトでは、すべての設定オプションは、 `$_defaultConfig` プロパティーとマージされます。 このプロパティーは、ヘルパーが必要とする設定のデフォルト値を定義する必要があります。例えば: namespace App\View\Helper; use Cake\View\Helper; use Cake\View\StringTemplateTrait; class AwesomeHelper extends Helper { use StringTemplateTrait; protected $_defaultConfig = [\ 'errorClass' => 'error',\ 'templates' => [\ 'label' => '',\ ],\ ]; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ヘルパーのコンストラクターに提供される任意の設定は、構築時にデフォルト値とマージされ、 マージされたデータは、 `_config` に設定されます。 実行時設定を読み取るために `config()` メソッドを使用することができます。 : // errorClass 設定オプションを読み込み $class = $this->Awesome->config('errorClass'); 1 2 ヘルパー設定を使用すると、宣言的にヘルパーを設定し、コントローラーロジックから設定ロジックを 削除することができます。クラス宣言の一部として組み込むことができない設定オプションがある場合は、 コントローラーの beforeRender コールバックで設定します。 : class PostsController extends AppController { public function beforeRender(Event $event) { parent::beforeRender($event); $builder = $this->viewBuilder(); $builder->helpers([\ 'CustomStuff' => $this->_getCustomStuffConfig(),\ ]); } } 1 2 3 4 5 6 7 8 9 10 11 ### ヘルパーの別名 [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC%E3%81%AE%E5%88%A5%E5%90%8D) 共通設定の一つに `className` オプションがあります。 このオプションを使うとビュー内に別名のヘルパーを作成することができます。 この機能は `$this->Html` や他のヘルパーの参照を独自実装に置き換えたい時に便利です。 : // src/View/AppView.php class AppView extends View { public function initialize() { $this->loadHelper('Html', [\ 'className' => 'MyHtml'\ ]); } } // src/View/Helper/MyHtmlHelper.php namespace App\View\Helper; use Cake\View\Helper\HtmlHelper; class MyHtmlHelper extends HtmlHelper { // コア HtmlHelper を上書きするコードを追加 } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 上記の例ではビューにて `MyHtmlHelper` に `$this->Html` という _別名_ をつけています。 NOTE 別名をつけられたヘルパーは、ヘルパーが使われるあらゆる場所のインスタンスを置き換えます。 これは、他のヘルパーの内部を含みます。 ヘルパーの使用 [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC%E3%81%AE%E4%BD%BF%E7%94%A8) ----------------------------------------------------------------------------------------------------------------------------------------- コントローラーで使用するヘルパーを設定すると、各ヘルパーはビューのパブリックプロパティーとして公開されます。 例えば、 `HtmlHelper` を使用していた場合、次を実行することによってアクセスすることが できます。 : echo $this->Html->css('styles'); 1 上記は HtmlHelper の `css()` メソッドを呼び出します。 `$this->{$helperName}` を使用して任意の読み込まれたヘルパーにアクセスすることができます。 ### ヘルパーの動的ロード [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC%E3%81%AE%E5%8B%95%E7%9A%84%E3%83%AD%E3%83%BC%E3%83%88%E3%82%99) ビュー内から動的にヘルパーを読み込む必要がある状況があるかもしれません。 これを行うには、 ビューの `Cake\View\HelperRegistry` を使用することができます。 : // どちらか1つが動作 $mediaHelper = $this->loadHelper('Media', $mediaConfig); $mediaHelper = $this->helpers()->load('Media', $mediaConfig); 1 2 3 HelperRegistry は [レジストリー](https://book.cakephp.org/3.x/ja/core-libraries/registry-objects.html) です。 そして、 CakePHP の他の場所で使用されるレジストリー API をサポートしています。 コールバックメソッド [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E3%82%B3%E3%83%BC%E3%83%AB%E3%83%8F%E3%82%99%E3%83%83%E3%82%AF%E3%83%A1%E3%82%BD%E3%83%83%E3%83%88%E3%82%99) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ヘルパーは、ビューレンダリングプロセスを強化するためのコールバックをいくつか備えています。 詳細は [Helper Api](https://book.cakephp.org/3.x/ja/views/helpers.html#helper-api) と [イベントシステム](https://book.cakephp.org/3.x/ja/core-libraries/events.html) ドキュメントをご覧ください。 ヘルパーの作成 [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC%E3%81%AE%E4%BD%9C%E6%88%90) ----------------------------------------------------------------------------------------------------------------------------------------- アプリケーションやプラグインで使用するための独自のヘルパークラスを作成することができます。 CakePHP のコンポーネントと同様に、ヘルパークラスは、いくつかの規約があります。 * ヘルパークラスファイルは、 **src/View/Helper** に置かれます。 例: **src/View/Helper/LinkHelper.php** * ヘルパークラスは、末尾に `Helper` を付ける必要があります。例: `LinkHelper` 。 * ヘルパークラス名を参照するときは、 末尾の `Helper` を省略しなければなりません。 例: `$this->loadHelper('Link');` 。 また、正しく動作させるために `Helper` を継承します。 : /* src/View/Helper/LinkHelper.php */ namespace App\View\Helper; use Cake\View\Helper; class LinkHelper extends Helper { public function makeEdit($title, $url) { // 特別な形式のリンクを作成するロジックをここに... } } 1 2 3 4 5 6 7 8 9 10 11 12 ### 他のヘルパーの読み込み [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E4%BB%96%E3%81%AE%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF) 別のヘルパーに既に存在する機能を使用したい場合があります。 その場合、 `$helpers` 配列に使いたいヘルパーを明示することで実現出来ます。 フォーマットは、コントローラーで指定する場合と同じようにして下さい。 : /* src/View/Helper/LinkHelper.php (他のヘルパーを使用) */ namespace App\View\Helper; use Cake\View\Helper; class LinkHelper extends Helper { public $helpers = ['Html']; public function makeEdit($title, $url) { // 出力に HTML ヘルパーを使用 // 整形されたデータ: $link = $this->Html->link($title, $url, ['class' => 'edit']); return '
    ' . $link . '
    '; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ### 独自のヘルパーを使用 [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E7%8B%AC%E8%87%AA%E3%81%AE%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC%E3%82%92%E4%BD%BF%E7%94%A8) ヘルパーを作成して **src/View/Helper/** に配置すると、ビューに読み込めます。 : class AppView extends View { public function initialize() { parent::initialize(); $this->loadHelper('Link'); } } 1 2 3 4 5 6 7 8 ヘルパーが読み込まれたら、一致するビュープロパティーにアクセスしてビュー内で使用できます。 : Link->makeEdit('レシピの変更', '/recipes/edit/5') ?> 1 2 NOTE `HelperRegistry` は、 `コントローラー` で明示されていないヘルパーを 遅延ロードしようとします。 ### ヘルパー内部でビュー変数にアクセス [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC%E5%86%85%E9%83%A8%E3%81%A6%E3%82%99%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E5%A4%89%E6%95%B0%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9) ヘルパー内部でビュー変数にアクセスしたい場合は、次のように `$this->_View->get()` を使用することができます。 : class AwesomeHelper extends Helper { public $helpers = ['Html']; public function someMethod() { // meta description の設定 echo $this->Html->meta( 'description', $this->_View->get('metaDescription'), ['block' => 'meta'] ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 ### ヘルパー内部でビューエレメントの描画 [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E3%83%98%E3%83%AB%E3%83%8F%E3%82%9A%E3%83%BC%E5%86%85%E9%83%A8%E3%81%A6%E3%82%99%E3%83%92%E3%82%99%E3%83%A5%E3%83%BC%E3%82%A8%E3%83%AC%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AE%E6%8F%8F%E7%94%BB) ヘルパー内部でエレメントを描画したい場合は、次のように `$this->_View->element()` を使用することができます。 : class AwesomeHelper extends Helper { public function someFunction() { // ヘルパー内で直接出力 echo $this->_View->element( '/path/to/element', ['foo'=>'bar','bar'=>'foo'] ); // または、ビューに返す return $this->_View->element( '/path/to/element', ['foo'=>'bar','bar'=>'foo'] ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Helper クラス [​](https://book.cakephp.org/3.x/ja/views/helpers.html#helper-%E3%82%AF%E3%83%A9%E3%82%B9) ------------------------------------------------------------------------------------------------------ `class` **Helper** ### コールバック [​](https://book.cakephp.org/3.x/ja/views/helpers.html#%E3%82%B3%E3%83%BC%E3%83%AB%E3%83%8F%E3%82%99%E3%83%83%E3%82%AF) ヘルパーにコールバックメソッドを実装することで、CakePHP は関連するイベントにヘルパーを自動的に 登録します。以前のバージョンの CakePHP とは異なり、ヘルパークラスはコールバックメソッドを 実装していないので、あなたのコールバックでは `parent` を _コールしてはいけません_ 。 `method` Helper::**beforeRenderFile**(Event $event, $viewFile) `method` Helper::**afterRenderFile**(Event $event, $viewFile, $content) `method` Helper::**beforeRender**(Event $event, $viewFile) `method` Helper::**afterRender**(Event $event, $viewFile) `method` Helper::**beforeLayout**(Event $event, $layoutFile) `method` Helper::**afterLayout**(Event $event, $layoutFile) --- # Blog Tutorial - Part 3 | CakePHP [Skip to content](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-three.html#VPContent) Return to top Blog Tutorial - Part 3 [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-three.html#blog-tutorial-part-3) ========================================================================================================================== Create a Tree Category [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-three.html#create-a-tree-category) ---------------------------------------------------------------------------------------------------------------------------- Let's continue our blog application and imagine we want to categorize our articles. We want the categories to be ordered, and for this, we will use the [Tree behavior](https://book.cakephp.org/3.x/orm/behaviors/tree.html) to help us organize the categories. But first, we need to modify our tables. Migrations Plugin [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-three.html#migrations-plugin) ------------------------------------------------------------------------------------------------------------------ We will use the [migrations plugin](https://github.com/cakephp/migrations) to create a table in our database. If you already have an articles table in your database, erase it. Now open your application's **composer.json** file. Normally you would see that the migrations plugin is already under `require`. If not, add it by executing: composer require cakephp/migrations:~1.0 The migrations plugin will now be in your application's **plugins** folder. Also, add `$this->addPlugin('Migrations');` to your application's `bootstrap` method. Once the plugin is loaded, run the following command to create a migration file: bin/cake bake migration CreateArticles title:string body:text category_id:integer created modified A migration file will be generated in the **/config/Migrations** folder with the following: table('articles'); $table->addColumn('title', 'string', [\ 'default' => null,\ 'limit' => 255,\ 'null' => false,\ ]); $table->addColumn('body', 'text', [\ 'default' => null,\ 'null' => false,\ ]); $table->addColumn('category_id', 'integer', [\ 'default' => null,\ 'limit' => 11,\ 'null' => false,\ ]); $table->addColumn('created', 'datetime', [\ 'default' => null,\ 'null' => false,\ ]); $table->addColumn('modified', 'datetime', [\ 'default' => null,\ 'null' => false,\ ]); $table->create(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 Run another command to create a `categories` table. If you need to specify a field length, you can do it within brackets in the field type, ie: bin/cake bake migration CreateCategories parent_id:integer lft:integer[10] rght:integer[10] name:string[100] description:string created modified This will generate the following file in **config/Migrations**: table('categories'); $table->addColumn('parent_id', 'integer', [\ 'default' => null,\ 'limit' => 11,\ 'null' => false,\ ]); $table->addColumn('lft', 'integer', [\ 'default' => null,\ 'limit' => 10,\ 'null' => false,\ ]); $table->addColumn('rght', 'integer', [\ 'default' => null,\ 'limit' => 10,\ 'null' => false,\ ]); $table->addColumn('name', 'string', [\ 'default' => null,\ 'limit' => 100,\ 'null' => false,\ ]); $table->addColumn('description', 'string', [\ 'default' => null,\ 'limit' => 255,\ 'null' => false,\ ]); $table->addColumn('created', 'datetime', [\ 'default' => null,\ 'null' => false,\ ]); $table->addColumn('modified', 'datetime', [\ 'default' => null,\ 'null' => false,\ ]); $table->create(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 Now that the migration files are created, you can edit them before creating your tables. We need to change the `'null' => false` for the `parent_id` field with `'null' => true` because a top-level category has a null `parent_id`. Run the following command to create your tables: bin/cake migrations migrate Modifying the Tables [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-three.html#modifying-the-tables) ------------------------------------------------------------------------------------------------------------------------ With our tables set up, we can now focus on categorizing our articles. We suppose you already have the files (Tables, Controllers and Templates of Articles) from part 2. So we'll just add the references to categories. We need to associate the Articles and Categories tables together. Open the **src/Model/Table/ArticlesTable.php** file and add the following: // src/Model/Table/ArticlesTable.php namespace App\Model\Table; use Cake\ORM\Table; class ArticlesTable extends Table { public function initialize(array $config) { $this->addBehavior('Timestamp'); // Just add the belongsTo relation with CategoriesTable $this->belongsTo('Categories', [\ 'foreignKey' => 'category_id',\ ]); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Generate Skeleton Code for Categories [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-three.html#generate-skeleton-code-for-categories) ---------------------------------------------------------------------------------------------------------------------------------------------------------- Create all files by launching bake commands: bin/cake bake model Categories bin/cake bake controller Categories bin/cake bake template Categories Alternatively, you can bake all with just one line: bin/cake bake all Categories The bake tool has created all your files in a snap. You can give them a quick read if you want re-familiarize yourself with how CakePHP works. NOTE If you are on Windows remember to use \\ instead of /. You'll need to edit the following in **src/Template/Categories/add.ctp** and **src/Template/Categories/edit.ctp**: echo $this->Form->control('parent_id', [\ 'options' => $parentCategories,\ 'empty' => 'No parent category'\ ]); 1 2 3 4 Attach TreeBehavior to CategoriesTable [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-three.html#attach-treebehavior-to-categoriestable) ------------------------------------------------------------------------------------------------------------------------------------------------------------ The [TreeBehavior](https://book.cakephp.org/3.x/orm/behaviors/tree.html) helps you manage hierarchical Tree structures in database table. It uses the [MPTT logic](https://www.sitepoint.com/hierarchical-data-database-2/) to manage the data. MPTT tree structures are optimized for reads, which often makes them a good fit for read heavy applications like blogs. If you open the **src/Model/Table/CategoriesTable.php** file, you'll see that the TreeBehavior has been attached to your CategoriesTable in the `initialize()` method. Bake adds this behavior to any Tables that contain `lft` and `rght` columns: $this->addBehavior('Tree'); 1 With the TreeBehavior attached you'll be able to access some features like reordering the categories. We'll see that in a moment. But for now, you have to remove the following controls in your Categories add and edit template files: echo $this->Form->control('lft'); echo $this->Form->control('rght'); 1 2 In addition you should disable or remove the requirePresence from the validator for both the `lft` and `rght` columns in your CategoriesTable model: public function validationDefault(Validator $validator) { $validator ->add('id', 'valid', ['rule' => 'numeric']) ->allowEmptyString('id', 'create'); $validator ->add('lft', 'valid', ['rule' => 'numeric']) // ->requirePresence('lft', 'create') ->notEmpty('lft'); $validator ->add('rght', 'valid', ['rule' => 'numeric']) // ->requirePresence('rght', 'create') ->notEmpty('rght'); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 These fields are automatically managed by the TreeBehavior when a category is saved. Using your web browser, add some new categories using the `/yoursite/categories/add` controller action. Reordering Categories with TreeBehavior [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-three.html#reordering-categories-with-treebehavior) -------------------------------------------------------------------------------------------------------------------------------------------------------------- In your categories index template file, you can list the categories and re-order them. Let's modify the index method in your **CategoriesController.php** and add `moveUp()` and `moveDown()` methods to be able to reorder the categories in the tree: class CategoriesController extends AppController { public function index() { $categories = $this->Categories->find() ->order(['lft' => 'ASC']); $this->set(compact('categories')); $this->set('_serialize', ['categories']); } public function moveUp($id = null) { $this->request->allowMethod(['post', 'put']); $category = $this->Categories->get($id); if ($this->Categories->moveUp($category)) { $this->Flash->success('The category has been moved Up.'); } else { $this->Flash->error('The category could not be moved up. Please, try again.'); } return $this->redirect($this->referer(['action' => 'index'])); } public function moveDown($id = null) { $this->request->allowMethod(['post', 'put']); $category = $this->Categories->get($id); if ($this->Categories->moveDown($category)) { $this->Flash->success('The category has been moved down.'); } else { $this->Flash->error('The category could not be moved down. Please, try again.'); } return $this->redirect($this->referer(['action' => 'index'])); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 In **src/Template/Categories/index.ctp** replace the existing content with:

    • Html->link(__('New Category'), ['action' => 'add']) ?>
    Id Parent Id Lft Rght Name Description Created
    id ?> parent_id ?> lft ?> rght ?> name) ?> description) ?> created) ?> Html->link(__('View'), ['action' => 'view', $category->id]) ?> Html->link(__('Edit'), ['action' => 'edit', $category->id]) ?> Form->postLink(__('Delete'), ['action' => 'delete', $category->id], ['confirm' => __('Are you sure you want to delete # {0}?', $category->id)]) ?> Form->postLink(__('Move down'), ['action' => 'moveDown', $category->id], ['confirm' => __('Are you sure you want to move down # {0}?', $category->id)]) ?> Form->postLink(__('Move up'), ['action' => 'moveUp', $category->id], ['confirm' => __('Are you sure you want to move up # {0}?', $category->id)]) ?>
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 Modifying the ArticlesController [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-three.html#modifying-the-articlescontroller) ------------------------------------------------------------------------------------------------------------------------------------------------ In our `ArticlesController`, we'll get the list of all the categories. This will allow us to choose a category for an Article when creating or editing it: // src/Controller/ArticlesController.php namespace App\Controller; // Prior to 3.6 use Cake\Network\Exception\NotFoundException use Cake\Http\Exception\NotFoundException; class ArticlesController extends AppController { // ... public function add() { $article = $this->Articles->newEntity(); if ($this->request->is('post')) { // Prior to 3.4.0 $this->request->data() was used. $article = $this->Articles->patchEntity($article, $this->request->getData()); if ($this->Articles->save($article)) { $this->Flash->success(__('Your article has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('Unable to add your article.')); } $this->set('article', $article); // Just added the categories list to be able to choose // one category for an article $categories = $this->Articles->Categories->find('treeList'); $this->set(compact('categories')); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Modifying the Articles Templates [​](https://book.cakephp.org/3.x/tutorials-and-examples/blog/part-three.html#modifying-the-articles-templates) ------------------------------------------------------------------------------------------------------------------------------------------------ The article add file should look something like this:

    Add Article

    Form->create($article); // just added the categories control echo $this->Form->control('category_id'); echo $this->Form->control('title'); echo $this->Form->control('body', ['rows' => '3']); echo $this->Form->button(__('Save Article')); echo $this->Form->end(); 1 2 3 4 5 6 7 8 9 10 11 When you go to the address /yoursite/categories/add you should see a list of categories to choose. --- # Html | CakePHP [Skip to content](https://book.cakephp.org/3.x/views/helpers/html.html#VPContent) Return to top Html [​](https://book.cakephp.org/3.x/views/helpers/html.html#html) ==================================================================== `class` Cake\\View\\Helper\\**HtmlHelper**(View $view, array $config = \[\]) The role of the HtmlHelper in CakePHP is to make HTML-related options easier, faster, and more resilient to change. Using this helper will enable your application to be more light on its feet, and more flexible on where it is placed in relation to the root of a domain. Many HtmlHelper methods include a `$attributes` parameter, that allow you to tack on any extra attributes on your tags. Here are a few examples of how to use the `$attributes` parameter: Desired attributes: Array parameter: ['class' => 'someClass'] Desired attributes: Array parameter: ['name' => 'foo', 'value' => 'bar'] 1 2 3 4 5 Inserting Well-Formatted Elements [​](https://book.cakephp.org/3.x/views/helpers/html.html#inserting-well-formatted-elements) ------------------------------------------------------------------------------------------------------------------------------ The most important task the HtmlHelper accomplishes is creating well formed markup. This section will cover some of the methods of the HtmlHelper and how to use them. ### Creating Charset Tags [​](https://book.cakephp.org/3.x/views/helpers/html.html#creating-charset-tags) `method` Cake\\View\\Helper\\HtmlHelper::**charset**($charset=null) Used to create a meta tag specifying the document's character. The default value is UTF-8. An example use: echo $this->Html->charset(); 1 Will output: 1 Alternatively, : echo $this->Html->charset('ISO-8859-1'); 1 Will output: 1 ### Linking to CSS Files [​](https://book.cakephp.org/3.x/views/helpers/html.html#linking-to-css-files) `method` Cake\\View\\Helper\\HtmlHelper::**css**(mixed $path, array $options = \[\]) Creates a link(s) to a CSS style-sheet. If the `block` option is set to `true`, the link tags are added to the `css` block which you can print inside the head tag of the document. You can use the `block` option to control which block the link element will be appended to. By default it will append to the `css` block. If key 'rel' in `$options` array is set to 'import' the stylesheet will be imported. This method of CSS inclusion assumes that the CSS file specified resides inside the **webroot/css** directory if path doesn't start with a '/'. : echo $this->Html->css('forms'); 1 Will output: 1 The first parameter can be an array to include multiple files. : echo $this->Html->css(['forms', 'tables', 'menu']); 1 Will output: 1 2 3 You can include CSS files from any loaded plugin using `plugin syntax`. To include **plugins/DebugKit/webroot/css/toolbar.css** you could use the following: echo $this->Html->css('DebugKit.toolbar.css'); 1 If you want to include a CSS file which shares a name with a loaded plugin you can do the following. For example if you had a `Blog` plugin, and also wanted to include **webroot/css/Blog.common.css**, you would: echo $this->Html->css('Blog.common.css', ['plugin' => false]); 1 ### Creating CSS Programatically [​](https://book.cakephp.org/3.x/views/helpers/html.html#creating-css-programatically) `method` Cake\\View\\Helper\\HtmlHelper::**style**(array $data, boolean $oneline = true) Builds CSS style definitions based on the keys and values of the array passed to the method. Especially handy if your CSS file is dynamic. : echo $this->Html->style([\ 'background' => '#633',\ 'border-bottom' => '1px solid #000',\ 'padding' => '10px'\ ]); 1 2 3 4 5 Will output: background:#633; border-bottom:1px solid #000; padding:10px; 1 ### Creating meta Tags [​](https://book.cakephp.org/3.x/views/helpers/html.html#creating-meta-tags) `method` Cake\\View\\Helper\\HtmlHelper::**meta**(string|array $type, string $url = null, array $options = \[\]) This method is handy for linking to external resources like RSS/Atom feeds and favicons. Like css(), you can specify whether or not you'd like this tag to appear inline or appended to the `meta` block by setting the 'block' key in the $attributes parameter to `true`, ie - `['block' => true]`. If you set the "type" attribute using the $attributes parameter, CakePHP contains a few shortcuts: | type | translated value | | --- | --- | | html | text/html | | rss | application/rss+xml | | atom | application/atom+xml | | icon | image/x-icon | Html->meta( 'favicon.ico', '/favicon.ico', ['type' => 'icon'] ); ?> // Output (line breaks added) // Note: The helper code makes two meta tags to ensure the // icon is downloaded by both newer and older browsers // which require different rel attribute values. Html->meta( 'Comments', '/comments/index.rss', ['type' => 'rss'] ); ?> // Output (line breaks added) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 This method can also be used to add the meta keywords and descriptions. Example: Html->meta( 'keywords', 'enter any meta keyword here' ); ?> // Output Html->meta( 'description', 'enter any meta description here' ); ?> // Output 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 In addition to making predefined meta tags, you can create link elements: Html->meta([\ 'link' => 'http://example.com/manifest',\ 'rel' => 'manifest'\ ]); ?> // Output 1 2 3 4 5 6 7 Any attributes provided to meta() when called this way will be added to the generated link tag. ### Creating DOCTYPE [​](https://book.cakephp.org/3.x/views/helpers/html.html#creating-doctype) `method` Cake\\View\\Helper\\HtmlHelper::**docType**(string $type = 'html5') Returns a (X)HTML DOCTYPE (document type declaration). Supply the document type according to the following table: | type | translated value | | --- | --- | | html4-strict | HTML 4.01 Strict | | html4-trans | HTML 4.01 Transitional | | html4-frame | HTML 4.01 Frameset | | html5 (default) | HTML5 | | xhtml-strict | XHTML 1.0 Strict | | xhtml-trans | XHTML 1.0 Transitional | | xhtml-frame | XHTML 1.0 Frameset | | xhtml11 | XHTML 1.1 | echo $this->Html->docType(); // Outputs: echo $this->Html->docType('html4-trans'); // Outputs: // 1 2 3 4 5 6 7 ### Linking to Images [​](https://book.cakephp.org/3.x/views/helpers/html.html#linking-to-images) `method` Cake\\View\\Helper\\HtmlHelper::**image**(string $path, array $options = \[\]) Creates a formatted image tag. The path supplied should be relative to **webroot/img/**. : echo $this->Html->image('cake_logo.png', ['alt' => 'CakePHP']); 1 Will output: CakePHP 1 To create an image link specify the link destination using the `url` option in `$attributes`. : echo $this->Html->image("recipes/6.jpg", [\ "alt" => "Brownies",\ 'url' => ['controller' => 'Recipes', 'action' => 'view', 6]\ ]); 1 2 3 4 Will output: Brownies 1 2 3 If you are creating images in emails, or want absolute paths to images you can use the `fullBase` option: echo $this->Html->image("logo.png", ['fullBase' => true]); 1 Will output: 1 You can include image files from any loaded plugin using `plugin syntax`. To include **plugins/DebugKit/webroot/img/icon.png** You could use the following: echo $this->Html->image('DebugKit.icon.png'); 1 If you want to include an image file which shares a name with a loaded plugin you can do the following. For example if you had a `Blog` plugin, and also wanted to include **webroot/img/Blog.icon.png**, you would: echo $this->Html->image('Blog.icon.png', ['plugin' => false]); 1 If you would like the prefix of the URL to not be `/img`, you can override this setting by specifying the prefix in the `$options` array : echo $this->Html->image("logo.png", ['pathPrefix' => '']); 1 Will output: 1 ### Creating Links [​](https://book.cakephp.org/3.x/views/helpers/html.html#creating-links) `method` Cake\\View\\Helper\\HtmlHelper::**link**(string $title, mixed $url = null, array $options = \[\]) General purpose method for creating HTML links. Use `$options` to specify attributes for the element and whether or not the `$title` should be escaped. : echo $this->Html->link( 'Enter', '/pages/home', ['class' => 'button', 'target' => '_blank'] ); 1 2 3 4 5 Will output: Enter 1 Use `'_full'=>true` option for absolute URLs: echo $this->Html->link( 'Dashboard', ['controller' => 'Dashboards', 'action' => 'index', '_full' => true] ); 1 2 3 4 Will output: Dashboard 1 Specify `confirm` key in options to display a JavaScript `confirm()` dialog: echo $this->Html->link( 'Delete', ['controller' => 'Recipes', 'action' => 'delete', 6], ['confirm' => 'Are you sure you wish to delete this recipe?'] ); 1 2 3 4 5 Will output: Delete 1 2 3 4 5 6 Query strings can also be created with `link()`. : echo $this->Html->link('View image', [\ 'controller' => 'Images',\ 'action' => 'view',\ 1,\ '?' => ['height' => 400, 'width' => 500]\ ]); 1 2 3 4 5 6 Will output: View image 1 HTML special characters in `$title` will be converted to HTML entities. To disable this conversion, set the escape option to `false` in the `$options` array. : echo $this->Html->link( $this->Html->image("recipes/6.jpg", ["alt" => "Brownies"]), "recipes/view/6", ['escape' => false] ); 1 2 3 4 5 Will output: Brownies 1 2 3 Setting `escape` to `false` will also disable escaping of attributes of the link. You can use the option `escapeTitle` to disable just escaping of title and not the attributes. : echo $this->Html->link( $this->Html->image('recipes/6.jpg', ['alt' => 'Brownies']), 'recipes/view/6', ['escapeTitle' => false, 'title' => 'hi "howdy"'] ); 1 2 3 4 5 Will output: Brownies 1 2 3 Also check `Cake\View\Helper\UrlHelper::build()` method for more examples of different types of URLs. ### Linking to Videos and Audio Files [​](https://book.cakephp.org/3.x/views/helpers/html.html#linking-to-videos-and-audio-files) `method` Cake\\View\\Helper\\HtmlHelper::**media**(string|array $path, array $options) Options: * `type` Type of media element to generate, valid values are "audio" or "video". If type is not provided media type is guessed based on file's mime type. * `text` Text to include inside the video tag * `pathPrefix` Path prefix to use for relative URLs, defaults to 'files/' * `fullBase` If provided the src attribute will get a full address including domain name Returns a formatted audio/video tag: Html->media('audio.mp3') ?> // Output Html->media('video.mp4', [\ 'fullBase' => true,\ 'text' => 'Fallback text'\ ]) ?> // Output Html->media( ['video.mp4', ['src' => 'video.ogg', 'type' => "video/ogg; codecs='theora, vorbis'"]], ['autoplay'] ) ?> // Output 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ### Linking to Javascript Files [​](https://book.cakephp.org/3.x/views/helpers/html.html#linking-to-javascript-files) `method` Cake\\View\\Helper\\HtmlHelper::**script**(mixed $url, mixed $options) Include a script file(s), contained either locally or as a remote URL. By default, script tags are added to the document inline. If you override this by setting `$options['block']` to `true`, the script tags will instead be added to the `script` block which you can print elsewhere in the document. If you wish to override which block name is used, you can do so by setting `$options['block']`. `$options['once']` controls whether or not you want to include this script once per request or more than once. This defaults to `true`. You can use $options to set additional properties to the generated script tag. If an array of script tags is used, the attributes will be applied to all of the generated script tags. This method of JavaScript file inclusion assumes that the JavaScript file specified resides inside the **webroot/js** directory: echo $this->Html->script('scripts'); 1 Will output: 1 You can link to files with absolute paths as well to link files that are not in **webroot/js**: echo $this->Html->script('/otherdir/script_file'); 1 You can also link to a remote URL: echo $this->Html->script('https://code.jquery.com/jquery.min.js'); 1 Will output: 1 The first parameter can be an array to include multiple files. : echo $this->Html->script(['jquery', 'wysiwyg', 'scripts']); 1 Will output: 1 2 3 You can append the script tag to a specific block using the `block` option: echo $this->Html->script('wysiwyg', ['block' => 'scriptBottom']); 1 In your layout you can output all the script tags added to 'scriptBottom': echo $this->fetch('scriptBottom'); 1 You can include script files from any loaded plugin using `plugin syntax`. To include **plugins/DebugKit/webroot/js/toolbar.js** You could use the following: echo $this->Html->script('DebugKit.toolbar.js'); 1 If you want to include a script file which shares a name with a loaded plugin you can do the following. For example if you had a `Blog` plugin, and also wanted to include **webroot/js/Blog.plugins.js**, you would: echo $this->Html->script('Blog.plugins.js', ['plugin' => false]); 1 ### Creating Inline Javascript Blocks [​](https://book.cakephp.org/3.x/views/helpers/html.html#creating-inline-javascript-blocks) `method` Cake\\View\\Helper\\HtmlHelper::**scriptBlock**($code, $options = \[\]) To generate Javascript blocks from PHP view code, you can use one of the script block methods. Scripts can either be output in place, or buffered into a block: // Define a script block all at once, with the defer attribute. $this->Html->scriptBlock('alert("hi")', ['defer' => true]); // Buffer a script block to be output later. $this->Html->scriptBlock('alert("hi")', ['block' => true]); 1 2 3 4 5 `method` Cake\\View\\Helper\\HtmlHelper::**scriptStart**($options = \[\]) `method` Cake\\View\\Helper\\HtmlHelper::**scriptEnd**() You can use the `scriptStart()` method to create a capturing block that will output into a `'\ ]); 1 2 3 4 You can load a configuration file containing templates using the templater directly: // Load a configuration file with templates. $this->Html->templater()->load('my_tags'); 1 2 When loading files of templates, your file should look like: ''\ ]; 1 2 3 4 WARNING Template strings containing a percentage sign (`%`) need special attention, you should prefix this character with another percentage so it looks like `%%`. The reason is that internally templates are compiled to be used with `sprintf()`. Example: `
    ` Creating Breadcrumb Trails with HtmlHelper [​](https://book.cakephp.org/3.x/views/helpers/html.html#creating-breadcrumb-trails-with-htmlhelper) ------------------------------------------------------------------------------------------------------------------------------------------------ `method` Cake\\View\\Helper\\HtmlHelper::**addCrumb**(string $name, string $link = null, mixed $options = null) `method` Cake\\View\\Helper\\HtmlHelper::**getCrumbs**(string $separator = '»', string $startText = false) `method` Cake\\View\\Helper\\HtmlHelper::**getCrumbList**(array $options = \[\], $startText = false) Many applications have breadcrumb trails to ease end user navigations. You can create a breadcrumb trail in your app with some help from HtmlHelper. To make bread crumbs, first the following in your layout template: echo $this->Html->getCrumbs(' > ', 'Home'); 1 The `$startText` option can also accept an array. This gives more control over the generated first link: echo $this->Html->getCrumbs(' > ', [\ 'text' => $this->Html->image('home.png'),\ 'url' => ['controller' => 'Pages', 'action' => 'display', 'home'],\ 'escape' => false\ ]); 1 2 3 4 5 Any keys that are not `text` or `url` will be passed to `~HtmlHelper::link()` as the `$options` parameter. Now, in your view you'll want to add the following to start the breadcrumb trails on each of the pages: $this->Html->addCrumb('Users', '/users'); $this->Html->addCrumb('Add User', ['controller' => 'Users', 'action' => 'add']); 1 2 This will add the output of "\*\*Home > Users > Add User\*\*" in your layout where `getCrumbs` was added. You can also fetch the crumbs formatted inside an HTML list: echo $this->Html->getCrumbList(); 1 As options you can use regular HTML parameter that fits in the `