diff --git a/.github/.markdownlint-cli2.jsonc b/.github/.markdownlint-cli2.jsonc new file mode 100644 index 0000000000..c1a37a8ee1 --- /dev/null +++ b/.github/.markdownlint-cli2.jsonc @@ -0,0 +1,83 @@ +{ + "config": { + "default": true, + "heading-increment": true, + "no-hard-tabs": true, + "no-multiple-blanks": true, + "line-length": false, + "commands-show-output": true, + "blanks-around-headings": true, + "heading-start-left": true, + "no-duplicate-heading": false, + "single-h1": false, + "no-trailing-punctuation": false, + "no-blanks-blockquote": false, + "list-marker-space": true, + "blanks-around-fences": true, + "blanks-around-lists": true, + "no-inline-html": { + "allowed_elements": [ + "Badge", + "div", + "span", + "br", + "style", + "details", + "summary", + "table", + "thead", + "tbody", + "tr", + "th", + "td", + "img", + "a", + "svg", + "path", + "figure", + "p", + "colgroup", + "col", + "strong", + "sup", + "section", + "hr", + "ol", + "ul", + "li", + "em", + "code" + ] + }, + "no-bare-urls": true, + "fenced-code-language": true, + "first-line-heading": false, + "code-block-style": false, + "code-fence-style": { + "style": "backtick" + }, + "emphasis-style": { + "style": "asterisk" + }, + "strong-style": { + "style": "asterisk" + }, + "spaces-after-emphasis-marker": true, + "spaces-after-code-fence-info": true, + "spaces-inside-emphasis-markers": true, + "spaces-inside-code-span-elements": true, + "single-trailing-newline": true, + "link-fragments": false, + "table-pipe-style": "leading_and_trailing", + "table-column-count": false, + "table-column-style": false, + "descriptive-link-text": false, + "no-emphasis-as-heading": false + }, + "customRules": [ + "./markdownlint-rules/no-space-after-fence.js" + ], + "ignores": [ + "node_modules/**" + ] +} diff --git a/.github/markdownlint-rules/no-space-after-fence.js b/.github/markdownlint-rules/no-space-after-fence.js new file mode 100644 index 0000000000..b6b0f479a7 --- /dev/null +++ b/.github/markdownlint-rules/no-space-after-fence.js @@ -0,0 +1,35 @@ +"use strict"; + +module.exports = { + names: ["no-space-after-fence"], + description: "Disallow spaces between a fence and the info string.", + tags: ["code", "fences", "whitespace"], + function: function noSpaceAfterFence(params, onError) { + const lines = params.lines || []; + + (params.tokens || []).forEach((token) => { + if (token.type !== "fence") { + return; + } + + if (!token.markup || token.markup[0] !== "`") { + return; + } + + if (!token.map || token.map.length === 0) { + return; + } + + const lineNumber = token.map[0] + 1; + const line = lines[lineNumber - 1] || ""; + + if (/^\s*`{3,}[ \t]+\S/.test(line)) { + onError({ + lineNumber, + detail: "Remove the space between the fence and the info string.", + context: line.trim() + }); + } + }); + } +}; diff --git a/.github/markdownlint.json b/.github/markdownlint.json deleted file mode 100644 index ddc76bcfea..0000000000 --- a/.github/markdownlint.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "default": true, - "heading-increment": true, - "no-hard-tabs": true, - "no-multiple-blanks": true, - "line-length": false, - "commands-show-output": true, - "blanks-around-headings": true, - "heading-start-left": true, - "no-duplicate-heading": false, - "single-h1": false, - "no-trailing-punctuation": false, - "no-blanks-blockquote": false, - "list-marker-space": true, - "blanks-around-fences": true, - "blanks-around-lists": true, - "no-inline-html": { - "allowed_elements": [ - "Badge", - "div", - "span", - "br", - "style", - "details", - "summary", - "table", - "thead", - "tbody", - "tr", - "th", - "td", - "img", - "a", - "svg", - "path", - "figure", - "p", - "colgroup", - "col", - "strong", - "sup", - "section", - "hr", - "ol", - "ul", - "li", - "em", - "code" - ] - }, - "no-bare-urls": true, - "fenced-code-language": true, - "first-line-heading": false, - "code-block-style": false, - "code-fence-style": { - "style": "backtick" - }, - "emphasis-style": { - "style": "asterisk" - }, - "strong-style": { - "style": "asterisk" - }, - "spaces-after-emphasis-marker": true, - "spaces-after-code-fence-info": true, - "spaces-inside-emphasis-markers": true, - "spaces-inside-code-span-elements": true, - "single-trailing-newline": true, - "link-fragments": false, - "table-pipe-style": "leading_and_trailing", - "table-column-count": false, - "table-column-style": false, - "descriptive-link-text": false, - "no-emphasis-as-heading": false -} diff --git a/.github/workflows/docs-validation.yml b/.github/workflows/docs-validation.yml index 7070721dd7..91911bf2f6 100644 --- a/.github/workflows/docs-validation.yml +++ b/.github/workflows/docs-validation.yml @@ -57,11 +57,10 @@ jobs: uses: actions/checkout@v6 - name: Lint markdown files - uses: articulate/actions-markdownlint@v1 + uses: DavidAnson/markdownlint-cli2-action@v22 with: - config: .github/markdownlint.json - files: 'docs/**/*.md' - ignore: 'node_modules' + config: './.github/.markdownlint-cli2.jsonc' + globs: 'docs/**/*.md' spell-check: name: Spell Check diff --git a/docs/en/appendices/5-0-migration-guide.md b/docs/en/appendices/5-0-migration-guide.md index 316e412112..4492d6eec4 100644 --- a/docs/en/appendices/5-0-migration-guide.md +++ b/docs/en/appendices/5-0-migration-guide.md @@ -225,7 +225,7 @@ high memory usage due to the entire result set being buffered in memory. You can work around this issue by disabling results buffering for the query: -``` php +```php $results = $articles->find() ->disableBufferedResults() ->all(); @@ -233,7 +233,7 @@ $results = $articles->find() Depending on your use case, you may also consider using disabling hydration: -``` php +```php $results = $articles->find() ->disableHydration() ->all(); @@ -350,7 +350,7 @@ properties more strictly. The new behavior is called 'required fields'. When enabled, accessing properties that are not defined in the entity will raise exceptions. This impacts the following usage: -``` php +```php $entity->get(); $entity->has(); $entity->getOriginal(); @@ -368,7 +368,7 @@ this the default behavior in the future. Table finders can now have typed arguments as required instead of an options array. For e.g. a finder for fetching posts by category or user: -``` php +```php public function findByCategoryOrUser(SelectQuery $query, array $options): SelectQuery { if (isset($options['categoryId'])) { @@ -384,7 +384,7 @@ public function findByCategoryOrUser(SelectQuery $query, array $options): Select can now be written as: -``` php +```php public function findByCategoryOrUser(SelectQuery $query, ?int $categoryId = null, ?int $userId = null): SelectQuery { if ($categoryId) { @@ -404,7 +404,7 @@ You can even include the special named arguments for setting query clauses. A similar change has been applied to the `RepositoryInterface::get()` method: -``` php +```php public function view(int $id) { $author = $this->Authors->get($id, [ @@ -416,7 +416,7 @@ public function view(int $id) can now be written as: -``` php +```php public function view(int $id) { $author = $this->Authors->get($id, contain: ['Books'], finder: 'latest'); diff --git a/docs/en/appendices/5-0-upgrade-guide.md b/docs/en/appendices/5-0-upgrade-guide.md index 77d1fc9d48..7c458f713b 100644 --- a/docs/en/appendices/5-0-upgrade-guide.md +++ b/docs/en/appendices/5-0-upgrade-guide.md @@ -11,7 +11,7 @@ First, check that your application is running on latest CakePHP 4.x version. Once your application is running on latest CakePHP 4.x, enable deprecation warnings in **config/app.php**: -``` php +```php 'Error' => [ 'errorLevel' => E_ALL, ], @@ -43,7 +43,7 @@ Because CakePHP 5 leverages union types and `mixed`, there are many backwards incompatible changes concerning method signatures and file renames. To help expedite fixing these tedious changes there is an upgrade CLI tool: -``` bash +```bash # Install the upgrade tool git clone https://github.com/cakephp/upgrade cd upgrade @@ -54,7 +54,7 @@ composer install --no-dev With the upgrade tool installed you can now run it on your application or plugin: -``` bash +```bash bin/cake upgrade rector --rules cakephp50 bin/cake upgrade rector --rules chronos3 ``` diff --git a/docs/en/appendices/5-1-migration-guide.md b/docs/en/appendices/5-1-migration-guide.md index e99f6aae07..dadebc3e70 100644 --- a/docs/en/appendices/5-1-migration-guide.md +++ b/docs/en/appendices/5-1-migration-guide.md @@ -15,7 +15,7 @@ The [upgrade tool](../appendices/migration-guides) provides rector rules for automating some of the migration work. Run rector before updating your `composer.json` dependencies: -``` bash +```bash bin/cake upgrade rector --rules cakephp51 ``` diff --git a/docs/en/appendices/5-2-migration-guide.md b/docs/en/appendices/5-2-migration-guide.md index a720a3a5bd..277ac03aa5 100644 --- a/docs/en/appendices/5-2-migration-guide.md +++ b/docs/en/appendices/5-2-migration-guide.md @@ -15,7 +15,7 @@ The [upgrade tool](../appendices/migration-guides) provides rector rules for automating some of the migration work. Run rector before updating your `composer.json` dependencies: -``` bash +```bash bin/cake upgrade rector --rules cakephp52 ``` diff --git a/docs/en/appendices/5-3-migration-guide.md b/docs/en/appendices/5-3-migration-guide.md index 6458e19b2f..ba29464945 100644 --- a/docs/en/appendices/5-3-migration-guide.md +++ b/docs/en/appendices/5-3-migration-guide.md @@ -15,7 +15,7 @@ The [upgrade tool](../appendices/migration-guides) provides rector rules for automating some of the migration work. Run rector before updating your `composer.json` dependencies: -``` bash +```bash bin/cake upgrade rector --rules cakephp53 ``` diff --git a/docs/en/appendices/glossary.md b/docs/en/appendices/glossary.md index 6ae9138c3a..63fb7895e5 100644 --- a/docs/en/appendices/glossary.md +++ b/docs/en/appendices/glossary.md @@ -6,29 +6,35 @@ description: "CakePHP terminology reference: understand common abbreviations, te # Glossary ## CDN + Content Delivery Network. A 3rd party vendor you can pay to help distribute your content to data centers around the world. This helps put your static assets closer to geographically distributed users. ## columns + Used in the ORM when referring to the table columns in an database table. ## CSRF + Cross Site Request Forgery. Prevents replay attacks, double submissions and forged requests from other domains. ## DI Container + In `Application::services()` you can configure application services and their dependencies. Application services are automatically injected into Controller actions, and Command Constructors. See [Dependency Injection](../development/dependency-injection). ## DSN + Data Source Name. A connection string format that is formed like a URI. CakePHP supports DSNs for Cache, Database, Log and Email connections. ## dot notation + Dot notation defines an array path, by separating nested levels with `.` For example: @@ -36,7 +42,7 @@ For example: Would point to the following value: -``` php +```php [ 'Cache' => [ 'default' => [ @@ -47,19 +53,22 @@ Would point to the following value: ``` ## DRY + Don't repeat yourself. Is a principle of software development aimed at reducing repetition of information of all kinds. In CakePHP DRY is used to allow you to code things once and re-use them across your application. ## fields + A generic term used to describe both entity properties, or database columns. Often used in conjunction with the FormHelper. ## HTML attributes + An array of key => values that are composed into HTML attributes. For example: -``` php +```php // Given ['class' => 'my-class', 'target' => '_blank'] @@ -70,7 +79,7 @@ class="my-class" target="_blank" If an option can be minimized or accepts its name as the value, then `true` can be used: -``` php +```php // Given ['checked' => true] @@ -79,18 +88,21 @@ checked="checked" ``` ## PaaS + Platform as a Service. Platform as a Service providers will provide cloud based hosting, database and caching resources. Some popular providers include Heroku, EngineYard and PagodaBox ## properties + Used when referencing columns mapped onto an ORM entity. ## plugin syntax + Plugin syntax refers to the dot separated class name indicating classes are part of a plugin: -``` php +```php // The plugin is "DebugKit", and the class name is "Toolbar". 'DebugKit.Toolbar' @@ -99,15 +111,17 @@ are part of a plugin: ``` ## routes.php + A file in the `config/` directory that contains routing configuration. This file is included before each request is processed. It should connect all the routes your application needs so requests can be routed to the correct controller + action. ## routing array + An array of attributes that are passed to `Router::url()`. They typically look like: -``` php +```php ['controller' => 'Posts', 'action' => 'view', 5] ``` diff --git a/docs/en/appendices/migration-guides.md b/docs/en/appendices/migration-guides.md index 28185f8820..5e4b034630 100644 --- a/docs/en/appendices/migration-guides.md +++ b/docs/en/appendices/migration-guides.md @@ -17,7 +17,7 @@ method renames and signature updates. To use the upgrade tool: -``` bash +```bash # Install the upgrade tool git clone https://github.com/cakephp/upgrade cd upgrade diff --git a/docs/en/appendices/phpunit-upgrade.md b/docs/en/appendices/phpunit-upgrade.md index 6cb5897ecc..8b374913c8 100644 --- a/docs/en/appendices/phpunit-upgrade.md +++ b/docs/en/appendices/phpunit-upgrade.md @@ -34,7 +34,7 @@ With this command out of the way your `phpunit.xml` already has most of the reco PHPUnit 10 removed the old hook system and introduced a new [Event system](https://docs.phpunit.de/en/10.5/extending-phpunit.html#extending-the-test-runner) which requires the following code in your `phpunit.xml` to be adjusted from: -``` xml +```xml @@ -42,7 +42,7 @@ which requires the following code in your `phpunit.xml` to be adjusted from: to: -``` xml +```xml @@ -55,13 +55,13 @@ to: You can convert the removed `->withConsecutive()` method to a working interim solution like you can see here: -``` php +```php ->withConsecutive(['firstCallArg'], ['secondCallArg']) ``` should be converted to: -``` php +```php ->with( ...self::withConsecutive(['firstCallArg'], ['secondCallArg']), ) @@ -75,13 +75,13 @@ to the base `Cake\TestSuite\TestCase` class so you don't have to manually add th If your test cases leverage the data provider feature of PHPUnit then you have to adjust your data providers to be static: -``` php +```php public function myProvider(): array ``` should be converted to: -``` php +```php public static function myProvider(): array ``` @@ -93,7 +93,7 @@ PHPUnit 11 requires PHP 8.2 or later. PHPUnit 11 deprecates annotations in docblocks. You should migrate to PHP 8 attributes: -``` php +```php // Before (deprecated) /** * @dataProvider myProvider @@ -125,7 +125,7 @@ Methods for creating mock objects for abstract classes and traits are hard-depre Configuring expectations on an object created with `createStub()` triggers a deprecation warning: -``` php +```php // Avoid - will warn in PHPUnit 11 $stub = $this->createStub(SomeClass::class); $stub->expects($this->once())->method('foo'); @@ -159,7 +159,7 @@ Configuring expectations on objects created with `createStub()` no longer works. [Rector](https://getrector.com/) can automate many of these changes: -``` bash +```bash composer require --dev rector/rector rector/rector-phpunit # Create rector.php config diff --git a/docs/en/console-commands.md b/docs/en/console-commands.md index c30a883e1c..47212fcc07 100644 --- a/docs/en/console-commands.md +++ b/docs/en/console-commands.md @@ -23,7 +23,7 @@ bash the CakePHP console is compatible with any *nix shell and windows. A CakePHP application contains **src/Command** directory that contain its commands. It also comes with an executable in the **bin** directory: -``` bash +```bash cd /path/to/app bin/cake ``` @@ -34,7 +34,7 @@ bin/cake Running the Console with no arguments will list out available commands. You could then run the any of the listed commands by using its name: -``` bash +```bash # run server command bin/cake server @@ -59,7 +59,7 @@ commands, when building standalone console applications. You can use your `Application`'s `console()` hook to limit which commands are exposed and rename commands that are exposed: -``` php +```php // in src/Application.php namespace App; @@ -99,7 +99,7 @@ do this, you can register your commands to create any desired naming. You can customize the command names by defining each command in your plugin: -``` php +```php public function console(CommandCollection $commands): CommandCollection { // Add commands with nested naming @@ -158,7 +158,7 @@ bootstrap or config, for example. For sending emails, you should provide Email class with the host you want to send the email with: -``` php +```php use Cake\Mailer\Email; $email = new Email(); diff --git a/docs/en/console-commands/cache.md b/docs/en/console-commands/cache.md index f8a367411a..7fe52dc2bb 100644 --- a/docs/en/console-commands/cache.md +++ b/docs/en/console-commands/cache.md @@ -8,7 +8,7 @@ description: "Manage cache from CLI in CakePHP: clear all caches, specific cache To help you better manage cached data from a CLI environment, a console command is available for clearing cached data your application has: -``` bash +```bash // Clear one cache config bin/cake cache clear diff --git a/docs/en/console-commands/commands.md b/docs/en/console-commands/commands.md index 88e9b7140d..55cb26ebd8 100644 --- a/docs/en/console-commands/commands.md +++ b/docs/en/console-commands/commands.md @@ -17,7 +17,7 @@ Let's create our first Command. For this example, we'll create a simple Hello world command. In your application's **src/Command** directory create **HelloCommand.php**. Put the following code inside it: -``` php +```php fetchTable()` since command use the `LocatorAwareTrait`: -``` php +```php getArgument('name'); @@ -253,7 +253,7 @@ You can pass any desired exit code into `abort()`. You may need to call other commands from your command. You can use `executeCommand` to do that: -``` php +```php // You can pass an array of CLI options and arguments. $this->executeCommand(OtherCommand::class, ['--verbose', 'deploy']); @@ -271,7 +271,7 @@ $this->executeCommand($command, ['--verbose', 'deploy']); You may want to set a command description via: -``` php +```php class UserCommand extends Command { public static function getDescription(): string @@ -283,11 +283,11 @@ class UserCommand extends Command This will show your description in the Cake CLI: -``` bash +```bash bin/cake ``` -``` +```text App: - user └─── My custom description @@ -295,11 +295,11 @@ App: As well as in the help section of your command: -``` bash +```bash cake user --help ``` -``` +```text My custom description Usage: @@ -312,7 +312,7 @@ By default, in the help output CakePHP will group commands into core, app, and plugin groups. You can customize the grouping of commands by implementing `getGroup()`: -``` php +```php class CleanupCommand extends Command { public static function getGroup(): string @@ -333,7 +333,7 @@ collection without needing to remove and re-add it. This is particularly useful when using `autoDiscover` and you want to replace a command with a customized version: -``` php +```php // In your Application::console() method public function console(CommandCollection $commands): CommandCollection { @@ -353,7 +353,7 @@ public function console(CommandCollection $commands): CommandCollection The `TreeHelper` outputs an array as a tree structure. This is useful for displaying filesystem directories or any hierarchical data: -``` php +```php public function execute(Arguments $args, ConsoleIo $io): int { $helper = $io->helper('Tree'); @@ -392,7 +392,7 @@ you would use in the CLI to this method. Let's start with a very simple command, located in **src/Command/UpdateTableCommand.php**: -``` php +```php namespace App\Command; use Cake\Command\Command; @@ -416,7 +416,7 @@ To write an integration test for this command, we would create a test case in `Cake\TestSuite\ConsoleIntegrationTestTrait` trait. This command doesn't do much at the moment, but let's just test that our command's description is displayed in `stdout`: -``` php +```php namespace App\Test\TestCase\Command; use Cake\TestSuite\ConsoleIntegrationTestTrait; @@ -438,7 +438,7 @@ Our test passes! While this is very trivial example, it shows that creating an integration test case for console applications can follow command line conventions. Let's continue by adding more logic to our command: -``` php +```php namespace App\Command; use Cake\Command\Command; @@ -478,7 +478,7 @@ class UpdateTableCommand extends Command This is a more complete command that has required options and relevant logic. Modify your test case to the following snippet of code: -``` php +```php namespace Cake\Test\TestCase\Command; use Cake\Command\Command; @@ -538,7 +538,7 @@ included as an array in the order that you expect them. Continuing with our example command, let's add an interactive confirmation. Update the command class to the following: -``` php +```php namespace App\Command; use Cake\Command\Command; @@ -584,7 +584,7 @@ that we receive the proper response, and one that tests that we receive an incorrect response. Remove the `testUpdateModified` method and, add the following methods to **tests/TestCase/Command/UpdateTableCommandTest.php**: -``` php +```php public function testUpdateModifiedSure() { $now = new DateTime('2017-01-01 00:00:00'); @@ -624,7 +624,7 @@ our error message was written to `stderr`. The `Cake\TestSuite\ConsoleIntegrationTestTrait` trait provides a number of assertion methods that make help assert against console output: -``` php +```php // assert that the command exited as success $this->assertExitSuccess(); @@ -652,7 +652,7 @@ $this->assertErrorRegExp($expected); You can use `debugOutput()` to output the exit code, stdout and stderr of the last run command: -``` php +```php $this->exec('update_table Users'); $this->assertExitCode(Command::CODE_SUCCESS); $this->debugOutput(); @@ -687,7 +687,7 @@ The `beforeExecute()` and `afterExecute()` hook methods were added. Called before the `execute()` method runs. Useful for initialization and validation: -``` php +```php use Cake\Event\EventInterface; class MyCommand extends Command @@ -712,7 +712,7 @@ class MyCommand extends Command Called after the `execute()` method completes. Useful for cleanup and logging: -``` php +```php public function afterExecute(EventInterface $event, Arguments $args, ConsoleIo $io, mixed $result): void { parent::afterExecute($event); diff --git a/docs/en/console-commands/completion.md b/docs/en/console-commands/completion.md index 66a808c736..3d87f5edaf 100644 --- a/docs/en/console-commands/completion.md +++ b/docs/en/console-commands/completion.md @@ -82,7 +82,7 @@ Save the file, then restart your console. This is the code you need to put inside the **cake** file in the correct location in order to get autocompletion when using the CakePHP console: -``` bash +```bash # # Bash completion file for CakePHP console # @@ -146,7 +146,7 @@ Three type of autocompletion are provided. The following output are from a fresh Sample output for commands autocompletion: -``` bash +```bash $ bin/cake bake i18n schema_cache routes console migrations plugin server @@ -156,7 +156,7 @@ console migrations plugin server Sample output for subcommands autocompletion: -``` bash +```bash $ bin/cake bake behavior helper command cell mailer command_helper @@ -170,7 +170,7 @@ form plugin Sample output for subcommands options autocompletion: -``` bash +```bash $ bin/cake bake - -c --everything --force --help --plugin -q -t -v --connection -f -h -p --prefix --quiet --theme --verbose diff --git a/docs/en/console-commands/counter-cache.md b/docs/en/console-commands/counter-cache.md index 6abfcb2b75..34e2762360 100644 --- a/docs/en/console-commands/counter-cache.md +++ b/docs/en/console-commands/counter-cache.md @@ -10,7 +10,7 @@ in your application and plugin models. It can be used in maintenance and recovery operations, or to populate new counter caches added to your application. -``` bash +```bash bin/cake counter_cache Comments --assoc Articles ``` @@ -18,7 +18,7 @@ This would rebuild the `Comments` related counters on the `Articles` table. For very large tables you may need to rebuild counters in batches. You can use the `--limit` and `--page` options to incrementally rebuild counter state. -``` bash +```bash bin/cake counter_cache Comments --assoc Articles --limit 100 --page 2 ``` diff --git a/docs/en/console-commands/cron-jobs.md b/docs/en/console-commands/cron-jobs.md index 359444fb0c..0316a76eaf 100644 --- a/docs/en/console-commands/cron-jobs.md +++ b/docs/en/console-commands/cron-jobs.md @@ -9,7 +9,7 @@ A common thing to do with a shell is making it run as a cronjob to clean up the database once in a while or send newsletters. This is trivial to setup, for example: -``` text +```text */5 * * * * cd /full/path/to/root && bin/cake myshell myparam # * * * * * command to execute # │ │ │ │ │ diff --git a/docs/en/console-commands/i18n.md b/docs/en/console-commands/i18n.md index 74ce6c8f8d..a62ef336e8 100644 --- a/docs/en/console-commands/i18n.md +++ b/docs/en/console-commands/i18n.md @@ -21,7 +21,7 @@ command. This command will scan your entire application for `__()` style function calls, and extract the message string. Each unique string in your application will be combined into a single POT file: -``` bash +```bash bin/cake i18n extract ``` @@ -34,7 +34,7 @@ correctly set the `Plural-Forms` header line. You can generate a POT file for a specific plugin using: -``` bash +```bash bin/cake i18n extract --plugin ``` @@ -49,7 +49,7 @@ from this directory as well as from the `src/` directory. You can do it by using the `--paths` option. It takes a comma-separated list of absolute paths to extract: -``` bash +```bash bin/cake i18n extract --paths /var/www/app/config,/var/www/app/src ``` @@ -58,7 +58,7 @@ bin/cake i18n extract --paths /var/www/app/config,/var/www/app/src You can pass a comma separated list of folders that you wish to be excluded. Any path containing a path segment with the provided values will be ignored: -``` bash +```bash bin/cake i18n extract --exclude vendor,tests ``` @@ -67,7 +67,7 @@ bin/cake i18n extract --exclude vendor,tests By adding `--overwrite`, the shell script will no longer warn you if a POT file already exists and will overwrite by default: -``` bash +```bash bin/cake i18n extract --overwrite ``` @@ -77,7 +77,7 @@ By default, the extract shell script will ask you if you like to extract the messages used in the CakePHP core libraries. Set `--extract-core` to yes or no to set the default behavior: -``` bash +```bash bin/cake i18n extract --extract-core yes // or diff --git a/docs/en/console-commands/input-output.md b/docs/en/console-commands/input-output.md index ffe62286da..c49b16bc7f 100644 --- a/docs/en/console-commands/input-output.md +++ b/docs/en/console-commands/input-output.md @@ -17,7 +17,7 @@ enable better re-use and testability of console formatting code, CakePHP command helpers provide 'macros' for console formatting logic. Command Helpers can be accessed and used from any command: -``` php +```php // Output some data as a table. $io->helper('Table')->output($data); @@ -28,7 +28,7 @@ $io->helper('Plugin.HelperName')->output($data); You can also get instances of helpers and call any public methods, to manipulate state and generate updated output: -``` php +```php // Get and use the Progress Helper. $progress = $io->helper('Progress'); $progress->increment(10); @@ -42,7 +42,7 @@ application or plugins. As an example, we'll create a simple helper to generate fancy headings. First create the **src/Command/Helper/HeadingHelper.php** and put the following in it: -``` php +```php helper('Heading')->output(['It works!']); @@ -83,7 +83,7 @@ implement additional methods that take any form of arguments. The TableHelper assists in making well formatted ASCII art tables. Using it is pretty simple: -``` php +```php $data = [ ['Header 1', 'Header', 'Long Header'], ['short', 'Longish thing', 'short'], @@ -103,7 +103,7 @@ $io->helper('Table')->output($data); You can use the `` formatting tag in tables to right align content: -``` php +```php $data = [ ['Name', 'Total Price'], ['Cake Mix', '1.50'], @@ -123,7 +123,7 @@ $io->helper('Table')->output($data); The ProgressHelper can be used in two different ways. The simple mode lets you provide a callback that is invoked until the progress is complete: -``` php +```php $io->helper('Progress')->output(['callback' => function ($progress) { // Do work here. $progress->increment(20); @@ -141,7 +141,7 @@ You can control the progress bar more by providing additional options: An example of all the options in use would be: -``` php +```php $io->helper('Progress')->output([ 'total' => 10, 'width' => 20, @@ -155,7 +155,7 @@ $io->helper('Progress')->output([ The progress helper can also be used manually to increment and re-render the progress bar as necessary: -``` php +```php $progress = $io->helper('Progress'); $progress->init([ 'total' => 10, @@ -171,7 +171,7 @@ $progress->draw(); The `BannerHelper` can be used to format one or more lines of text into a banner with a background and horizontal padding: -``` php +```php $io->helper('Banner') ->withPadding(5) ->withStyle('success.bg') @@ -189,7 +189,7 @@ The `BannerHelper` was added in 5.1 When building interactive console applications you'll need to get user input. CakePHP provides a way to do this: -``` php +```php // Get arbitrary text from the user. $color = $io->ask('What color do you like?'); @@ -207,7 +207,7 @@ Creating files is often important part of many console commands that help automate development and deployment. The `createFile()` method gives you a simple interface for creating files with interactive confirmation: -``` php +```php // Create a file with confirmation on overwrite $io->createFile('bower.json', $stuff); @@ -221,7 +221,7 @@ $io->createFile('bower.json', $stuff, true); Writing to `stdout` is done using the `out()` method: -``` php +```php // Write to stdout $io->out('Normal message'); ``` @@ -230,7 +230,7 @@ $io->out('Normal message'); Writing to `stderr` is done using the `err()` method: -``` php +```php // Write to stderr $io->err('Error message'); ``` @@ -238,7 +238,7 @@ $io->err('Error message'); In addition to vanilla output methods, CakePHP provides wrapper methods that style output with appropriate ANSI colors: -``` php +```php // Green text on stdout $io->success('Success message'); @@ -260,7 +260,7 @@ true, or if the `NO_COLOR` environment variable is set. `ConsoleIo` provides two convenience methods regarding the output level: -``` php +```php // Would only appear when verbose output is enabled (-v) $io->verbose('Verbose message'); @@ -270,7 +270,7 @@ $io->quiet('Quiet message'); You can also create blank lines or draw lines of dashes: -``` php +```php // Output 2 newlines $io->out($io->nl(2)); @@ -280,7 +280,7 @@ $io->hr(); Lastly, you can update the current line of text on the screen: -``` php +```php $io->out('Counting down'); $io->out('10', 0); for ($i = 9; $i > 0; $i--) { @@ -311,7 +311,7 @@ command. There are 3 levels: You can mark output as follows: -``` php +```php // Would appear at all levels. $io->out('Quiet message', 1, ConsoleIo::QUIET); $io->quiet('Quiet message'); @@ -357,7 +357,7 @@ are several built-in styles, and you can create more. The built-in ones are You can create additional styles using `$io->setStyle()`. To declare a new output style you could do: -``` php +```php $io->setStyle('flashy', ['text' => 'magenta', 'blink' => true]); ``` @@ -396,7 +396,7 @@ The `info.bg`, `warning.bg`, `error.bg`, and `success.bg` were added. Although coloring is pretty, there may be times when you want to turn it off, or force it on: -``` php +```php $io->outputAs(ConsoleOutput::RAW); ``` diff --git a/docs/en/console-commands/option-parsers.md b/docs/en/console-commands/option-parsers.md index e1aa2bbca5..87d84a4e01 100644 --- a/docs/en/console-commands/option-parsers.md +++ b/docs/en/console-commands/option-parsers.md @@ -15,7 +15,7 @@ get information from the terminal into your commands. Commands and Shells provide a `buildOptionParser($parser)` hook method that you can use to define the options and arguments for your commands: -``` php +```php protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser { // Define your options and arguments. @@ -28,7 +28,7 @@ protected function buildOptionParser(ConsoleOptionParser $parser): ConsoleOption Shell classes use the `getOptionParser()` hook method to define their option parser: -``` php +```php public function getOptionParser() { // Get an empty parser from the framework. @@ -51,7 +51,7 @@ arguments as well as make them required. You can add arguments one at a time with `$parser->addArgument();` or multiple at once with `$parser->addArguments();`: -``` php +```php $parser->addArgument('model', ['help' => 'The model to bake']); ``` @@ -83,7 +83,7 @@ The `separator` option was added. If you have an array with multiple arguments you can use `$parser->addArguments()` to add multiple arguments at once. -``` php +```php $parser->addArguments([ 'node' => ['help' => 'The node to create', 'required' => true], 'parent' => ['help' => 'The parent node', 'required' => true], @@ -100,7 +100,7 @@ indicate that an argument must be present when a shell is called. Additionally, you can use `choices` to force an argument to be from a list of valid choices: -``` php +```php $parser->addArgument('type', [ 'help' => 'The type of node to interact with.', 'required' => true, @@ -121,7 +121,7 @@ arguments for your commands. Options can define both verbose and short aliases. They can accept a value (e.g `--connection=default`) or be boolean options (e.g `--verbose`). Options are defined with the `addOption()` method: -``` php +```php $parser->addOption('connection', [ 'short' => 'c', 'help' => 'connection', @@ -136,7 +136,7 @@ when invoking the shell. Boolean switches do not accept or consume values, and their presence just enables them in the parsed parameters: -``` php +```php $parser->addOption('no-commit', ['boolean' => true]); ``` @@ -174,7 +174,7 @@ The `separator` option was added. If you have an array with multiple options you can use `$parser->addOptions()` to add multiple options at once. -``` php +```php $parser->addOptions([ 'node' => ['short' => 'n', 'help' => 'The node to create'], 'parent' => ['short' => 'p', 'help' => 'The parent node'], @@ -190,7 +190,7 @@ Options can be provided with a set of choices much like positional arguments can be. When an option has defined choices, those are the only valid choices for an option. All other values will raise an `InvalidArgumentException`: -``` php +```php $parser->addOption('accept', [ 'help' => 'What version to accept.', 'choices' => ['working', 'theirs', 'mine'], @@ -204,7 +204,7 @@ create some flag options. Like options with defaults, boolean options always include themselves into the parsed parameters. When the flags are present they are set to `true`, when they are absent they are set to `false`: -``` php +```php $parser->addOption('verbose', [ 'help' => 'Enable verbose output.', 'boolean' => true, @@ -226,7 +226,7 @@ for arguments, and options, should follow the format that `Cake\Console\ConsoleOptionParser::addOptions()` use. You can also use `buildFromArray` on its own, to build an option parser: -``` php +```php public function getOptionParser() { return ConsoleOptionParser::buildFromArray([ @@ -251,7 +251,7 @@ public function getOptionParser() When building a group command, you maybe want to combine several parsers for this: -``` php +```php $parser->merge($anotherParser); ``` @@ -266,7 +266,7 @@ automatically generate rudimentary help information and add a `--help` and `-h` to each of your commands. Using one of these options will allow you to see the generated help content: -``` bash +```bash bin/cake bake --help bin/cake bake -h ``` @@ -274,7 +274,7 @@ bin/cake bake -h Would both generate the help for bake. You can also get help for nested commands: -``` bash +```bash bin/cake bake model --help bin/cake bake model -h ``` @@ -288,7 +288,7 @@ CakePHP shell commands, it's nice to have help available in a machine parse-able By providing the `xml` option when requesting help you can have help content returned as XML: -``` bash +```bash cake bake --help xml cake bake -h xml ``` @@ -297,7 +297,7 @@ The above would return an XML document with the generated help, options, and arguments for the selected shell. A sample XML document would look like: -``` xml +```xml bake fixture @@ -358,7 +358,7 @@ epilog. The description displays above the argument and option information. By passing in either an array or a string, you can set the value of the description: -``` php +```php // Set multiple lines at once $parser->setDescription(['line one', 'line two']); @@ -374,7 +374,7 @@ Gets or sets the epilog for the option parser. The epilog is displayed after the argument and option information. By passing in either an array or a string, you can set the value of the epilog: -``` php +```php // Set multiple lines at once $parser->setEpilog(['line one', 'line two']); diff --git a/docs/en/console-commands/plugin.md b/docs/en/console-commands/plugin.md index 5ae23f0441..3a1f97a252 100644 --- a/docs/en/console-commands/plugin.md +++ b/docs/en/console-commands/plugin.md @@ -10,7 +10,7 @@ description: "Manage plugins via CLI in CakePHP: load/unload plugins, configure The plugin tool allows you to load and unload plugins via the command prompt. If you need help, run: -``` bash +```bash bin/cake plugin --help ``` @@ -19,13 +19,13 @@ bin/cake plugin --help Via the `Load` task you are able to load plugins in your **config/bootstrap.php**. You can do this by running: -``` bash +```bash bin/cake plugin load MyPlugin ``` This will add the following to your **src/Application.php**: -``` php +```php // In the bootstrap method add: $this->addPlugin('MyPlugin'); ``` @@ -34,7 +34,7 @@ $this->addPlugin('MyPlugin'); You can unload a plugin by specifying its name: -``` bash +```bash bin/cake plugin unload MyPlugin ``` @@ -48,7 +48,7 @@ While this is a good convenience, it is recommended to symlink / copy the plugin assets under app's webroot so that they can be directly served by the web server without invoking PHP. You can do this by running: -``` bash +```bash bin/cake plugin assets symlink ``` @@ -58,6 +58,6 @@ respective folders instead of being symlinked. You can symlink assets of one particular plugin by specifying its name: -``` bash +```bash bin/cake plugin assets symlink MyPlugin ``` diff --git a/docs/en/console-commands/repl.md b/docs/en/console-commands/repl.md index f7e06d90b0..664fffa596 100644 --- a/docs/en/console-commands/repl.md +++ b/docs/en/console-commands/repl.md @@ -14,7 +14,7 @@ you explore some CakePHP and your application in an interactive console. You can start the interactive console using: -``` bash +```bash bin/cake console ``` @@ -22,7 +22,7 @@ This will bootstrap your application and start an interactive console. At this point you can interact with your application code and execute queries using your application's models: -``` bash +```bash bin/cake console >>> $articles = Cake\Datasource\FactoryLocator::get('Table')->get('Articles'); @@ -35,7 +35,7 @@ bin/cake console Since your application has been bootstrapped you can also test routing using the REPL: -``` php +```php >>> Cake\Routing\Router::parse('/articles/view/1'); // [ // 'controller' => 'Articles', @@ -49,7 +49,7 @@ REPL: You can also test generating URLs: -``` php +```php >>> Cake\Routing\Router::url(['controller' => 'Articles', 'action' => 'edit', 99]); // '/articles/edit/99' ``` diff --git a/docs/en/console-commands/routes.md b/docs/en/console-commands/routes.md index 8739ba65e8..d2493bfd61 100644 --- a/docs/en/console-commands/routes.md +++ b/docs/en/console-commands/routes.md @@ -11,7 +11,7 @@ parameters will generate. ## Getting a List of all Routes -``` bash +```bash bin/cake routes ``` @@ -19,14 +19,14 @@ bin/cake routes You can quickly see how a URL will be parsed using the `check` method: -``` bash +```bash bin/cake routes check /articles/edit/1 ``` If your route contains any query string parameters remember to surround the URL in quotes: -``` bash +```bash bin/cake routes check "/articles/?page=1&sort=title&direction=desc" ``` @@ -35,6 +35,6 @@ bin/cake routes check "/articles/?page=1&sort=title&direction=desc" You can see the URL a `routing array` will generate using the `generate` method: -``` bash +```bash bin/cake routes generate controller:Articles action:edit 1 ``` diff --git a/docs/en/console-commands/schema-cache.md b/docs/en/console-commands/schema-cache.md index e826bc71ec..96485b3837 100644 --- a/docs/en/console-commands/schema-cache.md +++ b/docs/en/console-commands/schema-cache.md @@ -10,7 +10,7 @@ metadata caches. In deployment situations it is helpful to rebuild the metadata cache in-place without clearing the existing cache data. You can do this by running: -``` bash +```bash bin/cake schema_cache build --connection default ``` @@ -18,14 +18,14 @@ This will rebuild the metadata cache for all tables on the `default` connection. If you only need to rebuild a single table you can do that by providing its name: -``` bash +```bash bin/cake schema_cache build --connection default articles ``` In addition to building cached data, you can use the SchemaCacheShell to remove cached metadata as well: -``` bash +```bash # Clear all metadata bin/cake schema_cache clear diff --git a/docs/en/console-commands/server.md b/docs/en/console-commands/server.md index e69a9d1998..2364d6dbb7 100644 --- a/docs/en/console-commands/server.md +++ b/docs/en/console-commands/server.md @@ -10,7 +10,7 @@ webserver. While this server is *not* intended for production use it can be handy in development when you want to quickly try an idea out and don't want to spend time configuring Apache or Nginx. You can start the server command with: -``` bash +```bash bin/cake server ``` @@ -26,6 +26,6 @@ terminal. You can customize the port and document root using options: -``` bash +```bash bin/cake server --port 8080 --document_root path/to/app ``` diff --git a/docs/en/contributing/backwards-compatibility.md b/docs/en/contributing/backwards-compatibility.md index 3168fb1ab3..cc2231dbba 100644 --- a/docs/en/contributing/backwards-compatibility.md +++ b/docs/en/contributing/backwards-compatibility.md @@ -277,7 +277,7 @@ locate code that needs to be updated before it breaks. If you wish to disable runtime warnings you can do so using the `Error.errorLevel` configuration value: -``` php +```php // in config/app.php // ... 'Error' => [ diff --git a/docs/en/contributing/cakephp-coding-conventions.md b/docs/en/contributing/cakephp-coding-conventions.md index 08564b7253..12f63ad3d2 100644 --- a/docs/en/contributing/cakephp-coding-conventions.md +++ b/docs/en/contributing/cakephp-coding-conventions.md @@ -37,7 +37,7 @@ Four spaces will be used for indentation. So, indentation should look like this: -``` php +```php // base level // level 1 // level 2 @@ -47,7 +47,7 @@ So, indentation should look like this: Or: -``` php +```php $booleanVariable = true; $stringVariable = 'moose'; if ($booleanVariable) { @@ -68,7 +68,7 @@ guidelines: As an example, instead of using the following formatting: -``` php +```php $matches = array_intersect_key($this->_listeners, array_flip(preg_grep($matchPattern, array_keys($this->_listeners), 0))); @@ -76,7 +76,7 @@ $matches = array_intersect_key($this->_listeners, Use this instead: -``` php +```php $matches = array_intersect_key( $this->_listeners, array_flip( @@ -103,7 +103,7 @@ In short: Control structures are for example "`if`", "`for`", "`foreach`", "`while`", "`switch`" etc. Below, an example with "`if`": -``` php +```php if ((expr_1) || (expr_2)) { // action_1; } elseif (!(expr_3) && (expr_4)) { @@ -126,7 +126,7 @@ if ((expr_1) || (expr_2)) { within it should gain a new level of indentation. - Inline assignments should not be used inside of the control structures. -``` php +```php // wrong = no brackets, badly placed statement if (expr) statement; @@ -158,7 +158,7 @@ line. Longer ternaries should be split into `if else` statements. Ternary operators should not ever be nested. Optionally parentheses can be used around the condition check of the ternary for clarity: -``` php +```php // Good, simple and readable $variable = isset($options['variable']) ? $options['variable'] : true; @@ -173,7 +173,7 @@ Keyword control structures are easier to read in complex template files. Control structures can either be contained in a larger PHP block, or in separate PHP tags: -``` php +```php You are the admin user.

'; @@ -192,7 +192,7 @@ might be wise to comment it as such to avoid confusing it for a mistake. For testing if a variable is null, it is recommended to use a strict check: -``` php +```php if ($value === null) { // ... } @@ -200,7 +200,7 @@ if ($value === null) { The value to check against should be placed on the right side: -``` php +```php // not recommended if (null === $this->foo()) { // ... @@ -218,7 +218,7 @@ Functions should be called without space between function's name and starting parenthesis. There should be one space between every parameter of a function call: -``` php +```php $var = foo($bar, $bar2, $bar3); ``` @@ -228,7 +228,7 @@ As you can see above there should be one space on both sides of equals sign (=). Example of a method definition: -``` php +```php public function someFunction(string $arg1, string $arg2 = ''): mixed { if (expr) { @@ -243,7 +243,7 @@ Parameters with a default value, should be placed last in function definition. Try to make your functions return something, at least `true` or `false`, so it can be determined whether the function call was successful: -``` php +```php public function connection(string|array $dns, bool $persistent = false): bool { if (is_array($dns)) { @@ -266,7 +266,7 @@ There are spaces on both side of the equals sign. Try to avoid unnecessary nesting by bailing early: -``` php +```php public function run(array $data): bool { ... @@ -295,7 +295,7 @@ This helps to keep the logic sequential which improves readability. Arguments that expect objects, arrays or callbacks (callable) can be typehinted. We only typehint public methods, though, as typehinting is not cost-free: -``` php +```php /** * Some method description. * @@ -316,7 +316,7 @@ Note that if you want to allow `$array` to be also an instance of `\ArrayObject` you should not typehint as `array` accepts only the primitive type: -``` php +```php /** * Some method description. * @@ -333,7 +333,7 @@ Defining anonymous functions follows the [PSR-12](https://www.php-fig.org/psr/ps declared with a space after the `function` keyword, and a space before and after the `use` keyword: -``` php +```php $closure = function ($arg1, $arg2) use ($var1, $var2) { // code }; @@ -344,7 +344,7 @@ $closure = function ($arg1, $arg2) use ($var1, $var2) { Method chaining should have multiple methods spread across separate lines, and indented with four spaces: -``` php +```php $email->from('foo@example.com') ->to('bar@example.com') ->subject('A great message') @@ -373,7 +373,7 @@ tags: PhpDoc tags are very much like JavaDoc tags in Java. Tags are only processed if they are the first thing in a DocBlock line, for example: -``` php +```php /** * Tag example. * @@ -382,7 +382,7 @@ they are the first thing in a DocBlock line, for example: */ ``` -``` php +```php /** * Example of inline phpDoc tags. * @@ -455,7 +455,7 @@ For more than two types it is usually best to just use `mixed`. When returning the object itself (for example, for chaining), one should use `$this` instead: -``` php +```php /** * Foo function. * @@ -472,7 +472,7 @@ public function foo(): static `include`, `require`, `include_once` and `require_once` do not have parentheses: -``` php +```php // wrong = parentheses require_once('ClassFileName.php'); require_once ($class); @@ -496,7 +496,7 @@ The short echo should be used in template files in place of ` @@ -512,7 +512,7 @@ The short echo tag (` # do this for each conflicted file. git rebase --continue ``` Check that all your tests continue to pass. Then push your branch to your fork: -``` bash +```bash git push origin ``` If you've rebased after pushing your branch, you'll need to use force push: -``` bash +```bash git push --force origin ``` diff --git a/docs/en/controllers.md b/docs/en/controllers.md index 897d5b256e..01976a3892 100644 --- a/docs/en/controllers.md +++ b/docs/en/controllers.md @@ -44,7 +44,7 @@ to all of your application's controllers. `AppController` itself extends the `AppController` is defined in **src/Controller/AppController.php** as follows: -``` php +```php namespace App\Controller; use Cake\Controller\Controller; @@ -63,7 +63,7 @@ You can use your `AppController` to load components that will be used in every controller in your application. CakePHP provides a `initialize()` method that is invoked at the end of a Controller's constructor for this kind of use: -``` php +```php namespace App\Controller; use Cake\Controller\Controller; @@ -100,7 +100,7 @@ name. Returning to our online bakery example, our RecipesController might contai `view()`, `share()`, and `search()` actions. The controller would be found in **src/Controller/RecipesController.php** and contain: -``` php +```php // src/Controller/RecipesController.php class RecipesController extends AppController @@ -158,7 +158,7 @@ The `Controller::set()` method is the main way to send data from your controller to your view. Once you've used `Controller::set()`, the variable can be accessed in your view: -``` php +```php // First you pass data from the controller: $this->set('color', 'pink'); @@ -173,7 +173,7 @@ The `Controller::set()` method also takes an associative array as its first parameter. This can often be a quick way to assign a set of information to the view: -``` php +```php $data = [ 'color' => 'pink', 'type' => 'sugar', @@ -197,7 +197,7 @@ theme that will be used when rendering the view, you can use the `viewBuilder()` method to get a builder. This builder can be used to define properties of the view before it is created: -``` php +```php $this->viewBuilder() ->addHelper('MyCustom') ->setTheme('Modern') @@ -213,7 +213,7 @@ By default, view options set via `ViewBuilder` are deep-merged with the View class's default configuration. You can control this behavior using `setConfigMergeStrategy()`: -``` php +```php use Cake\View\ViewBuilder; $this->viewBuilder() @@ -245,7 +245,7 @@ The default view file used by render is determined by convention. If the `search()` action of the RecipesController is requested, the view file in **templates/Recipes/search.php** will be rendered: -``` php +```php namespace App\Controller; class RecipesController extends AppController @@ -269,7 +269,7 @@ If `$view` starts with '/', it is assumed to be a view or element file relative to the **templates** folder. This allows direct rendering of elements, very useful in AJAX calls: -``` php +```php // Render the element in templates/element/ajaxreturn.php $this->render('/element/ajaxreturn'); ``` @@ -283,7 +283,7 @@ In your controller, you may want to render a different view than the conventional one. You can do this by calling `Controller::render()` directly. Once you have called `Controller::render()`, CakePHP will not try to re-render the view: -``` php +```php namespace App\Controller; class PostsController extends AppController @@ -302,7 +302,7 @@ You can also render views inside plugins using the following syntax: `$this->render('PluginName.PluginController/custom_file')`. For example: -``` php +```php namespace App\Controller; class PostsController extends AppController @@ -330,7 +330,7 @@ render an HTML view or render a JSON or XML response. To define the list of supported view classes for a controller is done with the `addViewClasses()` method: -``` php +```php namespace App\Controller; use Cake\View\JsonView; @@ -352,7 +352,7 @@ other view can be selected based on the request's `Accept` header or routing extension. If your application only supports content types for a specific actions, you can call `addClasses()` within your action too: -``` php +```php public function export(): void { // Use a custom CSV view for data exports. @@ -366,7 +366,7 @@ If within your controller actions you need to process the request or load data differently based on the content type you can use [Check The Request](controllers/request-response#check-the-request): -``` php +```php // In a controller action // Load additional data when preparing JSON responses @@ -390,7 +390,7 @@ will use the base `View` class. If you want to require content-type negotiation, you can use the `NegotiationRequiredView` which sets a `406` status code: -``` php +```php public function initialize(): void { parent::initialize(); @@ -403,7 +403,7 @@ public function initialize(): void You can use the `TYPE_MATCH_ALL` content type value to build your own fallback view logic: -``` php +```php namespace App\View; use Cake\View\View; @@ -427,7 +427,7 @@ In applications that use hypermedia or AJAX clients, you often need to render view contents without the wrapping layout. You can use the `AjaxView` that is bundled with the application skeleton: -``` php +```php // In a controller action, or in beforeRender. if ($this->request->is('ajax')) { $this->viewBuilder()->setClassName('Ajax'); @@ -450,7 +450,7 @@ controller action and rendering a view. You can redirect using `routing array` values: -``` php +```php return $this->redirect([ 'controller' => 'Orders', 'action' => 'confirm', @@ -465,7 +465,7 @@ return $this->redirect([ Or using a relative or absolute URL: -``` php +```php return $this->redirect('/orders/confirm'); return $this->redirect('https://www.example.com'); @@ -473,13 +473,13 @@ return $this->redirect('https://www.example.com'); Or to the referer page: -``` php +```php return $this->redirect($this->referer()); ``` By using the second parameter you can define a status code for your redirect: -``` php +```php // Do a 301 (moved permanently) return $this->redirect('/order/confirm', 301); @@ -497,7 +497,7 @@ a life-cycle handler. The `fetchTable()` method comes handy when you need to use an ORM table that is not the controller's default one: -``` php +```php // In a controller method. $recentArticles = $this->fetchTable('Articles')->find('all', limit: 5, @@ -512,7 +512,7 @@ $recentArticles = $this->fetchTable('Articles')->find('all', The `fetchModel()` method is useful to load non ORM models or ORM tables that are not the controller's default: -``` php +```php // ModelAwareTrait need to be explicitly added to your controller first for fetchModel() to work. use ModelAwareTrait; @@ -541,7 +541,7 @@ how to use `paginate()`. The `$paginate` attribute gives you a way to customize how `paginate()` behaves: -``` php +```php class ArticlesController extends AppController { protected array $paginate = [ @@ -559,7 +559,7 @@ class ArticlesController extends AppController In your Controller's `initialize()` method you can define any components you want loaded, and any configuration data for them: -``` php +```php public function initialize(): void { parent::initialize(); @@ -606,7 +606,7 @@ also provide a similar set of callbacks. Remember to call `AppController`'s callbacks within child controller callbacks for best results: -``` php +```php //use Cake\Event\EventInterface; public function beforeFilter(EventInterface $event): void { @@ -620,7 +620,7 @@ public function beforeFilter(EventInterface $event): void To redirect from within a controller callback method you can use the following: -``` php +```php public function beforeFilter(EventInterface $event): void { if (...) { @@ -648,7 +648,7 @@ a routing scope or within a controller. To define middleware for a specific controller use the `middleware()` method from your controller's `initialize()` method: -``` php +```php public function initialize(): void { parent::initialize(); diff --git a/docs/en/controllers/components.md b/docs/en/controllers/components.md index 1b9a7a10c5..2d9647f85d 100644 --- a/docs/en/controllers/components.md +++ b/docs/en/controllers/components.md @@ -27,7 +27,7 @@ the [Form Protection Component](../controllers/components/form-protection). Conf and for components in general, is usually done via `loadComponent()` in your Controller's `initialize()` method or via the `$components` array: -``` php +```php class PostsController extends AppController { public function initialize(): void @@ -45,7 +45,7 @@ You can configure components at runtime using the `setConfig()` method. Often, this is done in your controller's `beforeFilter()` method. The above could also be expressed as: -``` php +```php public function beforeFilter(EventInterface $event): void { $this->FormProtection->setConfig('unlockedActions', ['index']); @@ -55,7 +55,7 @@ public function beforeFilter(EventInterface $event): void Like helpers, components implement `getConfig()` and `setConfig()` methods to read and write configuration data: -``` php +```php // Read config data. $this->FormProtection->getConfig('unlockedActions'); @@ -74,7 +74,7 @@ alias components. This feature is useful when you want to replace `$this->Flash` or another common Component reference with a custom implementation: -``` php +```php // src/Controller/PostsController.php class PostsController extends AppController { @@ -108,7 +108,7 @@ You might not need all of your components available on every controller action. In situations like this you can load a component at runtime using the `loadComponent()` method in your controller: -``` php +```php // In a controller action $this->loadComponent('OneTimer'); $time = $this->OneTimer->getTime(); @@ -127,7 +127,7 @@ simple. Each component you use is exposed as a property on your controller. If you had loaded up the `Cake\Controller\Component\FlashComponent` in your controller, you could access it like so: -``` php +```php class PostsController extends AppController { public function initialize(): void @@ -165,7 +165,7 @@ The first step is to create a new component file and class. Create the file in **src/Controller/Component/MathComponent.php**. The basic structure for the component would look something like this: -``` php +```php namespace App\Controller\Component; use Cake\Controller\Component; @@ -186,7 +186,7 @@ class MathComponent extends Component Components can use [Dependency Injection](../development/dependency-injection) to receive services as constructor parameters: -``` php +```php namespace App\Controller\Component; use Cake\Controller\Component; @@ -214,7 +214,7 @@ controllers by loading it during the controller's `initialize()` method. Once loaded, the controller will be given a new attribute named after the component, through which we can access an instance of it: -``` php +```php // In a controller // Make the new component available at $this->Math, // as well as the standard $this->Flash @@ -231,7 +231,7 @@ set of parameters that will be passed on to the Component's constructor. These parameters can then be handled by the Component: -``` php +```php // In your controller. public function initialize(): void { @@ -252,7 +252,7 @@ The above would pass the array containing precision and randomGenerator to Sometimes one of your components may need to use another component. You can load other components by adding them to the `$components` property: -``` php +```php // src/Controller/Component/CustomComponent.php namespace App\Controller\Component; @@ -298,7 +298,7 @@ class ExistingComponent extends Component From within a Component you can access the current controller through the registry: -``` php +```php $controller = $this->getController(); ``` @@ -323,7 +323,7 @@ augment the request cycle. To redirect from within a component callback method you can use the following: -``` php +```php public function beforeFilter(EventInterface $event): void { if (...) { @@ -341,7 +341,7 @@ component callbacks to run, and that the controller should not handle the action any further. As of 4.1.0 you can raise a `RedirectException` to signal a redirect: -``` php +```php use Cake\Http\Exception\RedirectException; use Cake\Routing\Router; @@ -355,7 +355,7 @@ Raising an exception will halt all other event listeners and create a new response that doesn't retain or inherit any of the current response's headers. When raising a `RedirectException` you can include additional headers: -``` php +```php throw new RedirectException(Router::url('/'), 302, [ 'Header-Key' => 'value', ]); diff --git a/docs/en/controllers/components/check-http-cache.md b/docs/en/controllers/components/check-http-cache.md index ca3a3cb736..416f9a8f3a 100644 --- a/docs/en/controllers/components/check-http-cache.md +++ b/docs/en/controllers/components/check-http-cache.md @@ -13,7 +13,7 @@ a response to the client. Under this model, you mostly save bandwidth, but when used correctly you can also save some CPU processing, reducing response times: -``` php +```php // in a Controller public function initialize(): void { diff --git a/docs/en/controllers/components/flash.md b/docs/en/controllers/components/flash.md index bcf122001a..6529f0b024 100644 --- a/docs/en/controllers/components/flash.md +++ b/docs/en/controllers/components/flash.md @@ -22,7 +22,7 @@ maps to an element located under the **templates/element/flash** directory. By convention, camelcased methods will map to the lowercased and underscored element name: -``` php +```php // Uses templates/element/flash/success.php $this->Flash->success('This was successful'); @@ -33,7 +33,7 @@ $this->Flash->greatSuccess('This was greatly successful'); Alternatively, to set a plain-text message without rendering an element, you can use the `set()` method: -``` php +```php $this->Flash->set('This is a message'); ``` @@ -56,7 +56,7 @@ parameter, an array of options: An example of using these options: -``` php +```php // In your Controller $this->Flash->success('The user has been saved', [ 'key' => 'positive', @@ -80,7 +80,7 @@ Note that the parameter `element` will be always overridden while using `__call()`. In order to retrieve a specific element from a plugin, you should set the `plugin` parameter. For example: -``` php +```php // In your Controller $this->Flash->warning('My message', ['plugin' => 'PluginName']); ``` @@ -101,7 +101,7 @@ message. It is possible to output HTML in flash messages by using the `'escape'` option key: -``` php +```php $this->Flash->info(sprintf('%s %s', h($highlight), h($message)), ['escape' => false]); ``` diff --git a/docs/en/controllers/components/form-protection.md b/docs/en/controllers/components/form-protection.md index 6f276aa6ec..7aa0e76c00 100644 --- a/docs/en/controllers/components/form-protection.md +++ b/docs/en/controllers/components/form-protection.md @@ -57,10 +57,12 @@ Configuring the form protection component is generally done in the controller's Available options are: ### validate + Set to `false` to completely skip the validation of POST requests, essentially turning off form validation. ### unlockedFields + Set to a list of form fields to exclude from POST validation. Fields can be unlocked either in the Component, or with `FormHelper::unlockField()`. Fields that have been unlocked are @@ -68,15 +70,17 @@ not required to be part of the POST and hidden unlocked fields do not have their values checked. ### unlockedActions + Actions to exclude from POST validation checks. ### validationFailureCallback + Callback to call in case of validation failure. Must be a valid Closure. Unset by default in which case exception is thrown on validation failure. ## Disabling form tampering checks -``` php +```php namespace App\Controller; use App\Controller\AppController; @@ -111,7 +115,7 @@ There may be cases where you want to disable form tampering prevention for an action (ex. AJAX requests). You may "unlock" these actions by listing them in `$this->FormProtection->setConfig('unlockedActions', ['edit']);` in your `beforeFilter()`: -``` php +```php namespace App\Controller; use App\Controller\AppController; @@ -145,7 +149,7 @@ configuration option to a callback function in the controller. By configuring a callback method you can customize how the failure handling process works: -``` php +```php use Cake\Controller\Exception\FormProtectionException; public function beforeFilter(EventInterface $event): void diff --git a/docs/en/controllers/middleware.md b/docs/en/controllers/middleware.md index e98b3d0f54..f2d5547b49 100644 --- a/docs/en/controllers/middleware.md +++ b/docs/en/controllers/middleware.md @@ -74,7 +74,7 @@ To apply middleware to all requests, use the `middleware` method of your called at the beginning of the request process, you can use the `MiddlewareQueue` object to attach middleware: -``` php +```php namespace App; use Cake\Core\Configure; @@ -103,7 +103,7 @@ class Application extends BaseApplication In addition to adding to the end of the `MiddlewareQueue` you can do a variety of operations: -``` php +```php $layer = new \App\Middleware\CustomMiddleware; // Added middleware will be last in line. @@ -142,7 +142,7 @@ or [Controller middleware](../controllers#controller-middleware). Plugins can use their `middleware` hook method to apply any middleware they have to the application's middleware queue: -``` php +```php // in plugins/ContactManager/src/Plugin.php namespace ContactManager; @@ -177,7 +177,7 @@ for smaller tasks they make testing harder, and can create a complicated Middleware can return a response either by calling `$handler->handle()` or by creating their own response. We can see both options in our simple middleware: -``` php +```php // In src/Middleware/TrackingCookieMiddleware.php namespace App\Middleware; @@ -216,7 +216,7 @@ class TrackingCookieMiddleware implements MiddlewareInterface Now that we've made a very simple middleware, let's attach it to our application: -``` php +```php // In src/Application.php namespace App; @@ -242,7 +242,7 @@ class Application Routing middleware is responsible for applying your application's routes and resolving the plugin, controller, and action a request is going to: -``` php +```php // In Application.php public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue { @@ -258,7 +258,7 @@ protect against user tampering, you can use CakePHP's encrypted cookie middleware to transparently encrypt and decrypt cookie data via middleware. Cookie data is encrypted via OpenSSL using AES: -``` php +```php use Cake\Http\Middleware\EncryptedCookieMiddleware; $cookies = new EncryptedCookieMiddleware( @@ -285,7 +285,7 @@ is available via `$request->getParsedData()` and `$request->getData()`. By default only `json` bodies will be parsed, but XML parsing can be enabled with an option. You can also define your own parsers: -``` php +```php use Cake\Http\Middleware\BodyParserMiddleware; // only JSON will be parsed. diff --git a/docs/en/controllers/middleware/rate-limit.md b/docs/en/controllers/middleware/rate-limit.md index 6a6f3d625b..218a0e48f3 100644 --- a/docs/en/controllers/middleware/rate-limit.md +++ b/docs/en/controllers/middleware/rate-limit.md @@ -11,7 +11,7 @@ application to protect against abuse and ensure fair usage of resources. To use rate limiting in your application, add the middleware to your middleware queue: -``` php +```php // In src/Application.php use Cake\Http\Middleware\RateLimitMiddleware; @@ -79,7 +79,7 @@ The middleware accepts the following configuration options: The default identifier type tracks requests by IP address: -``` php +```php use Cake\Http\Middleware\RateLimitMiddleware; new RateLimitMiddleware([ @@ -92,7 +92,7 @@ new RateLimitMiddleware([ The middleware automatically handles proxy headers. You can configure which headers to check using the `ipHeader` option: -``` php +```php new RateLimitMiddleware([ 'identifier' => RateLimitMiddleware::IDENTIFIER_IP, 'ipHeader' => ['CF-Connecting-IP', 'X-Forwarded-For'], @@ -103,7 +103,7 @@ new RateLimitMiddleware([ Track requests per authenticated user: -``` php +```php new RateLimitMiddleware([ 'identifier' => RateLimitMiddleware::IDENTIFIER_USER, 'limit' => 1000, @@ -118,7 +118,7 @@ The middleware checks for users implementing `Authentication\IdentityInterface`. Apply different limits to different routes: -``` php +```php new RateLimitMiddleware([ 'identifier' => RateLimitMiddleware::IDENTIFIER_ROUTE, 'limit' => 10, @@ -132,7 +132,7 @@ This creates separate limits for each controller/action combination. Track requests by API key or token: -``` php +```php new RateLimitMiddleware([ 'identifier' => RateLimitMiddleware::IDENTIFIER_API_KEY, 'limit' => 5000, @@ -143,7 +143,7 @@ new RateLimitMiddleware([ By default, the middleware looks for tokens in the `Authorization` and `X-API-Key` headers. You can customize which headers to check: -``` php +```php new RateLimitMiddleware([ 'identifier' => RateLimitMiddleware::IDENTIFIER_TOKEN, 'tokenHeaders' => ['Authorization', 'X-API-Key', 'X-Auth-Token'], @@ -154,7 +154,7 @@ new RateLimitMiddleware([ You can create custom identifiers using a callback: -``` php +```php new RateLimitMiddleware([ 'identifierCallback' => function ($request) { // Custom logic to identify the client @@ -171,7 +171,7 @@ new RateLimitMiddleware([ The default strategy that provides smooth rate limiting by continuously adjusting the window based on request timing: -``` php +```php new RateLimitMiddleware([ 'strategy' => RateLimitMiddleware::STRATEGY_SLIDING_WINDOW, ]) @@ -181,7 +181,7 @@ new RateLimitMiddleware([ Resets the counter at fixed intervals: -``` php +```php new RateLimitMiddleware([ 'strategy' => RateLimitMiddleware::STRATEGY_FIXED_WINDOW, ]) @@ -191,7 +191,7 @@ new RateLimitMiddleware([ Allows for burst capacity while maintaining an average rate: -``` php +```php new RateLimitMiddleware([ 'strategy' => RateLimitMiddleware::STRATEGY_TOKEN_BUCKET, 'limit' => 100, // bucket capacity @@ -204,7 +204,7 @@ new RateLimitMiddleware([ You can use a custom rate limiter strategy by specifying the `strategyClass` option. Your class must implement `Cake\Http\RateLimiter\RateLimiterInterface`: -``` php +```php new RateLimitMiddleware([ 'strategyClass' => App\RateLimiter\MyCustomRateLimiter::class, ]) @@ -217,7 +217,7 @@ The `strategyClass` option takes precedence over the `strategy` option. For complex applications, you can define named limiter configurations and resolve them dynamically per request: -``` php +```php new RateLimitMiddleware([ 'limiters' => [ 'default' => [ @@ -252,7 +252,7 @@ new RateLimitMiddleware([ Skip rate limiting for certain requests: -``` php +```php new RateLimitMiddleware([ 'skipCheck' => function ($request) { // Skip rate limiting for health checks @@ -265,7 +265,7 @@ new RateLimitMiddleware([ Assign different costs to different types of requests: -``` php +```php new RateLimitMiddleware([ 'costCallback' => function ($request) { // POST requests cost 5x more @@ -278,7 +278,7 @@ new RateLimitMiddleware([ Set different limits for different users or plans: -``` php +```php new RateLimitMiddleware([ 'limitCallback' => function ($request, $identifier) { $user = $request->getAttribute('identity'); @@ -294,7 +294,7 @@ new RateLimitMiddleware([ Customize how cache keys are generated: -``` php +```php new RateLimitMiddleware([ 'keyGenerator' => function ($request, $identifier) { // Include the HTTP method in the key for per-method limits @@ -312,7 +312,7 @@ To programmatically reset a rate limit for a specific identifier, use the - Resetting limits when a user upgrades their plan - Clearing state between tests -``` php +```php use Cake\Cache\Cache; use Cake\Http\RateLimit\SlidingWindowRateLimiter; @@ -343,7 +343,7 @@ When a client exceeds the limit, a `Retry-After` header is also included You can apply multiple rate limiters with different configurations: -``` php +```php // Strict limit for login attempts $middlewareQueue->add(new RateLimitMiddleware([ 'identifier' => RateLimitMiddleware::IDENTIFIER_IP, @@ -367,7 +367,7 @@ $middlewareQueue->add(new RateLimitMiddleware([ The rate limiter stores its data in cache. Make sure you have a persistent cache configured: -``` php +```php // In config/app.php 'Cache' => [ 'rate_limit' => [ @@ -380,7 +380,7 @@ cache configured: Then use it in the middleware: -``` php +```php new RateLimitMiddleware([ 'cache' => 'rate_limit', ]) diff --git a/docs/en/controllers/pagination.md b/docs/en/controllers/pagination.md index 3e09624447..1251d99db8 100644 --- a/docs/en/controllers/pagination.md +++ b/docs/en/controllers/pagination.md @@ -24,7 +24,7 @@ to generate pagination controls. You can call `paginate()` using an ORM table instance or `Query` object: -``` php +```php public function index() { // Paginate the ORM table. @@ -44,7 +44,7 @@ conditions serve as the basis for you pagination queries. They are augmented by the `sort`, `direction`, `limit`, and `page` parameters passed in from the URL: -``` php +```php class ArticlesController extends AppController { protected array $paginate = [ @@ -61,7 +61,7 @@ class ArticlesController extends AppController You can also use [Custom Find Methods](../orm/retrieving-data-and-resultsets#custom-find-methods) in pagination by using the `finder` option: -``` php +```php class ArticlesController extends AppController { protected array $paginate = [ @@ -75,7 +75,7 @@ Note: This only works with Table as string input in `$this->paginate('MyTable')` If your finder method requires additional options you can pass those as values for the finder: -``` php +```php class ArticlesController extends AppController { // find articles by tag @@ -108,7 +108,7 @@ In addition to defining general pagination values, you can define more than one set of pagination defaults in the controller. The name of each model can be used as a key in the `$paginate` property: -``` php +```php class ArticlesController extends AppController { protected array $paginate = [ @@ -134,7 +134,7 @@ that page number links can be rendered. On very large datasets this count query can be very expensive. In situations where you only want to show 'Next' and 'Previous' links you can use the 'simple' paginator which does not do a count query: -``` php +```php class ArticlesController extends AppController { protected array $paginate = [ @@ -152,7 +152,7 @@ You can paginate multiple models in a single controller action, using the `scope` option both in the controller's `$paginate` property and in the call to the `paginate()` method: -``` php +```php // Paginate property protected array $paginate = [ 'Articles' => ['scope' => 'article'], @@ -179,7 +179,7 @@ elements and URLs for pagination. To paginate the same model multiple times within a single controller action you need to define an alias for the model. -``` php +```php // In a controller action $this->paginate = [ 'Articles' => [ @@ -225,7 +225,7 @@ using the `sortableFields` option. This option is required when you want to sort on any associated data, or computed fields that may be part of your pagination query: -``` php +```php protected array $paginate = [ 'sortableFields' => [ 'id', 'title', 'Users.username', 'created', @@ -248,7 +248,7 @@ multi-column support and direction control. You can configure sortable fields using a callable that receives a `SortableFieldsBuilder` instance: -``` php +```php use Cake\Datasource\Paging\SortField; use Cake\Datasource\Paging\SortableFieldsBuilder; @@ -271,7 +271,7 @@ The builder supports mapping a single sort key to multiple database fields with independent direction control. Use the `SortField` class to define complex sorting: -``` php +```php use Cake\Datasource\Paging\SortField; protected array $paginate = [ @@ -299,7 +299,7 @@ price becomes DESC. You can lock a sort direction to prevent users from toggling it. This is useful when a field should always be sorted in a specific direction: -``` php +```php protected array $paginate = [ 'sortableFields' => function ($builder) { return $builder @@ -317,7 +317,7 @@ regardless of the `direction` parameter in the URL. In addition to the traditional `?sort=field&direction=asc` format, you can use combined sorting keys in URLs: -``` text +```text // These are equivalent ?sort=title&direction=asc ?sort=title-asc @@ -335,7 +335,7 @@ For basic use cases where you just need to allow sorting on specific fields without mapping or multi-column support, you can still use the simple array format: -``` php +```php protected array $paginate = [ 'sortableFields' => [ 'id', 'title', 'Users.username', 'created', @@ -353,7 +353,7 @@ number of rows that can be fetched to 100. If this default is not appropriate for your application, you can adjust it as part of the pagination options, for example reducing it to `10`: -``` php +```php protected array $paginate = [ // Other keys here. 'maxLimit' => 10, @@ -372,7 +372,7 @@ page count. So you could either let the normal error page be rendered or use a try catch block and take appropriate action when a `NotFoundException` is caught: -``` php +```php use Cake\Http\Exception\NotFoundException; public function index() @@ -390,7 +390,7 @@ public function index() You can also use a paginator directly. -``` php +```php // Create a paginator $paginator = new \Cake\Datasource\Paginator\NumericPaginator(); diff --git a/docs/en/controllers/request-response.md b/docs/en/controllers/request-response.md index 9a349640af..94bc8debce 100644 --- a/docs/en/controllers/request-response.md +++ b/docs/en/controllers/request-response.md @@ -46,13 +46,13 @@ use libraries from outside of CakePHP. The request exposes routing parameters through the `getParam()` method: -``` php +```php $controllerName = $this->request->getParam('controller'); ``` To get all routing parameters as an array use `getAttribute()`: -``` php +```php $parameters = $this->request->getAttribute('params'); ``` @@ -62,7 +62,7 @@ In addition to [Route Elements](../development/routing#route-elements), you also [Passed Arguments](../development/routing#passed-arguments). These are both available on the request object as well: -``` php +```php // Passed arguments $passedArgs = $this->request->getParam('pass'); ``` @@ -84,7 +84,7 @@ are also all found in the routing parameters: Query string parameters can be read using the `getQuery()` method: -``` php +```php // URL is /posts/index?page=1&sort=title $page = $this->request->getQuery('page'); ``` @@ -93,7 +93,7 @@ You can either directly access the query property, or you can use `getQuery()` method to read the URL query array in an error-free manner. Any keys that do not exist will return `null`: -``` php +```php $foo = $this->request->getQuery('value_that_does_not_exist'); // $foo === null @@ -104,14 +104,14 @@ $foo = $this->request->getQuery('does_not_exist', 'default val'); If you want to access all the query parameters you can use `getQueryParams()`: -``` php +```php $query = $this->request->getQueryParams(); ``` You can use the casting utility functions to provide typesafe access to request data and other input: -``` php +```php use function Cake\Core\toBool; use function Cake\Core\toInt; use function Cake\Core\toString; @@ -145,20 +145,20 @@ Casting functions were added. All POST data normally available through PHP's `$_POST` global variable can be accessed using `Cake\Http\ServerRequest::getData()`. For example: -``` php +```php // An input with a name attribute equal to 'title' is accessible at $title = $this->request->getData('title'); ``` You can use a dot separated names to access nested data. For example: -``` php +```php $value = $this->request->getData('address.street_name'); ``` For non-existent names the `$default` value will be returned: -``` php +```php $foo = $this->request->getData('value.that.does.not.exist'); // $foo == null ``` @@ -169,7 +169,7 @@ content types into an array, so that it's accessible through `ServerRequest::get If you want to access all the data parameters you can use `getParsedBody()`: -``` php +```php $data = $this->request->getParsedBody(); ``` @@ -181,7 +181,7 @@ Uploaded files can be accessed through the request body data, using the `Cake\Ht method described above. For example, a file from an input element with a name attribute of `attachment`, can be accessed like this: -``` php +```php $attachment = $this->request->getData('attachment'); ``` @@ -193,7 +193,7 @@ implementation, the `$attachment` variable in the above example would by default Accessing the uploaded file details is fairly simple, here's how you can obtain the same data as provided by the old style file upload array: -``` php +```php $name = $attachment->getClientFilename(); $type = $attachment->getClientMediaType(); $size = $attachment->getSize(); @@ -205,7 +205,7 @@ Moving the uploaded file from its temporary location to the desired target location, doesn't require manually accessing the temporary file, instead it can be easily done by using the objects `moveTo()` method: -``` php +```php $attachment->moveTo($targetPath); ``` @@ -220,7 +220,7 @@ origins, which makes testing file uploads possible. Returns the uploaded file at a specific path. The path uses the same dot syntax as the `Cake\Http\ServerRequest::getData()` method: -``` php +```php $attachment = $this->request->getUploadedFile('attachment'); ``` @@ -233,7 +233,7 @@ present at the given path, then this method will return `null`, just like it wou Returns all uploaded files in a normalized array structure. For the above example with the file input name of `attachment`, the structure would look like: -``` php +```php [ 'attachment' => object(Laminas\Diactoros\UploadedFile) { // ... @@ -247,7 +247,7 @@ This method sets the uploaded files of the request object, it accepts an array o [\Psr\Http\Message\UploadedFileInterface](https://www.php-fig.org/psr/psr-7/#16-uploaded-files). It will replace all possibly existing uploaded files: -``` php +```php $files = [ 'MyModel' => [ 'attachment' => new \Laminas\Diactoros\UploadedFile( @@ -286,7 +286,7 @@ will automatically be parsed and available via `$request->getData()` for `PUT` a `DELETE` requests. If you are accepting JSON or XML data, you can access the raw data with `getBody()`: -``` php +```php // Get the stream wrapper on the request body $body = $request->getBody(); @@ -306,13 +306,13 @@ types making the parsed data available in `$request->getData()` and `ServerRequest::getEnv()` is a wrapper for `getenv()` global function and acts as a getter for environment variables without possible undefined keys: -``` php +```php $host = $this->request->getEnv('HTTP_HOST'); ``` To access all the environment variables in a request use `getServerParams()`: -``` php +```php $env = $this->request->getServerParams(); ``` @@ -322,7 +322,7 @@ $env = $this->request->getServerParams(); a setter for environment variables without having to modify globals `$_SERVER` and `$_ENV`: -``` php +```php // Set a value, generally helpful in testing. $this->request->withEnv('REQUEST_METHOD', 'POST'); ``` @@ -334,7 +334,7 @@ non-URL-encoded post bodies. You can read input data in any format using `Cake\Http\ServerRequest::input()`. By providing a decoding function, you can receive the content in a deserialized format: -``` php +```php // Get JSON encoded data submitted to a PUT/POST action $jsonData = $this->request->input('json_decode'); ``` @@ -344,7 +344,7 @@ the 'as array' parameter on `json_decode`. If you want XML converted into a DOMDocument object, `Cake\Http\ServerRequest::input()` supports passing in additional parameters as well: -``` php +```php // Get XML encoded data submitted to a PUT/POST action $data = $this->request->input('Cake\Utility\Xml::build', ['return' => 'domdocument']); ``` @@ -356,7 +356,7 @@ application. The `base` and `webroot` attributes are useful for generating URLs, and determining whether or not your application is in a subdirectory. The attributes you can use are: -``` php +```php // Assume the current request URL is /subdir/articles/edit/1?page=1 // Holds /subdir/articles/edit/1?page=1 @@ -379,7 +379,7 @@ The request object provides a way to inspect certain conditions in a given request. By using the `is()` method you can check a number of common conditions, as well as inspect other application specific request criteria: -``` php +```php $isPost = $this->request->is('post'); ``` @@ -404,7 +404,7 @@ detectors. There are different types of detectors that you can create: Some examples would be: -``` php +```php // Add an environment detector. $this->request->addDetector( 'post', @@ -485,7 +485,7 @@ subdomains simpler. To access the session for a given request use the `getSession()` method or use the `session` attribute: -``` php +```php $session = $this->request->getSession(); $session = $this->request->getAttribute('session'); @@ -501,7 +501,7 @@ to use the session object. Returns the domain name your application is running on: -``` php +```php // Prints 'example.org' echo $request->domain(); ``` @@ -510,7 +510,7 @@ echo $request->domain(); Returns the subdomains your application is running on as an array: -``` php +```php // Returns ['my', 'dev'] for 'my.dev.example.org' $subdomains = $request->subdomains(); ``` @@ -519,7 +519,7 @@ $subdomains = $request->subdomains(); Returns the host your application is on: -``` php +```php // Prints 'my.dev.example.org' echo $request->host(); ``` @@ -530,7 +530,7 @@ echo $request->host(); Returns the HTTP method the request was made with: -``` php +```php // Output POST echo $request->getMethod(); ``` @@ -543,7 +543,7 @@ Set allowed HTTP methods. If not matched, will throw `MethodNotAllowedException`. The 405 response will include the required `Allow` header with the passed methods: -``` php +```php public function delete() { // Only accept POST and DELETE requests @@ -557,7 +557,7 @@ public function delete() Allows you to access any of the `HTTP_*` headers that were used for the request. For example: -``` php +```php // Get the header as a string $userAgent = $this->request->getHeaderLine('User-Agent'); @@ -588,7 +588,7 @@ values. The forwarded headers will not be used by CakePHP out of the box. To have the request object use these headers set the `trustProxy` property to `true`: -``` php +```php $this->request->trustProxy = true; // These methods will now use the proxied headers. @@ -603,7 +603,7 @@ address in the `X-Forwarded-For` header. If your application is behind multiple proxies, you can use `setTrustedProxies()` to define the IP addresses of proxies in your control: -``` php +```php $request->setTrustedProxies(['127.1.1.1', '127.8.1.3']); ``` @@ -620,13 +620,13 @@ particular type of content. Get all types: -``` php +```php $accepts = $this->request->accepts(); ``` Check for a single type: -``` php +```php $acceptsJson = $this->request->accepts('application/json'); ``` @@ -637,13 +637,13 @@ or check whether a specific language is accepted. Get the list of accepted languages: -``` php +```php $acceptsLanguages = $this->request->acceptLanguage(); ``` Check whether a specific language is accepted: -``` php +```php $acceptsSpanish = $this->request->acceptLanguage('es-es'); ``` @@ -653,7 +653,7 @@ $acceptsSpanish = $this->request->acceptLanguage('es-es'); Request cookies can be read through a number of methods: -``` php +```php // Get the cookie value, or null if the cookie is missing. $rememberMe = $this->request->getCookie('remember_me'); @@ -675,7 +675,7 @@ to work with cookie collection. Requests expose the uploaded file data in `getData()` or `getUploadedFiles()` as `UploadedFileInterface` objects: -``` php +```php // Get a list of UploadedFile objects $files = $request->getUploadedFiles(); @@ -693,7 +693,7 @@ $files[0]->moveTo($targetPath); Requests contain a URI object, which contains methods for interacting with the requested URI: -``` php +```php // Get the URI $uri = $request->getUri(); @@ -729,7 +729,7 @@ You can control the Content-Type of your application's responses with with content types that are not built into Response, you can map them with `setTypeMap()` as well: -``` php +```php // Add a vCard type $this->response->setTypeMap('vcf', ['text/v-card']); @@ -750,7 +750,7 @@ automatic view switching provided by [Controller Viewclasses](../controllers#con There are times when you want to send files as responses for your requests. You can accomplish that by using `Cake\Http\Response::withFile()`: -``` php +```php public function sendFile($id) { $file = $this->Attachments->getFile($id); @@ -770,7 +770,7 @@ in `Cake\Http\Response::$_mimeTypes`. You can add new types prior to calling If you want, you can also force a file to be downloaded instead of displayed in the browser by specifying the options: -``` php +```php $response = $this->response->withFile( $file['path'], ['download' => true, 'name' => 'foo'], @@ -792,7 +792,7 @@ download. You can respond with a file that does not exist on the disk, such as a pdf or an ics generated on the fly from a string: -``` php +```php public function sendIcs() { $icsString = $this->Calendars->generateIcs(); @@ -820,7 +820,7 @@ Setting headers is done with the `Cake\Http\Response::withHeader()` method. Like all the PSR-7 interface methods, this method returns a *new* instance with the new header: -``` php +```php // Add/replace a header $response = $response->withHeader('X-Extra', 'My header'); @@ -845,7 +845,7 @@ redirect location header. To set a string as the response body, do the following: -``` php +```php // Set a string into the body $response = $response->withStringBody('My Body'); @@ -859,7 +859,7 @@ $response = $response->withType('application/json') To set the response body, use the `withBody()` method, which is provided by the `Laminas\Diactoros\MessageTrait`: -``` php +```php $response = $response->withBody($stream); ``` @@ -868,7 +868,7 @@ See below on how to create a new stream. You can also stream responses from files using `Laminas\Diactoros\Stream` streams: -``` php +```php // To stream from a file use Laminas\Diactoros\Stream; @@ -880,7 +880,7 @@ You can also stream responses from a callback using the `CallbackStream`. This is useful when you have resources like images, CSV files or PDFs you need to stream to the client: -``` php +```php // Streaming from a callback use Cake\Http\CallbackStream; @@ -900,7 +900,7 @@ $response = $response->withBody($stream); Sets the charset that will be used in the response: -``` php +```php $this->response = $this->response->withCharset('UTF-8'); ``` @@ -912,7 +912,7 @@ You sometimes need to force browsers not to cache the results of a controller action. `Cake\Http\Response::withDisabledCache()` is intended for just that: -``` php +```php public function index() { // Disable caching @@ -929,7 +929,7 @@ public function index() You can also tell clients that you want them to cache responses. By using `Cake\Http\Response::withCache()`: -``` php +```php public function index() { // Enable caching @@ -982,7 +982,7 @@ The second parameter of this method is used to specify a `max-age` for the cache, which is the number of seconds after which the response is no longer considered fresh: -``` php +```php public function view() { // ... @@ -1009,7 +1009,7 @@ You can set the `Expires` header to a date and time after which the response is no longer considered fresh. This header can be set using the `withExpires()` method: -``` php +```php public function view() { $this->response = $this->response->withExpires('+5 days'); @@ -1038,7 +1038,7 @@ To take advantage of this header, you must either call the `isNotModified()` method manually or include the [Checking HTTP Cache](../controllers/components/check-http-cache) in your controller: -``` php +```php public function index() { $articles = $this->Articles->find('all')->all(); @@ -1075,7 +1075,7 @@ To take advantage of this header, you must either call the `isNotModified()` method manually or include the [Checking HTTP Cache](../controllers/components/check-http-cache) in your controller: -``` php +```php public function view() { $article = $this->Articles->find()->first(); @@ -1097,7 +1097,7 @@ This is often the case if you have a multilingual page or respond with different HTML depending on the browser. Under such circumstances you can use the `Vary` header: -``` php +```php $response = $this->response->withVary('User-Agent'); $response = $this->response->withVary('Accept-Encoding', 'User-Agent'); $response = $this->response->withVary('Accept-Language'); @@ -1111,7 +1111,7 @@ Compares the cache headers for the request object with the cache header from the response and determines whether it can still be considered fresh. If so, deletes the response content, and sends the `304 Not Modified` header: -``` php +```php // In a controller action. if ($this->response->isNotModified($this->request)) { return $this->response; @@ -1125,7 +1125,7 @@ if ($this->response->isNotModified($this->request)) { Cookies can be added to response using either an array or a `Cake\Http\Cookie\Cookie` object: -``` php +```php use Cake\Http\Cookie\Cookie; use DateTime; @@ -1149,7 +1149,7 @@ See the [Creating Cookies](#creating-cookies) section for how to use the cookie can use `withExpiredCookie()` to send an expired cookie in the response. This will make the browser remove its local cookie: -``` php +```php $this->response = $this->response->withExpiredCookie(new Cookie('remember_me')); ``` @@ -1161,7 +1161,7 @@ The `cors()` method returns a `CorsBuilder` instance which provides a fluent interface for defining [HTTP Access Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) related headers: -``` php +```php $this->response = $this->response->cors($this->request) ->allowOrigin(['*.cakephp.org']) ->allowMethods(['GET', 'POST']) @@ -1204,7 +1204,7 @@ Here are some common CORS configurations: **API accepting requests from a SPA frontend**: -``` php +```php // In your controller public function beforeFilter(EventInterface $event) { @@ -1238,7 +1238,7 @@ public function index() **Public API with relaxed CORS**: -``` php +```php $this->response = $this->response->cors($this->request) ->allowOrigin('*') ->allowMethods(['GET']) @@ -1251,7 +1251,7 @@ $this->response = $this->response->cors($this->request) For consistent CORS handling across your application, create a middleware: -``` php +```php // src/Middleware/CorsMiddleware.php namespace App\Middleware; @@ -1293,7 +1293,7 @@ class CorsMiddleware implements MiddlewareInterface Then add it to your application middleware stack in `src/Application.php`: -``` php +```php public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue { $middlewareQueue @@ -1336,7 +1336,7 @@ immutable objects can take some getting used to. Any method that starts with return a **new** instance. Forgetting to retain the modified instance is the most frequent mistake people make when working with immutable objects: -``` php +```php $this->response->withHeader('X-CakePHP', 'yes!'); ``` @@ -1344,7 +1344,7 @@ In the above code, the response will be lacking the `X-CakePHP` header, as the return value of the `withHeader()` method was not retained. To correct the above code you would write: -``` php +```php $this->response = $this->response->withHeader('X-CakePHP', 'yes!'); ``` @@ -1363,7 +1363,7 @@ allow the immutability of the request and response to be preserved. `Cookie` objects can be defined through constructor objects, or by using the fluent interface that follows immutable patterns: -``` php +```php use Cake\Http\Cookie\Cookie; // All arguments in the constructor @@ -1390,7 +1390,7 @@ $cookie = (new Cookie('remember_me')) Once you have created a cookie, you can add it to a new or existing `CookieCollection`: -``` php +```php use Cake\Http\Cookie\CookieCollection; // Create a new collection @@ -1409,7 +1409,7 @@ $cookies = $cookies->remove('remember_me'); Cookie objects can be added to responses: -``` php +```php // Add one cookie $response = $this->response->withCookie($cookie); @@ -1427,7 +1427,7 @@ Cookies set to responses can be encrypted using the Once you have a `CookieCollection` instance, you can access the cookies it contains: -``` php +```php // Check if a cookie exists $cookies->has('remember_me'); @@ -1448,7 +1448,7 @@ Once you have a `Cookie` object you can interact with its state and modify it. Keep in mind that cookies are immutable, so you'll need to update the collection if you modify a cookie: -``` php +```php // Get the value $value = $cookie->getValue() diff --git a/docs/en/core-libraries/app.md b/docs/en/core-libraries/app.md index 2a3e65c862..1efd452cea 100644 --- a/docs/en/core-libraries/app.md +++ b/docs/en/core-libraries/app.md @@ -18,7 +18,7 @@ The App class is responsible for resource location and path management. This method is used to resolve class names throughout CakePHP. It resolves the short form names CakePHP uses and returns the fully resolved class name: -``` php +```php // Resolve a short class name with the namespace + suffix. App::className('Flash', 'Controller/Component', 'Component'); // Returns Cake\Controller\Component\FlashComponent @@ -44,7 +44,7 @@ class names do not exist, `false` will be returned. The method returns paths set using `App.paths` app config: -``` php +```php // Get the templates path set using ``App.paths.templates`` app config. App::path('templates'); ``` @@ -59,7 +59,7 @@ The same way you can retrieve paths for `locales` and `plugins`. Used to get locations for paths based on conventions: -``` php +```php // Get the path to Controller/ in your application App::classPath('Controller'); ``` @@ -76,7 +76,7 @@ for. Used for finding the path to a package inside CakePHP: -``` php +```php // Get the path to Cache engines. App::core('Cache/Engine'); ``` @@ -99,7 +99,7 @@ If you had a library called AcmeLib, you could install it into you could autoload the classes within it using `classmap` in your application's `composer.json`: -``` json +```json "autoload": { "psr-4": { "App\\": "src/", @@ -115,7 +115,7 @@ If your vendor library does not use classes, and instead provides functions, you can configure Composer to load these files at the beginning of each request using the `files` autoloading strategy: -``` json +```json "autoload": { "psr-4": { "App\\": "src/", @@ -130,7 +130,7 @@ using the `files` autoloading strategy: After configuring the vendor libraries you will need to regenerate your application's autoloader using: -``` bash +```bash php composer.phar dump-autoload ``` diff --git a/docs/en/core-libraries/caching.md b/docs/en/core-libraries/caching.md index 10a9e5e667..904a99c17a 100644 --- a/docs/en/core-libraries/caching.md +++ b/docs/en/core-libraries/caching.md @@ -62,7 +62,7 @@ Using multiple engine configurations also lets you incrementally change the storage as needed. For example in your **config/app.php** you could put the following: -``` php +```php // ... 'Cache' => [ 'short' => [ @@ -85,7 +85,7 @@ following: Configuration options can also be provided as a `DSN` string. This is useful when working with environment variables or `PaaS` providers: -``` php +```php Cache::setConfig('short', [ 'url' => 'memcached://user:password@cache-host/?timeout=3600&prefix=myapp_', ]); @@ -96,7 +96,7 @@ query string arguments. You can also configure Cache engines at runtime: -``` php +```php // Using a short name Cache::setConfig('short', [ 'className' => 'File', @@ -123,7 +123,7 @@ parameter for `Cake\Cache\Cache::write()` and `Cake\Cache\Cache::read()`. When configuring cache engines you can refer to the class name using the following syntaxes: -``` php +```php // Short name (in App\ or Cake namespaces) Cache::setConfig('long', ['className' => 'File']); @@ -194,7 +194,7 @@ Redis Cluster support was added in 5.3 To use Redis Cluster, configure the `cluster` option with an array of server addresses: -``` php +```php Cache::setConfig('redis_cluster', [ 'className' => 'Redis', 'duration' => '+1 hours', @@ -240,7 +240,7 @@ cache failure. You can configure Cache configurations to fall back to a specified config using the `fallback` configuration key: -``` php +```php Cache::setConfig('redis', [ 'className' => 'Redis', 'duration' => '+1 hours', @@ -259,7 +259,7 @@ from throwing an uncaught exception. You can turn off cache fallbacks with `false`: -``` php +```php Cache::setConfig('redis', [ 'className' => 'Redis', 'duration' => '+1 hours', @@ -294,7 +294,7 @@ no `$config` is specified, default will be used. `Cache::write()` can store any type of object and is ideal for storing results of model finds: -``` php +```php $posts = Cache::read('posts'); if ($posts === null) { $posts = $someService->getAllPosts(); @@ -319,7 +319,7 @@ can use multiple calls to `write()`, `writeMany()` allows CakePHP to use more efficient storage APIs where available. For example using `writeMany()` save multiple network connections when using Memcached: -``` php +```php $result = Cache::writeMany([ 'article-' . $slug => $article, 'article-' . $slug . '-comments' => $comments, @@ -337,7 +337,7 @@ Using `Cache::add()` will let you atomically set a key to a value if the key does not already exist in the cache. If the key already exists in the cache backend or the write fails, `add()` will return `false`: -``` php +```php // Set a key to act as a lock $result = Cache::add($lockKey, true); if (!$result) { @@ -363,7 +363,7 @@ and the results stored in the cache at the provided key. For example, you often want to cache remote service call results. You could use `remember()` to make this simple: -``` php +```php class IssueService { public function allIssues(string $repo): mixed @@ -390,7 +390,7 @@ to check the success of the `Cache::read()` operation. For example: -``` php +```php $cloud = Cache::read('cloud'); if ($cloud !== null) { return $cloud; @@ -408,7 +408,7 @@ return $cloud; Or if you are using another cache configuration called `short`, you can specify it in `Cache::read()` and `Cache::write()` calls as below: -``` php +```php // Read key "cloud", but from short configuration instead of default $cloud = Cache::read('cloud', 'short'); if ($cloud === null) { @@ -431,7 +431,7 @@ well. While you could use multiple calls to `read()`, `readMany()` allows CakePHP to use more efficient storage APIs where available. For example using `readMany()` save multiple network connections when using Memcached: -``` php +```php $result = Cache::readMany([ 'article-' . $slug, 'article-' . $slug . '-comments', @@ -449,7 +449,7 @@ $result = Cache::readMany([ `Cache::delete()` will allow you to completely remove a cached object from the store: -``` php +```php // Remove a key Cache::delete('my_key'); ``` @@ -457,7 +457,7 @@ Cache::delete('my_key'); As of 4.4.0, the `RedisEngine` also provides a `deleteAsync()` method which uses the `UNLINK` operation to remove cache keys: -``` php +```php Cache::pool('redis')->deleteAsync('my_key'); ``` @@ -470,7 +470,7 @@ you could use multiple calls to `delete()`, `deleteMany()` allows CakePHP to use more efficient storage APIs where available. For example using `deleteMany()` save multiple network connections when using Memcached: -``` php +```php $result = Cache::deleteMany([ 'article-' . $slug, 'article-' . $slug . '-comments', @@ -490,7 +490,7 @@ Memcached, the cache configuration's prefix is used to remove cache entries. Make sure that different cache configurations have different prefixes: -``` php +```php // Will clear all keys. Cache::clear(); ``` @@ -498,7 +498,7 @@ Cache::clear(); As of 4.4.0, the `RedisEngine` also provides a `clearBlocking()` method which uses the `UNLINK` operation to remove cache keys: -``` php +```php Cache::pool('redis')->clearBlocking(); ``` @@ -526,7 +526,7 @@ lower the value by one, resulting in an incorrect value. After setting an integer value you can manipulate it using `increment()` and `decrement()`: -``` php +```php Cache::write('initial_count', 10); // Later on @@ -558,7 +558,7 @@ group or namespace. This is a common requirement for mass-invalidating keys whenever some information changes that is shared among all entries in the same group. This is possible by declaring the groups in cache configuration: -``` php +```php Cache::setConfig('site_home', [ 'className' => 'Redis', 'duration' => '+999 days', @@ -579,7 +579,7 @@ both group names. For instance, whenever a new post is added, we could tell the Cache engine to remove all entries associated to the `article` group: -``` php +```php // src/Model/Table/ArticlesTable.php public function afterSave(EventInterface $event, EntityInterface $entity, ArrayObject $options): void { @@ -596,7 +596,7 @@ public function afterSave(EventInterface $event, EntityInterface $entity, ArrayO `groupConfigs()` can be used to retrieve mapping between group and configurations, i.e.: having the same group: -``` php +```php // src/Model/Table/ArticlesTable.php /** @@ -628,7 +628,7 @@ You may need to disable all Cache read & writes when trying to figure out cache expiration related issues. You can do this using `enable()` and `disable()`: -``` php +```php // Disable all cache reads, and cache writes. Cache::disable(); ``` @@ -641,7 +641,7 @@ Once disabled, all reads and writes will return `null`. Once disabled, you can use `enable()` to re-enable caching: -``` php +```php // Re-enable all cache reads, and cache writes. Cache::enable(); ``` @@ -662,7 +662,7 @@ Or in **plugins/MyPlugin/src/Cache/Engine/MyCustomCacheEngine.php** as part of a plugin. Cache configs from plugins need to use the plugin dot syntax: -``` php +```php Cache::setConfig('custom', [ 'className' => 'MyPlugin.MyCustomCache', // ... @@ -715,7 +715,7 @@ You can add event listeners to the following events: an example listener in your `src/Application.php` or plugin class would be: -``` php +```php public function events(EventManagerInterface $eventManager): EventManagerInterface { $eventManager->on(CacheAfterGetEvent::NAME, function (CacheAfterGetEvent $event): void { diff --git a/docs/en/core-libraries/collections.md b/docs/en/core-libraries/collections.md index 0f6a661836..acad10a442 100644 --- a/docs/en/core-libraries/collections.md +++ b/docs/en/core-libraries/collections.md @@ -21,7 +21,7 @@ Collections can be created using an array or `Traversable` object. You'll also interact with collections every time you interact with the ORM in CakePHP. A simple use of a Collection would be: -``` php +```php use Cake\Collection\Collection; $items = ['a' => 1, 'b' => 2, 'c' => 3]; @@ -36,7 +36,7 @@ $overOne = $collection->filter(function ($value, $key, $iterator) { You can also use the `collection()` helper function instead of `new Collection()`: -``` php +```php $items = ['a' => 1, 'b' => 2, 'c' => 3]; // These both make a Collection instance. @@ -81,7 +81,7 @@ Collections can be iterated and/or transformed into new collections with the `each()` and `map()` methods. The `each()` method will not create a new collection, but will allow you to modify any objects within the collection: -``` php +```php $collection = new Collection($items); $collection = $collection->each(function ($value, $key) { echo "Element $key: $value"; @@ -98,7 +98,7 @@ collection immediately applying the callback to each value in the collection. The `map()` method will create a new collection based on the output of the callback being applied to each object in the original collection: -``` php +```php $items = ['a' => 1, 'b' => 2, 'c' => 3]; $collection = new Collection($items); @@ -125,7 +125,7 @@ column from a collection. If you are looking to build a list of elements containing the values for a particular property, you can use the `extract()` method: -``` php +```php $collection = new Collection($people); $names = $collection->extract('name'); @@ -137,7 +137,7 @@ As with many other functions in the collection class, you are allowed to specify a dot-separated path for extracting columns. This example will return a collection containing the author names from a list of articles: -``` php +```php $collection = new Collection($articles); $names = $collection->extract('author.name'); @@ -148,7 +148,7 @@ $result = $names->toList(); Finally, if the property you are looking after cannot be expressed as a path, you can use a callback function to return it: -``` php +```php $collection = new Collection($articles); $names = $collection->extract(function ($article) { return $article->author->name . ', ' . $article->author->last_name; @@ -160,7 +160,7 @@ arrays or objects that are deeply nested inside other structures. For those cases you can use the `{*}` matcher in the path key. This matcher is often helpful when matching HasMany and BelongsToMany association data: -``` php +```php $data = [ [ 'name' => 'James', @@ -199,7 +199,7 @@ Collections allow you to create a new collection made from keys and values in an existing collection. Both the key and value paths can be specified with dot notation paths: -``` php +```php $items = [ ['id' => 1, 'name' => 'foo', 'parent' => 'a'], ['id' => 2, 'name' => 'bar', 'parent' => 'b'], @@ -218,7 +218,7 @@ $result = $combined->toArray(); You can also optionally use a `groupPath` to group results based on a path: -``` php +```php $combined = (new Collection($items))->combine('id', 'name', 'parent'); $result = $combined->toArray(); @@ -233,7 +233,7 @@ Finally you can use *closures* to build keys/values/groups paths dynamically, for example when working with entities and dates (converted to `I18n\DateTime` instances by the ORM) you may want to group results by date: -``` php +```php $combined = (new Collection($entities))->combine( 'id', function ($entity) { return $entity; }, @@ -256,7 +256,7 @@ You can stop the iteration at any point using the `stopWhen()` method. Calling it in a collection will create a new one that will stop yielding results if the passed callable returns true for one of the elements: -``` php +```php $items = [10, 20, 50, 1, 2]; $collection = new Collection($items); @@ -278,7 +278,7 @@ with more items. If you wish to flatten the internal structure to iterate once over all elements you can use the `unfold()` method. It will create a new collection that will yield every single element nested in the collection: -``` php +```php $items = [[1, 2, 3], [4, 5]]; $collection = new Collection($items); $new = $collection->unfold(); @@ -291,7 +291,7 @@ When passing a callable to `unfold()` you can control what elements will be unfolded from each item in the original collection. This is useful for returning data from paginated services: -``` php +```php $pages = [1, 2, 3, 4]; $collection = new Collection($pages); $items = $collection->unfold(function ($page, $key) { @@ -305,7 +305,7 @@ $allPagesItems = $items->toList(); You can use the `yield` keyword inside `unfold()` to return as many elements for each item in the collection as you may need: -``` php +```php $oddNumbers = [1, 3, 5, 7]; $collection = new Collection($oddNumbers); $new = $collection->unfold(function ($oddNumber) { @@ -326,7 +326,7 @@ process the elements in batches instead of one by one. For splitting a collection into multiple arrays of a certain size, you can use the `chunk()` function: -``` php +```php $items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; $collection = new Collection($items); $chunked = $collection->chunk(2); @@ -336,7 +336,7 @@ $chunked->toList(); // [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11]] The `chunk` function is particularly useful when doing batch processing, for example with a database result: -``` php +```php $collection = new Collection($articles); $collection->map(function ($article) { // Change a property in the article @@ -356,7 +356,7 @@ Much like `chunk()`, `chunkWithKeys()` allows you to slice up a collection into smaller batches but with keys preserved. This is useful when chunking associative arrays: -``` php +```php $collection = new Collection([ 'a' => 1, 'b' => 2, @@ -383,7 +383,7 @@ Collections allow you to filter and create new collections based on the result of callback functions. You can use `filter()` to create a new collection of elements matching a criteria callback: -``` php +```php $collection = new Collection($people); $ladies = $collection->filter(function ($person, $key) { return $person->gender === 'female'; @@ -400,7 +400,7 @@ $guys = $collection->filter(function ($person, $key) { The inverse of `filter()` is `reject()`. This method does a negative filter, removing elements that match the filter function: -``` php +```php $collection = new Collection($people); $ladies = $collection->reject(function ($person, $key) { return $person->gender === 'male'; @@ -414,7 +414,7 @@ $ladies = $collection->reject(function ($person, $key) { You can do truth tests with filter functions. To see if every element in a collection matches a test you can use `every()`: -``` php +```php $collection = new Collection($people); $allYoungPeople = $collection->every(function ($person) { return $person->age < 21; @@ -432,7 +432,7 @@ $allYoungPeople = $collection->every(function ($person) { You can see if the collection contains at least one element matching a filter function using the `any()` method: -``` php +```php $collection = new Collection($people); $hasYoungPeople = $collection->any(function ($person) { return $person->age < 21; @@ -449,7 +449,7 @@ $hasYoungPeople = $collection->any(function ($person) { If you need to extract a new collection containing only the elements that contain a given set of properties, you should use the `match()` method: -``` php +```php $collection = new Collection($comments); $commentsFromMark = $collection->match(['user.name' => 'Mark']); ``` @@ -462,7 +462,7 @@ The property name can be a dot-separated path. You can traverse into nested entities and match the values they contain. When you only need the first matching element from a collection, you can use `firstMatch()`: -``` php +```php $collection = new Collection($comments); $comment = $collection->firstMatch([ 'user.name' => 'Mark', @@ -485,7 +485,7 @@ The counterpart of a `map()` operation is usually a `reduce`. This function will help you build a single result out of all the elements in a collection: -``` php +```php $totalPrice = $collection->reduce(function ($accumulated, $orderLine) { return $accumulated + $orderLine->price; }, 0); @@ -496,7 +496,7 @@ contained in the collection. Note the second argument for the `reduce()` function takes the initial value for the reduce operation you are performing: -``` php +```php $allTags = $collection->reduce(function ($accumulated, $article) { return array_merge($accumulated, $article->tags); }, []); @@ -510,7 +510,7 @@ To extract the minimum value for a collection based on a property, just use the `min()` function. This will return the full element from the collection and not just the smallest value found: -``` php +```php $collection = new Collection($people); $youngest = $collection->min('age'); @@ -520,7 +520,7 @@ echo $youngest->name; You are also able to express the property to compare by providing a path or a callback function: -``` php +```php $collection = new Collection($people); $personYoungestChild = $collection->min(function ($person) { return $person->child->age; @@ -536,7 +536,7 @@ $personWithYoungestDad = $collection->min('dad.age'); The same can be applied to the `max()` function, which will return a single element from the collection having the highest property value: -``` php +```php $collection = new Collection($people); $oldest = $collection->max('age'); @@ -554,7 +554,7 @@ $personWithOldestDad = $collection->max('dad.age'); Finally, the `sumOf()` method will return the sum of a property of all elements: -``` php +```php $collection = new Collection($people); $sumOfAges = $collection->sumOf('age'); @@ -573,7 +573,7 @@ Calculate the average value of the elements in the collection. Optionally provide a matcher path, or function to extract values to generate the average for: -``` php +```php $items = [ ['invoice' => ['total' => 100]], ['invoice' => ['total' => 200]], @@ -590,7 +590,7 @@ $average = (new Collection($items))->avg('invoice.total'); Calculate the median value of a set of elements. Optionally provide a matcher path, or function to extract values to generate the median for: -``` php +```php $items = [ ['invoice' => ['total' => 400]], ['invoice' => ['total' => 500]], @@ -612,7 +612,7 @@ $median = (new Collection($items))->median('invoice.total'); Collection values can be grouped by different keys in a new collection when they share the same value for a property: -``` php +```php $students = [ ['name' => 'Mark', 'grade' => 9], ['name' => 'Andrew', 'grade' => 10], @@ -639,7 +639,7 @@ $result = $studentsByGrade->toArray(); As usual, it is possible to provide either a dot-separated path for nested properties or your own callback function to generate the groups dynamically: -``` php +```php $commentsByUserId = $comments->groupBy('user.id'); $classResults = $students->groupBy(function ($student) { @@ -655,7 +655,7 @@ If you only wish to know the number of occurrences per group, you can do so by using the `countBy()` method. It takes the same arguments as `groupBy` so it should be already familiar to you: -``` php +```php $classResults = $students->countBy(function ($student) { return $student->grade > 6 ? 'approved' : 'denied'; }); @@ -672,7 +672,7 @@ There will be certain cases where you know an element is unique for the property you want to group by. If you wish a single result per group, you can use the function `indexBy()`: -``` php +```php $usersById = $users->indexBy('id'); // When converted to array result could look like @@ -686,7 +686,7 @@ $usersById = $users->indexBy('id'); As with the `groupBy()` function you can also use a property path or a callback: -``` php +```php $articlesByAuthorId = $articles->indexBy('author.id'); $filesByHash = $files->indexBy(function ($file) { @@ -702,7 +702,7 @@ The elements of different collections can be grouped together using the `zip()` method. It will return a new collection containing an array grouping the elements from each collection that are placed at the same position: -``` php +```php $odds = new Collection([1, 3, 5]); $pairs = new Collection([2, 4, 6]); $combined = $odds->zip($pairs)->toList(); // [[1, 2], [3, 4], [5, 6]] @@ -710,7 +710,7 @@ $combined = $odds->zip($pairs)->toList(); // [[1, 2], [3, 4], [5, 6]] You can also zip multiple collections at once: -``` php +```php $years = new Collection([2013, 2014, 2015, 2016]); $salaries = [1000, 1500, 2000, 2300]; $increments = [0, 500, 500, 300]; @@ -730,7 +730,7 @@ $result = $rows->toList(); As you can already see, the `zip()` method is very useful for transposing multidimensional arrays: -``` php +```php $data = [ 2014 => ['jan' => 100, 'feb' => 200], 2015 => ['jan' => 300, 'feb' => 500], @@ -761,7 +761,7 @@ Collection values can be sorted in ascending or descending order based on a column or custom function. To create a new sorted collection out of the values of another one, you can use `sortBy`: -``` php +```php $collection = new Collection($people); $sorted = $collection->sortBy('age'); ``` @@ -771,7 +771,7 @@ is present in the collection values. You are also able to specify a property path instead using the dot notation. The next example will sort articles by their author's name: -``` php +```php $collection = new Collection($articles); $sorted = $collection->sortBy('author.name'); ``` @@ -780,7 +780,7 @@ The `sortBy()` method is flexible enough to let you specify an extractor function that will let you dynamically select the value to use for comparing two different values in the collection: -``` php +```php $collection = new Collection($articles); $sorted = $collection->sortBy(function ($article) { return $article->author->name . '-' . $article->title; @@ -792,7 +792,7 @@ to provide either `SORT_ASC` or `SORT_DESC` as the second parameter for sorting in ascending or descending direction respectively. By default, collections are sorted in descending direction: -``` php +```php $collection = new Collection($people); $sorted = $collection->sortBy('age', SORT_ASC); ``` @@ -809,7 +809,7 @@ argument in the `sortBy()` function with one of the following constants: By default, `SORT_NUMERIC` is used: -``` php +```php $collection = new Collection($articles); $sorted = $collection->sortBy('title', SORT_ASC, SORT_NATURAL); ``` @@ -834,7 +834,7 @@ Two parameters are required for this function. The first one is the property representing the item identifier. The second parameter is the name of the property representing the identifier for the parent item: -``` php +```php $collection = new Collection([ ['id' => 1, 'parent_id' => null, 'name' => 'Birds'], ['id' => 2, 'parent_id' => 1, 'name' => 'Land Birds'], @@ -886,7 +886,7 @@ collection. Taking the input the nested collection built in the previous example, we can flatten it: -``` php +```php $result = $nested->listNested()->toList(); // $result contains @@ -903,7 +903,7 @@ $result = $nested->listNested()->toList(); By default, the tree is traversed from the root to the leaves. You can also instruct it to only return the leaf elements in the tree: -``` php +```php $result = $nested->listNested('leaves')->toList(); // $result contains @@ -918,7 +918,7 @@ $result = $nested->listNested('leaves')->toList(); Once you have converted a tree into a nested list, you can use the `printer()` method to configure how the list output should be formatted: -``` php +```php $result = $nested->listNested()->printer('name', 'id', '--')->toArray(); // $result contains @@ -935,7 +935,7 @@ $result = $nested->listNested()->printer('name', 'id', '--')->toArray(); The `printer()` method also lets you use a callback to generate the keys and or values: -``` php +```php $nested->listNested()->printer( function ($el) { return $el->name; @@ -954,7 +954,7 @@ $nested->listNested()->printer( Allows you to see if a collection contains any elements: -``` php +```php $collection = new Collection([]); // Returns true $collection->isEmpty(); @@ -971,7 +971,7 @@ $collection->isEmpty(); Collections allow you to quickly check if they contain one particular value: by using the `contains()` method: -``` php +```php $items = ['a' => 1, 'b' => 2, 'c' => 3]; $collection = new Collection($items); $hasThree = $collection->contains(3); @@ -988,7 +988,7 @@ Sometimes you may wish to show a collection of values in a random order. In order to create a new collection that will return each value in a randomized position, use the `shuffle`: -``` php +```php $collection = new Collection(['a' => 1, 'b' => 2, 'c' => 3]); // This could return [2, 3, 1] @@ -1002,7 +1002,7 @@ $collection->shuffle()->toList(); When you transpose a collection, you get a new collection containing a row made of the each of the original columns: -``` php +```php $items = [ ['Products', '2012', '2013', '2014'], ['Product A', '200', '100', '50'], @@ -1033,7 +1033,7 @@ random values out of a collection so that more tests can be performed on those. For example, if you wanted to select 5 random users to which you'd like to apply some A/B tests to, you can use the `sample()` function: -``` php +```php $collection = new Collection($people); // Withdraw maximum 20 random users from this collection @@ -1052,7 +1052,7 @@ Whenever you want to take a slice of a collection use the `take()` function, it will create a new collection with at most the number of values you specify in the first argument, starting from the position passed in the second argument: -``` php +```php $topFive = $collection->sortBy('age')->take(5); // Take 5 people from the collection starting from position 4 @@ -1069,7 +1069,7 @@ While the second argument of `take()` can help you skip some elements before getting them from the collection, you can also use `skip()` for the same purpose as a way to take the rest of the elements after a certain position: -``` php +```php $collection = new Collection([1, 2, 3, 4]); $allExceptFirstTwo = $collection->skip(2)->toList(); // [3, 4] ``` @@ -1082,7 +1082,7 @@ One of the most common uses of `take()` is getting the first element in the collection. A shortcut method for achieving the same goal is using the `first()` method: -``` php +```php $collection = new Collection([5, 4, 3, 2]); $collection->first(); // Returns 5 ``` @@ -1094,7 +1094,7 @@ $collection->first(); // Returns 5 Similarly, you can get the last element of a collection using the `last()` method: -``` php +```php $collection = new Collection([5, 4, 3, 2]); $collection->last(); // Returns 2 ``` @@ -1110,7 +1110,7 @@ gather data from various sources, concatenate it, and apply other collection functions to it very smoothly. The `append()` method will return a new collection containing the values from both sources: -``` php +```php $cakephpTweets = new Collection($tweets); $myTimeline = $cakephpTweets->append($phpTweets); @@ -1128,7 +1128,7 @@ Allows you to append an item with an optional key to the collection. If you specify a key that already exists in the collection, the value will not be overwritten: -``` php +```php $cakephpTweets = new Collection($tweets); $myTimeline = $cakephpTweets->appendItem($newTweet, 99); ``` @@ -1140,7 +1140,7 @@ $myTimeline = $cakephpTweets->appendItem($newTweet, 99); The `prepend()` method will return a new collection containing the values from both sources: -``` php +```php $cakephpTweets = new Collection($tweets); $myTimeline = $cakephpTweets->prepend($phpTweets); ``` @@ -1153,7 +1153,7 @@ Allows you to prepend an item with an optional key to the collection. If you specify a key that already exists in the collection, the value will not be overwritten: -``` php +```php $cakephpTweets = new Collection($tweets); $myTimeline = $cakephpTweets->prependItem($newTweet, 99); ``` @@ -1181,7 +1181,7 @@ Collections offer an `insert()` method that will allow you to insert each of the elements in one collection into a property inside each of the elements of another collection: -``` php +```php $users = [ ['username' => 'mark'], ['username' => 'juan'], @@ -1216,7 +1216,7 @@ element of the first collection. If there are not enough elements in the second collection to insert into the first one, then the target property will not be present: -``` php +```php $languages = [ ['PHP', 'Python', 'Ruby'], ['Bash', 'PHP', 'Javascript'], @@ -1248,7 +1248,7 @@ reused in multiple parts of your application. It is recommended that you consider extracting complex collection logic to separate classes. For example, imagine a lengthy closure like this one: -``` php +```php $collection ->map(function ($row, $key) { if (!empty($row['items'])) { @@ -1267,7 +1267,7 @@ $collection This can be refactored by creating another class: -``` php +```php class TotalOrderCalculator { public function __invoke(array $row, string $key): array @@ -1299,7 +1299,7 @@ of your application, but only if they are called in that specific order. In those cases you can use `through()` in combination with a class implementing `__invoke` to distribute your handy data processing calls: -``` php +```php $collection ->map(new ShippingCostCalculator) ->map(new TotalOrderCalculator) @@ -1311,7 +1311,7 @@ $collection The above method calls can be extracted into a new class so they don't need to be repeated every time: -``` php +```php class FinalCheckOutRowProcessor { public function __invoke(CollectionInterface $collection): CollectionInterface @@ -1346,7 +1346,7 @@ early. Additionally, lazy evaluation helps speed up some operations. Consider the following example: -``` php +```php $collection = new Collection($oneMillionItems); $collection = $collection->map(function ($item) { return $item * 2; @@ -1365,7 +1365,7 @@ Lazy evaluation comes with its downside too. You could be doing the same operations more than once if you optimize a collection prematurely. Consider this example: -``` php +```php $ages = $collection->extract('age'); $youngerThan30 = $ages->filter(function ($item) { @@ -1386,7 +1386,7 @@ Luckily we can overcome this issue with a single function. If you plan to reuse the values from certain operations more than once, you can compile the results into another collection using the `buffered()` function: -``` php +```php $ages = $collection->extract('age')->buffered(); $youngerThan30 = ... $olderThan30 = ... @@ -1400,7 +1400,7 @@ extracting operation once. The `buffered()` method is also useful for converting non-rewindable iterators into collections that can be iterated more than once: -``` php +```php public function results(): Generator { ... @@ -1422,7 +1422,7 @@ collection. This is useful when you need to iterate the same set from different places at the same time. In order to clone a collection out of another use the `compile()` method: -``` php +```php $ages = $collection->extract('age')->compile(); foreach ($ages as $age) { diff --git a/docs/en/core-libraries/email.md b/docs/en/core-libraries/email.md index b5aee863ca..8d26de55e8 100644 --- a/docs/en/core-libraries/email.md +++ b/docs/en/core-libraries/email.md @@ -14,13 +14,13 @@ email from any place inside of your application. First of all, you should ensure the class is loaded: -``` php +```php use Cake\Mailer\Mailer; ``` After you've loaded `Mailer`, you can send an email with the following: -``` php +```php $mailer = new Mailer('default'); $mailer->setFrom(['me@example.com' => 'My Site']) ->setTo('you@example.com') @@ -36,7 +36,7 @@ to set its properties with method chaining. that the first three will overwrite what was already set and the latter will just add more recipients to their respective field: -``` php +```php $mailer = new Mailer(); $mailer->setTo('to@example.com', 'To Example'); $mailer->addTo('to2@example.com', 'To2 Example'); @@ -50,7 +50,7 @@ $mailer->setTo('test@example.com', 'ToTest Example'); When sending email on behalf of other people, it's often a good idea to define the original sender using the Sender header. You can do so using `setSender()`: -``` php +```php $mailer = new Mailer(); $mailer->setSender('app@example.com', 'MyApp emailer'); ``` @@ -76,7 +76,7 @@ more difficult. To load a predefined configuration, you can use the `setProfile()` method or pass it to the constructor of `Mailer`: -``` php +```php $mailer = new Mailer(); $mailer->setProfile('default'); @@ -87,7 +87,7 @@ $mailer = new Mailer('default'); Instead of passing a string which matches a preset configuration name, you can also just load an array of options: -``` php +```php $mailer = new Mailer(); $mailer->setProfile(['from' => 'me@example.org', 'transport' => 'my_custom']); @@ -160,7 +160,7 @@ to facilitate that, CakePHP provides a way to send emails using CakePHP's The templates for emails reside in a special folder `templates/email/` of your application. Mailer views can also use layouts and elements just like normal views: -``` php +```php $mailer = new Mailer(); $mailer ->setEmailFormat('html') @@ -177,7 +177,7 @@ The above would use **templates/email/html/welcome.php** for the view and **templates/layout/email/html/fancy.php** for the layout. You can send multipart templated email messages as well: -``` php +```php $mailer = new Mailer(); $mailer ->setEmailFormat('both') @@ -205,7 +205,7 @@ You can set all view related config using the view builder instance got by You can set view variables with `Mailer::setViewVars()`: -``` php +```php $mailer = new Mailer('templated'); $mailer->setViewVars(['value' => 12345]); ``` @@ -215,7 +215,7 @@ Or you can use the view builder methods `ViewBuilder::setVar()` and In your email templates you can use these with: -``` html +```html

Here is your value:

``` @@ -223,7 +223,7 @@ You can use helpers in emails as well, much like you can in normal template file By default, only the `HtmlHelper` is loaded. You can load additional helpers using the `ViewBuilder::addHelpers()` method: -``` php +```php $mailer->viewBuilder()->addHelpers(['Html', 'Custom', 'Text']); ``` @@ -236,7 +236,7 @@ helpers loaded in your email template. If you want to send email using templates in a plugin you can use the familiar `plugin syntax` to do so: -``` php +```php $mailer = new Mailer(); $mailer->viewBuilder()->setTemplate('Blog.new_comment'); ``` @@ -246,7 +246,7 @@ The above would use template and layout from the Blog plugin as an example. In some cases, you might need to override the default template provided by plugins. You can do this using themes: -``` php +```php $mailer->viewBuilder() ->setTemplate('Blog.new_comment') ->setLayout('Blog.auto_message') @@ -278,7 +278,7 @@ you want the filenames to appear in the recipient's mail client: 3. Nested arrays: - ``` php + ```php $mailer->setAttachments([ 'photo.png' => [ 'file' => '/full/some_hash.png', @@ -321,7 +321,7 @@ If you are having validation issues when sending to non-compliant addresses, you can relax the pattern used to validate email addresses. This is sometimes necessary when dealing with some ISPs: -``` php +```php $mailer = new Mailer('default'); // Relax the email pattern, so you can send @@ -335,7 +335,7 @@ When sending emails within a CLI script (Shells, Tasks, ...) you should manually set the domain name for Mailer to use. It will serve as the host name for the message id (since there is no host name in a CLI environment): -``` php +```php $mailer->setDomain('www.example.org'); // Results in message ids like ```` (valid) // Instead of ``` (invalid) @@ -356,7 +356,7 @@ emails. To create our `UserMailer`, create the file **src/Mailer/UserMailer.php**. The contents of the file should look like the following: -``` php +```php namespace App\Mailer; use Cake\Mailer\Mailer; @@ -390,7 +390,7 @@ We are now able to use our `UserMailer` to send out our user-related emails from anywhere in our application. For example, if we wanted to send our welcome email we could do the following: -``` php +```php namespace App\Controller; use Cake\Mailer\MailerAwareTrait; @@ -419,7 +419,7 @@ application's code, we can have our `UserMailer` subscribe to the application's user-related classes completely free of email-related logic and instructions. For example, we could add the following to our `UserMailer`: -``` php +```php public function implementedEvents(): array { return [ @@ -439,7 +439,7 @@ You can now register the mailer as an event listener and the `onRegistration()` method will be invoked every time the `Model.afterSave` event is fired: -``` php +```php // attach to Users event manager $this->Users->getEventManager()->on($this->getMailer('User')); ``` @@ -458,7 +458,7 @@ is useful for debugging. Configuring transports allows you to keep configuration data out of your application code and makes deployment simpler as you can simply change the configuration data. An example transport configuration looks like: -``` php +```php // In config/app.php 'EmailTransport' => [ // Sample Mail configuration @@ -480,7 +480,7 @@ change the configuration data. An example transport configuration looks like: Transports can also be configured at runtime using `TransportFactory::setConfig()`: -``` php +```php use Cake\Mailer\TransportFactory; // Define an SMTP transport @@ -497,7 +497,7 @@ You can configure SSL SMTP servers, like Gmail. To do so, put the `ssl://` prefix in the host and configure the port value accordingly. You can also enable TLS SMTP using the `tls` option: -``` php +```php use Cake\Mailer\TransportFactory; TransportFactory::setConfig('gmail', [ @@ -516,7 +516,7 @@ To configure your mailer to use a specific transport you can use `Cake\Mailer\Mailer::setTransport()` method or have the transport in your configuration: -``` php +```php // Use a named transport already configured using TransportFactory::setConfig() $mailer->setTransport('gmail'); @@ -540,7 +540,7 @@ $mailer->setTransport(new \Cake\Mailer\Transport\DebugTransport()); Configuration options can also be provided as a `DSN` string. This is useful when working with environment variables or `PaaS` providers: -``` php +```php TransportFactory::setConfig('default', [ 'url' => 'smtp://my@gmail.com:secret@smtp.gmail.com:587?tls=true', ]); @@ -563,7 +563,7 @@ like SendGrid, MailGun or Postmark. To create your transport, first create the f **src/Mailer/Transport/ExampleTransport.php** (where Example is the name of your transport). To start, your file should look like: -``` php +```php namespace App\Mailer\Transport; use Cake\Mailer\AbstractTransport; @@ -590,7 +590,7 @@ If you want you can use these classes directly with the `Mailer` too. For example: -``` php +```php $render = new \Cake\Mailer\Renderer(); $render->viewBuilder() ->setTemplate('custom') @@ -621,7 +621,7 @@ on the mail that would be delivered. Add the trait to your test case to start testing emails, and load routes if your emails need to generate URLs: -``` php +```php namespace App\Test\TestCase\Mailer; use App\Mailer\WelcomeMailer; @@ -645,7 +645,7 @@ class WelcomeMailerTestCase extends TestCase Let's assume we have a mailer that delivers welcome emails when a new user registers. We want to check that the subject and body contain the user's name: -``` php +```php // in our WelcomeMailerTestCase class. public function testName() { @@ -666,7 +666,7 @@ public function testName() The `Cake\TestSuite\EmailTrait` trait provides the following assertions: -``` php +```php // Asserts an expected number of emails were sent $this->assertMailCount($count); diff --git a/docs/en/core-libraries/events.md b/docs/en/core-libraries/events.md index 2ca8ed37f6..24885525bc 100644 --- a/docs/en/core-libraries/events.md +++ b/docs/en/core-libraries/events.md @@ -52,7 +52,7 @@ For example, in your Cart plugin you have an Orders model that deals with creating orders. You'd like to notify the rest of the application that an order has been created. To keep your Orders model clean you could use events: -``` php +```php // Cart/Model/Table/OrdersTable.php namespace Cart\Model\Table; @@ -88,7 +88,7 @@ objects that focus on those concerns. In CakePHP events are triggered against event managers. Event managers are available in every Table, View and Controller using `getEventManager()`: -``` php +```php $events = $this->getEventManager(); ``` @@ -106,7 +106,7 @@ difficult. The global manager is a singleton instance of dispatcher will be fired before instance listeners at the same priority. You can access the global manager using a static method: -``` php +```php // In any configuration file or piece of code that executes before the event use Cake\Event\EventManager; @@ -135,13 +135,13 @@ To keep a list of events that are fired on a particular `EventManager`, you can enable event tracking. To do so, simply attach an `Cake\Event\EventList` to the manager: -``` php +```php EventManager::instance()->setEventList(new EventList()); ``` After firing an event on the manager, you can retrieve it from the event list: -``` php +```php $eventsFired = EventManager::instance()->getEventList(); $firstEvent = $eventsFired[0]; ``` @@ -167,7 +167,7 @@ response has been sent, such as logging or sending emails. You can listen to this event using an event manager instance: -``` php +```php use Cake\Event\EventInterface; use Cake\Event\EventManager; @@ -179,7 +179,7 @@ EventManager::instance()->on('Server.terminate', function (EventInterface $event Or using the `events` hook in your Application/Plugin class: -``` php +```php use Cake\Event\EventInterface; use Cake\Event\EventManagerInterface; @@ -213,7 +213,7 @@ and the `afterExecute` event also contains the `exitCode` which is returned by t You can listen to this event using an event manager instance: -``` php +```php use Cake\Event\EventInterface; use Cake\Event\EventManager; @@ -230,7 +230,7 @@ EventManager::instance()->on('Command.afterExecute', function (EventInterface $e Or using the `events` hook in your Application/Plugin class: -``` php +```php use Cake\Event\EventInterface; use Cake\Event\EventManagerInterface; @@ -266,7 +266,7 @@ global site statistics. This is a great place to use a listener class. Doing so allows you to concentrate the statistics logic in one place and react to events as necessary. Our `UserStatistics` listener might start out like: -``` php +```php namespace App\Event; use Cake\Event\EventInterface; @@ -304,7 +304,7 @@ The `events` hook was added to the `BaseApplication` as well as the `BasePlugin` As of CakePHP 5.1 it is recommended to register event listeners by adding them via the `events` hook in your application or plugin class: -``` php +```php namespace App; use App\Event\UserStatistic; @@ -332,7 +332,7 @@ you can also bind any `callable` as an event listener. For example if we wanted to put any orders into the log files, we could use a simple anonymous function to do so: -``` php +```php use Cake\Event\EventInterface; use Cake\Log\Log; @@ -348,7 +348,7 @@ $this->Orders->getEventManager()->on('Order.afterPlace', function (EventInterfac In addition to anonymous functions you can use any other callable type that PHP supports: -``` php +```php $events = [ 'email-sending' => 'EmailSender::sendBuyEmail', 'inventory' => [$this->InventoryManager, 'decrement'], @@ -365,7 +365,7 @@ like to know when a Feedback record has been saved and ultimately act on it. You can listen to the global `Model.afterSave` event. However, you can take a more direct approach and only listen to the event you really need: -``` php +```php // You can create the following before the // save operation, i.e. config/bootstrap.php use Cake\Datasource\FactoryLocator; @@ -393,7 +393,7 @@ You can use this same approach to bind listener objects. Assuming several event listeners have been registered the presence or absence of a particular event pattern can be used as the basis of some action. -``` php +```php // Attach listeners to EventManager. $this->getEventManager()->on('User.Registration', [$this, 'userRegistration']); $this->getEventManager()->on('User.Verification', [$this, 'userVerification']); @@ -436,7 +436,7 @@ with a the order they were attached. You set priorities using the `on()` method for callbacks, and declaring it in the `implementedEvents()` function for event listeners: -``` php +```php // Setting priority for a callback $callback = [$this, 'doSomething']; $this->getEventManager()->on( @@ -471,7 +471,7 @@ When events have data provided in their constructor, the provided data is converted into arguments for the listeners. An example from the View layer is the afterRender callback: -``` php +```php $this->getEventManager() ->dispatch(new Event('View.afterRender', $this, ['view' => $viewFileName])); ``` @@ -479,7 +479,7 @@ $this->getEventManager() The listeners of the `View.afterRender` callback should have the following signature: -``` php +```php function (EventInterface $event, string $fileName) ``` @@ -499,7 +499,7 @@ using `Cake\Event\EventManager::dispatch()`. This method takes an instance of the `Cake\Event\Event` class. Let's look at dispatching an event: -``` php +```php // An event listener has to be instantiated before dispatching an event. // Create a new event and dispatch it. $event = new Event('Order.afterPlace', $this, [ @@ -540,7 +540,7 @@ the code detects it cannot proceed any further. In order to stop events you can either return `false` in your callbacks or call the `stopPropagation()` method on the event object: -``` php +```php public function doSomething(EventInterface $event): bool { // ... @@ -563,7 +563,7 @@ operation from occurring. To check if an event was stopped, you call the `isStopped()` method in the event object: -``` php +```php public function place(Order $order): bool { $event = new Event('Order.beforePlace', $this, ['order' => $order]); @@ -591,7 +591,7 @@ example and let callbacks modify the `$order` data. Event results can be altered either using the event object result property directly or returning the value in the callback itself: -``` php +```php // A listener callback public function doSomething(EventInterface $event): mixed { @@ -634,7 +634,7 @@ If for any reason you want to remove any callback from the event manager just call the `Cake\Event\EventManager::off()` method using as arguments the first two parameters you used for attaching it: -``` php +```php // Attaching a function $this->getEventManager()->on('My.event', [$this, 'doSomething']); diff --git a/docs/en/core-libraries/form.md b/docs/en/core-libraries/form.md index 83997544cf..52b22c09d6 100644 --- a/docs/en/core-libraries/form.md +++ b/docs/en/core-libraries/form.md @@ -19,7 +19,7 @@ form. This makes testing easier, and lets you re-use your form. Forms are put into **src/Form** and usually have `Form` as a class suffix. For example, a simple contact form would look like: -``` php +```php // in src/Form/ContactForm.php namespace App\Form; @@ -74,7 +74,7 @@ The `_execute` method was deprecated, and replaced by `process`. Once you've defined your form, you can use it in your controller to process and validate request data: -``` php +```php // In a controller namespace App\Controller; @@ -103,7 +103,7 @@ In the above example, we use the `execute()` method to run our form's accordingly. If we want to use a non-default validation set we can use the `validate` option: -``` php +```php if ($contact->execute($this->request->getData(), 'update')) { // Handle form success. } @@ -114,7 +114,7 @@ This option can also be set to `false` to disable validation. We could have also used the `validate()` method to only validate the request data: -``` php +```php $isValid = $form->validate($this->request->getData()); // You can also use other validation sets. The following @@ -127,7 +127,7 @@ $isValid = $form->validate($this->request->getData(), 'update'); You can set default values for modelless forms using the `setData()` method. Values set with this method will overwrite existing data in the form object: -``` php +```php // In a controller namespace App\Controller; @@ -164,7 +164,7 @@ you will overwrite your previous POST Data which might have validation errors that need corrections. You can use `set()` to add or replace individual fields or a subset of fields: -``` php +```php // Set one field. $contact->set('name', 'John Doe'); @@ -179,7 +179,7 @@ $contact->set([ Once a form has been validated you can retrieve the errors from it: -``` php +```php $errors = $form->getErrors(); /* $errors contains [ @@ -203,7 +203,7 @@ use of the Validator class. The most common use case for this is when the validation is done on a remote server. In such case, you must manually invalidate the fields accordingly to the feedback from the remote server: -``` php +```php // in src/Form/ContactForm.php public function setErrors(array $errors): void { @@ -214,14 +214,14 @@ public function setErrors(array $errors): void According to how the validator class would have returned the errors, `$errors` must be in this format: -``` php +```php ['fieldName' => ['validatorName' => 'The error message to display']] ``` Now you will be able to invalidate form fields by setting the fieldName, then set the error messages: -``` php +```php // In a controller $contact = new ContactForm(); $contact->setErrors(['email' => ['_required' => 'Your email is required']]); @@ -234,7 +234,7 @@ Proceed to Creating HTML with FormHelper to see the results. Once you've created a Form class, you'll likely want to create an HTML form for it. FormHelper understands Form objects just like ORM entities: -``` php +```php echo $this->Form->create($contact); echo $this->Form->control('name'); echo $this->Form->control('email'); diff --git a/docs/en/core-libraries/global-constants-and-functions.md b/docs/en/core-libraries/global-constants-and-functions.md index 557ebac43c..61b6f930e9 100644 --- a/docs/en/core-libraries/global-constants-and-functions.md +++ b/docs/en/core-libraries/global-constants-and-functions.md @@ -22,7 +22,7 @@ convenience wrappers for other CakePHP functionality, such as debugging and translating content. By default, only namespaced functions are autoloaded, however you can optionally load global aliases by adding: -``` php +```php require CAKE . 'functions.php'; ``` @@ -37,13 +37,13 @@ This function handles localization in CakePHP applications. The `$string_id` identifies the ID for a translation. You can supply additional arguments to replace placeholders in your string: -``` php +```php __('You have {0} unread messages', $number); ``` You can also provide a name-indexed array of replacements: -``` php +```php __('You have {unread} unread messages', ['unread' => $number]); ``` diff --git a/docs/en/core-libraries/hash.md b/docs/en/core-libraries/hash.md index 28f5cc653e..2be82fdf94 100644 --- a/docs/en/core-libraries/hash.md +++ b/docs/en/core-libraries/hash.md @@ -69,7 +69,7 @@ or object implementing `ArrayAccess` interface, along arbitrary paths quickly without having to loop through the data structures. Instead you use path expressions to qualify which elements you want returned: -``` php +```php // Common Usage: $users = [ ['id' => 1, 'name' => 'mark'], @@ -88,7 +88,7 @@ $results = Hash::extract($users, '{n}.id'); Inserts `$values` into an array as defined by `$path`: -``` php +```php $a = [ 'pages' => ['name' => 'page'], ]; @@ -107,13 +107,13 @@ $result = Hash::insert($a, 'files', ['name' => 'files']);   You can use paths using `{n}`, `{s}` and `{*}` to insert data into multiple points: -``` php +```php $users = Hash::insert($users, '{n}.new', 'value'); ``` Attribute matchers work with `insert()` as well: -``` php +```php $data = [ 0 => ['up' => true, 'Item' => ['id' => 1, 'title' => 'first']], 1 => ['Item' => ['id' => 2, 'title' => 'second']], @@ -139,7 +139,7 @@ $result = Hash::insert($data, '{n}[up].Item[id=4].new', 9); Removes all elements from an array that match `$path`: -``` php +```php $a = [ 'pages' => ['name' => 'page'], 'files' => ['name' => 'files'], @@ -158,7 +158,7 @@ $result = Hash::remove($a, 'files'); Using `{n}`, `{s}` and `{*}` will allow you to remove multiple values at once. You can also use attribute matchers with `remove()`: -``` php +```php $data = [ 0 => ['clear' => true, 'Item' => ['id' => 1, 'title' => 'first']], 1 => ['Item' => ['id' => 2, 'title' => 'second']], @@ -188,7 +188,7 @@ specified, or doesn't match anything, values will be initialized to null. You can optionally group the values by what is obtained when following the path specified in `$groupPath`: -``` php +```php $a = [ [ 'User' => [ @@ -294,7 +294,7 @@ You can provide arrays for both `$keyPath` and `$valuePath`. If you do this, the first value will be used as a format string, for values extracted by the other paths: -``` php +```php $result = Hash::combine( $a, '{n}.User.id', @@ -332,7 +332,7 @@ $result = Hash::combine( Returns a series of values extracted from an array, formatted with a format string: -``` php +```php $data = [ [ 'Person' => [ @@ -389,7 +389,7 @@ $res = Hash::format($data, ['{n}.Person.first_name', '{n}.Person.something'], '% Determines if one Hash or array contains the exact keys and values of another: -``` php +```php $a = [ 0 => ['name' => 'main'], 1 => ['name' => 'about'], @@ -415,7 +415,7 @@ $result = Hash::contains($b, $a); Checks if a particular path is set in an array: -``` php +```php $set = [ 'My Index 1' => ['First' => 'The first item'], ]; @@ -457,7 +457,7 @@ Filters empty elements out of array, excluding '0'. You can also supply a custom `$callback` to filter the array elements. The callback should return `false` to remove elements from the resulting array: -``` php +```php $data = [ '0', false, @@ -487,7 +487,7 @@ $res = Hash::filter($data); Collapses a multi-dimensional array into a single dimension: -``` php +```php $arr = [ [ 'Post' => ['id' => '1', 'title' => 'First Post'], @@ -520,7 +520,7 @@ $res = Hash::flatten($arr); Expands an array that was previously flattened with `Hash::flatten()`: -``` php +```php $data = [ '0.Post.id' => 1, '0.Post.title' => First Post, @@ -560,7 +560,7 @@ containing strings (unlike `array_merge_recursive`). > This function will work with an unlimited amount of arguments and > typecasts non-array parameters into arrays. -``` php +```php $array = [ [ 'id' => '48c2570e-dfa8-4c32-a35e-0d71cbdd56cb', @@ -605,7 +605,7 @@ $res = Hash::merge($array, $arrayB, $arrayC, $arrayD); Checks to see if all the values in the array are numeric: -``` php +```php $data = ['one']; $res = Hash::numeric(array_keys($data)); // $res is true @@ -622,7 +622,7 @@ $res = Hash::numeric($data); Counts the dimensions of an array. This method will only consider the dimension of the first element in the array: -``` php +```php $data = ['one', '2', 'three']; $result = Hash::dimensions($data); // $result == 1 @@ -651,7 +651,7 @@ $result = Hash::dimensions($data); Similar to `~Hash::dimensions()`, however this method returns, the deepest number of dimensions of any element in the array: -``` php +```php $data = ['1' => '1.1', '2', '3' => ['3.1' => '3.1.1']]; $result = Hash::maxDimensions($data); // $result == 2 @@ -669,7 +669,7 @@ Creates a new array, by extracting `$path`, and mapping `$function` across the results. You can use both expression and matching elements with this method: -``` php +```php // Call the noop function $this->noop() on every element of $data $result = Hash::map($data, "{n}", [$this, 'noop']); @@ -695,7 +695,7 @@ with this method. Apply a callback to a set of extracted values using `$function`. The function will get the extracted values as the first argument: -``` php +```php $data = [ ['date' => '01-01-2016', 'booked' => true], ['date' => '01-01-2016', 'booked' => false], @@ -717,7 +717,7 @@ $result = Hash::apply($data, '{n}[booked=true].date', 'array_count_values'); Sorts an array by any value, determined by a [Hash Path Syntax](#hash-path-syntax) Only expression elements are supported by this method: -``` php +```php $a = [ 0 => ['Person' => ['name' => 'Jeff']], 1 => ['Shirt' => ['color' => 'black']], @@ -754,7 +754,7 @@ can be one of the following values: Computes the difference between two arrays: -``` php +```php $a = [ 0 => ['name' => 'main'], 1 => ['name' => 'about'], @@ -784,7 +784,7 @@ data to the bottom of the resultant array. **Example 1:** -``` php +```php $array1 = ['ModelOne' => ['id' => 1001, 'field_one' => 'a1.m1.f1', 'field_two' => 'a1.m1.f2']]; $array2 = ['ModelOne' => ['id' => 1003, 'field_one' => 'a3.m1.f1', 'field_two' => 'a3.m1.f2', 'field_three' => 'a3.m1.f3']]; $res = Hash::mergeDiff($array1, $array2); @@ -803,7 +803,7 @@ $res = Hash::mergeDiff($array1, $array2); **Example 2:** -``` php +```php $array1 = ["a" => "b", 1 => 20938, "c" => "string"]; $array2 = ["b" => "b", 3 => 238, "c" => "string", ["extra_field"]]; $res = Hash::mergeDiff($array1, $array2); @@ -830,7 +830,7 @@ normalized to be an associative array. Numeric keys with values, will be converted to string keys with `$default` values. Normalizing an array, makes using the results with `Hash::merge()` easier: -``` php +```php $a = ['Tree', 'CounterCache', 'Upload' => [ 'folder' => 'products', @@ -896,7 +896,7 @@ Takes a flat array set, and creates a nested, or threaded data structure. For example, if you had the following array of data: -``` php +```php $data = [ ['ThreadPost' => ['id' => 1, 'parent_id' => null]], ['ThreadPost' => ['id' => 2, 'parent_id' => 1]], diff --git a/docs/en/core-libraries/httpclient.md b/docs/en/core-libraries/httpclient.md index 9176c43e84..3c4c13083f 100644 --- a/docs/en/core-libraries/httpclient.md +++ b/docs/en/core-libraries/httpclient.md @@ -15,7 +15,7 @@ remote APIs. Doing requests is simple and straight forward. Doing a GET request looks like: -``` php +```php use Cake\Http\Client; $http = new Client(); @@ -34,7 +34,7 @@ $response = $http->get('https://example.com/search', ['q' => 'widget'], [ Doing POST and PUT requests is equally simple: -``` php +```php // Send a POST request with application/x-www-form-urlencoded encoded data $http = new Client(); $response = $http->post('https://example.com/posts/add', [ @@ -57,7 +57,7 @@ $http->patch(/* ... */); If you have created a PSR-7 request object you can send it using `sendRequest()`: -``` php +```php use Cake\Http\Client; use Cake\Http\Client\Request as ClientRequest; @@ -73,7 +73,7 @@ $response = $http->sendRequest($request); You can include files in request bodies by including a filehandle in the array: -``` php +```php $http = new Client(); $response = $http->post('https://example.com/api', [ 'image' => fopen('/path/to/a/file', 'r'), @@ -88,7 +88,7 @@ There may be times when you need to build a request body in a very specific way. In these situations you can often use `Cake\Http\Client\FormData` to craft the specific multipart HTTP request you want: -``` php +```php use Cake\Http\Client\FormData; $data = new FormData(); @@ -118,7 +118,7 @@ $response = $http->post( When dealing with REST APIs you often need to send request bodies that are not form encoded. Http\Client exposes this through the type option: -``` php +```php // Send a JSON request body. $http = new Client(); $response = $http->post( @@ -133,7 +133,7 @@ When using the `type` option, you should provide the data as a string. If you're doing a GET request that needs both querystring parameters and a request body you can do the following: -``` php +```php // Send a JSON body in a GET request with query string parameters. $http = new Client(); $response = $http->get( @@ -185,7 +185,7 @@ context. An example of basic authentication: -``` php +```php $http = new Client(); $response = $http->get('https://example.com/profile/1', [], [ 'auth' => ['username' => 'mark', 'password' => 'secret'], @@ -199,7 +199,7 @@ By default, `Cake\Http\Client` will use basic authentication if there is no An example of basic authentication: -``` php +```php $http = new Client(); $response = $http->get('https://example.com/profile/1', [], [ 'auth' => [ @@ -233,7 +233,7 @@ Many modern web-services require OAuth authentication to access their APIs. The included OAuth authentication assumes that you already have your consumer key and consumer secret: -``` php +```php $http = new Client(); $response = $http->get('https://example.com/profile/1', [], [ 'auth' => [ @@ -252,7 +252,7 @@ $response = $http->get('https://example.com/profile/1', [], [ Because OAuth2 is often a single header, there is not a specialized authentication adapter. Instead you can create a client with the access token: -``` php +```php $http = new Client([ 'headers' => ['Authorization' => 'Bearer ' . $accessToken], ]); @@ -265,7 +265,7 @@ Some proxies require authentication to use them. Generally this authentication is Basic, but it can be implemented by any authentication adapter. By default Http\Client will assume Basic authentication, unless the type key is set: -``` php +```php $http = new Client(); $response = $http->get('https://example.com/test.php', [], [ 'proxy' => [ @@ -289,7 +289,7 @@ Having to re-type the domain name, authentication and proxy settings can become tedious & error prone. To reduce the chance for mistake and relieve some of the tedium, you can create scoped clients: -``` php +```php // Create a scoped client. $http = new Client([ 'host' => 'api.example.com', @@ -304,7 +304,7 @@ $response = $http->get('/test.php'); If your scoped client only needs information from the URL you can use `createFromUrl()`: -``` php +```php $http = Client::createFromUrl('https://api.example.com/v1/test'); ``` @@ -328,7 +328,7 @@ The following information can be used when creating a scoped client: Any of these options can be overridden by specifying them when doing requests. host, scheme, proxy, port are overridden in the request URL: -``` php +```php // Using the scoped client we created earlier. $response = $http->get('http://foo.com/test.php'); ``` @@ -347,7 +347,7 @@ instance of Http\Client. The cookies stored in a Client instance are automatically included in future requests to domain + path combinations that match: -``` php +```php $http = new Client([ 'host' => 'cakephp.org', ]); @@ -363,7 +363,7 @@ $response2 = $http->get('/changelogs'); You can always override the auto-included cookies by setting them in the request's `$options` parameters: -``` php +```php // Replace a stored cookie with a custom value. $response = $http->get('/changelogs', [], [ 'cookies' => ['sessionid' => '123abc'], @@ -373,7 +373,7 @@ $response = $http->get('/changelogs', [], [ You can add cookie objects to the client after creating it using the `addCookie()` method: -``` php +```php use Cake\Http\Cookie\Cookie; $http = new Client([ @@ -403,14 +403,14 @@ Response objects have a number of methods for inspecting the response data. You read the entire response body as a string: -``` php +```php // Read the entire response as a string. $response->getStringBody(); ``` You can also access the stream object for the response and use its methods: -``` php +```php // Get a Psr\Http\Message\StreamInterface containing the response body $stream = $response->getBody(); @@ -428,7 +428,7 @@ Since JSON and XML responses are commonly used, response objects provide a way to use accessors to read decoded data. JSON data is decoded into an array, while XML data is decoded into a `SimpleXMLElement` tree: -``` php +```php // Get some XML $http = new Client(); $response = $http->get('https://example.com/test.xml'); @@ -448,7 +448,7 @@ multiple times has no additional cost. You can access headers through a few different methods. Header names are always treated as case-insensitive values when accessing them through methods: -``` php +```php // Get all the headers as an associative array. $response->getHeaders(); @@ -467,7 +467,7 @@ $response->getEncoding(); You can read cookies with a few different methods depending on how much data you need about the cookies: -``` php +```php // Get all cookies (full data) $response->getCookies(); @@ -483,7 +483,7 @@ $response->getCookieData('session_id'); Response objects provide a few methods for checking status codes: -``` php +```php // Was the response a 20x $response->isOk(); @@ -500,7 +500,7 @@ By default, `Http\Client` will prefer using a `curl` based transport adapter. If the curl extension is not available a stream based adapter will be used instead. You can force select a transport adapter using a constructor option: -``` php +```php use Cake\Http\Client\Adapter\Stream; $http = new Client(['adapter' => Stream::class]); @@ -514,7 +514,7 @@ caching, logging etc. ### HttpClient.beforeSend -``` php +```php // Somewhere before calling one of the HTTP client's methods which makes a request $http->getEventManager()->on( 'HttpClient.beforeSend', @@ -538,7 +538,7 @@ $http->getEventManager()->on( ### HttpClient.afterSend -``` php +```php // Somewhere before calling one of the HTTP client's methods which makes a request $http->getEventManager()->on( 'HttpClient.afterSend', @@ -568,7 +568,7 @@ In tests you will often want to create mock responses to external APIs. You can use the `HttpClientTrait` to define responses to the requests your application is making: -``` php +```php use Cake\Http\TestSuite\HttpClientTrait; use Cake\TestSuite\TestCase; @@ -591,7 +591,7 @@ class CartControllerTests extends TestCase There are methods to mock the most commonly used HTTP methods: -``` php +```php $this->mockClientGet(/* ... */); $this->mockClientPatch(/* ... */); $this->mockClientPost(/* ... */); @@ -607,7 +607,7 @@ As seen above you can use the `newClientResponse()` method to create responses for the requests your application will make. The headers need to be a list of strings: -``` php +```php $headers = [ 'Content-Type: application/json', 'Connection: close', diff --git a/docs/en/core-libraries/inflector.md b/docs/en/core-libraries/inflector.md index 2b1b16c187..91d76bd23a 100644 --- a/docs/en/core-libraries/inflector.md +++ b/docs/en/core-libraries/inflector.md @@ -133,7 +133,7 @@ Both `pluralize` and `singularize()` work on most English nouns. If you need to support other languages, you can use [Inflection Configuration](#inflection-configuration) to customize the rules used: -``` php +```php // Apples echo Inflector::pluralize('Apple'); ``` @@ -141,7 +141,7 @@ echo Inflector::pluralize('Apple'); > [!NOTE] > `pluralize()` should not be used on a noun that is already in its plural form. -``` php +```php // Person echo Inflector::singularize('People'); ``` @@ -161,7 +161,7 @@ echo Inflector::singularize('People'); These methods are useful when creating class names, or property names: -``` php +```php // ApplePie Inflector::camelize('Apple_pie') @@ -182,7 +182,7 @@ underscore. This method is useful when converting underscored forms into "Title Case" forms for human readable values: -``` php +```php // Apple Pie Inflector::humanize('apple_pie'); ``` @@ -204,7 +204,7 @@ Inflector::humanize('apple_pie'); When generating code, or using CakePHP's conventions you may need to inflect table names or class names: -``` php +```php // UserProfileSetting Inflector::classify('user_profile_settings'); @@ -224,7 +224,7 @@ Inflector::tableize('UserProfileSetting'); Variable names are often useful when doing meta-programming tasks that involve generating code or doing work based on conventions: -``` php +```php // applePie Inflector::variable('apple_pie'); ``` @@ -252,7 +252,7 @@ special cases. Define new inflection and transliteration rules for Inflector to use. Often, this method is used in your **config/bootstrap.php**: -``` php +```php Inflector::rules('singular', ['/^(bil)er$/i' => '\1', '/^(inflec|contribu)tors$/i' => '\1ta']); Inflector::rules('uninflected', ['singulars']); Inflector::rules('irregular', ['phylum' => 'phyla']); // The key is singular form, value is plural form diff --git a/docs/en/core-libraries/internationalization-and-localization.md b/docs/en/core-libraries/internationalization-and-localization.md index 5abb9214e7..f4b2c66c86 100644 --- a/docs/en/core-libraries/internationalization-and-localization.md +++ b/docs/en/core-libraries/internationalization-and-localization.md @@ -23,14 +23,14 @@ multilingual application, the first of which is to make use of the `__()` function in your code. Below is an example of some code for a single-language application: -``` html +```html

Popular Articles

``` To internationalize your code, all you need to do is to wrap strings in `__()` like so: -``` html +```html

``` @@ -95,7 +95,7 @@ As of 4.5.0 plugins can contain multiple translation domains. Use `MyPlugin.addi An example translation file could look like this: -``` pot +```pot msgid "My name is {0}" msgstr "Je m'appelle {0}" @@ -122,7 +122,7 @@ learn more. The default locale can be set in your **config/app.php** file by setting `App.defaultLocale`: -``` php +```php 'App' => [ ... 'defaultLocale' => env('APP_DEFAULT_LOCALE', 'en_US'), @@ -138,7 +138,7 @@ of those is displayed using the localization libraries that CakePHP provides. To change the language for translated strings you can call this method: -``` php +```php use Cake\I18n\I18n; I18n::setLocale('de_DE'); @@ -154,7 +154,7 @@ application. The most frequently used one is `__()`. This function is used to retrieve a single translation message or return the same string if no translation was found: -``` php +```php echo __('Popular Articles'); ``` @@ -162,7 +162,7 @@ If you need to group your messages, for example, translations inside a plugin, you can use the `__d()` function to fetch messages from another domain: -``` php +```php echo __d('my_plugin', 'Trending right now'); ``` @@ -177,7 +177,7 @@ This can happen if two strings are identical but refer to different things. For example, 'letter' has multiple meanings in English. To solve that problem, you can use the `__x()` function: -``` php +```php echo __x('written communication', 'He read the first letter'); echo __x('alphabet learning', 'He read the first letter'); @@ -186,7 +186,7 @@ echo __x('alphabet learning', 'He read the first letter'); The first argument is the context of the message and the second is the message to be translated. -``` pot +```pot msgctxt "written communication" msgid "He read the first letter" msgstr "Er las den ersten Brief" @@ -197,20 +197,20 @@ msgstr "Er las den ersten Brief" Translation functions allow you to interpolate variables into the messages using special markers defined in the message itself or in the translated string: -``` php +```php echo __("Hello, my name is {0}, I'm {1} years old", ['Sara', 12]); ``` Markers are numeric, and correspond to the keys in the passed array. You can also pass variables as independent arguments to the function: -``` php +```php echo __("Small step for {0}, Big leap for {1}", 'Man', 'Humanity'); ``` All translation functions support placeholder replacements: -``` php +```php __d('validation', 'The field {0} cannot be left empty', 'Name'); __x('alphabet', 'He read the letter {0}', 'Z'); @@ -220,13 +220,13 @@ The `'` (single quote) character acts as an escape code in translation messages. Any variables between single quotes will not be replaced and is treated as literal text. For example: -``` php +```php __("This variable '{0}' be replaced.", 'will not'); ``` By using two adjacent quotes your variables will be replaced properly: -``` php +```php __("This variable ''{0}'' be replaced.", 'will'); ``` @@ -235,7 +235,7 @@ These functions take advantage of the so you can translate messages and localize dates, numbers and currency at the same time: -``` php +```php echo __( 'Hi {0}, your balance on the {1,date} is {2,number,currency}', ['Charles', new DateTime('2014-01-13 11:12:00'), 1354.37], @@ -248,7 +248,7 @@ Hi Charles, your balance on the Jan 13, 2014, 11:12 AM is $ 1,354.37 Numbers in placeholders can be formatted as well with fine grain control of the output: -``` php +```php echo __( 'You have traveled {0,number} kilometers in {1,number,integer} weeks', [5423.344, 5.1], @@ -284,7 +284,7 @@ You can also use named placeholders like `{name}` in the message strings. When using named placeholders, pass the placeholder and replacement in an array using key/value pairs, for example: -``` php +```php // echos: Hi. My name is Sara. I'm 12 years old. echo __("Hi. My name is {name}. I'm {age} years old.", ['name' => 'Sara', 'age' => 12]); ``` @@ -301,7 +301,7 @@ The first one is taking advantage of the `ICU` message format that comes by default in the translation functions. In the translations file you could have the following strings -``` pot +```pot msgid "{0,plural,=0{No records found} =1{Found 1 record} other{Found # records}}" msgstr "{0,plural,=0{Ningún resultado} =1{1 resultado} other{# resultados}}" @@ -312,7 +312,7 @@ msgstr "{placeholder,plural,=0{Ningún resultado} =1{1 resultado} other{{1} resu And in the application use the following code to output either of the translations for such string: -``` php +```php __('{0,plural,=0{No records found }=1{Found 1 record} other{Found # records}}', [0]); // Returns "Ningún resultado" as the argument {0} is 0 @@ -330,7 +330,7 @@ __('{placeholder,plural,=0{No records found} =1{Found 1 record} other{Found {1} A closer look to the format we just used will make it evident how messages are built: -``` text +```text { [count placeholder],plural, case1{message} case2{message} case3{...} ... } ``` @@ -344,14 +344,14 @@ use `#`. You can of course use simpler message ids if you don't want to type the full plural selection sequence in your code -``` pot +```pot msgid "search.results" msgstr "{0,plural,=0{Ningún resultado} =1{1 resultado} other{{1} resultados}}" ``` Then use the new string in your code: -``` php +```php __('search.results', [2, 2]); // Returns: "2 resultados" @@ -367,13 +367,13 @@ languages like Arabic require a different plural when you refer to few things and other plural form for many things. In those cases you can use the ICU matching aliases. Instead of writing: -``` text +```text =0{No results} =1{...} other{...} ``` You can do: -``` text +```text zero{No Results} one{One result} few{...} many{...} other{...} ``` @@ -387,7 +387,7 @@ The second plural selection format accepted is using the built-in capabilities of Gettext. In this case, plurals will be stored in the `.po` file by creating a separate message translation line per plural form: -``` pot +```pot # One message identifier for singular msgid "One file removed" # Another one for plural @@ -401,7 +401,7 @@ msgstr[1] "{0} ficheros eliminados" When using this other format, you are required to use another translation function: -``` php +```php // Returns: "10 ficheros eliminados" $count = 10; __n('One file removed', '{0} files removed', $count, $count); @@ -414,7 +414,7 @@ The number inside `msgstr[]` is the number assigned by Gettext for the plural form of the language. Some languages have more than two plural forms, for example Croatian: -``` pot +```pot msgid "One file removed" msgid_plural "{0} files removed" msgstr[0] "{0} datoteka je uklonjena" @@ -432,7 +432,7 @@ translation messages are stored, you can create your own translation message loader. The easiest way to create your own translator is by defining a loader for a single domain and locale: -``` php +```php use Cake\I18n\Package; // Prior to 4.2 you need to use Aura\Intl\Package @@ -458,7 +458,7 @@ minimum that is required for creating a translator is that the loader function should return a `Cake\I18n\Package` object (prior to 4.2 it should be an `Aura\Intl\Package` object). Once the code is in place you can use the translation functions as usual: -``` php +```php I18n::setLocale('fr_FR'); __d('animals', 'Dog'); // Returns "Chien" ``` @@ -469,7 +469,7 @@ another file, calling another function, etc. CakePHP provides a few loader functions you can reuse if you just need to change where messages are loaded. For example, you can still use **.po** files, but loaded from another location: -``` php +```php use Cake\I18n\MessagesFileLoader as Loader; // Load messages from resources/locales/folder/sub_folder/filename.po @@ -487,7 +487,7 @@ a message parser other than `PoFileParser`. For example, if you wanted to load translation messages using `YAML`, you will first need to create the parser class: -``` php +```php namespace App\I18n\Parser; class YamlFileParser @@ -503,7 +503,7 @@ The file should be created in the **src/I18n/Parser** directory of your application. Next, create the translations file under **resources/locales/fr_FR/animals.yaml** -``` yaml +```yaml Dog: Chien Cat: Chat Bird: Oiseau @@ -511,7 +511,7 @@ Bird: Oiseau And finally, configure the translation loader for the domain and locale: -``` php +```php use Cake\I18n\MessagesFileLoader as Loader; I18n::setTranslator( @@ -531,7 +531,7 @@ generic translator loaders for each domain. Imagine that you wanted to load all translations for the default domain and for any language from an external service: -``` php +```php use Cake\I18n\Package; // Prior to 4.2 you need to use Aura\Intl\Package @@ -556,7 +556,7 @@ If you'd like to change how packages are loaded for all packages, that don't have specific loaders set you can replace the fallback package loader by using the `_fallback` package: -``` php +```php I18n::config('_fallback', function ($domain, $locale) { // Custom code that yields a package here. }); @@ -569,7 +569,7 @@ to store messages under different domains or to trigger Gettext-style plural selection. The following is an example of storing translations for the same key in different contexts: -``` php +```php [ 'He reads the letter {0}' => [ 'alphabet' => 'Él lee la letra {0}', @@ -581,7 +581,7 @@ in different contexts: Similarly, you can express Gettext-style plurals using the messages array by having a nested array key per plural form: -``` php +```php [ 'I have read one book' => 'He leído un libro', 'I have read {0} books' => [ @@ -601,14 +601,14 @@ variables in translation messages and selecting the correct plural form. If you're dealing with a legacy application, or you don't need the power offered by the ICU message formatting, CakePHP also provides the `sprintf` formatter: -``` php +```php return Package('sprintf', 'fallback_domain', $messages); ``` The messages to be translated will be passed to the `sprintf()` function for interpolating the variables: -``` php +```php __('Hello, my name is %s and I am %d years old', 'José', 29); ``` @@ -616,7 +616,7 @@ It is possible to set the default formatter for all translators created by CakePHP before they are used for the first time. This does not include manually created translators using the `setTranslator()` and `config()` methods: -``` php +```php I18n::setDefaultFormatter('sprintf'); ``` @@ -629,7 +629,7 @@ that you wish your page to be displayed. In order to change how dates and numbers are displayed you just need to change the current locale setting and use the right classes: -``` php +```php use Cake\I18n\I18n; use Cake\I18n\DateTime; use Cake\I18n\Number; @@ -659,7 +659,7 @@ information in a user's localized format. In a controller, or [Middleware](../controllers/middleware) you can configure the Date, Time, and DateTime types to parse localized formats: -``` php +```php use Cake\Database\TypeFactory; // Enable default locale format parsing. @@ -684,7 +684,7 @@ the datetimes in request data into your application's timezone. You can use `setUserTimezone()` from a controller or [Middleware](../controllers/middleware) to make this process simpler: -``` php +```php // Set the user's timezone TypeFactory::build('datetime')->setUserTimezone($user->timezone); ``` @@ -697,7 +697,7 @@ working in the timezone defined in `App.defaultTimezone`. If your application handles datetime information in a number of actions you can use a middleware to define both timezone conversion and locale parsing: -``` php +```php namespace App\Middleware; use Cake\Database\TypeFactory; @@ -731,7 +731,7 @@ class DatetimeMiddleware implements MiddlewareInterface By using the `LocaleSelectorMiddleware` in your application, CakePHP will automatically set the locale based on the current user: -``` php +```php // in src/Application.php use Cake\I18n\Middleware\LocaleSelectorMiddleware; diff --git a/docs/en/core-libraries/logging.md b/docs/en/core-libraries/logging.md index 2bcda64d8a..5d2dce83c3 100644 --- a/docs/en/core-libraries/logging.md +++ b/docs/en/core-libraries/logging.md @@ -30,7 +30,7 @@ The **config/app.php** file is intended for just this. You can define as many or as few loggers as your application needs. Loggers should be configured using `Cake\Log\Log`. An example would be: -``` php +```php use Cake\Log\Engine\FileLog; use Cake\Log\Log; @@ -73,7 +73,7 @@ It is also possible to create loggers by providing a closure. This is useful when you need full control over how the logger object is built. The closure has to return the constructed logger instance. For example: -``` php +```php Log::setConfig('special', function () { return new \Cake\Log\Engine\FileLog(['path' => LOGS, 'file' => 'log']); }); @@ -82,7 +82,7 @@ Log::setConfig('special', function () { Configuration options can also be provided as a `DSN` string. This is useful when working with environment variables or `PaaS` providers: -``` php +```php Log::setConfig('error', [ 'url' => 'file:///full/path/to/logs/?levels[]=warning&levels[]=error&file=error', ]); @@ -104,7 +104,7 @@ information. Writing to the log files can be done in two different ways. The first is to use the static `Cake\Log\Log::write()` method: -``` php +```php Log::write('debug', 'Something did not work'); ``` @@ -112,7 +112,7 @@ The second is to use the `log()` shortcut function available on any class using the `LogTrait`. Calling `log()` will internally call `Log::write()`: -``` php +```php // Executing this inside a class using LogTrait $this->log('Something did not work!', 'debug'); ``` @@ -128,7 +128,7 @@ If you need to log dynamically defined data, you can use placeholders in your log messages and provide an array of key/value pairs in the `$context` parameter: -``` php +```php // Will log `Could not process for userid=1` Log::write('error', 'Could not process for userid={user}', ['user' => $user->id]); ``` @@ -136,7 +136,7 @@ Log::write('error', 'Could not process for userid={user}', ['user' => $user->id] Placeholders that do not have keys defined will not be replaced. If you need to use a literal braced word, you must escape the placeholder: -``` php +```php // Will log `No {replace}` Log::write('error', 'No \\{replace}', ['replace' => 'no']); ``` @@ -185,7 +185,7 @@ CakePHP exposes this concept as logging scopes. When log messages are written you can include a scope name. If there is a configured logger for that scope, the log messages will be directed to those loggers. For example: -``` php +```php use Cake\Log\Engine\FileLog; // Configure logs/shops.log to receive all levels, but only @@ -215,7 +215,7 @@ Log::warning('this gets written to both shops.log and payments.log', ['scope' => Scopes can also be passed as a single string or a numerically indexed array. Note that using this form will limit the ability to pass more data as context: -``` php +```php Log::warning('This is a warning', ['orders']); Log::warning('This is a warning', 'payments'); ``` @@ -234,7 +234,7 @@ message being written determines the name of the file the message is stored in. If a level is not supplied, `LOG_ERR` is used which writes to the error log. The default log location is **logs/`$level.log`**: -``` php +```php // Executing this inside a CakePHP class $this->log("Something didn't work!"); @@ -249,7 +249,7 @@ You can configure additional/alternate FileLog locations when configuring a logger. FileLog accepts a `path` which allows for custom paths to be used: -``` php +```php Log::setConfig('custom_path', [ 'className' => 'File', 'path' => '/path/to/custom/place/', @@ -286,7 +286,7 @@ to specify `Syslog` as the engine to be used for logging. The following configuration snippet will replace the default logger with syslog, this should be done in the **config/bootstrap.php** file: -``` php +```php Log::setConfig('default', [ 'engine' => 'Syslog', ]); @@ -319,7 +319,7 @@ plugins. If for example you had a database logger called engine you should use `Cake\Log\Log::setConfig()`. For example configuring our DatabaseLog would look like: -``` php +```php // For src/Log Log::setConfig('otherFile', [ 'className' => 'Database', @@ -339,7 +339,7 @@ When configuring a log engine the `className` parameter is used to locate and load the log handler. All of the other configuration properties are passed to the log engine's constructor as an array. -``` php +```php namespace App\Log\Engine; use Cake\Log\Engine\BaseLog; @@ -370,7 +370,7 @@ a formatter configured to maintain backwards compatible output. However, you can adjust the formatters to fit your requirements. Formatters are configured alongside the logging engine: -``` php +```php use Cake\Log\Engine\SyslogLog; use App\Log\Formatter\CustomFormatter; @@ -404,7 +404,7 @@ To test logging, add `Cake\TestSuite\LogTestTrait` to your test case. The messages your application is making. Once you have captured logs you can perform assertions on log messages your application is emitting. For example: -``` php +```php namespace App\Test\TestCase\Controller; use Cake\TestSuite\LogTestTrait; @@ -549,7 +549,7 @@ logger. After installing Monolog using composer, configure the logger using the `Log::setConfig()` method: -``` php +```php // config/bootstrap.php use Monolog\Logger; @@ -569,7 +569,7 @@ Log::drop('error'); Use similar methods if you want to configure a different logger for your console: -``` php +```php // config/bootstrap_cli.php use Monolog\Logger; diff --git a/docs/en/core-libraries/number.md b/docs/en/core-libraries/number.md index 6cb4601e24..3c1a774628 100644 --- a/docs/en/core-libraries/number.md +++ b/docs/en/core-libraries/number.md @@ -10,7 +10,7 @@ description: "Format numbers in CakePHP: display currency, percentages, file siz If you need `NumberHelper` functionalities outside of a `View`, use the `Number` class: -``` php +```php namespace App\Controller; use Cake\I18n\Number; @@ -49,7 +49,7 @@ automatically echo the output into the view. This method is used to display a number in common currency formats (EUR, GBP, USD), based on the 3-letter ISO 4217 currency code. Usage in a view looks like: -``` php +```php // Called as NumberHelper echo $this->Number->currency($value, $currency); @@ -88,7 +88,7 @@ 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: -``` php +```php Number::setDefaultCurrencyFormat(Number::FORMAT_CURRENCY_ACCOUNTING); ``` @@ -123,7 +123,7 @@ 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. -``` php +```php // Called as NumberHelper echo $this->Number->precision(456.91873645, 2); @@ -149,7 +149,7 @@ 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. -``` php +```php // Called as NumberHelper. Output: 45.69% echo $this->Number->toPercentage(45.691873645); @@ -174,7 +174,7 @@ displayed with a two-digit precision level, according to the size of data supplied (i.e. higher sizes are expressed in larger terms): -``` php +```php // Called as NumberHelper echo $this->Number->toReadableSize(0); // 0 Byte echo $this->Number->toReadableSize(1024); // 1 KB @@ -199,7 +199,7 @@ 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: -``` php +```php // Called as NumberHelper $this->Number->format($value, $options); @@ -230,7 +230,7 @@ resides. Example: -``` php +```php // Called as NumberHelper echo $this->Number->format('123456.7890', [ 'places' => 2, @@ -266,7 +266,7 @@ This method will output an ordinal number. Examples: -``` php +```php echo Number::ordinal(1); // Output '1st' @@ -290,7 +290,7 @@ echo Number::ordinal(410); This method displays differences in value as a signed number: -``` php +```php // Called as NumberHelper $this->Number->formatDelta($value, $options); @@ -315,7 +315,7 @@ The `$options` parameter takes the same keys as `Number::format()` itself: Example: -``` php +```php // Called as NumberHelper echo $this->Number->formatDelta('123456.7890', [ 'places' => 2, @@ -346,7 +346,7 @@ to various methods. Example: -``` php +```php Number::config('en_IN', \NumberFormatter::CURRENCY, [ 'pattern' => '#,##,##0', ]); diff --git a/docs/en/core-libraries/plugin.md b/docs/en/core-libraries/plugin.md index bdc2903ade..3f1dd0f5b5 100644 --- a/docs/en/core-libraries/plugin.md +++ b/docs/en/core-libraries/plugin.md @@ -18,7 +18,7 @@ The Plugin class is responsible for resource location and path management of plu Plugins can be located with Plugin. Using `Plugin::path('DebugKit');` for example, will give you the full path to the DebugKit plugin: -``` php +```php $path = Plugin::path('DebugKit'); ``` @@ -26,7 +26,7 @@ $path = Plugin::path('DebugKit'); You can check dynamically inside your code if a specific plugin has been loaded: -``` php +```php $isLoaded = Plugin::isLoaded('DebugKit'); ``` @@ -40,7 +40,7 @@ Use `Plugin::loaded()` if you want to get a list of all currently loaded plugins Used to get the location of the plugin's class files: -``` php +```php $path = App::classPath('DebugKit'); ``` @@ -52,12 +52,12 @@ $path = App::classPath('DebugKit'); The method returns the path to the plugins' templates: -``` php +```php $path = Plugin::templatePath('DebugKit'); ``` The same goes for the config path: -``` php +```php $path = Plugin::configPath('DebugKit'); ``` diff --git a/docs/en/core-libraries/registry-objects.md b/docs/en/core-libraries/registry-objects.md index 6f7ff98ff6..0f4ef89dda 100644 --- a/docs/en/core-libraries/registry-objects.md +++ b/docs/en/core-libraries/registry-objects.md @@ -17,7 +17,7 @@ for Helpers, Behaviors, and Tasks in addition to Components. Objects can be loaded on-the-fly using `add()` Example: -``` php +```php $this->loadComponent('Acl.Acl'); $this->addHelper('Flash') ``` @@ -25,7 +25,7 @@ $this->addHelper('Flash') This will result in the `Acl` property and `Flash` helper being loaded. Configuration can also be set on-the-fly. Example: -``` php +```php $this->loadComponent('Cookie', ['name' => 'sweet']); ``` @@ -35,7 +35,7 @@ used to alias objects in a registry. This allows you to have component names that do not reflect the classnames, which can be helpful when extending core components: -``` php +```php $this->Flash = $this->loadComponent('Flash', ['className' => 'MyCustomFlash']); $this->Flash->error(); // Actually using MyCustomFlash::error(); ``` @@ -53,7 +53,7 @@ objects from receiving callbacks. You should use the features in the events syst accomplish this now. For example, you could disable component callbacks in the following way: -``` php +```php // Remove MyComponent from callbacks. $this->getEventManager()->off($this->MyComponent); diff --git a/docs/en/core-libraries/security.md b/docs/en/core-libraries/security.md index a163895584..6c7eb774e8 100644 --- a/docs/en/core-libraries/security.md +++ b/docs/en/core-libraries/security.md @@ -29,7 +29,7 @@ The [openssl](https://php.net/openssl) extension is required for encrypting/decr An example use would be: -``` php +```php // Assuming key is stored somewhere it can be re-used for // decryption later. $key = 'wt1U5MACWJFTXGenFoZoiLwQGrLgdbHA'; @@ -46,7 +46,7 @@ Decrypt a previously encrypted value. The `$key` and `$hmacSalt` parameters must match the values used to encrypt or decryption will fail. An example use would be: -``` php +```php // Assuming the key is stored somewhere it can be re-used for // Decryption later. $key = 'wt1U5MACWJFTXGenFoZoiLwQGrLgdbHA'; @@ -68,7 +68,7 @@ Create a hash from string using given method. Fallback on next available method. If `$salt` is set to `true`, the application's salt value will be used: -``` php +```php // Using the application's salt value $sha1 = Security::hash('CakePHP Framework', 'sha1', true); diff --git a/docs/en/core-libraries/text.md b/docs/en/core-libraries/text.md index 27f18e9649..9aa39ac0d9 100644 --- a/docs/en/core-libraries/text.md +++ b/docs/en/core-libraries/text.md @@ -14,7 +14,7 @@ strings and is normally accessed statically. Example: If you need `Cake\View\Helper\TextHelper` functionalities outside of a `View`, use the `Text` class: -``` php +```php namespace App\Controller; use Cake\Utility\Text; @@ -57,7 +57,7 @@ multiple conversion pairs separated by `;`. You can find more info about transliterator identifiers [here](https://unicode-org.github.io/icu/userguide/transforms/general/#transliterator-identifiers): -``` php +```php // apple puree Text::transliterate('apple purée'); @@ -87,7 +87,7 @@ options are: - `preserve` Specific non-word character to preserve. Defaults to `null`. For example, this option can be set to '.' to generate clean file names: - ``` php + ```php // apple-puree Text::slug('apple purée'); @@ -108,7 +108,7 @@ The UUID method is used to generate unique identifiers as per `4122`. The UUID is a 128-bit string in the format of `485fc381-e790-47a3-9794-1337c0a8fe68`. -``` php +```php Text::uuid(); // 485fc381-e790-47a3-9794-1337c0a8fe68 ``` @@ -119,7 +119,7 @@ You can now configure a custom UUID generator using dependency injection. Starting from CakePHP 5.3.0, you can configure a custom UUID generator by setting a closure in your configuration: -``` php +```php // In your config/app.php or config/bootstrap.php use Cake\Core\Configure; @@ -145,7 +145,7 @@ that appears between `$leftBound` and `$rightBound`. This method can be useful when splitting up data that has regular formatting such as tag lists: -``` php +```php $data = "cakephp 'great framework' php"; $result = Text::tokenize($data, ' ', "'", "'"); // Result contains @@ -159,7 +159,7 @@ $result = Text::tokenize($data, ' ', "'", "'"); This method unformats a number from a human-readable byte size to an integer number of bytes: -``` php +```php $int = Text::parseFileSize('2GB'); ``` @@ -172,7 +172,7 @@ $int = Text::parseFileSize('2GB'); The insert method is used to create string templates and to allow for key/value replacements: -``` php +```php Text::insert( 'My name is :name and I am :age years old.', ['name' => 'Bob', 'age' => '65'], @@ -192,7 +192,7 @@ unneeded markup around placeholders that did not get replaced by You can use the following options in the options array: -``` php +```php $options = [ 'clean' => [ 'method' => 'text', // or html @@ -211,7 +211,7 @@ $options = [ Wraps a block of text to a set width and indents blocks as well. Can intelligently wrap text so words are not sliced across lines: -``` php +```php $text = 'This is the song that never ends.'; $result = Text::wrap($text, 22); @@ -237,7 +237,7 @@ exceed a certain length even with internal indentation, you need to use `wrapBlock()` instead of `wrap()`. This is particularly useful to generate text for the console for example. It accepts the same options as `wrap()`: -``` php +```php $text = 'This is the song that never ends. This is the song that never ends.'; $result = Text::wrapBlock($text, [ 'width' => 22, @@ -272,7 +272,7 @@ Options: Example: -``` php +```php // Called as TextHelper echo $this->Text->highlight( $lastSentence, @@ -310,7 +310,7 @@ 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: -``` php +```php [ 'ellipsis' => '...', 'exact' => true, @@ -320,7 +320,7 @@ possible keys by default, all of which are optional: Example: -``` php +```php // Called as TextHelper echo $this->Text->truncate( 'The killer crept forward and tripped on the rug.', @@ -363,7 +363,7 @@ 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: -``` php +```php [ 'ellipsis' => '...', 'exact' => true, @@ -372,7 +372,7 @@ possible keys by default, all of which are optional: Example: -``` php +```php $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' @@ -414,7 +414,7 @@ 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. -``` php +```php // Called as TextHelper echo $this->Text->excerpt($lastParagraph, 'method', 50, '...'); @@ -437,7 +437,7 @@ Output: Creates a comma-separated list where the last two items are joined with 'and': -``` php +```php $colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']; // Called as TextHelper diff --git a/docs/en/core-libraries/time.md b/docs/en/core-libraries/time.md index 8598157bd8..ddfe0f13fb 100644 --- a/docs/en/core-libraries/time.md +++ b/docs/en/core-libraries/time.md @@ -10,7 +10,7 @@ description: "Manipulate dates and times in CakePHP: parse, format, compare, mod If you need `TimeHelper` functionalities outside of a `View`, use the `DateTime` class: -``` php +```php use Cake\I18n\DateTime; class UsersController extends AppController @@ -48,7 +48,7 @@ to data, and avoids order based dependency issues. There are a few ways to create `DateTime` instances: -``` php +```php use Cake\I18n\DateTime; // Create from a string datetime. @@ -76,7 +76,7 @@ as a UNIX timestamp. In test cases, you can mock out `now()` using `setTestNow()`: -``` php +```php // Fixate time. $time = new DateTime('2021-01-31 22:11:30'); DateTime::setTestNow($time); @@ -95,7 +95,7 @@ echo $now->i18nFormat('yyyy-MM-dd HH:mm:ss'); Remember, `DateTime` instance always return a new instance from setters instead of modifying itself: -``` php +```php $time = DateTime::now(); // Create and reassign a new instance @@ -108,14 +108,14 @@ echo $newTime->i18nFormat('yyyy-MM-dd HH:mm:ss'); You can also use the methods provided by PHP's built-in `DateTime` class: -``` php +```php $time = $time->setDate(2013, 10, 31); ``` Failing to reassign the new `DateTime` instances will result in the original, unmodified instance being used: -``` php +```php $time->year(2013) ->month(10) ->day(31); @@ -126,7 +126,7 @@ echo $time->i18nFormat('yyyy-MM-dd HH:mm:ss'); You can create another instance with modified dates, through subtraction and addition of their components: -``` php +```php $time = DateTime::create(2021, 1, 31, 22, 11, 30); $newTime = $time->subDays(5) ->addHours(-2) @@ -142,7 +142,7 @@ echo $newTime; You can get the internal components of a date by accessing its properties: -``` php +```php $time = DateTime::create(2021, 1, 31, 22, 11, 30); echo $time->year; // 2021 echo $time->month; // 1 @@ -158,7 +158,7 @@ echo $time->timezoneName; // America/New_York This method sets the default format used when converting an object to json: -``` php +```php DateTime::setJsonEncodeFormat('yyyy-MM-dd HH:mm:ss'); // For any immutable DateTime Date::setJsonEncodeFormat('yyyy-MM-dd HH:mm:ss'); // For any mutable Date @@ -189,7 +189,7 @@ The `callable` parameter type was added. A very common thing to do with `Time` instances is to print out formatted dates. CakePHP makes this a snap: -``` php +```php $time = DateTime::parse('2021-01-31 22:11:30'); // Prints a localized datetime stamp. Outputs '1/31/21, 10:11 PM' @@ -216,7 +216,7 @@ specified in the following resource: You can also format dates with non-gregorian calendars: -``` php +```php // On ICU version 66.1 $time = DateTime::create(2021, 1, 31, 22, 11, 30); @@ -256,7 +256,7 @@ The following calendar types are supported: Print out a predefined 'nice' format: -``` php +```php $time = DateTime::parse('2021-01-31 22:11:30', new \DateTimeZone('America/New_York')); // Outputs 'Jan 31, 2021, 10:11 PM' in en-US @@ -267,7 +267,7 @@ You can alter the timezone in which the date is displayed without altering the `DateTime` object itself. This is useful when you store dates in one timezone, but want to display them in a user's own timezone: -``` php +```php // Outputs 'Monday, February 1, 2021 at 4:11:30 AM Central European Standard Time' echo $time->i18nFormat(\IntlDateFormatter::FULL, 'Europe/Paris'); @@ -280,14 +280,14 @@ echo $time->timezoneName; Leaving the first parameter as `null` will use the default formatting string: -``` php +```php // Outputs '2/1/21, 4:11 AM' echo $time->i18nFormat(null, 'Europe/Paris'); ``` Finally, it is possible to use a different locale for displaying a date: -``` php +```php // Outputs 'lundi 1 février 2021 à 04:11:30 heure normale d’Europe centrale' echo $time->i18nFormat(\IntlDateFormatter::FULL, 'Europe/Paris', 'fr-FR'); @@ -302,7 +302,7 @@ The default locale in which dates are displayed when using `nice` [intl.default_locale](https://www.php.net/manual/en/intl.configuration.php#ini.intl.default-locale). You can, however, modify this default at runtime: -``` php +```php DateTime::setDefaultLocale('es-ES'); Date::setDefaultLocale('es-ES'); @@ -316,7 +316,7 @@ a different locale is specified directly in the formatting method. Likewise, it is possible to alter the default formatting string to be used for `i18nFormat`: -``` php +```php DateTime::setToStringFormat(\IntlDateFormatter::SHORT); // For any DateTime Date::setToStringFormat(\IntlDateFormatter::SHORT); // For any Date @@ -350,7 +350,7 @@ format string. Often it is useful to print times relative to the present: -``` php +```php $time = new DateTime('Jan 31, 2021'); // On June 12, 2021, this would output '4 months, 1 week, 6 days ago' echo $time->timeAgoInWords( @@ -362,7 +362,7 @@ The `end` option lets you define at which point after which relative times should be formatted using the `format` option. The `accuracy` option lets us control what level of detail should be used for each interval range: -``` php +```php // Outputs '4 months ago' echo $time->timeAgoInWords([ 'accuracy' => ['month' => 'month'], @@ -373,7 +373,7 @@ echo $time->timeAgoInWords([ By setting `accuracy` to a string, you can specify what is the maximum level of detail you want output: -``` php +```php $time = new DateTime('+23 hours'); // Outputs 'in about a day' echo $time->timeAgoInWords([ @@ -394,7 +394,7 @@ echo $time->timeAgoInWords([ Once created, you can convert `DateTime` instances into timestamps or quarter values: -``` php +```php $time = new DateTime('2021-01-31'); echo $time->toQuarter(); // Outputs '1' echo $time->toUnixString(); // Outputs '1612069200' @@ -406,7 +406,7 @@ The `toQuarterRange()` method was added. You can also get the date range for a quarter: -``` php +```php $time = new DateTime('2021-01-31'); $range = $time->toQuarterRange(); // Outputs ['2021-01-01', '2021-03-31'] @@ -436,7 +436,7 @@ $range = $time->toQuarterRange(); You can compare a `DateTime` instance with the present in a variety of ways: -``` php +```php $time = new DateTime('+3 days'); debug($time->isYesterday()); @@ -457,7 +457,7 @@ not the `DateTime` instance matches the present. You can see if a `DateTime` instance falls within a given range using `wasWithinLast()` and `isWithinNext()`: -``` php +```php $time = new DateTime('+3 days'); // Within 2 days. Outputs 'false' @@ -473,7 +473,7 @@ debug($time->isWithinNext('2 weeks')); You can also compare a `DateTime` instance within a range in the past: -``` php +```php $time = new DateTime('-72 hours'); // Within past 2 days. Outputs 'false' @@ -506,7 +506,7 @@ time and timezones. The `Date` class wraps the `Cake\Chronos\ChronosDate` class. Returns an integer timestamp for the date: -``` php +```php $date = new Date('2021-01-31'); echo $date->getTimestamp(); ``` @@ -525,7 +525,7 @@ CakePHP provides `DateTimePeriod` and `DatePeriod` classes that wrap PHP's `DatePeriod`. When iterating, `DateTimePeriod` returns `DateTime` instances and `DatePeriod` returns `Date` instances: -``` php +```php use Cake\I18n\DateTime; use Cake\I18n\DateTimePeriod; diff --git a/docs/en/core-libraries/validation.md b/docs/en/core-libraries/validation.md index 9ca0823a2b..2a7e343016 100644 --- a/docs/en/core-libraries/validation.md +++ b/docs/en/core-libraries/validation.md @@ -18,7 +18,7 @@ Validator objects contain a mapping between fields and validation sets. In turn, the validation sets contain a collection of rules that apply to the field they are attached to. Creating a validator is simple: -``` php +```php use Cake\Validation\Validator; $validator = new Validator(); @@ -27,7 +27,7 @@ $validator = new Validator(); Once created, you can start defining sets of rules for the fields you want to validate: -``` php +```php $validator ->requirePresence('title') ->notEmptyString('title', 'Please fill this field') @@ -72,13 +72,13 @@ By default, `true` is used. Key presence is checked by using `array_key_exists()` so that null values will count as present. You can set the mode using the second parameter: -``` php +```php $validator->requirePresence('author_id', 'create'); ``` If you have multiple fields that are required, you can define them as a list: -``` php +```php // Define multiple fields for create $validator->requirePresence(['author_id', 'title'], 'create'); @@ -130,7 +130,7 @@ when a field can or cannot be empty: An example of these methods in action is: -``` php +```php $validator->allowEmptyDateTime('published') ->allowEmptyString('title', 'Title cannot be empty', false) ->allowEmptyString('body', 'Body cannot be empty', 'update') @@ -144,7 +144,7 @@ The `Validator` class provides methods that make building validators simple and expressive. For example adding validation rules to a username could look like: -``` php +```php $validator = new Validator(); $validator ->email('username') @@ -162,7 +162,7 @@ full set of validator methods. In addition to using methods on the `Validator`, and coming from providers, you can also use any callable, including anonymous functions, as validation rules: -``` php +```php // Use a global function $validator->add('title', 'custom', [ 'rule' => 'validate_title', @@ -226,7 +226,7 @@ should be used as the error message. Possible existing error messages defined via the `message` option will be overwritten by the ones returned from the validation rule method: -``` php +```php $validator->add('length', 'custom', [ 'rule' => function (mixed $value, array $context) { if (!$value) { @@ -257,7 +257,7 @@ values will make the rule apply to only create or update operations. Additionally, you can provide a callable function that will determine whether or not a particular rule should be applied: -``` php +```php $validator->add('picture', 'file', [ 'rule' => ['mimeType', ['image/jpeg', 'image/png']], 'on' => function (array $context): bool { @@ -271,7 +271,7 @@ array. The above example will make the rule for 'picture' optional depending on whether the value for `show_profile_picture` is empty. You could also use the `uploadedFile` validation rule to create optional file upload inputs: -``` php +```php $validator->add('picture', 'file', [ 'rule' => ['uploadedFile', ['optional' => true]], ]); @@ -282,7 +282,7 @@ accept a callback function as their last argument. If present, the callback determines whether or not the rule should be applied. For example, a field is sometimes allowed to be empty: -``` php +```php $validator->allowEmptyString('tax', 'This field is required', function (array $context): bool { return !$context['data']['is_taxable']; }); @@ -291,7 +291,7 @@ $validator->allowEmptyString('tax', 'This field is required', function (array $c Likewise, a field can be required to be populated when certain conditions are met: -``` php +```php $validator->notEmptyString('email_frequency', 'This field is required', function (array $context): bool { return !empty($context['data']['wants_newsletter']); }); @@ -303,7 +303,7 @@ the user wants to receive the newsletter. Further it's also possible to require a field to be present under certain conditions only: -``` php +```php $validator->requirePresence('full_name', function (array $context): bool { if (isset($context['data']['action'])) { return $context['data']['action'] === 'subscribe'; @@ -334,7 +334,7 @@ previous one has failed. This allows you to collect as many validation errors as you can in a single pass. If you want to stop execution after a specific rule has failed, you can set the `last` option to `true`: -``` php +```php $validator = new Validator(); $validator ->add('body', [ @@ -358,7 +358,7 @@ run. You can have the `last` option automatically applied to each rule you can use the `setStopOnFailure()` method to enable this behavior: -``` php +```php public function validationDefault(Validator $validator): Validator { $validator @@ -387,7 +387,7 @@ rules. When using Validators and the ORM together, additional providers are configured for the table and entity objects. You can use the `setProvider()` method to add any additional providers your application needs: -``` php +```php $validator = new Validator(); // Use an object instance. @@ -401,7 +401,7 @@ Validation providers can be objects, or class names. If a class name is used the methods must be static. To use a provider other than 'default', be sure to set the `provider` key in your rule: -``` php +```php // Use a rule from the table provider $validator->add('title', 'custom', [ 'rule' => 'customTableMethod', @@ -412,7 +412,7 @@ $validator->add('title', 'custom', [ If you wish to add a `provider` to all `Validator` objects that are created in the future, you can use the `addDefaultProvider()` method as follows: -``` php +```php use Cake\Validation\Validator; // Use an object instance. @@ -431,7 +431,7 @@ You can use the [Localized plugin](https://github.com/cakephp/localized) to get providers based on countries. With this plugin, you'll be able to validate model fields, depending on a country, ie: -``` php +```php namespace App\Model\Table; use Cake\ORM\Table; @@ -460,7 +460,7 @@ validation, like en, fr, de. There are a few methods that are common to all classes, defined through the [ValidationInterface interface](https://github.com/cakephp/localized/blob/master/src/Validation/ValidationInterface.php): -``` text +```text phone() to check a phone number postal() to check a postal code personId() to check a country specific person ID @@ -474,7 +474,7 @@ nested data you have. CakePHP makes it simple to add validators to specific attributes. For example, assume you are working with a non-relational database and need to store an article and its comments: -``` php +```php $data = [ 'title' => 'Best article', 'comments' => [ @@ -485,7 +485,7 @@ $data = [ To validate the comments you would use a nested validator: -``` php +```php $validator = new Validator(); $validator->add('title', 'not-blank', ['rule' => 'notBlank']); @@ -505,7 +505,7 @@ contribute to the parent validator's errors and influence the final result. Like other validator features, nested validators support error messages and conditional application: -``` php +```php $validator->addNestedMany( 'comments', $commentValidator, @@ -524,7 +524,7 @@ While defining validators inline where they are used makes for good example code, it doesn't lead to maintainable applications. Instead, you should create `Validator` sub-classes for your reusable validation logic: -``` php +```php // In src/Model/Validation/ContactValidator.php namespace App\Model\Validation; @@ -547,7 +547,7 @@ start using it to validate data. Validators are able to validate array data. For example, if you wanted to validate a contact form before creating and sending an email you could do the following: -``` php +```php use Cake\Validation\Validator; $validator = new Validator(); @@ -571,7 +571,7 @@ if (!$errors) { The `getErrors()` method will return a non-empty array when there are validation failures. The returned array of errors will be structured like: -``` php +```php $errors = [ 'email' => ['E-mail must be valid'], ]; @@ -582,7 +582,7 @@ be returned per field. By default, the `getErrors()` method applies rules for the 'create' mode. If you'd like to apply 'update' rules you can do the following: -``` php +```php $errors = $validator->validate($this->request->getData(), false); if (!$errors) { // Send an email. @@ -605,7 +605,7 @@ interfaces used to populate the entities. The request data is validated automatically when using the `newEntity()`, `newEntities()`, `patchEntity()` or `patchEntities()` methods of `Table` class: -``` php +```php // In the ArticlesController class $article = $this->Articles->newEntity($this->request->getData()); if ($article->getErrors()) { @@ -616,7 +616,7 @@ if ($article->getErrors()) { Similarly, when you need to validate multiple entities at a time, you can use the `newEntities()` method: -``` php +```php // In the ArticlesController class $entities = $this->Articles->newEntities($this->request->getData()); foreach ($entities as $entity) { @@ -630,7 +630,7 @@ The `newEntity()`, `patchEntity()`, `newEntities()` and `patchEntities()` methods allow you to specify which associations are validated, and which validation sets to apply using the `options` parameter: -``` php +```php $valid = $this->Articles->newEntity($article, [ 'associated' => [ 'Comments' => [ @@ -660,7 +660,7 @@ Some of the validation methods accept additional parameters to define boundary conditions or valid options. You can provide these boundary conditions and options as follows: -``` php +```php $validator = new Validator(); $validator ->add('title', 'minLength', [ @@ -680,7 +680,7 @@ parameters as the remaining parameters. You can validate that a value is a valid IP address or an IP range (subnet) using the `ipOrRange()` rule: -``` php +```php $validator->add('ip_address', 'validRange', [ 'rule' => 'ipOrRange', 'message' => 'Please provide a valid IP or IP range.', diff --git a/docs/en/core-libraries/xml.md b/docs/en/core-libraries/xml.md index 050915f3e0..1e112e3fd8 100644 --- a/docs/en/core-libraries/xml.md +++ b/docs/en/core-libraries/xml.md @@ -22,7 +22,7 @@ or DOMDocument object. You can use `Xml::build()` to build XML objects from a variety of sources. For example, you can load XML from strings: -``` php +```php $text = ' 1 @@ -34,14 +34,14 @@ $xml = Xml::build($text); You can also build Xml objects from local files by overriding the default option: -``` php +```php // Local file $xml = Xml::build('/home/awesome/unicorns.xml', ['readFile' => true]); ``` You can also build Xml objects using an array: -``` php +```php $data = [ 'post' => [ 'id' => 1, @@ -54,7 +54,7 @@ $xml = Xml::build($data); If your input is invalid, the Xml class will throw an exception: -``` php +```php $xmlString = 'What is XML?'; try { $xmlObject = Xml::build($xmlString); // Here will throw an exception @@ -73,7 +73,7 @@ try { HTML documents can be parsed into `SimpleXmlElement` or `DOMDocument` objects with `loadHtml()`: -``` php +```php $html = Xml::loadHtml($htmlString, ['return' => 'domdocument']); ``` @@ -89,7 +89,7 @@ can be enabled with the `loadEntities` and `parseHuge` options respectively. Converting XML strings into arrays is simple with the Xml class as well. By default you'll get a SimpleXml object back: -``` php +```php $xmlString = 'value'; $xmlArray = Xml::toArray(Xml::build($xmlString)); ``` @@ -98,7 +98,7 @@ If your XML is invalid a `Cake\Utility\Exception\XmlException` will be raised. ## Transforming an Array into a String of XML -``` php +```php $xmlArray = ['root' => ['child' => 'value']]; // You can use Xml::build() too. $xmlObject = Xml::fromArray($xmlArray, ['format' => 'tags']); @@ -109,7 +109,7 @@ Your array must have only one element in the "top level" and it can not be numeric. If the array is not in this format, Xml will throw an exception. Examples of invalid arrays: -``` php +```php // Top level with numeric key [ ['key' => 'value'], @@ -126,7 +126,7 @@ By default, array values will be output as XML tags. If you want to define attributes or text values you can prefix the keys that are supposed to be attributes with `@`. For value text, use `@` as the key: -``` php +```php $xmlArray = [ 'project' => [ '@id' => 1, @@ -140,7 +140,7 @@ $xmlString = $xmlObject->asXML(); The content of `$xmlString` will be: -``` php +```php Value of projectName of project, as tag ``` @@ -151,7 +151,7 @@ To use XML Namespaces, create a key in your array with the name `xmlns:` in a generic namespace or input the prefix `xmlns:` in a custom namespace. See the samples: -``` php +```php $xmlArray = [ 'root' => [ 'xmlns:' => 'https://cakephp.org', @@ -176,7 +176,7 @@ $xml2 = Xml::fromArray($xmlArray); The value of `$xml1` and `$xml2` will be, respectively: -``` php +```php value @@ -189,7 +189,7 @@ The value of `$xml1` and `$xml2` will be, respectively: After you have created your XML document, you just use the native interfaces for your document type to add, remove, or manipulate child nodes: -``` php +```php // Using SimpleXML $myXmlOriginal = 'value'; $xml = Xml::build($myXmlOriginal); diff --git a/docs/en/deployment.md b/docs/en/deployment.md index 19e3b4a84e..c2aff09f7a 100644 --- a/docs/en/deployment.md +++ b/docs/en/deployment.md @@ -51,7 +51,7 @@ For example, you can set an environment variable in your Apache configuration: And then you can set the debug level dynamically in **app_local.php**: -``` php +```php $debug = (bool)getenv('CAKEPHP_DEBUG'); return [ @@ -124,7 +124,7 @@ CakePHP uses `assert()` internally to provide runtime type checking and provide better error messages during development. You can have PHP skip these assertions by updating your `php.ini` to include: -``` ini +```ini ; Turn off assert() code generation. zend.assertions = -1 ``` diff --git a/docs/en/development/application.md b/docs/en/development/application.md index ebda15ce17..1b65cbebd4 100644 --- a/docs/en/development/application.md +++ b/docs/en/development/application.md @@ -52,7 +52,7 @@ configure low-level concerns of your application, you can also use the `Application::bootstrap()` hook method to load/initialize plugins, and attach global event listeners: -``` php +```php // in src/Application.php namespace App; diff --git a/docs/en/development/configuration.md b/docs/en/development/configuration.md index 3d63c5bbef..41368515db 100644 --- a/docs/en/development/configuration.md +++ b/docs/en/development/configuration.md @@ -34,7 +34,7 @@ If your application has many configuration options it can be helpful to split configuration into multiple files. After creating each of the files in your **config/** directory you can load them in **bootstrap.php**: -``` php +```php use Cake\Core\Configure; use Cake\Core\Configure\Engine\PhpConfig; @@ -74,7 +74,7 @@ should go in each one. Once your environment variables have been set, you can use `env()` to read data from the environment: -``` php +```php $debug = env('APP_DEBUG', false); ``` @@ -236,7 +236,7 @@ Additional class paths are setup through the autoloaders your application uses. When using `composer` to generate your autoloader, you could do the following, to provide fallback paths for controllers in your application: -``` json +```json "autoload": { "psr-4": { "App\\Controller\\": "/path/to/directory/with/controller/folders/", @@ -250,7 +250,7 @@ namespace. The first key will be searched, and if that path does not contain the class/file the second key will be searched. You can also map a single namespace to multiple directories with the following: -``` json +```json "autoload": { "psr-4": { "App\\": ["src/", "/path/to/directory/"] @@ -264,7 +264,7 @@ Since plugins, view templates and locales are not classes, they cannot have an autoloader configured. CakePHP provides three Configure variables to setup additional paths for these resources. In your **config/app.php** you can set these variables: -``` php +```php return [ // More configuration 'App' => [ @@ -310,7 +310,7 @@ won't end up breaking the MVC structure CakePHP provides. Use `write()` to store data in the application's configuration: -``` php +```php Configure::write('Company.name', 'Pizza, Inc.'); Configure::write('Company.slogan', 'Pizza for your body and soul'); ``` @@ -321,7 +321,7 @@ Configure::write('Company.slogan', 'Pizza for your body and soul'); The above example could also be written in a single call: -``` php +```php Configure::write('Company', [ 'name' => 'Pizza, Inc.', 'slogan' => 'Pizza for your body and soul', @@ -343,7 +343,7 @@ Used to read configuration data from the application. If a key is supplied, the data is returned. Using our examples from write() above, we can read that data back: -``` php +```php // Returns 'Pizza Inc.' Configure::read('Company.name'); @@ -366,7 +366,7 @@ Reads configuration data just like `Cake\Core\Configure::read()` but expects to find a key/value pair. In case the requested pair does not exist, a `RuntimeException` will be thrown: -``` php +```php Configure::readOrFail('Company.name'); // Yields: 'Pizza, Inc.' Configure::readOrFail('Company.geolocation'); // Will throw an exception @@ -382,7 +382,7 @@ Configure::readOrFail('Company'); Used to check if a key/path exists and has non-null value: -``` php +```php $exists = Configure::check('Company.name'); ``` @@ -392,7 +392,7 @@ $exists = Configure::check('Company.name'); Used to delete information from the application's configuration: -``` php +```php Configure::delete('Company.name'); ``` @@ -409,7 +409,7 @@ Consumes configuration data just like `Cake\Core\Configure::consume()` but expects to find a key/value pair. In case the requested pair does not exist, a `RuntimeException` will be thrown: -``` php +```php Configure::consumeOrFail('Company.name'); // Yields: 'Pizza, Inc.' Configure::consumeOrFail('Company.geolocation'); // Will throw an exception @@ -431,7 +431,7 @@ files. See the [PHP documentation](https://php.net/parse_ini_file) for more information on the specifics of ini files. To use a core config engine, you'll need to attach it to Configure using `Configure::config()`: -``` php +```php use Cake\Core\Configure\Engine\PhpConfig; // Read config files from config @@ -446,7 +446,7 @@ kinds or sources of configuration files. You can interact with attached engines using a few other methods on Configure. To check which engine aliases are attached you can use `Configure::configured()`: -``` php +```php // Get the array of aliases for attached engines. Configure::configured(); @@ -460,7 +460,7 @@ You can also remove attached engines. `Configure::drop('default')` would remove the default engine alias. Any future attempts to load configuration files with that engine would fail: -``` php +```php Configure::drop('default'); ``` @@ -471,7 +471,7 @@ Configure::drop('default'); Once you've attached a config engine to Configure you can load configuration files: -``` php +```php // Load my_file.php using the 'default' engine object. Configure::load('my_file', 'default'); ``` @@ -519,13 +519,13 @@ a PHP configuration file loadable by the Given that the 'default' engine is an instance of PhpConfig. Save all data in Configure to the file `my_config.php`: -``` php +```php Configure::dump('my_config', 'default'); ``` Save only the error handling configuration: -``` php +```php Configure::dump('error', 'default', ['Error', 'Exception']); ``` @@ -541,7 +541,7 @@ Since configure only remembers values for the current request, you will need to store any modified configuration information if you want to use it in subsequent requests: -``` php +```php // Store the current configuration in the 'user_1234' key in the 'default' cache. Configure::store('user_1234', 'default'); ``` @@ -556,7 +556,7 @@ Stored configuration data is persisted in the named cache configuration. See the Once you've stored runtime configuration, you'll probably need to restore it so you can access it again. `Configure::restore()` does exactly that: -``` php +```php // Restore runtime configuration from the cache. Configure::restore('user_1234', 'default'); ``` diff --git a/docs/en/development/debugging.md b/docs/en/development/debugging.md index 736a2d5614..2209f9b8d8 100644 --- a/docs/en/development/debugging.md +++ b/docs/en/development/debugging.md @@ -39,7 +39,7 @@ If you have [Psysh](https://psysh.org/) installed you can use this function in CLI environments to open an interactive console with the current local scope: -``` php +```php // Some code eval(breakpoint()); ``` @@ -79,7 +79,7 @@ The `Debugger.editorBasePath` configure option was added. Dump prints out the contents of a variable. It will print out all properties and methods (if any) of the supplied variable: -``` php +```php $foo = [1,2,3]; Debugger::dump($foo); @@ -111,7 +111,7 @@ When dumping data with `Debugger` or rendering error pages, you may want to hide sensitive keys like passwords or API keys. In your **config/bootstrap.php** you can mask specific keys: -``` php +```php Debugger::setOutputMask([ 'password' => 'xxxxx', 'awsKey' => 'yyyyy', @@ -139,7 +139,7 @@ Returns the current stack trace. Each line of the trace includes the calling method, including which file and line the call originated from: -``` php +```php // In PostsController::index() pr(Debugger::trace()); @@ -162,7 +162,7 @@ Grab an excerpt from the file at `$path` (which is an absolute filepath), highlights line number `$line` with `$context` number of lines around it. -``` php +```php pr(Debugger::excerpt(ROOT . DS . LIBS . 'debugger.php', 321, 2)); // Will output the following. @@ -191,7 +191,7 @@ Exception and error pages can contain URLs that directly open in your editor or IDE. CakePHP ships with URL formats for several popular editors, and you can add additional editor formats if required during application bootstrap: -``` php +```php // Generate links for vscode. Debugger::setEditor('vscode'); @@ -213,7 +213,7 @@ Logging messages is another good way to debug applications, and you can use use `LogTrait` have an instance method `log()` which can be used to log messages: -``` php +```php $this->log('Got here', 'debug'); ``` @@ -222,7 +222,7 @@ to help debug methods that involve redirects or complicated loops. You can also use `Cake\Log\Log::write()` to write log messages. This method can be called statically anywhere in your application one Log has been loaded: -``` php +```php // At the top of the file you want to log in. use Cake\Log\Log; diff --git a/docs/en/development/dependency-injection.md b/docs/en/development/dependency-injection.md index cccda1d1c4..0de78be3f6 100644 --- a/docs/en/development/dependency-injection.md +++ b/docs/en/development/dependency-injection.md @@ -397,7 +397,7 @@ public function services(ContainerInterface $container): void ## Controller Example -``` php +```php // In src/Controller/UsersController.php class UsersController extends AppController { @@ -427,7 +427,7 @@ testing. ## Command Example -``` php +```php // In src/Command/CheckUsersCommand.php use Cake\Console\CommandFactoryInterface; @@ -464,7 +464,7 @@ of the command. ## Component Example -``` php +```php // In src/Controller/Component/SearchComponent.php class SearchComponent extends Component { @@ -501,7 +501,7 @@ In order to have services created by the container, you need to tell it which classes it can create and how to build those classes. The simplest definition is via a class name: -``` php +```php // Add a class by its name. $container->add(BillingService::class); ``` @@ -509,7 +509,7 @@ $container->add(BillingService::class); Your application and plugins define the services they have in the `services()` hook method: -``` php +```php // in src/Application.php namespace App; @@ -528,7 +528,7 @@ class Application extends BaseApplication You can define implementations for interfaces that your application uses: -``` php +```php use App\Service\AuditLogServiceInterface; use App\Service\AuditLogService; @@ -540,7 +540,7 @@ $container->add(AuditLogServiceInterface::class, AuditLogService::class); The container can leverage factory functions to create objects if necessary: -``` php +```php $container->add(AuditLogServiceInterface::class, function (...$args) { return new AuditLogService(...$args); }); @@ -552,7 +552,7 @@ as arguments. Once you've defined a class, you also need to define the dependencies it requires. Those dependencies can be either objects or primitive values: -``` php +```php // Add a primitive value like a string, array or number. $container->add('apiKey', 'abc123'); @@ -572,7 +572,7 @@ By default, services are not shared. Every object (and dependencies) is created each time it is fetched from the container. If you want to re-use a single instance, often referred to as a singleton, you can mark a service as 'shared': -``` php +```php // in your Application::services() method. $container->addShared(BillingService::class); @@ -583,7 +583,7 @@ $container->addShared(BillingService::class); If you want to have ORM Tables injected as a dependency to a service, you can add `TableContainer` to your application's service container: -``` php +```php use Cake\ORM\Locator\TableContainer; // In your Application::services() method. @@ -601,7 +601,7 @@ Once a service is defined you can modify or update the service definition by extending them. This allows you to add additional arguments to services defined elsewhere: -``` php +```php // Add an argument to a partially defined service elsewhere. $container->extend(BillingService::class) ->addArgument('logLevel'); @@ -613,7 +613,7 @@ By tagging services you can get all of those services resolved at the same time. This can be used to build services that combine collections of other services like in a reporting system: -``` php +```php $container->add(BillingReport::class)->addTag('reports'); $container->add(UsageReport::class)->addTag('reports'); @@ -630,7 +630,7 @@ Often you'll need configuration data in your services. If you need a specific va you can inject it as a constructor argument using the `Cake\Core\Attribute\Configure` attribute: -``` php +```php use Cake\Core\Attribute\Configure; class InjectedService @@ -647,7 +647,7 @@ class InjectedService If you want to inject a copy of all configuration data, CakePHP includes an injectable configuration reader: -``` php +```php use Cake\Core\ServiceConfig; // Use a shared instance @@ -669,7 +669,7 @@ their first use. An example ServiceProvider would look like: -``` php +```php namespace App\ServiceProvider; use Cake\Core\ContainerInterface; @@ -701,7 +701,7 @@ in it not be loadable from the container. To load a service provider add it into the container using the `addServiceProvider()` method: -``` php +```php // in your Application::services() method. $container->addServiceProvider(new BillingServiceProvider()); ``` @@ -714,7 +714,7 @@ service provider needs to load additional configuration files, load additional service providers or modify a service defined elsewhere in your application. An example of a bootable service would be: -``` php +```php namespace App\ServiceProvider; use Cake\Core\ServiceProvider; @@ -1234,7 +1234,7 @@ class ArticlesController extends AppController Auto Wiring is turned off by default. To enable it: -``` php +```php // In src/Application.php use League\Container\ReflectionContainer; @@ -1250,7 +1250,7 @@ While your dependencies will now be resolved automatically, this approach will not cache resolutions which can be detrimental to performance. To enable caching: -``` php +```php use League\Container\ReflectionContainer; $container->delegate( diff --git a/docs/en/development/errors.md b/docs/en/development/errors.md index 5bb912796c..8b0b4974b1 100644 --- a/docs/en/development/errors.md +++ b/docs/en/development/errors.md @@ -62,7 +62,7 @@ deprecated. We also recommend this system for use in your plugins and application code when useful. You can trigger deprecation warnings with `deprecationWarning()`: -``` php +```php deprecationWarning('5.0', 'The example() method is deprecated. Use getExample() instead.'); ``` @@ -75,7 +75,7 @@ You can temporarily disable deprecation warnings in one of a few ways: 2. Using the `Error.ignoredDeprecationPaths` configuration option to ignore deprecations with glob compatible expressions. For example: - ``` php + ```php 'Error' => [ 'ignoredDeprecationPaths' => [ 'vendors/company/contacts/*', @@ -113,7 +113,7 @@ when they handle errors. You can listen to the `Error.beforeRender` event to be notified of PHP errors. The `Exception.beforeRender` event is dispatched when an exception is handled: -``` php +```php $errorTrap = new ErrorTrap(Configure::read('Error')); $errorTrap->getEventManager()->on( 'Error.beforeRender', @@ -166,7 +166,7 @@ data returned by `getAttributes()` will be exposed as view variables as well. By default, error templates use **templates/layout/error.php** for a layout. You can use the `layout` property to pick a different layout: -``` php +```php // inside templates/Error/error400.php $this->layout = 'my_error'; ``` @@ -189,7 +189,7 @@ If your application uses [Prefix Routing](../development/routing#prefix-routing) controllers for each routing prefix. For example, if you had an `Admin` prefix. You could create the following class: -``` php +```php namespace App\Controller\Admin; use App\Controller\AppController; @@ -220,7 +220,7 @@ application errors. For example a `MissingWidgetException` would be handled by a `missingWidget()` controller method, and CakePHP would use `templates/Error/missing_widget.php` as the template. For example: -``` php +```php namespace App\Controller\Admin; use App\Controller\AppController; @@ -252,7 +252,7 @@ assume our application uses `App\Exception\MissingWidgetException` to indicate a missing widget. We could create an exception renderer that renders specific error pages when this error is handled: -``` php +```php // In src/Error/AppExceptionRenderer.php namespace App\Error; @@ -284,7 +284,7 @@ Exception rendering methods receive the handled exception as an argument, and should return a `Response` object. You can also implement methods to add additional logic when handling CakePHP errors: -``` php +```php // In src/Error/AppExceptionRenderer.php namespace App\Error; @@ -305,7 +305,7 @@ The exception renderer dictates which controller is used for exception rendering. If you want to change which controller is used to render exceptions, override the `_getController()` method in your exception renderer: -``` php +```php // in src/Error/AppExceptionRenderer namespace App\Error; @@ -336,7 +336,7 @@ exceptions](https://php.net/manual/en/spl.exceptions.php), `Exception` itself, or `Cake\Core\Exception\Exception`. If your application contained the following exception: -``` php +```php use Cake\Core\Exception\CakeException; class MissingWidgetException extends CakeException @@ -357,7 +357,7 @@ pass in additional data. This additional data is interpolated into the `_messageTemplate`. This allows you to create data rich exceptions, that provide more context around your errors: -``` php +```php use Cake\Core\Exception\CakeException; class MissingWidgetException extends CakeException @@ -444,7 +444,7 @@ You can throw these exceptions from your controllers to indicate failure states, or HTTP errors. An example use of the HTTP exceptions could be rendering 404 pages for items that have not been found: -``` php +```php use Cake\Http\Exception\NotFoundException; public function view($id = null) @@ -466,7 +466,7 @@ RESTful responses to client applications and users. You can throw any of the HTTP related exceptions from your controller actions to indicate failure states. For example: -``` php +```php use Cake\Http\Exception\NotFoundException; public function view($id = null) @@ -581,7 +581,7 @@ log messages and log them to the appropriate place. You can replace the error logger using the `Error.logger` configure value. An example error logger: -``` php +```php namespace App\Error; use Cake\Error\ErrorLoggerInterface; @@ -623,7 +623,7 @@ CakePHP includes error renderers for both web and console environments. If however, you would like to replace the logic that renders errors you can create a class: -``` php +```php // src/Error/CustomErrorRenderer.php namespace App\Error; diff --git a/docs/en/development/rest.md b/docs/en/development/rest.md index 7557509cc9..4ffe3413d0 100644 --- a/docs/en/development/rest.md +++ b/docs/en/development/rest.md @@ -21,7 +21,7 @@ To get started with adding a REST API to your application, we'll first need a controller containing actions that we want to expose as an API. A basic controller might look something like this: -``` php +```php // src/Controller/RecipesController.php use Cake\View\JsonView; @@ -99,7 +99,7 @@ the `serialize` option to tell CakePHP which view variables should be serialized when making API responses. We'll connect our controller to the application URLs with [Resource Routes](../development/routing#resource-routes): -``` php +```php // in config/routes.php $routes->scope('/', function (RouteBuilder $routes): void { $routes->setExtensions(['json']); @@ -139,7 +139,7 @@ contained the JSON representation. In our `Application` class ensure the following is present: -``` php +```php $middlewareQueue->add(new BodyParserMiddleware()); ``` diff --git a/docs/en/development/routing.md b/docs/en/development/routing.md index 78bc126c00..208cdf46a9 100644 --- a/docs/en/development/routing.md +++ b/docs/en/development/routing.md @@ -22,7 +22,7 @@ This section will teach you by example the most common uses of the CakePHP Router. Typically you want to display something as a landing page, so you add this to your **config/routes.php** file: -``` php +```php /** @var \Cake\Routing\RouteBuilder $routes */ $routes->connect('/', ['controller' => 'Articles', 'action' => 'index']); ``` @@ -32,7 +32,7 @@ homepage of your site is visited. Sometimes you need dynamic routes that will accept multiple parameters, this would be the case, for example of a route for viewing an article's content: -``` php +```php $routes->connect('/articles/*', ['controller' => 'Articles', 'action' => 'view']); ``` @@ -41,7 +41,7 @@ method `view(15)` in the `ArticlesController`. This will not, though, prevent people from trying to access URLs looking like `/articles/foobar`. If you wish, you can restrict some parameters to conform to a regular expression: -``` php +```php // Using fluent interface $routes->connect( '/articles/{id}', @@ -68,7 +68,7 @@ option later. The CakePHP Router can also reverse match routes. That means that from an array containing matching parameters, it is capable of generating a URL string: -``` php +```php use Cake\Routing\Router; echo Router::url(['controller' => 'Articles', 'action' => 'view', 'id' => 15]); @@ -80,7 +80,7 @@ Routes can also be labelled with a unique name, this allows you to quickly reference them when building links instead of specifying each of the routing parameters: -``` php +```php // In routes.php $routes->connect( '/upgrade', @@ -100,7 +100,7 @@ A scope defines a common path segment, and optionally route defaults. Any routes connected inside a scope will inherit the path/defaults from their wrapping scopes: -``` php +```php $routes->scope('/blog', ['plugin' => 'Blog'], function (RouteBuilder $routes) { $routes->connect('/', ['controller' => 'Articles']); }); @@ -123,7 +123,7 @@ scopes not only let you keep your code DRY, they also help Router optimize its operation. This method defaults to the `/` scope. To create a scope and connect some routes we'll use the `scope()` method: -``` php +```php // In config/routes.php use Cake\Routing\RouteBuilder; use Cake\Routing\Route\DashedRoute; @@ -141,7 +141,7 @@ match elements in the URL. The basic format for a route definition is: -``` php +```php $routes->connect( '/url/template', ['targetKey' => 'targetValue'], @@ -153,14 +153,14 @@ The first parameter is used to tell the router what sort of URL you're trying to control. The URL is a normal slash delimited string, but can also contain a wildcard (*) or [Route Elements](#route-elements). Using a wildcard tells the router that you are willing to accept any additional arguments supplied. Routes without -a * only match the exact template pattern supplied. +a `*` only match the exact template pattern supplied. Once you've specified a URL, you use the last two parameters of `connect()` to tell CakePHP what to do with a request once it has been matched. The second parameter defines the route 'target'. This can be defined either as an array, or as a destination string. A few examples of route targets are: -``` php +```php // Array target to an application controller $routes->connect( '/users/view/*', @@ -185,13 +185,13 @@ The above example also illustrates string targets. String targets provide a compact way to define a route's destination. String targets have the following syntax: -``` text +```text [Plugin].[Prefix]/[Controller]::[action] ``` Some example string targets are: -``` text +```text // Application controller 'Articles::view' @@ -210,7 +210,7 @@ there is also the trailing star (`/**`). Using a trailing double star, will capture the remainder of a URL as a single passed argument. This is useful when you want to use an argument that included a `/` in it: -``` php +```php $routes->connect( '/pages/**', ['controller' => 'Pages', 'action' => 'show'] @@ -223,7 +223,7 @@ passed argument of `the-example-/-and-proof`. The second parameter of `connect()` can define any parameters that compose the default route parameters: -``` php +```php $routes->connect( '/government', ['controller' => 'Pages', 'action' => 'display', 5], @@ -240,7 +240,7 @@ accessing our users controller at `/users/some-action/5`, we'd like to be able to access it through `/cooks/some-action/5`. The following route takes care of that: -``` php +```php $routes->connect( '/cooks/{action}/*', ['controller' => 'Users'] ); @@ -264,7 +264,7 @@ a REST API you'll often want to map HTTP actions to different controller methods The `RouteBuilder` provides helper methods that make defining routes for specific HTTP verbs simpler: -``` php +```php // Create a route that only responds to GET requests. $routes->get( '/cooks/{id}', @@ -306,7 +306,7 @@ expression - this tells CakePHP how to know if the URL is correctly formed or not. If you choose to not provide a regular expression, any non `/` character will be treated as part of the parameter: -``` php +```php $routes->connect( '/{controller}/{id}', ['action' => 'view'], @@ -332,7 +332,7 @@ CakePHP does not automatically produce lowercased and dashed URLs when using the `{controller}` parameter. If you need this, the above example could be rewritten like so: -``` php +```php use Cake\Routing\Route\DashedRoute; // Create a builder with a different route class. @@ -366,14 +366,14 @@ controller. For example, to map all URLs to actions of the `home` controller, e.g have URLs like `/demo` instead of `/home/demo`, you can do the following: -``` php +```php $routes->connect('/{action}', ['controller' => 'Home']); ``` If you would like to provide a case insensitive URL, you can use regular expression inline modifiers: -``` php +```php $routes->connect( '/{userShortcut}', ['controller' => 'Teachers', 'action' => 'profile', 1], @@ -382,7 +382,7 @@ $routes->connect( One more example, and you'll be a routing pro: -``` php +```php $routes->connect( '/{controller}/{year}/{month}/{day}', ['action' => 'index'], @@ -446,7 +446,7 @@ connecting a route you can use its fluent builder methods to further configure the route. These methods replace many of the keys in the `$options` parameter of `connect()`: -``` php +```php $routes->connect( '/{lang}/articles/{slug}', ['controller' => 'Articles', 'action' => 'view'], @@ -480,7 +480,7 @@ using the `setOptions()` method. This is useful when you want to apply the same options (like `_host`, `_https`, or `_port`) to multiple routes without repeating them: -``` php +```php $routes->scope('/api', function (RouteBuilder $routes) { // Set default options for all routes in this scope $routes->setOptions([ @@ -502,7 +502,7 @@ Options set via `setOptions()` are: Example with nested scopes and overrides: -``` php +```php $routes->scope('/api', function (RouteBuilder $routes) { $routes->setOptions(['_host' => 'api.example.com']); @@ -537,7 +537,7 @@ elements be passed arguments instead. The `pass` option indicates which route elements should also be made available as arguments passed into the controller functions: -``` php +```php // src/Controller/BlogsController.php public function view($articleId = null, $slug = null) { @@ -566,7 +566,7 @@ $routes->scope('/', function (RouteBuilder $routes) { Now thanks to the reverse routing capabilities, you can pass in the URL array like below and CakePHP will know how to form the URL as defined in the routes: -``` php +```php // view.php // This will return a link to /blog/3-CakePHP_Rocks echo $this->Html->link('CakePHP Rocks', [ @@ -592,7 +592,7 @@ echo $this->Html->link('CakePHP Rocks', [ We talked about string targets above. The same also works for URL generation using `Router::pathUrl()`: -``` php +```php echo Router::pathUrl('Articles::index'); // outputs: /articles @@ -612,7 +612,7 @@ or you'd like to take advantage of the performance improvements that named routes have. When connecting routes you can specify a `_name` option, this option can be used in reverse routing to identify the route you want to use: -``` php +```php // Connect a route with a name. $routes->connect( '/login', @@ -647,7 +647,7 @@ When building named routes, you will probably want to stick to some conventions for the route names. CakePHP makes building up route names easier by allowing you to define name prefixes in each scope: -``` php +```php $routes->scope('/api', ['_namePrefix' => 'api:'], function (RouteBuilder $routes) { // This route's name will be `api:ping` $routes->get('/ping', ['controller' => 'Pings'], 'ping'); @@ -669,7 +669,7 @@ $routes->prefix('Admin', ['_namePrefix' => 'admin:'], function (RouteBuilder $ro You can also use the `_namePrefix` option inside nested scopes and it works as you'd expect: -``` php +```php $routes->plugin('Contacts', ['_namePrefix' => 'contacts:'], function (RouteBuilder $routes) { $routes->scope('/api', ['_namePrefix' => 'api:'], function (RouteBuilder $routes) { // This route's name will be `contacts:api:ping` @@ -693,7 +693,7 @@ privileged users can make changes. This is often done through a special URL such as `/admin/users/edit/5`. In CakePHP, prefix routing can be enabled by using the `prefix` scope method: -``` php +```php use Cake\Routing\Route\DashedRoute; $routes->prefix('Admin', function (RouteBuilder $routes) { @@ -716,7 +716,7 @@ The view file used would be **templates/Admin/Users/edit.php** You can map the URL /admin to your `index()` action of pages controller using following route: -``` php +```php $routes->prefix('Admin', function (RouteBuilder $routes) { // Because you are in the admin scope, // you do not need to include the /admin prefix @@ -728,7 +728,7 @@ $routes->prefix('Admin', function (RouteBuilder $routes) { When creating prefix routes, you can set additional route parameters using the `$options` argument: -``` php +```php $routes->prefix('Admin', ['param' => 'value'], function (RouteBuilder $routes) { // Routes connected here are prefixed with '/admin' and // have the 'param' routing key set. @@ -744,7 +744,7 @@ Multi word prefixes are by default converted using dasherize inflection, ie `MyP would be mapped to `my-prefix` in the URL. Make sure to set a path for such prefixes if you want to use a different format like for example underscoring: -``` php +```php $routes->prefix('MyPrefix', ['path' => '/my_prefix'], function (RouteBuilder $routes) { // Routes connected here are prefixed with '/my_prefix' $routes->connect('/{controller}'); @@ -753,7 +753,7 @@ $routes->prefix('MyPrefix', ['path' => '/my_prefix'], function (RouteBuilder $ro You can define prefixes inside plugin scopes as well: -``` php +```php $routes->plugin('DebugKit', function (RouteBuilder $routes) { $routes->prefix('Admin', function (RouteBuilder $routes) { $routes->connect('/{controller}'); @@ -766,7 +766,7 @@ The connected route would have the `plugin` and `prefix` route elements set. When defining prefixes, you can nest multiple prefixes if necessary: -``` php +```php $routes->prefix('Manager', function (RouteBuilder $routes) { $routes->prefix('Admin', function (RouteBuilder $routes) { $routes->connect('/{controller}/{action}'); @@ -785,7 +785,7 @@ When using prefix routes it's important to set the `prefix` option, and to use the same CamelCased format that is used in the `prefix()` method. Here's how to build this link using the HTML helper: -``` php +```php // Go into a prefixed route. echo $this->Html->link( 'Manage articles', @@ -804,7 +804,7 @@ echo $this->Html->link( You can create links that point to a prefix, by adding the prefix key to your URL array: -``` php +```php echo $this->Html->link( 'New admin todo', ['prefix' => 'Admin', 'controller' => 'TodoItems', 'action' => 'create'], @@ -813,7 +813,7 @@ echo $this->Html->link( When using nesting, you need to chain them together: -``` php +```php echo $this->Html->link( 'New todo', ['prefix' => 'Admin/MyPrefix', 'controller' => 'TodoItems', 'action' => 'create'], @@ -834,7 +834,7 @@ This would link to a controller with the namespace `App\Controller\Admin\MyPrefi Routes for [Plugins](../plugins) should be created using the `plugin()` method. This method creates a new routing scope for the plugin's routes: -``` php +```php $routes->plugin('DebugKit', function (RouteBuilder $routes) { // Routes connected here are prefixed with '/debug-kit' and // have the plugin route element set to 'DebugKit'. @@ -845,7 +845,7 @@ $routes->plugin('DebugKit', function (RouteBuilder $routes) { When creating plugin scopes, you can customize the path element used with the `path` option: -``` php +```php $routes->plugin('DebugKit', ['path' => '/debugger'], function (RouteBuilder $routes) { // Routes connected here are prefixed with '/debugger' and // have the plugin route element set to 'DebugKit'. @@ -855,7 +855,7 @@ $routes->plugin('DebugKit', ['path' => '/debugger'], function (RouteBuilder $rou When using scopes you can nest plugin scopes within prefix scopes: -``` php +```php $routes->prefix('Admin', function (RouteBuilder $routes) { $routes->plugin('DebugKit', function (RouteBuilder $routes) { $routes->connect('/{controller}'); @@ -872,7 +872,7 @@ It would have the `prefix`, and `plugin` route elements set. The You can create links that point to a plugin, by adding the plugin key to your URL array: -``` php +```php echo $this->Html->link( 'New todo', ['plugin' => 'Todo', 'controller' => 'TodoItems', 'action' => 'create'], @@ -882,7 +882,7 @@ echo $this->Html->link( Conversely if the active request is a plugin request and you want to create a link that has no plugin you can do the following: -``` php +```php echo $this->Html->link( 'New todo', ['plugin' => null, 'controller' => 'Users', 'action' => 'profile'], @@ -903,7 +903,7 @@ For example, if we had a `ToDo` plugin, with a `TodoItems` controller, and a `showItems()` action, it could be accessed at `/to-do/todo-items/show-items` with the following router connection: -``` php +```php use Cake\Routing\Route\DashedRoute; $routes->plugin('ToDo', ['path' => 'to-do'], function (RouteBuilder $routes) { @@ -915,7 +915,7 @@ $routes->plugin('ToDo', ['path' => 'to-do'], function (RouteBuilder $routes) { Routes can match specific HTTP methods using the HTTP verb helper methods: -``` php +```php $routes->scope('/', function (RouteBuilder $routes) { // This route only matches on POST requests. $routes->post( @@ -939,7 +939,7 @@ parameter is a routing key, it participates in both URL parsing and URL generation. To generate URLs for method specific routes you'll need to include the `_method` key when generating the URL: -``` php +```php $url = Router::url([ 'controller' => 'Reviews', 'action' => 'start', @@ -952,7 +952,7 @@ $url = Router::url([ Routes can use the `_host` option to only match specific hosts. You can use the `*.` wildcard to match any subdomain: -``` php +```php $routes->scope('/', function (RouteBuilder $routes) { // This route only matches on http://images.example.com $routes->connect( @@ -973,7 +973,7 @@ specifies an exact domain, that domain will be included in the generated URL. However, if you use a wildcard, then you will need to provide the `_host` parameter when generating URLs: -``` php +```php // If you have this route $routes->connect( '/images/old-logo.png', @@ -997,7 +997,7 @@ echo Router::url([ To handle different file extensions in your URLs, you can define the extensions using the `Cake\Routing\RouteBuilder::setExtensions()` method: -``` php +```php $routes->scope('/', function (RouteBuilder $routes) { $routes->setExtensions(['json', 'xml']); }); @@ -1019,7 +1019,7 @@ By using extensions, you tell the router to remove any matching file extensions from the URL, and then parse what remains. If you want to create a URL such as /page/title-of-page.html you would create your route using: -``` php +```php $routes->scope('/page', function (RouteBuilder $routes) { $routes->setExtensions(['json', 'xml', 'html']); $routes->connect( @@ -1031,7 +1031,7 @@ $routes->scope('/page', function (RouteBuilder $routes) { Then to create links which map back to the routes simply use: -``` php +```php $this->Html->link( 'Link title', ['controller' => 'Pages', 'action' => 'view', 'title' => 'super-article', '_ext' => 'html'], @@ -1052,7 +1052,7 @@ how/where it is being applied. Before middleware can be applied to a scope, it needs to be registered into the route collection: -``` php +```php // in config/routes.php use Cake\Http\Middleware\CsrfProtectionMiddleware; use Cake\Http\Middleware\EncryptedCookieMiddleware; @@ -1064,7 +1064,7 @@ $routes->registerMiddleware('cookies', new EncryptedCookieMiddleware()); Once registered, scoped middleware can be applied to specific scopes: -``` php +```php $routes->scope('/cms', function (RouteBuilder $routes) { // Enable CSRF & cookies middleware $routes->applyMiddleware('csrf', 'cookies'); @@ -1075,7 +1075,7 @@ $routes->scope('/cms', function (RouteBuilder $routes) { In situations where you have nested scopes, inner scopes will inherit the middleware applied in the containing scope: -``` php +```php $routes->scope('/api', function (RouteBuilder $routes) { $routes->applyMiddleware('ratelimit', 'auth.api'); $routes->scope('/v1', function (RouteBuilder $routes) { @@ -1089,7 +1089,7 @@ In the above example, the routes defined in `/v1` will have 'ratelimit', 'auth.api', and 'v1compat' middleware applied. If you re-open a scope, the middleware applied to routes in each scope will be isolated: -``` php +```php $routes->scope('/blog', function (RouteBuilder $routes) { $routes->applyMiddleware('auth'); // Connect the authenticated actions for the blog here. @@ -1109,7 +1109,7 @@ To help keep your route code `DRY (Do not Repeat Yourself)` middleware can be combined into groups. Once combined groups can be applied like middleware can: -``` php +```php $routes->registerMiddleware('cookie', new EncryptedCookieMiddleware()); $routes->registerMiddleware('auth', new AuthenticationMiddleware()); $routes->registerMiddleware('csrf', new CsrfProtectionMiddleware()); @@ -1127,7 +1127,7 @@ Router helps generate RESTful routes for your controllers. RESTful routes are helpful when you are creating API endpoints for your application. If we wanted to allow REST access to a recipe controller, we'd do something like this: -``` php +```php // In config/routes.php... $routes->scope('/', function (RouteBuilder $routes) { @@ -1172,7 +1172,7 @@ Once you have connected resources in a scope, you can connect routes for sub-resources as well. Sub-resource routes will be prepended by the original resource name and a id parameter. For example: -``` php +```php $routes->scope('/api', function (RouteBuilder $routes) { $routes->resources('Articles', function (RouteBuilder $routes) { $routes->resources('Comments'); @@ -1183,14 +1183,14 @@ $routes->scope('/api', function (RouteBuilder $routes) { Will generate resource routes for both `articles` and `comments`. The comments routes will look like: -``` text +```text /api/articles/{article_id}/comments /api/articles/{article_id}/comments/{id} ``` You can get the `article_id` in `CommentsController` by: -``` php +```php $this->request->getParam('article_id'); ``` @@ -1198,7 +1198,7 @@ By default, resource routes map to the same prefix as the containing scope. If you have both nested and non-nested resource controllers you can use a different controller in each context by using prefixes: -``` php +```php $routes->scope('/api', function (RouteBuilder $routes) { $routes->resources('Articles', function (RouteBuilder $routes) { $routes->resources('Comments', ['prefix' => 'Articles']); @@ -1220,7 +1220,7 @@ compatible with [Prefix Routing](#prefix-routing). By default, CakePHP will connect 6 routes for each resource. If you'd like to only connect specific resource routes you can use the `only` option: -``` php +```php $routes->resources('Articles', [ 'only' => ['index', 'view'], ]); @@ -1245,7 +1245,7 @@ You may need to change the controller action names that are used when connecting routes. For example, if your `edit()` action is called `put()` you can use the `actions` key to rename the actions used: -``` php +```php $routes->resources('Articles', [ 'actions' => ['update' => 'put', 'create' => 'add'], ]); @@ -1258,7 +1258,7 @@ instead of `create()`. You can map additional resource methods using the `map` option: -``` php +```php $routes->resources('Articles', [ 'map' => [ 'deleteAll' => [ @@ -1275,7 +1275,7 @@ In addition to the default routes, this would also connect a route for can use the 'path' key inside the resource definition to customize the path name: -``` php +```php $routes->resources('Articles', [ 'map' => [ 'updateAll' => [ @@ -1296,7 +1296,7 @@ the 'only' list. Resource routes can be connected to controllers in routing prefixes by connecting routes within a prefixed scope or by using the `prefix` option: -``` php +```php $routes->resources('Articles', [ 'prefix' => 'Api', ]); @@ -1309,7 +1309,7 @@ $routes->resources('Articles', [ You can provide `connectOptions` key in the `$options` array for `resources()` to provide custom setting used by `connect()`: -``` php +```php $routes->scope('/', function (RouteBuilder $routes) { $routes->resources('Books', [ 'connectOptions' => [ @@ -1327,7 +1327,7 @@ would be **/blog-posts**. You can specify an alternative inflection type using the `inflect` option: -``` php +```php $routes->scope('/', function (RouteBuilder $routes) { $routes->resources('BlogPosts', [ 'inflect' => 'underscore', // Will use ``Inflector::underscore()`` @@ -1342,7 +1342,7 @@ The above will generate URLs styled like: **/blog_posts**. By default, resource routes use an inflected form of the resource name for the URL segment. You can set a custom URL segment with the `path` option: -``` php +```php $routes->scope('/', function (RouteBuilder $routes) { $routes->resources('BlogPosts', ['path' => 'posts']); }); @@ -1366,7 +1366,7 @@ the passed arguments as well. If you were to visit the previously mentioned URL, and you had a controller action that looked like: -``` php +```php class CalendarsController extends AppController { public function view($arg1, $arg2) @@ -1378,7 +1378,7 @@ class CalendarsController extends AppController You would get the following output: -``` text +```text Array ( [0] => recent @@ -1390,13 +1390,13 @@ This same data is also available at `$this->request->getParam('pass')` in your controllers, views, and helpers. The values in the pass array are numerically indexed based on the order they appear in the called URL: -``` php +```php debug($this->request->getParam('pass')); ``` Either of the above would output: -``` text +```text Array ( [0] => recent @@ -1407,7 +1407,7 @@ Array When generating URLs, using a `routing array` you add passed arguments as values without string keys in the array: -``` php +```php ['controller' => 'Articles', 'action' => 'view', 5] ``` @@ -1424,7 +1424,7 @@ allow you to change your URL structure without having to modify all your code. If you create URLs using strings like: -``` php +```php $this->Html->link('View', '/articles/view/' . $id); ``` @@ -1432,7 +1432,7 @@ And then later decide that `/articles` should really be called 'posts' instead, you would have to go through your entire application renaming URLs. However, if you defined your link like: -``` php +```php //`link()` uses Router::url() internally and accepts a routing array $this->Html->link( @@ -1443,7 +1443,7 @@ $this->Html->link( or: -``` php +```php //'Router::reverse()' operates on the request parameters array //and will produce a url string, valid input for `link()` @@ -1465,7 +1465,7 @@ situations where the array elements required are fixed or easily deduced. It will provide reverse routing when the destination url is well defined: -``` php +```php $this->Html->link( 'View', ['controller' => 'Articles', 'action' => 'view', $id], @@ -1475,7 +1475,7 @@ $this->Html->link( It is also useful when the destination is unknown but follows a well defined pattern: -``` php +```php $this->Html->link( 'View', ['controller' => $controller, 'action' => 'view', $id], @@ -1487,7 +1487,7 @@ Elements with numeric keys are treated as [Passed Arguments](#passed-arguments). When using routing arrays, you can define both query string parameters and document fragments using special keys: -``` php +```php $routes->url([ 'controller' => 'Articles', 'action' => 'index', @@ -1540,7 +1540,7 @@ or draft only. To keep the code DRY, it would be best to include the links through an element: -``` php +```php // element/filter_published.php $params = $this->getRequest()->getAttribute('params'); @@ -1570,7 +1570,7 @@ reverse routing methods is in the way they include pass parameters. Routing arrays include pass parameters as un-keyed values in the array: -``` php +```php $url = [ 'controller' => 'Articles', 'action' => 'View', @@ -1581,7 +1581,7 @@ $url = [ Request parameters include pass parameters on the 'pass' key of the array: -``` php +```php $url = [ 'controller' => 'Articles', 'action' => 'View', @@ -1600,7 +1600,7 @@ a routing array or vice versa. The `Asset` class provides methods for generating URLs to your application's css, javascript, images and other static asset files: -``` php +```php use Cake\Routing\Asset; // Generate a URL to APP/webroot/js/app.js @@ -1627,7 +1627,7 @@ The above methods also accept an array of options as their second parameter: when debug is true. Set to `'force'` to always enable timestamping regardless of debug value. -``` php +```php // Generates https://example.com/img/logo.png $img = Asset::url('logo.png', ['fullBase' => true]); @@ -1638,7 +1638,7 @@ $img = Asset::url('logo.png', ['timestamp' => true]); To generate asset URLs for files in plugins use `plugin syntax`: -``` php +```php // Generates `/debug_kit/img/cake.png` $img = Asset::imageUrl('DebugKit.cake.png'); ``` @@ -1654,7 +1654,7 @@ Redirection routes are different from normal routes as they perform an actual header redirection if a match is found. The redirection can occur to a destination within your application or an outside location: -``` php +```php $routes->scope('/', function (RouteBuilder $routes) { $routes->redirect( '/home/*', @@ -1672,7 +1672,7 @@ you to use other routes to define where a URL string should be redirected to. You can redirect to external locations using string URLs as the destination: -``` php +```php $routes->scope('/', function (RouteBuilder $routes) { $routes->redirect('/articles/*', 'http://google.com', ['status' => 302]); }); @@ -1688,7 +1688,7 @@ Entity routing allows you to use an entity, an array or object implement routes more easily, and generate URLs with less code. For example, if you start off with a route that looks like: -``` php +```php $routes->get( '/view/{id}', ['controller' => 'Articles', 'action' => 'view'], @@ -1698,7 +1698,7 @@ $routes->get( You can generate URLs to this route using: -``` php +```php // $article is an entity in the local scope. Router::url(['_name' => 'articles:view', 'id' => $article->id]); ``` @@ -1709,7 +1709,7 @@ the `articles:view` route, which could take some time. If we use entity routes we pass the entire article entity into URL generation allowing us to skip any rework when URLs require more parameters: -``` php +```php use Cake\Routing\Route\EntityRoute; // Create entity routes for the rest of this scope. @@ -1725,7 +1725,7 @@ $routes->get( Now we can generate URLs using the `_entity` key: -``` php +```php Router::url(['_name' => 'articles:view', '_entity' => $article]); ``` @@ -1738,7 +1738,7 @@ CakePHP provides a `RedirectTrait` that can be used to create custom redirect route classes. If you need redirect behavior with custom logic, you can create a route class that uses this trait: -``` php +```php namespace App\Routing\Route; use Cake\Routing\Route\RedirectTrait; @@ -1775,7 +1775,7 @@ returned. You can use a custom route class when making a route by using the `routeClass` option: -``` php +```php $routes->connect( '/{slug}', ['controller' => 'Articles', 'action' => 'view'], @@ -1805,7 +1805,7 @@ default `Route`, you can do so by calling `RouteBuilder::setRouteClass()` before setting up any routes and avoid having to specify the `routeClass` option for each route. For example using: -``` php +```php use Cake\Routing\Route\DashedRoute; $routes->setRouteClass(DashedRoute::class); @@ -1824,7 +1824,7 @@ provided the class returned by `RouteBuilder::setRouteClass()` is used. Calling fallbacks like so: -``` php +```php use Cake\Routing\Route\DashedRoute; $routes->fallbacks(DashedRoute::class); @@ -1832,7 +1832,7 @@ $routes->fallbacks(DashedRoute::class); Is equivalent to the following explicit calls: -``` php +```php use Cake\Routing\Route\DashedRoute; $routes->connect('/{controller}', ['action' => 'index'], ['routeClass' => DashedRoute::class]); @@ -1867,7 +1867,7 @@ The URL filter function should *always* return the parameters even if unmodified URL filters allow you to implement features like persistent parameters: -``` php +```php Router::addUrlFilter(function (array $params, ServerRequest $request) { if ($request->getParam('lang') && !isset($params['lang'])) { $params['lang'] = $request->getParam('lang'); @@ -1882,7 +1882,7 @@ Filter functions are applied in the order they are connected. Another use case is changing a certain route on runtime (plugin routes for example): -``` php +```php Router::addUrlFilter(function (array $params, ServerRequest $request) { if (empty($params['plugin']) || $params['plugin'] !== 'MyPlugin' || empty($params['controller'])) { return $params; @@ -1900,13 +1900,13 @@ Router::addUrlFilter(function (array $params, ServerRequest $request) { This will alter the following route: -``` php +```php Router::url(['plugin' => 'MyPlugin', 'controller' => 'Languages', 'action' => 'view', 'es']); ``` into this: -``` php +```php Router::url(['plugin' => 'MyPlugin', 'controller' => 'Locations', 'action' => 'index', 'language' => 'es']); ``` diff --git a/docs/en/development/sessions.md b/docs/en/development/sessions.md index 0a70ec1933..08c4104a1e 100644 --- a/docs/en/development/sessions.md +++ b/docs/en/development/sessions.md @@ -40,7 +40,7 @@ protocols, then you might have problems with sessions being lost. If you need access to the session on both SSL and non-SSL domains you will want to disable this: -``` php +```php Configure::write('Session', [ 'defaults' => 'php', 'ini' => [ @@ -53,7 +53,7 @@ CakePHP also sets the [SameSite](https://owasp.org/www-community/SameSite) attri by default for session cookies, which helps protect against CSRF attacks. You can change the default value by setting `session.cookie_samesite` php.ini config: -``` php +```php Configure::write('Session', [ 'defaults' => 'php', 'ini' => [ @@ -66,7 +66,7 @@ The session cookie path defaults to app's base path. To change this you can use the `session.cookie_path` ini value. For example if you want your session to persist across all subdomains you can do: -``` php +```php Configure::write('Session', [ 'defaults' => 'php', 'ini' => [ @@ -81,7 +81,7 @@ closed, regardless of the configured `Session.timeout` value. The cookie timeout is controlled by the `session.cookie_lifetime` ini value and can be configured using: -``` php +```php Configure::write('Session', [ 'defaults' => 'php', 'ini' => [ @@ -109,7 +109,7 @@ custom solution. To use defaults, simply set the 'defaults' key to the name of the default you want to use. You can then override any sub setting by declaring it in your Session config: -``` php +```php Configure::write('Session', [ 'defaults' => 'php', ]); @@ -118,7 +118,7 @@ Configure::write('Session', [ The above will use the built-in 'php' session configuration. You could augment part or all of it by doing the following: -``` php +```php Configure::write('Session', [ 'defaults' => 'php', 'cookie' => 'my_app', @@ -148,7 +148,7 @@ Cache and Database session handlers use this method for saving sessions. Additional settings for the handler should be placed inside the handler array. You can then read those values out from inside your handler: -``` php +```php 'Session' => [ 'handler' => [ 'engine' => 'DatabaseSession', @@ -169,7 +169,7 @@ from inside plugins. By setting the engine to `MyPlugin.PluginSessionHandler`. If you need to use a database to store your session data, configure as follows: -``` php +```php 'Session' => [ 'defaults' => 'database', ] @@ -177,7 +177,7 @@ If you need to use a database to store your session data, configure as follows: This configuration requires a database table, having this schema: -``` sql +```sql CREATE TABLE `sessions` ( `id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `created` datetime DEFAULT CURRENT_TIMESTAMP, -- Optional @@ -192,7 +192,7 @@ You can find a copy of the schema for the sessions table in the [application ske You can also use your own `Table` class to handle the saving of the sessions: -``` php +```php 'Session' => [ 'defaults' => 'database', 'handler' => [ @@ -217,7 +217,7 @@ start to expire as records are evicted. To use Cache based sessions you can configure you Session config like: -``` php +```php Configure::write('Session', [ 'defaults' => 'cache', 'handler' => [ @@ -234,7 +234,7 @@ configuration to use. The default cache configuration is `'default'`. The app skeleton comes preconfigured with a session config like this: -``` php +```php 'Session' => [ 'defaults' => 'php', ], @@ -265,7 +265,7 @@ configurations, as well as custom ones. The `ini` key in the session settings, allows you to specify individual configuration values. For example you can use it to control settings like `session.gc_divisor`: -``` php +```php Configure::write('Session', [ 'defaults' => 'php', 'ini' => [ @@ -288,7 +288,7 @@ First we'll need to create our custom class and put it in **src/Http/Session/ComboSession.php**. The class should look something like: -``` php +```php namespace App\Http\Session; use Cake\Cache\Cache; @@ -346,7 +346,7 @@ a `Cake\Cache\Cache` operation. This lets us fetch sessions from the fast cache, and not have to worry about what happens when we fill the cache. In **config/app.php** make the session block look like: -``` php +```php 'Session' => [ 'defaults' => 'database', 'handler' => [ @@ -381,7 +381,7 @@ This means the session is accessible from: A basic example of session usage in controllers, views and cells would be: -``` php +```php $name = $this->request->getSession()->read('User.name'); // If you are accessing the session multiple times, @@ -400,7 +400,7 @@ In components, use `$this->getController()->getRequest()`. You can read values from the session using `Hash::extract()` compatible syntax: -``` php +```php $session->read('Config.language', 'en'); ``` @@ -408,7 +408,7 @@ $session->read('Config.language', 'en'); The same as convenience wrapper around non-nullable return value: -``` php +```php $session->readOrFail('Config.language'); ``` @@ -419,13 +419,13 @@ for the existence in code itself. `$key` should be the dot separated path you wish to write `$value` to: -``` php +```php $session->write('Config.language', 'en'); ``` You may also specify one or multiple hashes like so: -``` php +```php $session->write([ 'Config.theme' => 'blue', 'Config.language' => 'en', @@ -436,7 +436,7 @@ $session->write([ When you need to delete data from the session, you can use `delete()`: -``` php +```php $session->delete('Some.value'); ``` @@ -449,7 +449,7 @@ $session->delete('Some.value'); When you need to read and delete data from the session, you can use `consume()`: -``` php +```php $session->consume('Some.value'); ``` @@ -457,7 +457,7 @@ $session->consume('Some.value'); If you want to see if data exists in the session, you can use `check()`: -``` php +```php if ($session->check('Config.language')) { // Config.language exists and is not null. } @@ -470,7 +470,7 @@ if ($session->check('Config.language')) { Destroying the session is useful when users log out. To destroy a session, use the `destroy()` method: -``` php +```php $session->destroy(); ``` @@ -485,7 +485,7 @@ While the `Authentication Plugin` automatically renews the session id when users logout, you may need to rotate the session id's manually. To do this use the `renew()` method: -``` php +```php $session->renew(); ``` diff --git a/docs/en/development/testing.md b/docs/en/development/testing.md index 7062cb987f..4acde5c865 100644 --- a/docs/en/development/testing.md +++ b/docs/en/development/testing.md @@ -23,7 +23,7 @@ through using either a [PHAR package](https://phpunit.de/#download) or To install PHPUnit with Composer: -``` bash +```bash php composer.phar require --dev phpunit/phpunit:"^11.5.3" ``` @@ -32,7 +32,7 @@ This will add the dependency to the `require-dev` section of your You can now run PHPUnit using: -``` bash +```bash vendor/bin/phpunit ``` @@ -41,7 +41,7 @@ vendor/bin/phpunit After you have downloaded the **phpunit.phar** file, you can use it to run your tests: -``` bash +```bash php phpunit.phar ``` @@ -65,7 +65,7 @@ any tests. Before running any tests you should be sure to add a `test` datasource configuration to **config/app_local.php**. This configuration is used by CakePHP for fixture tables and data: -``` php +```php 'Datasources' => [ 'test' => [ 'datasource' => 'Cake\Database\Driver\Mysql', @@ -88,7 +88,7 @@ After installing PHPUnit and setting up your `test` datasource configuration you can make sure you're ready to write and run your own tests by running your application's tests: -``` bash +```bash # For phpunit.phar php phpunit.phar @@ -101,7 +101,7 @@ To run a specific test you can supply the path to the test as a parameter to PHPUnit. For example, if you had a test case for ArticlesTable class you could run it with: -``` bash +```bash vendor/bin/phpunit tests/TestCase/Model/Table/ArticlesTableTest ``` @@ -134,7 +134,7 @@ In the following example, we'll create a test case for a very simple helper method. The helper we're going to test will be formatting progress bar HTML. Our helper looks like: -``` php +```php namespace App\View\Helper; use Cake\View\Helper; @@ -158,7 +158,7 @@ a simple test case. After creating and saving our helper, we'll create the test case file in **tests/TestCase/View/Helper/ProgressHelperTest.php**. In that file we'll start with the following: -``` php +```php namespace App\Test\TestCase\View\Helper; use App\View\Helper\ProgressHelper; @@ -183,7 +183,7 @@ in a test case class. Setup methods should initialize the objects needed for the test, and do any configuration needed. In our setup method we'll add the following: -``` php +```php public function setUp(): void { parent::setUp(); @@ -200,7 +200,7 @@ does a number things like backing up the values in Next, we'll fill out the test method. We'll use some assertions to ensure that our code creates the output we expect: -``` php +```php public function testBar(): void { $result = $this->Progress->bar(90); @@ -239,7 +239,7 @@ any changes to help ensure you haven't broken anything. By using `phpunit` you can run your application tests. To run your application's tests you can simply run: -``` bash +```bash vendor/bin/phpunit php phpunit.phar @@ -249,7 +249,7 @@ If you have cloned the [CakePHP source from GitHub](https://github.com/cakephp/c and wish to run CakePHP's unit-tests don't forget to execute the following `Composer` command prior to running `phpunit` so that any dependencies are installed: -``` bash +```bash composer install ``` @@ -257,7 +257,7 @@ From your application's root directory. To run tests for a plugin that is part of your application source, first `cd` into the plugin directory, then use `phpunit` command that matches how you installed phpunit: -``` bash +```bash cd plugins ../vendor/bin/phpunit @@ -268,7 +268,7 @@ php ../phpunit.phar To run tests on a standalone plugin, you should first install the project in a separate directory and install its dependencies: -``` bash +```bash git clone git://github.com/cakephp/debug_kit.git cd debug_kit php ~/composer.phar install @@ -281,7 +281,7 @@ When you have larger test cases, you will often want to run a subset of the test methods when you are trying to work on a single failing case. With the CLI runner you can use an option to filter test methods: -``` bash +```bash phpunit --filter testSave tests/TestCase/Model/Table/ArticlesTableTest ``` @@ -295,7 +295,7 @@ built-in code coverage tools. PHPUnit will generate a set of static HTML files containing the coverage results. You can generate coverage for a test case by doing the following: -``` bash +```bash phpunit --coverage-html webroot/coverage tests/TestCase/Model/Table/ArticlesTableTest ``` @@ -306,7 +306,7 @@ should be able to view the results by going to You can also use `phpdbg` to generate coverage instead of xdebug. `phpdbg` is generally faster at generating coverage: -``` bash +```bash phpdbg -qrr phpunit --coverage-html webroot/coverage tests/TestCase/Model/Table/ArticlesTableTest ``` @@ -318,7 +318,7 @@ running tests for each of the plugins that compose your application by adding additional `` sections to your application's **phpunit.xml.dist** file: -``` xml +```xml tests/TestCase/ @@ -338,7 +338,7 @@ If you are using `` to use fixtures from plugins that you have installed with composer, the plugin's `composer.json` file should add the fixture namespace to the autoload section. Example: -``` json +```json "autoload-dev": { "psr-4": { "PluginName\\Test\\Fixture\\": "tests/Fixture/" @@ -403,7 +403,7 @@ will attempt to use 'test_replica'. Before you can use fixtures you should double check that your `phpunit.xml` contains the fixture extension: -``` xml +```xml @@ -428,7 +428,7 @@ If you use CakePHP's [migrations plugin](https://book.cakephp.org/migrations) to application's schema, you can reuse those migrations to generate your test database schema as well: -``` php +```php // in tests/bootstrap.php use Migrations\TestSuite\Migrator; @@ -446,7 +446,7 @@ $migrator->run(['plugin' => 'Documents', 'connection' => 'test_docs']); If you need to run multiple sets of migrations, those can be run as follows: -``` php +```php $migrator->runMany([ // Run app migrations on test connection. ['connection' => 'test'], @@ -476,7 +476,7 @@ time-consuming to maintain. Each table can define `columns`, `constraints`, and `indexes`. An example table would be: -``` php +```php return [ 'articles' => [ 'columns' => [ @@ -517,7 +517,7 @@ created incrementally and you must take care to ensure that tables are created before foreign key references are made. Once you have created your schema file you can load it in your `tests/bootstrap.php` with: -``` php +```php $loader = new SchemaLoader(); $loader->loadInternalFile($pathToSchemaFile); ``` @@ -526,7 +526,7 @@ $loader->loadInternalFile($pathToSchemaFile); To load a SQL dump file you can use the following: -``` php +```php // in tests/bootstrap.php use Cake\TestSuite\Fixture\SchemaLoader; @@ -544,7 +544,7 @@ beginning of each test. Let's create our first fixture, that will be used to test our own Article model. Create a file named **ArticlesFixture.php** in your **tests/Fixture** directory, with the following content: -``` php +```php namespace App\Test\Fixture; use Cake\TestSuite\Fixture\TestFixture; @@ -615,7 +615,7 @@ As you evolve your schema your fixture records may accumulate unused or unsupported fields. You can enable `strictFields` on a fixture to have errors raised when a record contains fields that are not defined in the schema: -``` php +```php namespace App\Test\Fixture; use Cake\TestSuite\Fixture\TestFixture; @@ -640,7 +640,7 @@ enforce stricter maintenance of test data. To use functions or other dynamic data in your fixture records you can define your records in the fixture's `init()` method: -``` php +```php namespace App\Test\Fixture; use Cake\TestSuite\Fixture\TestFixture; @@ -673,7 +673,7 @@ In each test case you should load the fixtures you will need. You should load a fixture for every model that will have a query run against it. To load fixtures you define the `$fixtures` property in your model: -``` php +```php class ArticlesTest extends TestCase { protected array $fixtures =['app.Articles', 'app.Comments']; @@ -683,7 +683,7 @@ class ArticlesTest extends TestCase As of 4.1.0 you can use `getFixtures()` to define your fixture list with a method: -``` php +```php public function getFixtures(): array { return [ @@ -696,7 +696,7 @@ public function getFixtures(): array The above will load the Article and Comment fixtures from the application's Fixture directory. You can also load fixtures from CakePHP core, or plugins: -``` php +```php class ArticlesTest extends TestCase { protected array $fixtures =[ @@ -715,7 +715,7 @@ easier to organize your fixtures if you have a larger application. To load fixtures in subdirectories, simply include the subdirectory name in the fixture name: -``` php +```php class ArticlesTest extends CakeTestCase { protected array $fixtures =['app.Blog/Articles', 'app.Blog/Comments']; @@ -727,7 +727,7 @@ In the above example, both fixtures would be loaded from You can also directly include fixtures by FQCN: -``` php +```php public function getFixtures(): array { return [ @@ -750,7 +750,7 @@ data, as auto-increment values are not reset before each test. The fixture state management strategy can be defined within the test case: -``` php +```php use Cake\TestSuite\TestCase; use Cake\TestSuite\Fixture\FixtureStrategyInterface; use Cake\TestSuite\Fixture\TransactionStrategy; @@ -770,7 +770,7 @@ class ArticlesTableTest extends TestCase To switch out the general default strategy, use Configure key `TestSuite.fixtureStrategy` in your `app.php`: -``` php +```php 'TestSuite' => [ 'fixtureStrategy' => \Cake\TestSuite\Fixture\TransactionStrategy::class, ], @@ -800,13 +800,13 @@ Unnecessary interaction with the database will slow down your tests as well as your application. You can create test fixtures without persisting them which can be useful for testing methods without DB interaction: -``` php +```php $article = ArticleFactory::make()->getEntity(); ``` In order to persist: -``` php +```php $article = ArticleFactory::make()->persist(); ``` @@ -814,7 +814,7 @@ The factories help creating associated fixtures too. Assuming that articles belongs to many authors, we can now, for example, create 5 articles each with 2 authors: -``` php +```php $articles = ArticleFactory::make(5)->with('Authors', 2)->getEntities(); ``` @@ -829,7 +829,7 @@ routes and resolving URLs, you will need to load routes. During the `setUp()` of a class or during individual test methods you can use `loadRoutes()` to ensure your application routes are loaded: -``` php +```php public function setUp(): void { parent::setUp(); @@ -849,7 +849,7 @@ when developing plugins, or applications that are extensible. Just like loading existing application routes, this can be done during `setup()` of a test method, and/or in the individual test methods themselves: -``` php +```php use Cake\Routing\Route\DashedRoute; use Cake\Routing\RouteBuilder; use Cake\Routing\Router; @@ -887,7 +887,7 @@ may already exist, or are yet to be created in the environment. If your application would dynamically load plugins, you can use `loadPlugins()` to load one or more plugins during tests: -``` php +```php public function testMethodUsingPluginResources() { $this->loadPlugins(['Company/Cms']); @@ -900,7 +900,7 @@ public function testMethodUsingPluginResources() Let's say we already have our Articles Table class defined in **src/Model/Table/ArticlesTable.php**, and it looks like: -``` php +```php namespace App\Model\Table; use Cake\ORM\Table; @@ -923,7 +923,7 @@ We now want to set up a test that will test this table class. Let's now create a file named **ArticlesTableTest.php** in your **tests/TestCase/Model/Table** directory, with the following contents: -``` php +```php namespace App\Test\TestCase\Model\Table; use App\Model\Table\ArticlesTable; @@ -945,7 +945,7 @@ Let's now add a method to test the function `published()` in the Articles table. Edit the file **tests/TestCase/Model/Table/ArticlesTableTest.php** so it now looks like this: -``` php +```php namespace App\Test\TestCase\Model\Table; use App\Model\Table\ArticlesTable; @@ -987,7 +987,7 @@ section for more information on how to run your test case. Using the fixture factories, the test would now look like this: -``` php +```php namespace App\Test\TestCase\Model\Table; use App\Test\Factory\ArticleFactory; @@ -1025,7 +1025,7 @@ There will be times you'll want to mock methods on models when testing them. You should use `getMockForModel` to create testing mocks of table classes. It avoids issues with reflected properties that normal mocks have: -``` php +```php public function testSendingEmails(): void { $model = $this->getMockForModel('EmailVerification', ['send']); @@ -1039,7 +1039,7 @@ public function testSendingEmails(): void In your `tearDown()` method be sure to remove the mock with: -``` php +```php $this->getTableLocator()->clear(); ``` @@ -1062,7 +1062,7 @@ more high level test of your application and all its working parts. Say you have a typical ArticlesController, and its corresponding model. The controller code looks like: -``` php +```php namespace App\Controller; use App\Controller\AppController; @@ -1095,7 +1095,7 @@ class ArticlesController extends AppController Create a file named **ArticlesControllerTest.php** in your **tests/TestCase/Controller** directory and put the following inside: -``` php +```php namespace App\Test\TestCase\Controller; use Cake\TestSuite\IntegrationTestTrait; @@ -1174,7 +1174,7 @@ ensure your request had the correct side-effects. The `IntegrationTestTrait` trait comes with a number of helpers to to configure the requests you will send to your application under test: -``` php +```php // Set cookies $this->cookie('name', 'Uncle Bob'); @@ -1204,7 +1204,7 @@ When testing actions protected by either `CsrfProtectionMiddleware` or `FormProt can enable automatic token generation to ensure your tests won't fail due to token mismatches: -``` php +```php public function testAdd(): void { $this->enableCsrfToken(); @@ -1218,7 +1218,7 @@ It is also important to enable debug in tests that use tokens to prevent the environment. When testing with other methods like `requireSecure()` you can use `configRequest()` to set the correct environment variables: -``` php +```php // Fake out SSL connections. $this->configRequest([ 'environment' => ['HTTPS' => 'on'], @@ -1228,7 +1228,7 @@ $this->configRequest([ If your action requires unlocked fields you can declare them with `setUnlockedFields()`: -``` php +```php $this->setUnlockedFields(['dynamic_field']); ``` @@ -1242,7 +1242,7 @@ enable integration testing of your Application. You can customize the application class name used, and the constructor arguments, by using the `configApplication()` method: -``` php +```php public function setUp(): void { $this->configApplication('App\App', [CONFIG]); @@ -1260,7 +1260,7 @@ If you use the [Encrypted Cookie Middleware](../controllers/middleware#encrypted application, there are helper methods for setting encrypted cookies in your test cases: -``` php +```php // Set a cookie using AES and the default key. $this->cookieEncrypted('my_cookie', 'Some secret values'); @@ -1276,7 +1276,7 @@ If you want to assert the presence of flash messages in the session and not the rendered HTML, you can use `enableRetainFlashMessages()` in your tests to retain flash messages in the session so you can write assertions: -``` php +```php // Enable retention of flash messages instead of consuming them. $this->enableRetainFlashMessages(); $this->get('/articles/delete/9999'); @@ -1315,7 +1315,7 @@ JSON is a friendly and common format to use when building a web service. Testing the endpoints of your web service is very simple with CakePHP. Let us begin with a simple example controller that responds in JSON: -``` php +```php use Cake\View\JsonView; class MarkersController extends AppController @@ -1337,7 +1337,7 @@ class MarkersController extends AppController Now we create the file **tests/TestCase/Controller/MarkersControllerTest.php** and make sure our web service is returning the proper response: -``` php +```php class MarkersControllerTest extends TestCase { use IntegrationTestTrait; @@ -1387,7 +1387,7 @@ Let's assume articles have a teaser image, and a `Articles hasMany Attachments` association, the form would look like something like this accordingly, where one image file, and multiple attachments/files would be accepted: -``` php +```php Form->create($article, ['type' => 'file']) ?> Form->control('title') ?> Form->control('teaser_image', ['type' => 'file']) ?> @@ -1401,7 +1401,7 @@ image file, and multiple attachments/files would be accepted: The test that would simulate the corresponding request could look like this: -``` php +```php public function testAddWithUploads(): void { $teaserImage = new \Laminas\Diactoros\UploadedFile( @@ -1476,7 +1476,7 @@ public function testAddWithUploads(): void Likewise you can simulate [upload errors](https://www.php.net/manual/en/features.file-upload.errors.php) or otherwise invalid files that do not pass validation: -``` php +```php public function testAddWithInvalidUploads(): void { $missingTeaserImageUpload = new \Laminas\Diactoros\UploadedFile( @@ -1551,7 +1551,7 @@ errors it can be helpful to temporarily disable the error handling middleware to allow the underlying error to bubble up. You can use `disableErrorHandlerMiddleware()` to do this: -``` php +```php public function testGetMissing(): void { $this->disableErrorHandlerMiddleware(); @@ -1569,7 +1569,7 @@ checked. The `IntegrationTestTrait` trait provides a number of assertion methods that make testing responses much simpler. Some examples are: -``` php +```php // Check for a 2xx response code $this->assertResponseOk(); @@ -1666,7 +1666,7 @@ The `StringCompareTrait` adds a simple assert method for this purpose. Usage involves using the trait, setting the comparison base path and calling `assertSameAsFile`: -``` php +```php use Cake\TestSuite\StringCompareTrait; use Cake\TestSuite\TestCase; @@ -1695,7 +1695,7 @@ A mechanism is provided to write/update test files, by setting the environment variable `UPDATE_TEST_COMPARISON_FILES`, which will create and/or update test comparison files as they are referenced: -``` bash +```bash phpunit ... FAILURES! @@ -1744,7 +1744,7 @@ This component helps us set the pagination limit value across all the controllers that use it. Here is our example component located in **src/Controller/Component/PagematronComponent.php**: -``` php +```php class PagematronComponent extends Component { public ?Controller $controller = null; @@ -1784,7 +1784,7 @@ Now we can write tests to ensure our paginate `limit` parameter is being set correctly by the `adjust()` method in our component. We create the file **tests/TestCase/Controller/Component/PagematronComponentTest.php**: -``` php +```php namespace App\Test\TestCase\Controller\Component; use App\Controller\Component\PagematronComponent; @@ -1846,7 +1846,7 @@ First we create an example helper to test. The `CurrencyRendererHelper` will help us display currencies in our views and for simplicity only has one method `usd()`: -``` php +```php // src/View/Helper/CurrencyRendererHelper.php namespace App\View\Helper; @@ -1866,7 +1866,7 @@ separator to comma, and prefix the formatted number with 'USD' string. Now we create our tests: -``` php +```php // tests/TestCase/View/Helper/CurrencyRendererHelperTest.php namespace App\Test\TestCase\View\Helper; @@ -1924,7 +1924,7 @@ instead. Expanding on the Orders example, say we have the following tables: -``` php +```php class OrdersTable extends Table { public function place($order): bool @@ -1972,7 +1972,7 @@ To test the `OrdersTable` above, we enable tracking in `setUp()` then assert that the event was fired, and assert that the `$order` entity was passed in the event data: -``` php +```php namespace App\Test\TestCase\Model\Table; use App\Model\Table\OrdersTable; @@ -2010,7 +2010,7 @@ class OrdersTableTest extends TestCase By default, the global `EventManager` is used for assertions, so testing global events does not require passing the event manager: -``` php +```php $this->assertEventFired('My.Global.Event'); $this->assertEventFiredWith('My.Global.Event', 'user', 1); ``` @@ -2030,7 +2030,7 @@ suite. A test suite is composed of several test cases. You can either create test suites in your application's **phpunit.xml** file. A simple example would be: -``` xml +```xml src/Model @@ -2058,7 +2058,7 @@ for the `BlogPost` model from the plugins chapter of this manual. A difference from other tests is in the first line where 'Blog.BlogPost' is imported. You also need to prefix your plugin fixtures with `plugin.Blog.BlogPosts`: -``` php +```php namespace Blog\Test\TestCase\Model\Table; use Blog\Model\Table\BlogPostsTable; @@ -2086,7 +2086,7 @@ listener](#fixture-phpunit-configuration) configured in your `phpunit.xml` file. You should also ensure that your fixtures are loadable. Ensure the following is present in your **composer.json** file: -``` json +```json "autoload-dev": { "psr-4": { "MyPlugin\\Test\\": "plugins/MyPlugin/tests/" @@ -2105,7 +2105,7 @@ generate scaffolding, it will also generate test stubs. If you need to re-generate test case skeletons, or if you want to generate test skeletons for code you wrote, you can use `bake`: -``` bash +```bash bin/cake bake test ``` diff --git a/docs/en/intro.md b/docs/en/intro.md index c18ccaf7b7..bd75cadd0c 100644 --- a/docs/en/intro.md +++ b/docs/en/intro.md @@ -35,7 +35,7 @@ and retrieving user photos, finding suggestions for new friends, etc. The model objects can be thought of as "Friend", "User", "Comment", or "Photo". If we wanted to load some data from our `users` table we could do: -``` php +```php use Cake\ORM\Locator\LocatorAwareTrait; $users = $this->fetchTable('Users'); @@ -52,7 +52,7 @@ for table and entity classes that have not yet been defined. If we wanted to make a new user and save it (with validation) we would do something like: -``` php +```php use Cake\ORM\Locator\LocatorAwareTrait; $users = $this->fetchTable('Users'); @@ -69,7 +69,7 @@ to produce any presentational interface your application might need. For example, the view could use model data to render an HTML view template containing it, or a XML formatted result for others to consume: -``` php +```php // In a view template file, we'll render an 'element' for each user.
  • @@ -98,7 +98,7 @@ presentational data that the clients are accepting, and finally delegates the rendering process to the View layer. An example of a user registration controller would be: -``` php +```php public function add() { $user = $this->Users->newEmptyEntity(); diff --git a/docs/en/orm.md b/docs/en/orm.md index 8fc77753b2..76a74f0e96 100644 --- a/docs/en/orm.md +++ b/docs/en/orm.md @@ -35,7 +35,7 @@ if we wanted to load some data from our `articles` table we would start off creating our `Articles` table class. Create **src/Model/Table/ArticlesTable.php** with the following code: -``` php +```php fetchTable('Articles')->find()->all(); @@ -61,7 +61,7 @@ public function someMethod() In other contexts, you can use the `LocatorAwareTrait` which add accessor methods for ORM tables: -``` php +```php use Cake\ORM\Locator\LocatorAwareTrait; public function someMethod() @@ -74,7 +74,7 @@ public function someMethod() Within a static method you can use the `Cake\Datasource\FactoryLocator` to get the table locator: -``` php +```php $articles = TableRegistry::getTableLocator()->get('Articles'); ``` @@ -84,7 +84,7 @@ mutator methods, define custom logic for individual records and much more. We'll start off by adding the following to **src/Model/Entity/Article.php** after the `fetchTable('Articles'); diff --git a/docs/en/orm/associations.md b/docs/en/orm/associations.md index 24af8b0c4e..5afefd6dd2 100644 --- a/docs/en/orm/associations.md +++ b/docs/en/orm/associations.md @@ -22,7 +22,7 @@ object. Methods matching the association type allow you to define the associations in your application. For example if we wanted to define a belongsTo association in our ArticlesTable: -``` php +```php namespace App\Model\Table; use Cake\ORM\Table; @@ -41,7 +41,7 @@ associate with. By default, all the details of an association will use the CakePHP conventions. If you want to customize how your associations are handled you can modify them with setters: -``` php +```php class ArticlesTable extends Table { public function initialize(array $config): void @@ -57,13 +57,13 @@ class ArticlesTable extends Table The property name will be the property key (of the associated entity) on the entity object, in this case: -``` php +```php $authorEntity = $articleEntity->author; ``` You can also use arrays to customize your associations: -``` php +```php $this->belongsTo('Authors', [ 'className' => 'Publishing.Authors', 'foreignKey' => 'author_id', @@ -77,7 +77,7 @@ The same table can be used multiple times to define different types of associations. For example consider a case where you want to separate approved comments and those that have not been moderated yet: -``` php +```php class ArticlesTable extends Table { public function initialize(array $config): void @@ -98,7 +98,7 @@ As you can see, by specifying the `className` key, it is possible to use the same table as different associations for the same table. You can even create self-associated tables to create parent-child relationships: -``` php +```php class CategoriesTable extends Table { public function initialize(array $config): void @@ -118,7 +118,7 @@ You can also setup associations in mass by making a single call to `Table::addAssociations()` which accepts an array containing a set of table names indexed by association type as an argument: -``` php +```php class PostsTable extends Table { public function initialize(array $config): void @@ -165,7 +165,7 @@ called 'user_id'. The basic pattern is: Once you create the `UsersTable` and `AddressesTable` classes, you can make the association with the following code: -``` php +```php class UsersTable extends Table { public function initialize(array $config): void @@ -179,7 +179,7 @@ If you need more control, you can define your associations using the setters. For example, you might want to limit the association to include only certain records: -``` php +```php class UsersTable extends Table { public function initialize(array $config): void @@ -194,7 +194,7 @@ class UsersTable extends Table If you want to break different addresses into multiple associations, you can do something like: -``` php +```php class UsersTable extends Table { public function initialize(array $config): void @@ -254,7 +254,7 @@ Possible keys for hasOne association arrays include: Once this association has been defined, find operations on the Users table can contain the Address record if it exists: -``` php +```php // In a controller or table method. $query = $users->find('all')->contain(['Addresses'])->all(); foreach ($query as $user) { @@ -264,7 +264,7 @@ foreach ($query as $user) { The above would emit SQL that is similar to: -``` sql +```sql SELECT * FROM users INNER JOIN addresses ON addresses.user_id = users.id; ``` @@ -293,7 +293,7 @@ convention: We can define the belongsTo association in our Addresses table as follows: -``` php +```php class AddressesTable extends Table { public function initialize(array $config): void @@ -305,7 +305,7 @@ class AddressesTable extends Table We can also define a more specific relationship using the setters: -``` php +```php class AddressesTable extends Table { public function initialize(array $config): void @@ -344,7 +344,7 @@ Possible keys for belongsTo association arrays include: Once this association has been defined, find operations on the Addresses table can contain the User record if it exists: -``` php +```php // In a controller or table method. $query = $addresses->find('all')->contain(['Users'])->all(); foreach ($query as $address) { @@ -354,7 +354,7 @@ foreach ($query as $address) { The above would output SQL similar to: -``` sql +```sql SELECT * FROM addresses LEFT JOIN users ON addresses.user_id = users.id; ``` @@ -379,7 +379,7 @@ convention: We can define the hasMany association in our Articles model as follows: -``` php +```php class ArticlesTable extends Table { public function initialize(array $config): void @@ -391,7 +391,7 @@ class ArticlesTable extends Table We can also define a more specific relationship using the setters: -``` php +```php class ArticlesTable extends Table { public function initialize(array $config): void @@ -405,7 +405,7 @@ class ArticlesTable extends Table Sometimes you may want to configure composite keys in your associations: -``` php +```php // Within ArticlesTable::initialize() call $this->hasMany('Comments') ->setForeignKey([ @@ -420,7 +420,7 @@ automatically defined as `id` and `hash` respectively, but let's assume that you need to specify different binding fields than the defaults. You can setup it manually with `setBindingKey()`: -``` php +```php // Within ArticlesTable::initialize() call $this->hasMany('Comments') ->setForeignKey([ @@ -475,7 +475,7 @@ Possible keys for hasMany association arrays include: Once this association has been defined, find operations on the Articles table can contain the Comment records if they exist: -``` php +```php // In a controller or table method. $query = $articles->find('all')->contain(['Comments'])->all(); foreach ($query as $article) { @@ -485,7 +485,7 @@ foreach ($query as $article) { The above would output SQL similar to: -``` sql +```sql SELECT * FROM articles; SELECT * FROM comments WHERE article_id IN (1, 2, 3, 4, 5); ``` @@ -493,7 +493,7 @@ SELECT * FROM comments WHERE article_id IN (1, 2, 3, 4, 5); When the subquery strategy is used, SQL similar to the following will be generated: -``` sql +```sql SELECT * FROM articles; SELECT * FROM comments WHERE article_id IN (SELECT id FROM articles); ``` @@ -542,7 +542,7 @@ names. We can define the belongsToMany association in both our models as follows: -``` php +```php // In src/Model/Table/ArticlesTable.php class ArticlesTable extends Table { @@ -564,7 +564,7 @@ class TagsTable extends Table We can also define a more specific relationship using configuration: -``` php +```php // In src/Model/Table/TagsTable.php class TagsTable extends Table { @@ -630,7 +630,7 @@ Possible keys for belongsToMany association arrays include: Once this association has been defined, find operations on the Articles table can contain the Tag records if they exist: -``` php +```php // In a controller or table method. $query = $articles->find('all')->contain(['Tags'])->all(); foreach ($query as $article) { @@ -640,7 +640,7 @@ foreach ($query as $article) { The above would output SQL similar to: -``` sql +```sql SELECT * FROM articles; SELECT * FROM tags INNER JOIN articles_tags ON ( @@ -652,7 +652,7 @@ INNER JOIN articles_tags ON ( When the subquery strategy is used, SQL similar to the following will be generated: -``` sql +```sql SELECT * FROM articles; SELECT * FROM tags INNER JOIN articles_tags ON ( @@ -689,7 +689,7 @@ as a **hasMany through** association. That is, the association is a model itself. So, we can create a new model CoursesMemberships. Take a look at the following models: -``` php +```php class StudentsTable extends Table { public function initialize(array $config): void @@ -729,7 +729,7 @@ your query object. The `through` table can then be referenced in other condition such as a where condition by designating the through table name before the field you are filtering on: -``` php +```php // In a StudentsTable method or controller action. $query = $this->Students->find( 'list', @@ -768,20 +768,20 @@ above restrictions and can also use result formatters or map/reduce functions. By default, associations should be configured and referenced using the CamelCase style. This enables property chains to related tables in the following way: -``` php +```php $this->MyTableOne->MyTableTwo->find()->...; ``` Association properties on entities do not use CamelCase conventions though. Instead for a hasOne/belongsTo relation like "User belongsTo Roles", you would get a `role` property instead of `Role` or `Roles`: -``` php +```php // A single entity (or null if not available) $role = $user->role; ``` Whereas for the other direction "Roles hasMany Users" it would be: -``` php +```php // Collection of user entities (or null if not available) $users = $role->users; ``` diff --git a/docs/en/orm/behaviors.md b/docs/en/orm/behaviors.md index b69f0f1525..f6b576c6f5 100644 --- a/docs/en/orm/behaviors.md +++ b/docs/en/orm/behaviors.md @@ -46,7 +46,7 @@ behaviors: To create our sluggable behavior. Put the following into **src/Model/Behavior/SluggableBehavior.php**: -``` php +```php namespace App\Model\Behavior; use Cake\ORM\Behavior; @@ -59,7 +59,7 @@ class SluggableBehavior extends Behavior Similar to tables, behaviors also have an `initialize()` hook where you can put your behavior's initialization code, if required: -``` php +```php public function initialize(array $config): void { // Some initialization code here @@ -70,7 +70,7 @@ We can now add this behavior to one of our table classes. In this example we'll use an `ArticlesTable`, as articles often have slug properties for creating friendly URLs: -``` php +```php namespace App\Model\Table; use Cake\ORM\Table; @@ -92,7 +92,7 @@ slug a field. Public methods on behaviors can be called as normal methods: -``` php +```php $articles->getBehavior('Sluggable')->slug($value); ``` @@ -104,7 +104,7 @@ Behavior mixin methods will receive the exact same arguments that are provided to the table. For example, if our SluggableBehavior defined the following method: -``` php +```php public function slug(string $value): string { return Text::slug($value, $this->_config['replacement']); @@ -113,7 +113,7 @@ public function slug(string $value): string It could be invoked using: -``` php +```php $slug = $articles->slug('My article'); ``` @@ -128,7 +128,7 @@ public methods as mixin methods. In these cases you can use the `implementedMethods` configuration key to rename or exclude mixin methods. For example if we wanted to prefix our slug() method we could do the following: -``` php +```php protected array $_defaultConfig = [ 'implementedMethods' => [ 'superSlug' => 'slug', @@ -144,7 +144,7 @@ methods with the above configuration. Since the exposed methods are decided by configuration you can also rename/remove mixin methods when adding a behavior to a table. For example: -``` php +```php // In a table's initialize() method. $this->addBehavior('Sluggable', [ 'implementedMethods' => [ @@ -160,7 +160,7 @@ a callback listener to automatically slug a field when entities are saved. We'll also modify our slug method to accept an entity instead of just a plain value. Our behavior should now look like: -``` php +```php namespace App\Model\Behavior; use ArrayObject; @@ -203,7 +203,7 @@ The above code shows a few interesting features of behaviors: To prevent the save from continuing, simply stop event propagation in your callback: -``` php +```php public function beforeSave(EventInterface $event, EntityInterface $entity, ArrayObject $options): void { if (...) { @@ -225,7 +225,7 @@ a finder method so we can fetch articles by their slug. Behavior finder methods, use the same conventions as [Custom Find Methods](../orm/retrieving-data-and-resultsets#custom-find-methods) do. Our `find('slug')` method would look like: -``` php +```php public function findSlug(SelectQuery $query, string $slug): SelectQuery { return $query->where(['slug' => $slug]); @@ -234,7 +234,7 @@ public function findSlug(SelectQuery $query, string $slug): SelectQuery Once our behavior has the above method we can call it: -``` php +```php $article = $articles->find('slug', slug: $value)->first(); ``` @@ -246,7 +246,7 @@ these cases you can use the `implementedFinders` configuration key to rename or exclude finder methods. For example if we wanted to rename our `find(slug)` method we could do the following: -``` php +```php protected array $_defaultConfig = [ 'implementedFinders' => [ 'slugged' => 'findSlug', @@ -262,7 +262,7 @@ in the configuration. Since the exposed methods are decided by configuration you can also rename/remove finder methods when adding a behavior to a table. For example: -``` php +```php // In a table's initialize() method. $this->addBehavior('Sluggable', [ 'implementedFinders' => [ @@ -277,7 +277,7 @@ Behaviors can define logic for how the custom fields they provide are marshalled by implementing the `Cake\ORM\PropertyMarshalInterface`. This interface requires a single method to be implemented: -``` php +```php public function buildMarshalMap(Marshaller $marshaller, array $map, array $options): array { return [ @@ -296,7 +296,7 @@ that you might want to refer to. To remove a behavior from your table you can call the `removeBehavior()` method: -``` php +```php // Remove the loaded behavior $this->removeBehavior('Sluggable'); ``` @@ -306,7 +306,7 @@ $this->removeBehavior('Sluggable'); Once you've attached behaviors to your Table instance you can introspect the loaded behaviors, or access specific behaviors using the `BehaviorRegistry`: -``` php +```php // See which behaviors are loaded $table->behaviors()->loaded(); @@ -330,7 +330,7 @@ behavior you could do the following to add, modify or remove the configurations for the behavior. In this case, we will add an event we want Timestamp to respond to: -``` php +```php namespace App\Model\Table; use App\Model\Table\AppTable; // similar to AppController diff --git a/docs/en/orm/behaviors/counter-cache.md b/docs/en/orm/behaviors/counter-cache.md index bfffadaecc..f1304b008b 100644 --- a/docs/en/orm/behaviors/counter-cache.md +++ b/docs/en/orm/behaviors/counter-cache.md @@ -22,7 +22,7 @@ anything until you configure some relations and the field counts that should be stored on each of them. Using our example below, we could cache the comment count for each article with the following: -``` php +```php class CommentsTable extends Table { public function initialize(array $config): void @@ -59,7 +59,7 @@ If you need to keep a cached counter for less than all the related records, you can supply additional conditions or finder methods to generate a counter value: -``` php +```php // Use a specific find method. // In this case find(published) $this->addBehavior('CounterCache', [ @@ -74,7 +74,7 @@ $this->addBehavior('CounterCache', [ If you don't have a custom finder method you can provide an array of conditions to find records instead: -``` php +```php $this->addBehavior('CounterCache', [ 'Articles' => [ 'comment_count' => [ @@ -87,7 +87,7 @@ $this->addBehavior('CounterCache', [ If you want CounterCache to update multiple fields, for example both showing a conditional count and a basic count you can add these fields in the array: -``` php +```php $this->addBehavior('CounterCache', [ 'Articles' => ['comment_count', 'published_comment_count' => [ @@ -102,7 +102,7 @@ the `ignoreDirty` option to `true`. This will prevent the field from being recalculated if you've set it dirty before: -``` php +```php $this->addBehavior('CounterCache', [ 'Articles' => [ 'comment_count' => [ @@ -115,7 +115,7 @@ $this->addBehavior('CounterCache', [ Lastly, if a custom finder and conditions are not suitable you can provide a callback function. Your function must return the count value to be stored: -``` php +```php $this->addBehavior('CounterCache', [ 'Articles' => [ 'rating_avg' => function ($event, $entity, $table, $original) { @@ -150,7 +150,7 @@ It is possible to use the CounterCache behavior in a `belongsToMany` association First, you need to add the `through` and `cascadeCallbacks` options to the `belongsToMany` association: -``` php +```php 'through' => 'CommentsArticles', 'cascadeCallbacks' => true, ``` @@ -163,7 +163,7 @@ If you don't have it you should create it with the bake CLI tool. In this `src/Model/Table/CommentsArticlesTable.php` you then need to add the behavior with the same code as described above. -``` php +```php $this->addBehavior('CounterCache', [ 'Articles' => ['comments_count'], ]); @@ -179,7 +179,7 @@ The `updateCounterCache()` method allows you to update the counter cache values for all records of one or all configured associations in batches. This can be useful, for example, to update the counter cache after importing data directly into the database. -``` php +```php // Update the counter cache for all configured associations $table->getBehavior('CounterCache')->updateCounterCache(); diff --git a/docs/en/orm/behaviors/timestamp.md b/docs/en/orm/behaviors/timestamp.md index a0bb97186a..df9ed2f754 100644 --- a/docs/en/orm/behaviors/timestamp.md +++ b/docs/en/orm/behaviors/timestamp.md @@ -17,7 +17,7 @@ publishes. You enable the timestamp behavior like any other behavior: -``` php +```php class ArticlesTable extends Table { public function initialize(array $config): void @@ -38,7 +38,7 @@ The default configuration will do the following: If you need to modify fields with different names, or want to update additional timestamp fields on custom events you can use some additional configuration: -``` php +```php class OrdersTable extends Table { public function initialize(array $config): void @@ -67,7 +67,7 @@ Sometimes you'll want to update just the timestamps on an entity without changing any other properties. This is sometimes referred to as 'touching' a record. In CakePHP you can use the `touch()` method to do exactly this: -``` php +```php // Touch based on the Model.beforeSave event. $articles->getBehavior('Timestamp')->touch($article); @@ -86,7 +86,7 @@ article when a new comment is added. To disable the automatic modification of the `updated` timestamp column when saving an entity you can mark the attribute as 'dirty': -``` php +```php // Mark the modified column as dirty making // the current value be set on update. $order->setDirty('modified', true); diff --git a/docs/en/orm/behaviors/translate.md b/docs/en/orm/behaviors/translate.md index ad4739b17e..b2fb709f83 100644 --- a/docs/en/orm/behaviors/translate.md +++ b/docs/en/orm/behaviors/translate.md @@ -29,7 +29,7 @@ The behavior offers two strategies for how the translations are stored. Let's assume we have an `articles` table and we want it's `title` and `body` fields to be translated. For that we create a shadow table `articles_translations`: -``` sql +```sql CREATE TABLE `articles_translations` ( `id` int(11) NOT NULL, `locale` varchar(5) NOT NULL, @@ -65,7 +65,7 @@ In order to use the Eav strategy, you need to create a `i18n` table with the correct schema. Currently the only way of loading the `i18n` table is by manually running the following SQL script in your database: -``` sql +```sql CREATE TABLE i18n ( id int NOT NULL auto_increment, locale varchar(6) NOT NULL, @@ -86,7 +86,7 @@ The schema is also available as sql file in **/config/schema/i18n.sql**. Attaching the behavior can be done in the `initialize()` method in your Table class: -``` php +```php class ArticlesTable extends Table { public function initialize(array $config): void @@ -103,7 +103,7 @@ behavior can infer the fields from the shadow table columns. If you want to use the `EavStrategy` then you can configure the behavior as: -``` php +```php class ArticlesTable extends Table { public function initialize(array $config): void @@ -124,7 +124,7 @@ By default, the locale specified in `App.defaultLocale` config is used as defaul locale for the `TranslateBehavior`. You can override that by setting `defaultLocale` config of the behavior: -``` php +```php class ArticlesTable extends Table { public function initialize(array $config): void @@ -144,28 +144,28 @@ same API to manage translations. Now, select a language to be used for retrieving entities by changing the application language, which will affect all translations: -``` php +```php // In the Articles controller. Change the locale to Spanish, for example I18n::setLocale('es'); ``` Then, get an existing entity: -``` php +```php $article = $this->Articles->get(12); echo $article->title; // Echoes 'A title', not translated yet ``` Next, translate your entity: -``` php +```php $article->title = 'Un Artículo'; $this->Articles->save($article); ``` You can try now getting your entity again: -``` php +```php $article = $this->Articles->get(12); echo $article->title; // Echoes 'Un Artículo', yay piece of cake! ``` @@ -173,7 +173,7 @@ echo $article->title; // Echoes 'Un Artículo', yay piece of cake! Working with multiple translations can be done by using a special trait in your Entity class: -``` php +```php use Cake\ORM\Behavior\Translate\TranslateTrait; use Cake\ORM\Entity; @@ -185,7 +185,7 @@ class Article extends Entity Now you can find all translations for a single entity: -``` php +```php $article = $this->Articles->find('translations')->first(); echo $article->translation('es')->title; // 'Un Artículo' @@ -194,7 +194,7 @@ echo $article->translation('en')->title; // 'An Article'; And save multiple translations at once: -``` php +```php $article->translation('es')->title = 'Otro Título'; $article->translation('fr')->title = 'Un autre Titre'; $this->Articles->save($article); @@ -211,7 +211,7 @@ table in the behavior's configuration. This is common when you have multiple tables to translate and you want a cleaner separation of the data that is stored for each different table: -``` php +```php class ArticlesTable extends Table { public function initialize(array $config): void @@ -232,7 +232,7 @@ You need to make sure that any custom table you use has the columns `field`, As shown above you can use the `setLocale()` method to choose the active translation for entities that are loaded: -``` php +```php // Load I18n core functions at the beginning of your Articles Controller: use Cake\I18n\I18n; @@ -246,7 +246,7 @@ $results = $this->Articles->find()->all(); This method works with any finder in your tables. For example, you can use TranslateBehavior with `find('list')`: -``` php +```php I18n::setLocale('es'); $data = $this->Articles->find('list')->toArray(); @@ -263,7 +263,7 @@ When building interfaces for updating translated content, it is often helpful to show one or more translation(s) at the same time. You can use the `translations` finder for this: -``` php +```php // Find the first article with all corresponding translations $article = $this->Articles->find('translations')->first(); ``` @@ -272,7 +272,7 @@ In the example above you will get a list of entities back that have a `_translations` property set. This property will contain a list of translation data entities. For example the following properties would be accessible: -``` php +```php // Outputs 'en' echo $article->_translations['en']->locale; @@ -286,7 +286,7 @@ echo $article->_translations['en']->body; A more elegant way for dealing with this data is by adding a trait to the entity class that is used for your table: -``` php +```php use Cake\ORM\Behavior\Translate\TranslateTrait; use Cake\ORM\Entity; @@ -299,7 +299,7 @@ class Article extends Entity This trait contains a single method called `translation`, which lets you access or create new translation entities on the fly: -``` php +```php // Outputs 'title' echo $article->translation('en')->title; @@ -312,7 +312,7 @@ $article->translation('de')->title = 'Wunderbar'; You can limit the languages that are fetched from the database for a particular set of records: -``` php +```php $results = $this->Articles->find('translations', locales: ['en', 'es']); $article = $results->first(); $spanishTranslation = $article->translation('es'); @@ -328,7 +328,7 @@ this to overwrite the original field value. If this is undesired, you can ignore translations which are empty using the `allowEmptyTranslations` config key: -``` php +```php class ArticlesTable extends Table { public function initialize(array $config): void @@ -348,7 +348,7 @@ The above would only load translated data that had content. It is also possible to find translations for any association in a single find operation: -``` php +```php $article = $this->Articles->find('translations')->contain([ 'Categories' => function ($query) { return $query->find('translations'); @@ -384,7 +384,7 @@ Note that this only changes the locale of the Articles table, it would not affect the language of associated data. To affect associated data it's necessary to call the method on each table, for example: -``` php +```php I18n::setLocale('en'); // reset for illustration $this->Articles->getBehavior('Translate')->setLocale('es'); @@ -401,7 +401,7 @@ to it. TranslateBehavior does not substitute find conditions by default. You need to use `translationField()` method to compose find conditions on translated fields: -``` php +```php $this->Articles->getBehavior('Translate')->setLocale('es'); $query = $this->Articles->find()->where([ $this->Articles->getBehavior('Translate')->translationField('title') => 'Otro Título', @@ -415,7 +415,7 @@ representing the default language, and multiple translations that can override certain fields in such entity. Keeping this in mind, you can intuitively save translations for any given entity. For example, given the following setup: -``` php +```php // in src/Model/Table/ArticlesTable.php class ArticlesTable extends Table { @@ -445,7 +445,7 @@ So, after you save your first article, you can now save a translation for it, there are a couple ways to do it. The first one is setting the language directly into the entity: -``` php +```php $article->_locale = 'es'; $article->title = 'Mi primer Artículo'; @@ -456,7 +456,7 @@ After the entity has been saved, the translated field will be persisted as well, one thing to note is that values from the default language that were not overridden will be preserved: -``` php +```php // Outputs 'This is the content' echo $article->body; @@ -467,7 +467,7 @@ echo $article->title; Once you override the value, the translation for that field will be saved and can be retrieved as usual: -``` php +```php $article->body = 'El contendio'; $this->Articles->save($article); ``` @@ -475,7 +475,7 @@ $this->Articles->save($article); The second way to use for saving entities in another language is to set the default language directly to the table: -``` php +```php $article->title = 'Mi Primer Artículo'; $this->Articles->getBehavior('Translate')->setLocale('es'); @@ -492,7 +492,7 @@ It is a common requirement to be able to add or edit multiple translations to any database record at the same time. This can be done using the `TranslateTrait`: -``` php +```php use Cake\ORM\Behavior\Translate\TranslateTrait; use Cake\ORM\Entity; @@ -504,7 +504,7 @@ class Article extends Entity Now, You can populate translations before saving them: -``` php +```php $translations = [ 'fr' => ['title' => "Un article"], 'es' => ['title' => 'Un artículo'], @@ -519,7 +519,7 @@ $this->Articles->save($article); And create form controls for your translated fields: -``` php +```php // In a view template. Form->create($article); ?>
    @@ -536,7 +536,7 @@ And create form controls for your translated fields: In your controller, you can marshal the data as normal: -``` php +```php $article = $this->Articles->newEntity($this->request->getData()); $this->Articles->save($article); ``` @@ -551,7 +551,7 @@ When attaching `TranslateBehavior` to a model, you can define the validator that should be used when translation records are created/modified by the behavior during `newEntity()` or `patchEntity()`: -``` php +```php class ArticlesTable extends Table { public function initialize(array $config): void diff --git a/docs/en/orm/behaviors/tree.md b/docs/en/orm/behaviors/tree.md index 77a47c3149..b94da5f361 100644 --- a/docs/en/orm/behaviors/tree.md +++ b/docs/en/orm/behaviors/tree.md @@ -50,7 +50,7 @@ in this article describing the [MPTT logic](https://www.sitepoint.com/hierarchic You enable the Tree behavior by adding it to the Table you want to store hierarchical data in: -``` php +```php class CategoriesTable extends Table { public function initialize(array $config): void @@ -63,7 +63,7 @@ class CategoriesTable extends Table Once added, you can let CakePHP build the internal structure if the table is already holding some rows: -``` php +```php // In a controller $categories = $this->getTableLocator()->get('Categories'); $categories->recover(); @@ -72,7 +72,7 @@ $categories->recover(); You can verify it works by getting any row from the table and asking for the count of descendants it has: -``` php +```php $node = $categories->get(1); echo $categories->getBehavior('Tree')->childCount($node); ``` @@ -81,7 +81,7 @@ echo $categories->getBehavior('Tree')->childCount($node); Getting a flat list of the descendants for a node can be done with: -``` php +```php $descendants = $categories->find('children', for: 1); foreach ($descendants as $category) { @@ -91,7 +91,7 @@ foreach ($descendants as $category) { If you need to pass conditions you do so as per normal: -``` php +```php $descendants = $categories ->find('children', for: 1) ->where(['name LIKE' => '%Foo%']) @@ -105,7 +105,7 @@ foreach ($descendants as $category) { If you instead need a threaded list, where children for each node are nested in a hierarchy, you can stack the 'threaded' finder: -``` php +```php $children = $categories ->find('children', for: 1) ->find('threaded') @@ -129,7 +129,7 @@ only require a result set containing a single field from each level so you can display a list, in an HTML select for example, it is better to use the `treeList` finder: -``` php +```php $list = $categories->find('treeList')->toArray(); // In a CakePHP template file: @@ -163,7 +163,7 @@ The `treeList` finder takes a number of options: An example of all options in use is: -``` php +```php $query = $categories->find('treeList', keyPath: 'url', valuePath: 'id', @@ -173,7 +173,7 @@ $query = $categories->find('treeList', An example using closure: -``` php +```php $query = $categories->find('treeList', valuePath: function($entity){ return $entity->url . ' ' . $entity->id @@ -187,7 +187,7 @@ One very common task is to find the tree path from a particular node to the root of the tree. This is useful, for example, for adding the breadcrumbs list for a menu structure: -``` php +```php $nodeId = 5; $crumbs = $categories->find('path', for: $nodeId)->all(); @@ -201,7 +201,7 @@ than `lft`, this is because the internal representation of the tree depends on this sorting. Luckily, you can reorder the nodes inside the same level without having to change their parent: -``` php +```php $node = $categories->get(5); // Move the node so it shows up one position up when listing children. @@ -219,7 +219,7 @@ $categories->getBehavior('Tree')->moveDown($node, true); If the default column names that are used by this behavior don't match your own schema, you can provide aliases for them: -``` php +```php public function initialize(array $config): void { $this->addBehavior('Tree', [ @@ -236,7 +236,7 @@ Knowing the depth of tree nodes can be useful when you want to retrieve nodes only up to a certain level, for example, when generating menus. You can use the `level` option to specify the field that will save level of each node: -``` php +```php $this->addBehavior('Tree', [ 'level' => 'level', // Defaults to null, i.e. no level saving ]); @@ -251,7 +251,7 @@ Sometimes you want to persist more than one tree structure inside the same table, you can achieve that by using the 'scope' configuration. For example, in a locations table you may want to create one tree per country: -``` php +```php class LocationsTable extends Table { public function initialize(array $config): void @@ -267,14 +267,14 @@ In the previous example, all tree operations will be scoped to only the rows having the column `country_name` set to 'Brazil'. You can change the scoping on the fly by using the 'config' function: -``` php +```php $this->getBehavior('Tree')->setConfig('scope', ['country_name' => 'France']); ``` Optionally, you can have a finer grain control of the scope by passing a closure as the scope: -``` php +```php $this->getBehavior('Tree')->setConfig('scope', function ($query) { $country = $this->getConfigureContry(); // A made-up function return $query->where(['country_name' => $country]); @@ -288,7 +288,7 @@ the entities that are going to be deleted. Once loaded, these entities will be deleted individually using `Table::delete()`. This enables ORM callbacks to be fired when tree nodes are deleted: -``` php +```php $this->addBehavior('Tree', [ 'cascadeCallbacks' => true, ]); @@ -303,7 +303,7 @@ use UUIDs. If you need custom sorting for the recovery, you can set a custom order clause in your config: -``` php +```php $this->addBehavior('Tree', [ 'recoverOrder' => ['country_name' => 'DESC'], ]); @@ -316,7 +316,7 @@ internal representation of the hierarchical structure. The positions where nodes are placed in the tree are deduced from the `parent_id` column in each of your entities: -``` php +```php $aCategory = $categoriesTable->get(10); $aCategory->parent_id = 5; $categoriesTable->save($aCategory); @@ -328,7 +328,7 @@ the tree (making a node child of itself) will throw an exception. You can make a node into a root in the tree by setting the `parent_id` column to null: -``` php +```php $aCategory = $categoriesTable->get(10); $aCategory->parent_id = null; $categoriesTable->save($aCategory); @@ -341,7 +341,7 @@ Children for the new root node will be preserved. Deleting a node and all its sub-tree (any children it may have at any depth in the tree) is trivial: -``` php +```php $aCategory = $categoriesTable->get(10); $categoriesTable->delete($aCategory); ``` @@ -350,7 +350,7 @@ The TreeBehavior will take care of all internal deleting operations for you. It is also possible to only delete one node and re-assign all children to the immediately superior parent node in the tree: -``` php +```php $aCategory = $categoriesTable->get(10); $categoriesTable->getBehavior('Tree')->removeFromTree($aCategory); $categoriesTable->delete($aCategory); @@ -362,7 +362,7 @@ The deletion of a node is based off of the `lft` and `rght` values of the entity is important to note when looping through the various children of a node for conditional deletes: -``` php +```php $descendants = $teams->find('children', for: 1)->all(); foreach ($descendants as $descendant) { diff --git a/docs/en/orm/database-basics.md b/docs/en/orm/database-basics.md index 9c741d23f8..d5ec1e9c3b 100644 --- a/docs/en/orm/database-basics.md +++ b/docs/en/orm/database-basics.md @@ -19,7 +19,7 @@ complete ORM, you can read the [Query Builder](../orm/query-builder) and The easiest way to create a database connection is using a `DSN` string: -``` php +```php use Cake\Datasource\ConnectionManager; $dsn = 'mysql://root:password@localhost/my_database'; @@ -28,7 +28,7 @@ ConnectionManager::setConfig('default', ['url' => $dsn]); Once created, you can access the connection object to start using it: -``` php +```php $connection = ConnectionManager::get('default'); ``` @@ -39,7 +39,7 @@ $connection = ConnectionManager::get('default'); Running raw SQL queries is a breeze: -``` php +```php use Cake\Datasource\ConnectionManager; $connection = ConnectionManager::get('default'); @@ -48,7 +48,7 @@ $results = $connection->execute('SELECT * FROM articles')->fetchAll('assoc'); You can use prepared statements to insert parameters: -``` php +```php $results = $connection ->execute('SELECT * FROM articles WHERE id = :id', ['id' => 1]) ->fetchAll('assoc'); @@ -56,7 +56,7 @@ $results = $connection It is also possible to use complex data types as arguments: -``` php +```php use Cake\Datasource\ConnectionManager; use DateTime; @@ -72,7 +72,7 @@ $results = $connection Instead of writing the SQL manually, you can use the query builder: -``` php +```php // Prior to 4.5 use $connection->query() instead. $results = $connection ->selectQuery('*', 'articles') @@ -86,7 +86,7 @@ $results = $connection Inserting rows in the database is usually a matter of a couple lines: -``` php +```php use Cake\Datasource\ConnectionManager; use DateTime; @@ -102,7 +102,7 @@ $connection->insert('articles', [ Updating rows in the database is equally intuitive, the following example will update the article with **id** 10: -``` php +```php use Cake\Datasource\ConnectionManager; $connection = ConnectionManager::get('default'); $connection->update('articles', ['title' => 'New title'], ['id' => 10]); @@ -113,7 +113,7 @@ $connection->update('articles', ['title' => 'New title'], ['id' => 10]); Similarly, the `delete()` method is used to delete rows from the database, the following example deletes the article with **id** 10: -``` php +```php use Cake\Datasource\ConnectionManager; $connection = ConnectionManager::get('default'); $connection->delete('articles', ['id' => 10]); @@ -130,7 +130,7 @@ your application will be using. Sample connection information can be found in **config/app.default.php**. A sample connection configuration would look like: -``` php +```php 'Datasources' => [ 'default' => [ 'className' => 'Cake\Database\Connection', @@ -153,7 +153,7 @@ also define additional connections at runtime using `Cake\Datasource\ConnectionManager::setConfig()`. An example of that would be: -``` php +```php use Cake\Datasource\ConnectionManager; ConnectionManager::setConfig('default', [ @@ -173,7 +173,7 @@ ConnectionManager::setConfig('default', [ Configuration options can also be provided as a `DSN` string. This is useful when working with environment variables or `PaaS` providers: -``` php +```php ConnectionManager::setConfig('default', [ 'url' => 'mysql://my_app:sekret@localhost/my_app?encoding=utf8&timezone=UTC&cacheMetadata=true', ]); @@ -322,7 +322,7 @@ Role configurations override the values in the shared connection config. If the and write role configurations are the same, a single connection to the database is used for both: -``` php +```php 'default' => [ 'driver' => 'mysql', 'username' => '...', @@ -357,7 +357,7 @@ Once configured connections can be fetched using construct and load a connection if it has not been built before, or return the existing known connection: -``` php +```php use Cake\Datasource\ConnectionManager; $connection = ConnectionManager::get('default'); @@ -370,7 +370,7 @@ Attempting to load connections that do not exist will throw an exception. Using `setConfig()` and `get()` you can create new connections that are not defined in your configuration files at runtime: -``` php +```php ConnectionManager::setConfig('my_connection', $config); $connection = ConnectionManager::get('my_connection'); ``` @@ -539,7 +539,7 @@ vice versa. Can be used to map datetime columns that contain microseconds such as `DATETIME(6)` in MySQL. To use this type you need to add it as a mapped type: -``` php +```php // in config/bootstrap.php use Cake\Database\TypeFactory; use Cake\Database\Type\DateTimeFractionalType; @@ -553,7 +553,7 @@ TypeFactory::map('datetime', DateTimeFractionalType::class); Can be used to map datetime columns that contain time zones such as `TIMESTAMPTZ` in PostgreSQL. To use this type you need to add it as a mapped type: -``` php +```php // in config/bootstrap.php use Cake\Database\TypeFactory; use Cake\Database\Type\DateTimeTimezoneType; @@ -569,7 +569,7 @@ TypeFactory::map('datetime', DateTimeTimezoneType::class); Maps a [BackedEnum](https://www.php.net/manual/en/language.enumerations.backed.php) to a string or integer column. To use this type you need to specify which column is associated to which BackedEnum inside the table class: -``` php +```php use App\Model\Enum\ArticleStatus; use Cake\Database\Type\EnumType; @@ -584,7 +584,7 @@ public function initialize(array $config): void A simple `ArticleStatus` could look like: -``` php +```php namespace App\Model\Enum; enum ArticleStatus: string @@ -597,7 +597,7 @@ enum ArticleStatus: string CakePHP also provides the `EnumLabelInterface` which can be implemented by Enums that want to provide a map of human-readable labels: -``` php +```php namespace App\Model\Enum; use Cake\Database\Type\EnumLabelInterface; @@ -620,7 +620,7 @@ enum ArticleStatus: string implements EnumLabelInterface This can be useful if you want to use your enums in `FormHelper` select inputs. You can use [bake](../bake) to generate an enum class: -``` bash +```bash # generate an enum class with two cases and stored as an integer bin/cake bake enum UserStatus inactive:0,active:1 -i @@ -659,7 +659,7 @@ Geospatial schema types were added. You can retrieve the mapped class name for a specific type using `getMapped()`: -``` php +```php use Cake\Database\TypeFactory; // Returns the class name mapped to the 'datetime' type @@ -683,7 +683,7 @@ To fulfill the basic interface, extend `Cake\Database\Type`. For example if we wanted to add a PointMutation type, we could make the following type class: -``` php +```php // in src/Database/Type/PointMutationType.php namespace App\Database\Type; @@ -749,7 +749,7 @@ work for our new type. Once we've created our new type, we need to add it into the type mapping. During our application bootstrap we should do the following: -``` php +```php use Cake\Database\TypeFactory; TypeFactory::map('point_mutation', \App\Database\Type\PointMutationType:class); @@ -767,7 +767,7 @@ Table's [getSchema() method](../orm/saving-data#saving-complex-types) add the following: -``` php +```php class WidgetsTable extends Table { public function initialize(array $config): void @@ -783,7 +783,7 @@ datatype has an unambiguous SQL column definition. For example, we could have our PointMutation type be used anytime a `TEXT` column with a specific comment is used: -``` php +```php // in src/Database/Type/PointMutationType.php namespace App\Database\Type; @@ -857,7 +857,7 @@ build a simple Type class for handling `POINT` type data out of MySQL. First we'll define a 'value' object that we can use to represent `POINT` data in PHP: -``` php +```php // in src/Database/Point.php namespace App\Database; @@ -897,7 +897,7 @@ class Point With our value object created, we'll need a Type class to map data into this value object and into SQL expressions: -``` php +```php namespace App\Database\Type; use App\Database\Point; @@ -986,13 +986,13 @@ PDO. There are a few different ways you can run queries depending on the type of query you need to run and what kind of results you need back. The most basic method is `execute()` which allows you to run complet SQL queries: -``` php +```php $statement = $connection->execute('UPDATE articles SET published = 1 WHERE id = 2'); ``` For parameterized queries use the 2nd argument: -``` php +```php $statement = $connection->execute( 'UPDATE articles SET published = ? WHERE id = ?', [1, 2], @@ -1003,7 +1003,7 @@ Without any type hinting information, `execute` will assume all placeholders are string values. If you need to bind specific types of data, you can use their abstract type names when creating a query: -``` php +```php $statement = $connection->execute( 'UPDATE articles SET published_date = ? WHERE id = ?', [new DateTime('now'), 2], @@ -1021,7 +1021,7 @@ query builder, no SQL will be sent to the database server until the `execute()` method is called, or the query is iterated. Iterating a query will first execute it and then start iterating over the result set: -``` php +```php $query = $connection->selectQuery(); $query->select('*') ->from('articles') @@ -1040,7 +1040,7 @@ foreach ($query as $row) { This method provides you a builder for `UPDATE` queries: -``` php +```php $query = $connection->updateQuery('articles') ->set(['published' => true]) ->where(['id' => 2]); @@ -1051,7 +1051,7 @@ $statement = $query->execute(); This method provides you a builder for `INSERT` queries: -``` php +```php $query = $connection->insertQuery(); $query->into('articles') ->columns(['title']) @@ -1063,7 +1063,7 @@ $statement = $query->execute(); This method provides you a builder for `DELETE` queries: -``` php +```php $query = $connection->deleteQuery(); $query->delete('articles') ->where(['id' => 2]); @@ -1076,7 +1076,7 @@ The connection objects provide you a few simple ways you do database transactions. The most basic way of doing transactions is through the `begin()`, `commit()` and `rollback()` methods, which map to their SQL equivalents: -``` php +```php $connection->begin(); $connection->execute('UPDATE articles SET published = ? WHERE id = ?', [true, 2]); $connection->execute('UPDATE articles SET published = ? WHERE id = ?', [false, 4]); @@ -1089,7 +1089,7 @@ In addition to this interface connection instances also provide the `transactional()` method which makes handling the begin/commit/rollback calls much simpler: -``` php +```php $connection->transactional(function ($connection) { $connection->execute('UPDATE articles SET published = ? WHERE id = ?', [true, 2]); $connection->execute('UPDATE articles SET published = ? WHERE id = ?', [false, 4]); @@ -1119,7 +1119,7 @@ from the driver. After creating and executing a query object, or using Once a query is executed using `execute()`, results can be fetched using `fetch()`, `fetchAll()`: -``` php +```php $statement->execute(); // Read one row. @@ -1133,7 +1133,7 @@ $rows = $statement->fetchAll('assoc'); After executing a statement, you can fetch the number of affected rows: -``` php +```php $rowCount = $statement->rowCount(); ``` @@ -1143,7 +1143,7 @@ If your query was not successful, you can get related error information using the `errorCode()` and `errorInfo()` methods. These methods work the same way as the ones provided by PDO: -``` php +```php $code = $statement->errorCode(); $info = $statement->errorInfo(); ``` @@ -1161,7 +1161,7 @@ You will need to have a logger configured to capture this level & scope. Logging to `stderr` can be useful when working on unit tests, and logging to files/syslog can be useful when working with web requests: -``` php +```php use Cake\Log\Log; // Console logging @@ -1198,7 +1198,7 @@ If you are using a legacy schema that requires identifier quoting you can enable it using the `quoteIdentifiers` setting in your [Database Configuration](#database-configuration). You can also enable this feature at runtime: -``` php +```php $connection->getDriver()->enableAutoQuoting(); ``` @@ -1219,7 +1219,7 @@ metadata is stored in the `_cake_model_` cache configuration. You can define a custom cache configuration using the `cacheMetatdata` option in your datasource configuration: -``` php +```php 'Datasources' => [ 'default' => [ // Other keys go here. @@ -1233,7 +1233,7 @@ datasource configuration: You can also configure the metadata caching at runtime with the `cacheMetadata()` method: -``` php +```php // Disable the cache $connection->cacheMetadata(false); @@ -1252,7 +1252,7 @@ CakePHP also includes a CLI tool for managing metadata caches. See the If you want to create a connection without selecting a database you can omit the database name: -``` php +```php $dsn = 'mysql://root:password@localhost/'; ConnectionManager::setConfig('setup', ['url' => $dsn]); ``` @@ -1260,7 +1260,7 @@ ConnectionManager::setConfig('setup', ['url' => $dsn]); You can now use your connection object to execute queries that create/modify databases. For example to create a database: -``` php +```php $connection = ConnectionManager::get('setup'); $connection->execute("CREATE DATABASE IF NOT EXISTS my_database"); ``` diff --git a/docs/en/orm/deleting-data.md b/docs/en/orm/deleting-data.md index 1e36afc82e..812f08256c 100644 --- a/docs/en/orm/deleting-data.md +++ b/docs/en/orm/deleting-data.md @@ -14,7 +14,7 @@ description: "Delete data in CakePHP ORM. Remove single entities, cascade delete Once you've loaded an entity you can delete it by calling the originating table's delete method: -``` php +```php // In a controller. $entity = $this->Articles->get(2); $result = $this->Articles->delete($entity); @@ -35,7 +35,7 @@ When deleting entities a few things happen: By default, all deletes happen within a transaction. You can disable the transaction with the atomic option: -``` php +```php $result = $this->Articles->delete($entity, ['atomic' => false]); ``` @@ -56,7 +56,7 @@ have the ORM load related entities, and delete them individually by setting the `cascadeCallbacks` option to `true`. A sample HasMany association with both these options enabled would be: -``` php +```php // In a Table's initialize method. $this->hasMany('Comments', [ 'dependent' => true, @@ -76,7 +76,7 @@ $this->hasMany('Comments', [ If you have an array of entities you want to delete you can use `deleteMany()` to delete them in a single transaction: -``` php +```php // Get a boolean indicating success $success = $this->Articles->deleteMany($entities); @@ -95,7 +95,7 @@ There may be times when deleting rows one by one is not efficient or useful. In these cases it is more performant to use a bulk-delete to remove many rows at once: -``` php +```php // Delete all the spam public function destroySpam() { @@ -126,7 +126,7 @@ Using this method will throw an If you want to track down the entity that failed to delete, you can use the `Cake\ORM\Exception\PersistenceFailedException::getEntity()` method: -``` php +```php try { $table->deleteOrFail($entity); } catch (\Cake\ORM\Exception\PersistenceFailedException $e) { diff --git a/docs/en/orm/entities.md b/docs/en/orm/entities.md index 48e69719a7..e8ae9bce5c 100644 --- a/docs/en/orm/entities.md +++ b/docs/en/orm/entities.md @@ -23,7 +23,7 @@ However, if you want to have custom logic in your entities you will need to create classes. By convention entity classes live in **src/Model/Entity/**. If our application had an `articles` table we could create the following entity: -``` php +```php // src/Model/Entity/Article.php namespace App\Model\Entity; @@ -44,7 +44,7 @@ articles table, we'll get instances of this class. Entities can be directly instantiated: -``` php +```php use App\Model\Entity\Article; $article = new Article(); @@ -53,7 +53,7 @@ $article = new Article(); When instantiating an entity you can pass the fields with the data you want to store in them: -``` php +```php use App\Model\Entity\Article; $article = new Article([ @@ -66,7 +66,7 @@ $article = new Article([ The preferred way of getting new entities is using the `newEmptyEntity()` method from the `Table` objects: -``` php +```php use Cake\ORM\Locator\LocatorAwareTrait; $article = $this->fetchTable('Articles')->newEmptyEntity(); @@ -90,7 +90,7 @@ $article = $this->fetchTable('Articles')->newEntity([ Entities provide a few ways to access the data they contain. Most commonly you will access the data in an entity using object notation: -``` php +```php use App\Model\Entity\Article; $article = new Article; @@ -110,7 +110,7 @@ You can also use the `get()` and `set()` methods. For example: -``` php +```php $article->set('title', 'This is my first post'); echo $article->get('title'); ``` @@ -121,7 +121,7 @@ echo $article->get('title'); Using `patch()` you can mass assign multiple fields at once: -``` php +```php $article->patch([ 'title' => 'My first post', 'body' => 'It is the best ever!', @@ -138,7 +138,7 @@ $article->patch([ You can check if fields are defined in your entities with `has()`: -``` php +```php $article = new Article([ 'title' => 'First post', 'user_id' => null, @@ -151,7 +151,7 @@ $article->has('undefined'); // false The `has()` method will return `true` if a field is defined. You can use `hasValue()` to check if a field contains a 'non-empty' value: -``` php +```php $article = new Article([ 'title' => 'First post', 'user_id' => null, @@ -175,7 +175,7 @@ If you often partially load entities you should enable strict-property access behavior to ensure you're not using properties that haven't been loaded. On a per-entity basis you can enable this behavior: -``` php +```php $article->requireFieldPresence(); ``` @@ -198,7 +198,7 @@ capitalized) of the field name. They receive the basic value stored in the `_fields` array as their only argument. For example: -``` php +```php namespace App\Model\Entity; use Cake\ORM\Entity; @@ -216,7 +216,7 @@ The example above converts the value of the `title` field to an uppercase version each time it is read. It would be run when getting the field through any of these two ways: -``` php +```php echo $article->title; // returns FOO instead of foo echo $article->get('title'); // returns FOO instead of foo ``` @@ -241,7 +241,7 @@ You can also use mutators to set other fields. When doing this, be careful to not introduce any loops, as CakePHP will not prevent infinitely looping mutator methods. For example: -``` php +```php namespace App\Model\Entity; use Cake\ORM\Entity; @@ -263,7 +263,7 @@ given value in the `slug` field and stores an uppercase version in the `title` field. It would be run when setting the field through any of these two ways: -``` php +```php $user->title = 'foo'; // sets slug field and stores FOO instead of foo $user->set('title', 'foo'); // sets slug field and stores FOO instead of foo ``` @@ -281,7 +281,7 @@ By defining accessors you can provide access to fields that do not actually exist. For example if your users table has `first_name` and `last_name` you could create a method for the full name: -``` php +```php namespace App\Model\Entity; use Cake\ORM\Entity; @@ -298,7 +298,7 @@ class User extends Entity You can access virtual fields as if they existed on the entity. The property name will be the lower case and underscored version of the method (`full_name`): -``` php +```php echo $user->full_name; echo $user->get('full_name'); ``` @@ -315,7 +315,7 @@ You may want to make code conditional based on whether or not fields have changed in an entity. For example, you may only want to validate fields when they change: -``` php +```php // See if the title has been modified. $article->isDirty('title'); ``` @@ -324,7 +324,7 @@ You can also flag fields as being modified. This is handy when appending into array fields as this wouldn't automatically mark the field as dirty, only exchanging completely would. -``` php +```php // Add a comment and mark the field as changed. $article->comments[] = $newComment; $article->setDirty('comments', true); @@ -336,7 +336,7 @@ the original value of the field if it has been modified or its actual value. You can also check for changes to any field in the entity: -``` php +```php // See if the entity has changed $article->isDirty(); ``` @@ -344,20 +344,20 @@ $article->isDirty(); To remove the dirty mark from fields in an entity, you can use the `clean()` method: -``` php +```php $article->clean(); ``` When creating a new entity, you can avoid the fields from being marked as dirty by passing an extra option: -``` php +```php $article = new Article(['title' => 'New Article'], ['markClean' => true]); ``` To get a list of all dirty fields of an `Entity` you may call: -``` php +```php $dirtyFields = $entity->getDirty(); ``` @@ -367,7 +367,7 @@ After you [save an entity](../orm/saving-data#saving-entities) any validation er stored on the entity itself. You can access any validation errors using the `getErrors()`, `getError()` or `hasErrors()` methods: -``` php +```php // Get all the errors $errors = $user->getErrors(); @@ -384,7 +384,7 @@ $user->hasErrors(false); The `setErrors()` or `setError()` method can also be used to set the errors on an entity, making it easier to test code that works with error messages: -``` php +```php $user->setError('password', ['Password is required']); $user->setErrors([ 'password' => ['Password is required'], @@ -406,7 +406,7 @@ The `_accessible` property allows you to provide a map of fields and whether or not they can be mass-assigned. The values `true` and `false` indicate whether a field can or cannot be mass-assigned: -``` php +```php namespace App\Model\Entity; use Cake\ORM\Entity; @@ -423,7 +423,7 @@ class Article extends Entity In addition to concrete fields there is a special `*` field which defines the fallback behavior if a field is not specifically named: -``` php +```php namespace App\Model\Entity; use Cake\ORM\Entity; @@ -446,7 +446,7 @@ class Article extends Entity When creating a new entity using the `new` keyword you can tell it to not protect itself against mass assignment: -``` php +```php use App\Model\Entity\Article; $article = new Article(['id' => 1, 'title' => 'Foo'], ['guard' => false]); @@ -457,7 +457,7 @@ $article = new Article(['id' => 1, 'title' => 'Foo'], ['guard' => false]); You can modify the list of guarded fields at runtime using the `setAccess()` method: -``` php +```php // Make user_id accessible. $article->setAccess('user_id', true); @@ -478,7 +478,7 @@ to the [Changing Accessible Fields](../orm/saving-data#changing-accessible-field There are some situations when you want to allow mass-assignment to guarded fields: -``` php +```php $article->patch($fields, ['guard' => false]); ``` @@ -490,7 +490,7 @@ field list for a single call to `patch()`. It is often necessary to know if an entity represents a row that is already in the database. In those situations use the `isNew()` method: -``` php +```php if (!$article->isNew()) { echo 'This article was saved already!'; } @@ -499,7 +499,7 @@ if (!$article->isNew()) { If you are certain that an entity has already been persisted, you can use `setNew()`: -``` php +```php $article->setNew(false); $article->setNew(true); @@ -533,7 +533,7 @@ community plugins to do so. We recommend [the LazyLoad Plugin](https://github.co After adding the plugin to your entity, you will be able to do the following: -``` php +```php $article = $this->Articles->findById($id); // The comments property was lazy loaded @@ -555,7 +555,7 @@ For example if we had SoftDeletable plugin, it could provide a trait. This trait could give methods for marking entities as 'deleted', the method `softDelete` could be provided by a trait: -``` php +```php // SoftDelete/Model/Entity/SoftDeleteTrait.php namespace SoftDelete\Model\Entity; @@ -572,7 +572,7 @@ trait SoftDeleteTrait You could then use this trait in your entity class by importing it and including it: -``` php +```php namespace App\Model\Entity; use Cake\ORM\Entity; @@ -589,7 +589,7 @@ class Article extends Entity When building APIs, you may often need to convert entities into arrays or JSON data. CakePHP makes this simple: -``` php +```php // Get an array. // Associations will be converted with toArray() as well. $array = $user->toArray(); @@ -611,7 +611,7 @@ arrays or JSON. In order to expose virtual fields you need to make them visible. When defining your entity class you can provide a list of virtual field that should be exposed: -``` php +```php namespace App\Model\Entity; use Cake\ORM\Entity; @@ -624,7 +624,7 @@ class User extends Entity This list can be modified at runtime using the `setVirtual()` method: -``` php +```php $user->setVirtual(['full_name', 'is_admin']); ``` @@ -635,7 +635,7 @@ example it is often unwise to expose password hashes or account recovery questions. When defining an entity class, define which fields should be hidden: -``` php +```php namespace App\Model\Entity; use Cake\ORM\Entity; @@ -648,7 +648,7 @@ class User extends Entity This list can be modified at runtime using the `setHidden()` method: -``` php +```php $user->setHidden(['password', 'recovery_question']); ``` diff --git a/docs/en/orm/query-builder.md b/docs/en/orm/query-builder.md index 3ab593942a..2ea7e22f1d 100644 --- a/docs/en/orm/query-builder.md +++ b/docs/en/orm/query-builder.md @@ -22,7 +22,7 @@ modified. You can also use a table's connection object to access the lower level query builder that does not include ORM features, if necessary. See the [Database Queries](../orm/database-basics#database-queries) section for more information: -``` php +```php use Cake\ORM\Locator\LocatorAwareTrait; $articles = $this->fetchTable('Articles'); @@ -34,7 +34,7 @@ $query = $articles->find(); When inside a controller, you can use the automatic table variable that is created using the conventions system: -``` php +```php // Inside ArticlesController.php $query = $this->Articles->find(); @@ -42,7 +42,7 @@ $query = $this->Articles->find(); ### Selecting Rows From A Table -``` php +```php use Cake\ORM\Locator\LocatorAwareTrait; $query = $this->fetchTable('Articles')->find(); @@ -60,14 +60,14 @@ Almost every method in a `SelectQuery` object will return the same query, this m that `SelectQuery` objects are lazy, and will not be executed unless you tell them to: -``` php +```php $query->where(['id' => 1]); // Return the same query object $query->orderBy(['title' => 'DESC']); // Still same object, no SQL executed ``` You can of course chain the methods you call on SelectQuery objects: -``` php +```php $query = $articles ->find() ->select(['id', 'name']) @@ -82,7 +82,7 @@ foreach ($query->all() as $article) { If you try to call `debug()` on a SelectQuery object, you will see its internal state and the SQL that will be executed in the database: -``` php +```php debug($articles->find()->where(['id' => 1])); // Outputs @@ -94,7 +94,7 @@ debug($articles->find()->where(['id' => 1])); You can execute a query directly without having to use `foreach` on it. The easiest way is to either call the `all()` or `toList()` methods: -``` php +```php $resultsIteratorObject = $articles ->find() ->where(['id >' => 1]) @@ -130,7 +130,7 @@ result in the query being executed and results returned to you. You can use the `first()` method to get the first result in the query: -``` php +```php $article = $articles ->find() ->where(['id' => 1]) @@ -141,7 +141,7 @@ debug($article->title); ### Getting A List Of Values From A Column -``` php +```php // Use the extract() method from the collections library // This executes the query as well $allTitles = $articles->find()->all()->extract('title'); @@ -153,7 +153,7 @@ foreach ($allTitles as $title) { You can also get a key-value list out of a query result: -``` php +```php $list = $articles->find('list')->all(); foreach ($list as $id => $title) { echo "$id : $title" @@ -170,7 +170,7 @@ that you visit the [Collection](../core-libraries/collections) section to improve your skills in efficiently traversing the results. The ResultSet (returned by calling the `SelectQuery`'s `all()` method) implements the collection interface: -``` php +```php // Use the combine() method from the collections library // This is equivalent to find('list') $keyValueList = $articles->find()->all()->combine('id', 'title'); @@ -220,7 +220,7 @@ database [query logging](../orm/database-basics#database-query-logging) on. CakePHP makes building `SELECT` queries simple. To limit the fields fetched, you can use the `select()` method: -``` php +```php $query = $articles->find(); $query->select(['id', 'title', 'body']); foreach ($query->all() as $row) { @@ -230,7 +230,7 @@ foreach ($query->all() as $row) { You can set aliases for fields by providing fields as an associative array: -``` php +```php // Results in SELECT id AS pk, title AS aliased_title, body ... $query = $articles->find(); $query->select(['pk' => 'id', 'aliased_title' => 'title', 'body']); @@ -238,7 +238,7 @@ $query->select(['pk' => 'id', 'aliased_title' => 'title', 'body']); To select distinct fields, you can use the `distinct()` method: -``` php +```php // Results in SELECT DISTINCT country FROM ... $query = $articles->find(); $query->select(['country']) @@ -247,7 +247,7 @@ $query->select(['country']) To set some basic conditions you can use the `where()` method: -``` php +```php // Conditions are combined with AND $query = $articles->find(); $query->where(['title' => 'First Post', 'published' => true]); @@ -263,7 +263,7 @@ anonymous function will receive an instance of `\Cake\Database\Expression\QueryExpression` as its first argument, and `\Cake\ORM\Query\SelectQuery` as its second: -``` php +```php $query = $articles->find(); $query->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->eq('published', true); @@ -278,7 +278,7 @@ more complex `WHERE` conditions. By default, a query will select all fields from a table, the exception is when you call the `select()` function yourself and pass certain fields: -``` php +```php // Only select id and title from the articles table $articles->find()->select(['id', 'title']); ``` @@ -287,7 +287,7 @@ If you wish to still select all fields from a table after having called `select($fields)`, you can pass the table instance to `select()` for this purpose: -``` php +```php // Only all fields from the articles table including // a calculated slug field. $query = $articlesTable->find(); @@ -299,7 +299,7 @@ $query You can use `selectAlso()` to select all fields on a table and *also* select some additional fields: -``` php +```php $query = $articlesTable->find(); $query->selectAlso(['count' => $query->func()->count('*')]); ``` @@ -307,7 +307,7 @@ $query->selectAlso(['count' => $query->func()->count('*')]); If you want to select all but a few fields on a table, you can use `selectAllExcept()`: -``` php +```php $query = $articlesTable->find(); // Get all fields except the published field. @@ -325,7 +325,7 @@ function you want. For example, `concat` is implemented differently in MySQL, PostgreSQL and SQL Server. Using the abstraction allows your code to be portable: -``` php +```php // Results in SELECT COUNT(*) count FROM ... $query = $articles->find(); $query->select(['count' => $query->func()->count('*')]); @@ -334,7 +334,7 @@ $query->select(['count' => $query->func()->count('*')]); Note that most of the functions accept an additional argument to specify the types to bind to the arguments and/or the return type, for example: -``` php +```php $query->select(['minDate' => $query->func()->min('date', ['date']); ``` @@ -403,7 +403,7 @@ you can use, literal arguments and bound parameters. Identifier/Literal paramete you to reference columns or other SQL literals. Bound parameters can be used to safely add user data to SQL functions. For example: -``` php +```php $query = $articles->find()->innerJoinWith('Categories'); $concat = $query->func()->concat([ 'Articles.title' => 'identifier', @@ -425,7 +425,7 @@ parameters allowing you to safely pass user data to the function. The above example generates something like this in MYSQL. -``` sql +```sql SELECT CONCAT( Articles.title, :c0, @@ -445,7 +445,7 @@ it directly through `func()` and still safely pass arguments and user data as described. Make sure you pass the appropriate argument type for custom functions or they will be treated as bound parameters: -``` php +```php $query = $articles->find(); $year = $query->func()->year([ 'created' => 'identifier', @@ -462,7 +462,7 @@ $query->select([ These custom function would generate something like this in MYSQL: -``` sql +```sql SELECT YEAR(created) as yearCreated, DATE_FORMAT(created, '%H:%i') as timeCreated FROM articles; @@ -475,7 +475,7 @@ FROM articles; To apply ordering, you can use the `orderBy()` method: -``` php +```php $query = $articles->find() ->orderBy(['title' => 'ASC', 'id' => 'ASC']); ``` @@ -485,7 +485,7 @@ appended. However, when using finders you may sometimes need to overwrite the `ORDER BY`. Set the second parameter of `orderBy()` (as well as `orderByAsc()` or `orderByDesc()`) to `SelectQuery::OVERWRITE` or to `true`: -``` php +```php $query = $articles->find() ->orderBy(['title' => 'ASC']); // Later, overwrite the ORDER BY clause instead of appending to it. @@ -496,7 +496,7 @@ $query = $articles->find() The `orderByAsc` and `orderByDesc` methods can be used when you need to sort on complex expressions: -``` php +```php $query = $articles->find(); $concat = $query->func()->concat([ 'title' => 'identifier', @@ -507,7 +507,7 @@ $query->orderByAsc($concat); To build complex order clauses, use a Closure to build order expressions: -``` php +```php $query->orderByAsc(function (QueryExpression $exp, SelectQuery $query) { return $exp->addCase(/* ... */); }); @@ -518,7 +518,7 @@ $query->orderByAsc(function (QueryExpression $exp, SelectQuery $query) { To limit the number of rows or set the row offset you can use the `limit()` and `page()` methods: -``` php +```php // Fetch rows 50 to 100 $query = $articles->find() ->limit(50) @@ -534,7 +534,7 @@ calls. When using aggregate functions like `count` and `sum` you may want to use `group by` and `having` clauses: -``` php +```php $query = $articles->find(); $query->select([ 'count' => $query->func()->count('view_count'), @@ -553,7 +553,7 @@ need to specific data based on a condition. If we wished to know how many published articles are in our database, we could use the following SQL: -``` sql +```sql SELECT COUNT(CASE WHEN published = 'Y' THEN 1 END) AS number_published, COUNT(CASE WHEN published = 'N' THEN 1 END) AS number_unpublished @@ -562,7 +562,7 @@ FROM articles To do this with the query builder, we'd use the following code: -``` php +```php $query = $articles->find(); $publishedCase = $query->expr() ->case() @@ -584,7 +584,7 @@ for when you need additional logic to build the cases. If we wanted to classify cities into SMALL, MEDIUM, or LARGE based on population size, we could do the following: -``` php +```php $query = $cities->find(); $sizing = $query->expr()->case() ->when(['population <' => 100000]) @@ -604,7 +604,7 @@ $query = $query->select(['size' => $sizing]); You need to be careful when including user provided data into case expressions as it can create SQL injection vulnerabilities: -``` php +```php // Unsafe do *not* use $case->when($requestData['published']); @@ -615,7 +615,7 @@ $case->when(['published' => $requestData['published']]); For more complex scenarios you can use `QueryExpression` objects and bound values: -``` php +```php $userValue = $query->expr() ->case() ->when($query->expr('population >= :userData')) @@ -631,13 +631,13 @@ By using bindings you can safely embed user data into complex raw SQL snippets. value type based on the parameter type. If you need to bind a value as a different type you can declare the desired type: -``` php +```php $case->when(['published' => true])->then('1', 'integer'); ``` You can create `if ... then ... else` conditions by using `else()`: -``` php +```php $published = $query->expr() ->case() ->when(['published' => true]) @@ -649,7 +649,7 @@ $published = $query->expr() Also, it's possible to create the simple variant by passing a value to `case()`: -``` php +```php $published = $query->expr() ->case($query->identifier('published')) ->when(true) @@ -665,7 +665,7 @@ The `addCase` function can also chain together multiple statements to create If we wanted to classify cities into SMALL, MEDIUM, or LARGE based on population size, we could do the following: -``` php +```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->addCase( @@ -688,7 +688,7 @@ $query = $cities->find() Any time there are fewer case conditions than values, `addCase` will automatically produce an `if .. then .. else` statement: -``` php +```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->addCase( @@ -710,7 +710,7 @@ unnecessary. For example, when accessing aggregated data, building an Entity may not make sense. The process of converting the database results to entities is called hydration. If you wish to disable this process you can do this: -``` php +```php $query = $articles->find(); $query->enableHydration(false); // Results as arrays instead of entities $result = $query->toList(); // Execute the query and return the array @@ -718,7 +718,7 @@ $result = $query->toList(); // Execute the query and return the array After executing those lines, your result should look similar to this: -``` php +```php [ ['id' => 1, 'title' => 'First Article', 'body' => 'Article 1 body' ...], ['id' => 2, 'title' => 'Second Article', 'body' => 'Article 2 body' ...], @@ -747,7 +747,7 @@ advantages: The `projectAs()` method allows you to specify a DTO class that results will be hydrated into: -``` php +```php // Define a DTO class readonly class ArticleDto { @@ -773,7 +773,7 @@ CakePHP supports two approaches for creating DTOs: **Reflection-based constructor mapping** - CakePHP will use reflection to map database columns to constructor parameters: -``` php +```php readonly class ArticleDto { public function __construct( @@ -788,7 +788,7 @@ readonly class ArticleDto **Factory method pattern** - If your DTO class has a `createFromArray()` static method, CakePHP will use that instead: -``` php +```php class ArticleDto { public int $id; @@ -815,7 +815,7 @@ hydration. You can project associated data into nested DTOs. Use the `#[CollectionOf]` attribute to specify the type of elements in array properties: -``` php +```php use Cake\ORM\Attribute\CollectionOf; readonly class ArticleDto @@ -862,7 +862,7 @@ control the output structure independently from your database schema. You can define a DTO that represents your API contract and include custom serialization logic: -``` php +```php readonly class ArticleApiResponse { public function __construct( @@ -922,7 +922,7 @@ control over the process, or want to reduce results you should use the [Map/Reduce](../orm/retrieving-data-and-resultsets#map-reduce) feature instead. If you were querying a list of people, you could calculate their age with a result formatter: -``` php +```php // Assuming we have built the fields, conditions and containments. $query->formatResults(function (\Cake\Collection\CollectionInterface $results) { return $results->map(function ($row) { @@ -945,7 +945,7 @@ within contained associations as well. CakePHP will ensure that your formatters are properly scoped. For example, doing the following would work as you may expect: -``` php +```php // In a method in the Articles table $query->contain(['Authors' => function ($q) { return $q->formatResults(function (\Cake\Collection\CollectionInterface $authors) { @@ -973,7 +973,7 @@ If you want to replace the results of an association finder with `preserveKeys` to retain keys when results are mapped to the parent query. For example: -``` php +```php public function findSlugged(SelectQuery $query): SelectQuery { return $query->applyOptions(['preserveKeys' => true]) @@ -1000,7 +1000,7 @@ Grouped conditions can be expressed by providing combining `where()` and expression objects. For simple queries, you can build conditions using an array of conditions: -``` php +```php $query = $articles->find() ->where([ 'author_id' => 3, @@ -1010,7 +1010,7 @@ $query = $articles->find() The above would generate SQL like -``` sql +```sql SELECT * FROM articles WHERE author_id = 3 AND (view_count = 2 OR view_count = 3) ``` @@ -1019,7 +1019,7 @@ If you'd prefer to avoid deeply nested arrays, you can use the callback form of you to use the expression builder interface to build more complex conditions without arrays. For example: -``` php +```php $query = $articles->find()->where(function (QueryExpression $exp, SelectQuery $query) { // Use add() to add multiple conditions for the same field. $author = $query->expr()->or(['author_id' => 3])->add(['author_id' => 2]); @@ -1034,7 +1034,7 @@ $query = $articles->find()->where(function (QueryExpression $exp, SelectQuery $q The above generates SQL similar to: -``` sql +```sql SELECT * FROM articles WHERE ( @@ -1063,7 +1063,7 @@ depending on which combinator was used. The `QueryExpression` passed to the callback function defaults to `and()`: -``` php +```php $query = $articles->find() ->where(function (QueryExpression $exp) { return $exp @@ -1078,7 +1078,7 @@ Since we started off using `where()`, we don't need to call `and()`, as that happens implicitly. The above shows a few new condition methods being combined with `AND`. The resulting SQL would look like: -``` sql +```sql SELECT * FROM articles WHERE ( @@ -1091,7 +1091,7 @@ AND view_count > 10) However, if we wanted to use both `AND` & `OR` conditions we could do the following: -``` php +```php $query = $articles->find() ->where(function (QueryExpression $exp) { $orConditions = $exp->or(['author_id' => 2]) @@ -1106,7 +1106,7 @@ $query = $articles->find() Which would generate the SQL similar to: -``` sql +```sql SELECT * FROM articles WHERE ( @@ -1120,7 +1120,7 @@ The **combinators** also allow you pass in a callback which takes the new expression object as a parameter if you want to separate the method chaining: -``` php +```php $query = $articles->find() ->where(function (QueryExpression $exp) { $orConditions = $exp->or(function (QueryExpression $or) { @@ -1136,7 +1136,7 @@ $query = $articles->find() You can negate sub-expressions using `not()`: -``` php +```php $query = $articles->find() ->where(function (QueryExpression $exp) { $orConditions = $exp->or(['author_id' => 2]) @@ -1150,7 +1150,7 @@ $query = $articles->find() Which will generate the following SQL looking like: -``` sql +```sql SELECT * FROM articles WHERE ( @@ -1161,7 +1161,7 @@ WHERE ( It is also possible to build expressions using SQL functions: -``` php +```php $query = $articles->find() ->where(function (QueryExpression $exp, SelectQuery $q) { $year = $q->func()->year([ @@ -1176,7 +1176,7 @@ $query = $articles->find() Which will generate the following SQL looking like: -``` sql +```sql SELECT * FROM articles WHERE ( @@ -1190,7 +1190,7 @@ conditions: - `eq()` Creates an equality condition: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->eq('population', '10000'); @@ -1200,7 +1200,7 @@ conditions: - `notEq()` Creates an inequality condition: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->notEq('population', '10000'); @@ -1210,7 +1210,7 @@ conditions: - `like()` Creates a condition using the `LIKE` operator: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->like('name', '%A%'); @@ -1220,7 +1220,7 @@ conditions: - `notLike()` Creates a negated `LIKE` condition: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->notLike('name', '%A%'); @@ -1230,7 +1230,7 @@ conditions: - `in()` Create a condition using `IN`: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->in('country_id', ['AFG', 'USA', 'EST']); @@ -1240,7 +1240,7 @@ conditions: - `notIn()` Create a negated condition using `IN`: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->notIn('country_id', ['AFG', 'USA', 'EST']); @@ -1250,7 +1250,7 @@ conditions: - `gt()` Create a `>` condition: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->gt('population', '10000'); @@ -1260,7 +1260,7 @@ conditions: - `gte()` Create a `>=` condition: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->gte('population', '10000'); @@ -1270,7 +1270,7 @@ conditions: - `lt()` Create a `<` condition: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->lt('population', '10000'); @@ -1280,7 +1280,7 @@ conditions: - `lte()` Create a `<=` condition: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->lte('population', '10000'); @@ -1290,7 +1290,7 @@ conditions: - `isNull()` Create an `IS NULL` condition: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->isNull('population'); @@ -1300,7 +1300,7 @@ conditions: - `isNotNull()` Create a negated `IS NULL` condition: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->isNotNull('population'); @@ -1310,7 +1310,7 @@ conditions: - `between()` Create a `BETWEEN` condition: - ``` php + ```php $query = $cities->find() ->where(function (QueryExpression $exp, SelectQuery $q) { return $exp->between('population', 999, 5000000); @@ -1320,7 +1320,7 @@ conditions: - `exists()` Create a condition using `EXISTS`: - ``` php + ```php $subquery = $cities->find() ->select(['id']) ->where(function (QueryExpression $exp, SelectQuery $q) { @@ -1337,7 +1337,7 @@ conditions: - `notExists()` Create a negated condition using `EXISTS`: - ``` php + ```php $subquery = $cities->find() ->select(['id']) ->where(function (QueryExpression $exp, SelectQuery $q) { @@ -1356,7 +1356,7 @@ Expression objects should cover many commonly used functions and expressions. If you find yourself unable to create the required conditions with expressions you can may be able to use `bind()` to manually bind parameters into conditions: -``` php +```php $query = $cities->find() ->where([ 'start_date BETWEEN :start AND :end', @@ -1369,7 +1369,7 @@ In situations when you can't get, or don't want to use the builder methods to create the conditions you want you can also use snippets of SQL in where clauses: -``` php +```php // Compare two fields to each other $query->where(['Categories.parent_id != Parents.id']); ``` @@ -1385,7 +1385,7 @@ $query->where(['Categories.parent_id != Parents.id']); When you need to reference a column or SQL identifier in your queries you can use the `identifier()` method: -``` php +```php $query = $countries->find(); $query->select([ 'year' => $query->func()->year([$query->identifier('created')]), @@ -1397,7 +1397,7 @@ $query->select([ You can use `identifier()` in comparisons to aggregations too: -``` php +```php $query = $this->Orders->find(); $query->select(['Customers.customer_name', 'total_orders' => $query->func()->count('Orders.order_id')]) ->contain('Customers') @@ -1415,7 +1415,7 @@ In situations that you need to deal with accented characters, multilingual data or case-sensitive comparisons, you can use the `$collation` parameter of `IdentifierExpression` or `StringExpression` to apply a character expression to a certain collation: -``` php +```php use Cake\Database\Expression\IdentifierExpression; $collation = 'Latin1_general_CI_AI'; //sql server example @@ -1434,7 +1434,7 @@ types based on the schema data. If in your queries you'd like CakePHP to automatically convert equality to `IN` comparisons, you'll need to indicate the column data type: -``` php +```php $query = $articles->find() ->where(['id' => $ids], ['id' => 'integer[]']); @@ -1452,7 +1452,7 @@ be cast using the [type system](../orm/database-basics#data-types). This works w complex types as well. For example, you could take a list of DateTime objects using: -``` php +```php $query = $articles->find() ->where(['post_date' => $dates], ['post_date' => 'date[]']); ``` @@ -1462,7 +1462,7 @@ $query = $articles->find() When a condition value is expected to be `null` or any other value, you can use the `IS` operator to automatically create the correct expression: -``` php +```php $query = $categories->find() ->where(['parent_id IS' => $parentId]); ``` @@ -1475,7 +1475,7 @@ the type of `$parentId` When a condition value is expected not to be `null` or any other value, you can use the `IS NOT` operator to automatically create the correct expression: -``` php +```php $query = $categories->find() ->where(['parent_id IS NOT' => $parentId]); ``` @@ -1488,7 +1488,7 @@ depending on the type of `$parentId` When you cannot construct the SQL you need using the query builder, you can use expression objects to add snippets of SQL to your queries: -``` php +```php $query = $articles->find(); $expr = $query->expr()->add('1 + 1'); $query->select(['two' => $expr]); @@ -1507,7 +1507,7 @@ If you have configured [Read And Write Connections](../orm/database-basics#read- you can have a query run on the `read` connection using one of the role methods: -``` php +```php // Run a query on the read connection $query->useReadRole(); @@ -1524,7 +1524,7 @@ Query role methods were added in 4.5.0 It is possible to change the conjunction used to join conditions in a query expression using the method `setConjunction`: -``` php +```php $query = $articles->find(); $expr = $query->expr(['1','1'])->setConjunction('+'); $query->select(['two' => $expr]); @@ -1532,7 +1532,7 @@ $query->select(['two' => $expr]); And can be used combined with aggregations too: -``` php +```php $query = $products->find(); $query->select(function ($query) { $stockQuantity = $query->func()->sum('Stocks.quantity'); @@ -1557,7 +1557,7 @@ $query->select(function ($query) { Tuple comparison involves comparing two rows of data (tuples) element by element, typically using comparison operators like `<, >, =`: -``` php +```php $products->find() ->where([ 'OR' => [ @@ -1571,7 +1571,7 @@ $products->find() The same result can be achieved using `TupleComparison`: -``` php +```php use Cake\Database\Expression\TupleComparison; $products->find() @@ -1590,7 +1590,7 @@ $products->find() Tuple Comparison can also be used with `IN` and the result can be transformed even on DBMS that does not natively support it: -``` php +```php $articles->find() ->where( new TupleComparison( @@ -1612,7 +1612,7 @@ $articles->find() Optimizer hints allow you to control execution plans at the individual query level: -``` php +```php $query->optimizerHint(['NO_BKA(articles)']); ``` @@ -1629,7 +1629,7 @@ extension). You can get the `Driver` instance for the current connection role from a query: -``` php +```php $driver = $query->getDriver(); ``` @@ -1642,7 +1642,7 @@ $driver = $query->getDriver(); Once you've made your query, you'll want to retrieve rows from it. There are a few ways of doing this: -``` php +```php // Iterate the query foreach ($query as $row) { // Do stuff. @@ -1655,7 +1655,7 @@ $results = $query->all(); You can use [any of the collection](../core-libraries/collections) methods on your query objects to pre-process or transform the results: -``` php +```php // Use one of the collection methods. $ids = $query->map(function ($row) { return $row->id; @@ -1669,7 +1669,7 @@ $maxAge = $query->max(function ($max) { You can use `first` or `firstOrFail` to retrieve a single record. These methods will alter the query adding a `LIMIT 1` clause: -``` php +```php // Get just the first row $row = $query->first(); @@ -1684,14 +1684,14 @@ $row = $query->firstOrFail(); Using a single query object, it is possible to obtain the total number of rows found for a set of conditions: -``` php +```php $total = $articles->find()->where(['is_active' => true])->count(); ``` The `count()` method will ignore the `limit`, `offset` and `page` clauses, thus the following will return the same result: -``` php +```php $total = $articles->find()->where(['is_active' => true])->limit(10)->count(); ``` @@ -1704,7 +1704,7 @@ Moreover, it is possible to return the total count for a query containing group by clauses without having to rewrite the query in any way. For example, consider this query for retrieving article ids and their comments count: -``` php +```php $query = $articles->find(); $query->select(['Articles.id', $query->func()->count('Comments.id')]) ->matching('Comments') @@ -1715,7 +1715,7 @@ $total = $query->count(); After counting, the query can still be used for fetching the associated records: -``` php +```php $list = $query->all(); ``` @@ -1726,7 +1726,7 @@ expensive unneeded parts such as left joins. This becomes particularly handy when using the CakePHP built-in pagination system which calls the `count()` method: -``` php +```php $query = $query->where(['is_active' => true])->counter(function ($query) { return 100000; }); @@ -1743,7 +1743,7 @@ will receive the estimated hard-coded number of rows. When fetching entities that don't change often you may want to cache the results. The `SelectQuery` class makes this simple: -``` php +```php $query->cache('recent_articles'); ``` @@ -1751,7 +1751,7 @@ Will enable caching on the query's result set. If only one argument is provided to `cache()` then the 'default' cache configuration will be used. You can control which caching configuration is used with the second parameter: -``` php +```php // String config name. $query->cache('recent_articles', 'dbResults'); @@ -1764,7 +1764,7 @@ to generate the key. The function you give it will receive the query as an argument. You can then read aspects of the query to dynamically generate the cache key: -``` php +```php // Generate a key based on a simple checksum // of the query's where clause $query->cache(function ($q) { @@ -1806,7 +1806,7 @@ to fetch associated data from other tables is called **eager loading**. In addition to loading related data with `contain()`, you can also add additional joins with the query builder: -``` php +```php $query = $articles->find() ->join([ 'table' => 'comments', @@ -1819,7 +1819,7 @@ $query = $articles->find() You can append multiple joins at the same time by passing an associative array with multiple joins: -``` php +```php $query = $articles->find() ->join([ 'c' => [ @@ -1838,7 +1838,7 @@ $query = $articles->find() As seen above, when adding joins the alias can be the outer array key. Join conditions can also be expressed as an array of conditions: -``` php +```php $query = $articles->find() ->join([ 'c' => [ @@ -1859,7 +1859,7 @@ datatypes for the join conditions, the ORM can correctly convert data types into SQL. In addition to `join()` you can use `rightJoin()`, `leftJoin()` and `innerJoin()` to create joins: -``` php +```php // Join with an alias and string conditions $query = $articles->find(); $query->leftJoin( @@ -1885,7 +1885,7 @@ $query->innerJoin( It should be noted that if you set the `quoteIdentifiers` option to `true` when defining your `Connection`, join conditions between table fields should be set as follow: -``` php +```php $query = $articles->find() ->join([ 'c' => [ @@ -1906,7 +1906,7 @@ some database Drivers (PostgreSQL notably) Unlike earlier examples, you should can't use `find()` to create insert queries. Instead, create a new `InsertQuery` object using `insertQuery()`: -``` php +```php $query = $articles->insertQuery(); $query->insert(['title', 'body']) ->values([ @@ -1919,7 +1919,7 @@ $query->insert(['title', 'body']) To insert multiple rows with only one query, you can chain the `values()` method as many times as you need: -``` php +```php $query = $articles->insertQuery(); $query->insert(['title', 'body']) ->values([ @@ -1938,7 +1938,7 @@ Generally, it is easier to insert data using entities and `INSERT` query together, you can create `INSERT INTO ... SELECT` style queries: -``` php +```php $select = $articles->find() ->select(['title', 'body', 'published']) ->where(['id' => 3]); @@ -1961,7 +1961,7 @@ $query = $articles->insertQuery() As with insert queries, you should not use `find()` to create update queries. Instead, create new a `Query` object using `updateQuery()`: -``` php +```php $query = $articles->updateQuery(); $query->set(['published' => true]) ->where(['id' => $id]) @@ -1981,7 +1981,7 @@ Generally, it is easier to update data using entities and As with insert queries, you can't use `find()` to create delete queries. Instead, create new a query object using `deleteQuery()`: -``` php +```php $query = $articles->deleteQuery(); $query->where(['id' => $id]) ->execute(); @@ -1998,7 +1998,7 @@ issues, it is still possible to leave yourself vulnerable through improper use. When using condition arrays, the key/left-hand side as well as single value entries must not contain user data: -``` php +```php $query->where([ // Data on the key/left-hand side is unsafe, as it will be // inserted into the generated query as-is @@ -2014,7 +2014,7 @@ $query->where([ When using the expression builder, column names must not contain user data: -``` php +```php $query->where(function (QueryExpression $exp) use ($userData, $values) { // Column names in all expressions are not safe. return $exp->in($userData, $values); @@ -2024,7 +2024,7 @@ $query->where(function (QueryExpression $exp) use ($userData, $values) { When building function expressions, function names should never contain user data: -``` php +```php // Not safe. $query->func()->{$userData}($arg1); @@ -2035,7 +2035,7 @@ $query->func()->coalesce($userData); Raw expressions are never safe: -``` php +```php $expr = $query->expr()->add($userData); $query->select(['two' => $expr]); ``` @@ -2049,7 +2049,7 @@ method. The following example would be a safe variant of the unsafe, SQL injection prone example given above: -``` php +```php $query ->where([ 'MATCH (comment) AGAINST (:userData)', @@ -2073,7 +2073,7 @@ complex queries using the ORM query builder. Unions are created by composing one or more select queries together: -``` php +```php $inReview = $articles->find() ->where(['need_review' => true]); @@ -2085,7 +2085,7 @@ $unpublished->union($inReview); You can create `UNION ALL` queries using the `unionAll()` method: -``` php +```php $inReview = $articles->find() ->where(['need_review' => true]); @@ -2101,7 +2101,7 @@ Intersections allow you to combine the result sets of two queries together and finding results with overlapping results. Intersections are created by composing one or more select queries together: -``` php +```php $inReview = $articles->find() ->where(['need_review' => true]); @@ -2113,7 +2113,7 @@ $unpublished->intersect($inReview); You can create `INTERSECT ALL` queries using the `intersectAll()` method: -``` php +```php $inReview = $articles->find() ->where(['need_review' => true]); @@ -2132,7 +2132,7 @@ $unpublished->intersectAll($inReview); Subqueries enable you to compose queries together and build conditions and results based on the results of other queries: -``` php +```php $matchingComment = $articles->getAssociation('Comments')->find() ->select(['article_id']) ->distinct() @@ -2160,7 +2160,7 @@ referencing results in the outer query more complex. As of 4.2.0 you can use `Table::subquery()` to create a specialized query instance that will not generate aliases: -``` php +```php $comments = $articles->getAssociation('Comments')->getTarget(); $matchingComment = $comments->subquery() @@ -2177,7 +2177,7 @@ $query = $articles->find() Most relational database vendors support taking out locks when doing select operations. You can use the `epilog()` method for this: -``` php +```php // In MySQL $query->epilog('FOR UPDATE'); ``` @@ -2192,7 +2192,7 @@ current row. They are commonly used to calculate totals or offsets on partial se in the query. For example if we wanted to find the date of the earliest and latest comment on each article we could use window functions: -``` php +```php $query = $articles->find(); $query->select([ 'Articles.id', @@ -2210,7 +2210,7 @@ $query->select([ The above would generate SQL similar to: -``` sql +```sql SELECT Articles.id, Articles.title, @@ -2241,7 +2241,7 @@ by `AggregateExpresion`, but make sure you follow your database documentation on If you need to re-use the same window expression multiple times you can create named windows using the `window()` method: -``` php +```php $query = $articles->find(); // Define a named window @@ -2280,7 +2280,7 @@ derived tables and views in a couple ways: As an example lets fetch a list of customers and the number of orders each of them has made. In SQL we would use: -``` sql +```sql WITH orders_per_customer AS ( SELECT COUNT(*) AS order_count, customer_id FROM orders GROUP BY customer_id ) @@ -2291,7 +2291,7 @@ INNER JOIN orders_per_customer ON orders_per_customer.customer_id = customers.id To build that query with the ORM query builder we would use: -``` php +```php // Start the final query $query = $this->Customers->find(); diff --git a/docs/en/orm/retrieving-data-and-resultsets.md b/docs/en/orm/retrieving-data-and-resultsets.md index c46edbfeb9..132b9fa6d4 100644 --- a/docs/en/orm/retrieving-data-and-resultsets.md +++ b/docs/en/orm/retrieving-data-and-resultsets.md @@ -35,7 +35,7 @@ ways to inspect the data returned by the ORM. It is often convenient to load a single entity from the database when editing or viewing entities and their related data. You can do this by using `get()`: -``` php +```php // In a controller or table method. // Get a single article @@ -53,7 +53,7 @@ error. Like `find()`, `get()` also has caching integrated. You can use the `cache` option when calling `get()` to perform read-through caching: -``` php +```php // In a controller or table method. // Use any cache config or CacheEngine instance & a generated key @@ -70,7 +70,7 @@ Optionally you can `get()` an entity using [Custom Find Methods](#custom-find-me example you may want to get all translations for an entity. You can achieve that by using the `finder` option: -``` php +```php $article = $articles->get($id, 'translations'); ``` @@ -90,7 +90,7 @@ Before you can work with entities, you'll need to load them. The easiest way to do this is using the `find()` method. The find method provides a short and extensible way to find the data you are interested in: -``` php +```php // In a controller or table method. // Find all the articles @@ -103,7 +103,7 @@ refine a query after creating it. SelectQuery objects are evaluated lazily, and execute until you start fetching rows, convert it to an array, or when the `all()` method is called: -``` php +```php // In a controller or table method. // Find all the articles. @@ -126,7 +126,7 @@ $data = $query->toArray(); > interface to build more complex queries, adding additional conditions, > limits, or include associations using the fluent interface. -``` php +```php // In a controller or table method. $query = $articles->find('all') ->where(['Articles.created >' => new DateTime('-10 days')]) @@ -136,7 +136,7 @@ $query = $articles->find('all') You can also provide many commonly used options to `find()`: -``` php +```php // In a controller or table method. $query = $articles->find('all', conditions: ['Articles.created >' => new DateTime('-10 days')], @@ -148,7 +148,7 @@ $query = $articles->find('all', If your finder options are in an array, you can use the [splat operator](https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list) (`...`) to pass them into `find()`: -``` php +```php $options = [ 'conditions' => ['Articles.created >' => new DateTime('-10 days')], 'contain' => ['Authors', 'Comments'], @@ -182,7 +182,7 @@ methods will let you re-use your queries and make testing easier. By default, queries and result sets will return [Entities](../orm/entities) objects. You can retrieve basic arrays by disabling hydration: -``` php +```php $query->disableHydration(); // $data is ResultSet that contains array data. @@ -196,7 +196,7 @@ $data = $query->all(); The `first()` method allows you to fetch only the first row from a query. If the query has not been executed, a `LIMIT 1` clause will be applied: -``` php +```php // In a controller or table method. $query = $articles->find('all', order: ['Articles.created' => 'DESC']); $row = $query->first(); @@ -214,7 +214,7 @@ key. Once you have created a query object, you can use the `count()` method to get a result count of that query: -``` php +```php // In a controller or table method. $query = $articles->find('all', conditions: ['Articles.title LIKE' => '%Ovens%']); $number = $query->count(); @@ -231,7 +231,7 @@ application's data. For example, this is very useful when creating ` ``` @@ -170,7 +170,7 @@ data, that are the entity's data in the case of `EntityContext`. If however, you are building a form that needs to read from the query string, you can change where `FormHelper` reads input data from: -``` php +```php // Use query string instead of request data: echo $this->Form->create($article, [ 'type' => 'get', @@ -187,7 +187,7 @@ When input data has to be processed by the entity, i.e. marshal transformations, query result or entity computations, and displayed after one or multiple form submissions where request data is retained, you need to put `context` first: -``` php +```php // Prioritize context over request data: echo $this->Form->create($article, 'valueSources' => ['context', 'data'], @@ -201,13 +201,13 @@ is called. By using the `type` option you can change the HTTP method a form will use: -``` php +```php echo $this->Form->create($article, ['type' => 'get']); ``` Output: -``` html +```html
    ``` @@ -218,13 +218,13 @@ of the proper `enctype` attribute will cause the file uploads not to function. For example: -``` php +```php echo $this->Form->create($article, ['type' => 'file']); ``` Output: -``` html +```html ``` @@ -243,13 +243,13 @@ For example, if you'd like to point the form to the `publish()` action of the current controller, you would supply an `$options` array, like the following: -``` php +```php echo $this->Form->create($article, ['url' => ['action' => 'publish']]); ``` Output: -``` html +```html ``` @@ -257,7 +257,7 @@ If the desired form action isn't in the current controller, you can specify a complete URL for the form action. The supplied URL can be relative to your CakePHP application: -``` php +```php echo $this->Form->create(null, [ 'url' => [ 'controller' => 'Articles', @@ -268,13 +268,13 @@ echo $this->Form->create(null, [ Output: -``` html +```html ``` Or you can point to an external domain: -``` php +```php echo $this->Form->create(null, [ 'url' => 'https://www.google.com/search', 'type' => 'get', @@ -283,7 +283,7 @@ echo $this->Form->create(null, [ Output: -``` html +```html ``` @@ -296,7 +296,7 @@ mark fields required based on the specific validator your controller action is going to apply. For example, your Users table has specific validation rules that only apply when an account is being registered: -``` php +```php echo $this->Form->create($user, [ 'context' => ['validator' => 'register'], ]); @@ -307,7 +307,7 @@ are defined by `UsersTable::validationRegister()`, for `$user` and all related associations. If you are creating a form for associated entities, you can define validation rules for each association by using an array: -``` php +```php echo $this->Form->create($user, [ 'context' => [ 'validator' => [ @@ -323,7 +323,7 @@ comments. FormHelper uses validators to generate HTML5 required attributes, relevant ARIA attributes, and set error messages with the [browser validator API](https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Form_validation#Customized_error_messages) . If you would like to disable HTML5 validation messages use: -``` php +```php $this->Form->setConfig('autoSetCustomValidity', false); ``` @@ -339,7 +339,7 @@ you have implemented this interface you can wire your new context into the FormHelper. It is often best to do this in a `View.beforeRender` event listener, or in an application view class: -``` php +```php $this->Form->addContextProvider('myprovider', function ($request, $data) { if ($data['entity'] instanceof MyOrmClass) { return new MyProvider($data); @@ -378,7 +378,7 @@ methods of FormHelper. By default, the `control()` method will employ the following widget templates: -``` html +```html 'inputContainer' => '
    {{content}}
    ' 'input' => '' 'requiredClass' => 'required' @@ -387,7 +387,7 @@ By default, the `control()` method will employ the following widget templates: In case of validation errors it will also use: -``` html +```html 'inputContainerError' => '
    {{content}}{{error}}
    ' ``` @@ -449,7 +449,7 @@ file The `$options` parameter allows you to choose a specific control type if you need to: -``` php +```php echo $this->Form->control('published', ['type' => 'checkbox']); ``` @@ -467,7 +467,7 @@ validation rules for the model's field indicate that it is required and not allowed to be empty. You can disable automatic `required` flagging using the `'required'` option: -``` php +```php echo $this->Form->control('title', ['required' => false]); ``` @@ -482,7 +482,7 @@ For example, let's assume that your Users model includes fields for a *quote* (text). You can use the `control()` method of the FormHelper to create appropriate controls for all of these form fields: -``` php +```php echo $this->Form->create($user); // The following generates a Text input echo $this->Form->control('username'); @@ -500,7 +500,7 @@ echo $this->Form->end(); A more extensive example showing some options for a date field: -``` php +```php echo $this->Form->control('birth_date', [ 'label' => 'Date of birth', 'min' => date('Y') - 70, @@ -517,26 +517,26 @@ If you want to create a `select` form field while using a *belongsTo* (or *hasOne*) relation, you can add the following to your UsersController (assuming your User *belongsTo* Group): -``` php +```php $this->set('groups', $this->Users->Groups->find('list')->all()); ``` Afterwards, add the following to your view template: -``` php +```php echo $this->Form->control('group_id', ['options' => $groups]); ``` To make a `select` box for a *belongsToMany* Groups association you can add the following to your UsersController: -``` php +```php $this->set('groups', $this->Users->Groups->find('list')->all()); ``` Afterwards, add the following to your view template: -``` php +```php echo $this->Form->control('groups._ids', ['options' => $groups]); ``` @@ -546,7 +546,7 @@ data in a pluralised and [lower camelCased](https://en.wikipedia.org/wiki/Camel_case#Variations_and_synonyms) format as follows: -``` php +```php $this->set('userGroups', $this->UserGroups->find('list')->all()); ``` @@ -564,7 +564,7 @@ attributes in the form's entity. For example, if you created a form for an You can create controls for associated models, or arbitrary models by passing in `association.fieldname` as the first parameter: -``` php +```php echo $this->Form->control('association.fieldname'); ``` @@ -598,14 +598,14 @@ as well as HTML attributes. This subsection will cover the options specific to For example: - ``` php + ```php echo $this->Form->control('field', ['type' => 'file']); echo $this->Form->control('email', ['type' => 'email']); ``` Output: - ``` html + ```html
    @@ -623,7 +623,7 @@ as well as HTML attributes. This subsection will cover the options specific to For example: - ``` php + ```php echo $this->Form->control('name', [ 'label' => 'The User Alias', ]); @@ -631,7 +631,7 @@ as well as HTML attributes. This subsection will cover the options specific to Output: - ``` html + ```html
    @@ -643,13 +643,13 @@ as well as HTML attributes. This subsection will cover the options specific to For example: - ``` php + ```php echo $this->Form->control('name', ['label' => false]); ``` Output: - ``` html + ```html
    @@ -664,7 +664,7 @@ as well as HTML attributes. This subsection will cover the options specific to For example: - ``` php + ```php echo $this->Form->control('name', [ 'label' => [ 'class' => 'thingy', @@ -675,7 +675,7 @@ as well as HTML attributes. This subsection will cover the options specific to Output: - ``` html + ```html
    @@ -695,7 +695,7 @@ as well as HTML attributes. This subsection will cover the options specific to For example: - ``` php + ```php echo $this->Form->control('name', ['error' => false]); ``` @@ -704,7 +704,7 @@ as well as HTML attributes. This subsection will cover the options specific to For example: - ``` php + ```php $this->Form->control('name', [ 'error' => ['Not long enough' => __('This is not long enough')], ]); @@ -717,7 +717,7 @@ as well as HTML attributes. This subsection will cover the options specific to To disable the HTML entity encoding for error messages only, the `'escape'` sub key can be used: - ``` php + ```php $this->Form->control('name', [ 'error' => ['escape' => false], ]); @@ -751,7 +751,7 @@ as well as HTML attributes. This subsection will cover the options specific to For example: - ``` php + ```php echo $this->Form->control('name', ['readonly' => true]); ``` @@ -785,14 +785,14 @@ as follows: Example usage: - ``` php + ```php echo $this->Form->text('ingredient', ['default' => 'Sugar']); ``` Example with `select` field (size "Medium" will be selected as default): - ``` php + ```php $sizes = ['s' => 'Small', 'm' => 'Medium', 'l' => 'Large']; echo $this->Form->select('size', $sizes, ['default' => 'm']); ``` @@ -839,13 +839,13 @@ Creates a simple `input` HTML element of `text` type. For example: -``` php +```php echo $this->Form->text('username', ['class' => 'users']); ``` Will output: -``` html +```html ``` @@ -861,13 +861,13 @@ Creates a simple `input` element of `password` type. For example: -``` php +```php echo $this->Form->password('password'); ``` Will output: -``` html +```html ``` @@ -883,13 +883,13 @@ Creates a hidden form input. For example: -``` php +```php echo $this->Form->hidden('id'); ``` Will output: -``` html +```html ``` @@ -904,19 +904,19 @@ Will output: Creates a textarea control field. The default widget template used is: -``` html +```html 'textarea' => '' ``` For example: -``` php +```php echo $this->Form->textarea('notes'); ``` Will output: -``` html +```html ``` @@ -927,7 +927,7 @@ generated. Example: -``` html +```html @@ -943,7 +943,7 @@ couple of specific options: For example: - ``` php + ```php echo $this->Form->textarea('notes', ['escape' => false]); // OR.... echo $this->Form->control('notes', ['type' => 'textarea', 'escape' => false]); @@ -954,13 +954,13 @@ couple of specific options: For example: - ``` php + ```php echo $this->Form->textarea('comment', ['rows' => '5', 'cols' => '5']); ``` Output: - ``` html + ```html ``` @@ -989,7 +989,7 @@ methods are described in each method's own section.) combination with any select-type control, such as `date()`, `time()`, `dateTime()`: - ``` php + ```php echo $this->Form->time('close_time', [ 'value' => '13:30:00', ]); @@ -1003,7 +1003,7 @@ methods are described in each method's own section.) `true`, you can provide an array with the values you want to select by default: - ``` php + ```php // HTML