Skip to content

Commit 45b9a59

Browse files
committed
Merge branch '5.next' into 6.x
2 parents de1659b + 2554f33 commit 45b9a59

31 files changed

+993
-392
lines changed

.github/workflows/docs-validation.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ jobs:
4848
echo "✅ Valid: $file"
4949
done
5050
51+
toc-link-check:
52+
name: Validate TOC Links
53+
runs-on: ubuntu-latest
54+
55+
steps:
56+
- name: Checkout code
57+
uses: actions/checkout@v6
58+
59+
- name: Check TOC links exist
60+
run: node bin/check-toc-links.js
61+
5162
markdown-lint:
5263
name: Lint Markdown
5364
runs-on: ubuntu-latest

bin/check-toc-links.js

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* TOC Link Validator
5+
*
6+
* Validates that all links in toc_*.json files point to existing markdown files.
7+
*
8+
* Usage:
9+
* node bin/check-toc-links.js
10+
*/
11+
12+
const fs = require("fs");
13+
const path = require("path");
14+
15+
/**
16+
* Recursively extract all links from TOC items
17+
*/
18+
function extractLinks(items, links = []) {
19+
for (const item of items) {
20+
if (item.link && !item.link.startsWith("http")) {
21+
links.push(item.link);
22+
}
23+
if (item.items) {
24+
extractLinks(item.items, links);
25+
}
26+
}
27+
return links;
28+
}
29+
30+
/**
31+
* Check if a TOC link resolves to an existing file
32+
*/
33+
function checkLink(link, docsDir, lang) {
34+
// TOC links may include language prefix: "/ja/quickstart" or just "/quickstart"
35+
// Strip the language prefix if present
36+
let relativePath = link.startsWith("/") ? link.slice(1) : link;
37+
38+
// Remove language prefix if link starts with it (e.g., "ja/quickstart" -> "quickstart")
39+
const langPrefix = lang + "/";
40+
if (relativePath.startsWith(langPrefix)) {
41+
relativePath = relativePath.slice(langPrefix.length);
42+
}
43+
44+
const filePath = path.join(docsDir, relativePath + ".md");
45+
46+
return fs.existsSync(filePath);
47+
}
48+
49+
/**
50+
* Extract language code from TOC filename
51+
* e.g., "toc_en.json" -> "en"
52+
*/
53+
function getLangFromTocFile(tocFile) {
54+
const match = tocFile.match(/^toc_(\w+)\.json$/);
55+
return match ? match[1] : null;
56+
}
57+
58+
/**
59+
* Main validation function
60+
*/
61+
function validateTocFiles() {
62+
const tocFiles = fs.readdirSync(".").filter((f) => f.match(/^toc_.*\.json$/));
63+
64+
if (tocFiles.length === 0) {
65+
console.error("No toc_*.json files found");
66+
process.exit(1);
67+
}
68+
69+
let hasErrors = false;
70+
71+
for (const tocFile of tocFiles) {
72+
const lang = getLangFromTocFile(tocFile);
73+
if (!lang) {
74+
console.error(`Could not extract language from ${tocFile}`);
75+
continue;
76+
}
77+
78+
const docsDir = path.join("docs", lang);
79+
if (!fs.existsSync(docsDir)) {
80+
console.error(`Docs directory not found: ${docsDir}`);
81+
hasErrors = true;
82+
continue;
83+
}
84+
85+
console.log(`Checking ${tocFile} against ${docsDir}/...`);
86+
87+
const content = fs.readFileSync(tocFile, "utf8");
88+
const toc = JSON.parse(content);
89+
90+
// TOC structure has keys like "/" with arrays of items
91+
const allLinks = [];
92+
for (const key of Object.keys(toc)) {
93+
extractLinks(toc[key], allLinks);
94+
}
95+
96+
const missingFiles = [];
97+
for (const link of allLinks) {
98+
if (!checkLink(link, docsDir, lang)) {
99+
missingFiles.push(link);
100+
}
101+
}
102+
103+
if (missingFiles.length > 0) {
104+
hasErrors = true;
105+
console.error(`\n✗ ${tocFile}: ${missingFiles.length} broken link(s)\n`);
106+
for (const link of missingFiles) {
107+
// Calculate expected path (strip lang prefix if present)
108+
let relativePath = link.startsWith("/") ? link.slice(1) : link;
109+
const langPrefix = lang + "/";
110+
if (relativePath.startsWith(langPrefix)) {
111+
relativePath = relativePath.slice(langPrefix.length);
112+
}
113+
const expectedPath = path.join(docsDir, relativePath + ".md");
114+
console.error(` ${link}`);
115+
console.error(` Expected: ${expectedPath}`);
116+
}
117+
console.error("");
118+
} else {
119+
console.log(`✓ ${tocFile}: ${allLinks.length} link(s) valid\n`);
120+
}
121+
}
122+
123+
if (hasErrors) {
124+
console.error("TOC validation failed");
125+
process.exit(1);
126+
}
127+
128+
console.log("✓ All TOC links are valid!");
129+
}
130+
131+
validateTocFiles();
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# 5.4 Migration Guide
2+
3+
The 5.4.0 release is backwards compatible with 5.0. It adds new functionality
4+
and introduces new deprecations. Any functionality deprecated in 5.x will be
5+
removed in 6.0.0.
6+
7+
## Upgrade Tool
8+
9+
The [upgrade tool](../appendices/migration-guides) provides rector rules for
10+
automating some of the migration work. Run rector before updating your
11+
`composer.json` dependencies:
12+
13+
```text
14+
bin/cake upgrade rector --rules cakephp54 <path/to/app/src>
15+
```
16+
17+
## Behavior Changes
18+
19+
### I18n
20+
21+
`Number::parseFloat()` now returns `null` instead of `0.0` when parsing
22+
fails. This also affects `FloatType` and `DecimalType` database types.
23+
24+
### ORM
25+
26+
The default eager loading strategy for `HasMany` and `BelongsToMany` associations
27+
has changed from `select` to `subquery`. If you need the previous behavior,
28+
explicitly set `'strategy' => 'select'` when defining associations.
29+
30+
## Deprecations
31+
32+
- WIP
33+
34+
## New Features
35+
36+
### Controller
37+
38+
- Added `#[RequestToDto]` attribute for automatic mapping of request data to
39+
Data Transfer Objects in controller actions.
40+
See [Request to DTO Mapping](../development/dependency-injection#request-to-dto-mapping).
41+
- Added `unlockActions()` and `unlockFields()` convenience methods to
42+
`FormProtectionComponent`.
43+
See [Form Protection Component](../controllers/components/form-protection).
44+
45+
### Database
46+
47+
- Added `notBetween()` method for `NOT BETWEEN` expressions.
48+
See [Query Builder](../orm/query-builder#advanced-conditions).
49+
- Added `inOrNull()` and `notInOrNull()` methods for combining `IN` conditions with `IS NULL`.
50+
- Added `isDistinctFrom()` and `isNotDistinctFrom()` methods for null-safe comparisons.
51+
52+
### I18n
53+
54+
- `Number::toReadableSize()` now uses decimal units (KB = 1000 bytes) by default.
55+
Binary units (KiB = 1024 bytes) can be enabled via parameter or `Number::setUseIecUnits()`.
56+
57+
### ORM
58+
59+
- The `associated` option in `newEntity()` and `patchEntity()` now supports
60+
nested array format matching `contain()` syntax.
61+
See [Converting Request Data into Entities](../orm/saving-data#converting-request-data-into-entities).
62+
63+
### Utility
64+
65+
- Added `Cake\Utility\Fs\Finder` class for fluent file discovery with pattern matching,
66+
depth control, and custom filters. Added `Cake\Utility\Fs\Path` for cross-platform
67+
path manipulation.
68+
69+
### View
70+
71+
- Added `{{inputId}}` template variable to `inputContainer` and `error` templates
72+
in FormHelper. See [Built-in Template Variables](../views/helpers/form#built-in-template-variables).

docs/en/console-commands/commands.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class HelloCommand extends Command
3737
```
3838

3939
Command classes must implement an `execute()` method that does the bulk of
40-
their work. This method is called when a command is invoked. Let's call our first
41-
command application directory, run:
40+
their work. This method is called when a command is invoked. Let's call our
41+
first command. From your application directory, run:
4242

4343
```bash
4444
bin/cake hello
@@ -48,6 +48,16 @@ You should see the following output:
4848

4949
Hello world.
5050

51+
::: info
52+
The `Arguments` and `ConsoleIo` instances passed to `execute()` are also
53+
available on the command instance as `$this->args` and `$this->io`.
54+
In 6.x, the `execute()` method signature will drop these arguments
55+
and `$this->args` / `$this->io` will be the only way to access
56+
these objects. See the
57+
[6.x command refactor](https://github.com/cakephp/cakephp/pull/18983) for
58+
details.
59+
:::
60+
5161
Our `execute()` method isn't very interesting let's read some input from the
5262
command line:
5363

docs/en/console-commands/input-output.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,84 @@ $io->helper('Banner')
182182
The `BannerHelper` was added in 5.1
183183
:::
184184

185+
### Tree Helper
186+
187+
The `TreeHelper` formats nested arrays into a tree structure with visual
188+
connectors, similar to the output of the Unix `tree` command. This is useful
189+
for displaying hierarchical data such as directory structures, menu trees,
190+
or nested categories:
191+
192+
```php
193+
$data = [
194+
'src' => [
195+
'Controller' => [
196+
'AppController.php',
197+
'UsersController.php',
198+
],
199+
'Model' => [
200+
'Entity' => [
201+
'User.php',
202+
],
203+
'Table' => [
204+
'UsersTable.php',
205+
],
206+
],
207+
],
208+
'config' => [
209+
'app.php',
210+
'routes.php',
211+
],
212+
];
213+
$io->helper('Tree')->output($data);
214+
215+
// Outputs:
216+
// ├── src
217+
// │ ├── Controller
218+
// │ │ ├── AppController.php
219+
// │ │ └── UsersController.php
220+
// │ └── Model
221+
// │ ├── Entity
222+
// │ │ └── User.php
223+
// │ └── Table
224+
// │ └── UsersTable.php
225+
// └── config
226+
// ├── app.php
227+
// └── routes.php
228+
```
229+
230+
The helper supports various value types including strings, booleans, enums,
231+
and closures for lazy evaluation:
232+
233+
```php
234+
$data = [
235+
'debug' => true,
236+
'cache' => false,
237+
'status' => fn () => 'computed value',
238+
];
239+
$io->helper('Tree')->output($data);
240+
241+
// Outputs:
242+
// ├── debug
243+
// │ └── true
244+
// ├── cache
245+
// │ └── false
246+
// └── status
247+
// └── computed value
248+
```
249+
250+
You can customize the indentation using the `baseIndent` and `elementIndent`
251+
configuration options:
252+
253+
```php
254+
$io->helper('Tree')
255+
->setConfig('baseIndent', 4)
256+
->output($data);
257+
```
258+
259+
::: info Added in version 5.3.0
260+
The `TreeHelper` was added in 5.3
261+
:::
262+
185263
## Getting User Input
186264

187265
`method` Cake\\Console\\ConsoleIo::**ask**(string $prompt, ?string $default = null): string

docs/en/contents.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
- [Authorization](https://book.cakephp.org/authorization/3/)
6565
- [Bake](https://book.cakephp.org/bake/3/)
6666
- [Debug Kit](https://book.cakephp.org/debugkit/5/)
67-
- [Migrations](https://book.cakephp.org/migrations/4/)
67+
- [Migrations](https://book.cakephp.org/migrations/)
6868
- [Elasticsearch](https://book.cakephp.org/elasticsearch/4/)
6969
- [Phinx](https://book.cakephp.org/phinx/0/en/)
7070
- [Chronos](https://book.cakephp.org/chronos/3/)

docs/en/contributing/cakephp-coding-conventions.md

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -411,40 +411,18 @@ be preceded by a newline.
411411

412412
Variable types for use in DocBlocks:
413413

414-
Type
415-
Description
416-
417-
mixed
418-
A variable with undefined (or multiple) type.
419-
420-
int
421-
Integer type variable (whole number).
422-
423-
float
424-
Float type (point number).
425-
426-
bool
427-
Logical type (true or false).
428-
429-
string
430-
String type (any value in " " or ' ').
431-
432-
null
433-
Null type. Usually used in conjunction with another type.
434-
435-
array
436-
Array type.
437-
438-
object
439-
Object type. A specific class name should be used if possible.
440-
441-
resource
442-
Resource type (returned by for example mysql_connect()).
443-
Remember that when you specify the type as mixed, you should indicate
444-
whether it is unknown, or what the possible types are.
445-
446-
callable
447-
Callable function.
414+
| Type | Description |
415+
|------|-------------|
416+
| mixed | A variable with undefined (or multiple) type. |
417+
| int | Integer type variable (whole number). |
418+
| float | Float type (point number). |
419+
| bool | Logical type (true or false). |
420+
| string | String type (any value in " " or ' '). |
421+
| null | Null type. Usually used in conjunction with another type. |
422+
| array | Array type. |
423+
| object | Object type. A specific class name should be used if possible. |
424+
| resource | Resource type (returned by for example mysql_connect()). Remember that when you specify the type as mixed, you should indicate whether it is unknown, or what the possible types are. |
425+
| callable | Callable function. |
448426

449427
You can also combine types using the pipe char:
450428

0 commit comments

Comments
 (0)