Skip to content

Commit 26184f1

Browse files
authored
Merge pull request #8259 from cakephp/docs-54-migration-additions
Add missing 5.4 migration guide entries
2 parents 2554f33 + f326d2b commit 26184f1

File tree

4 files changed

+212
-9
lines changed

4 files changed

+212
-9
lines changed

docs/en/appendices/5-4-migration-guide.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ The default eager loading strategy for `HasMany` and `BelongsToMany` association
2727
has changed from `select` to `subquery`. If you need the previous behavior,
2828
explicitly set `'strategy' => 'select'` when defining associations.
2929

30+
### Controller
31+
32+
Loading a component with the same alias as the controller's default table now
33+
triggers a warning. See [Component Alias Conflicts](../controllers/components#component-alias-conflicts).
34+
3035
## Deprecations
3136

3237
- WIP
@@ -60,12 +65,24 @@ explicitly set `'strategy' => 'select'` when defining associations.
6065
nested array format matching `contain()` syntax.
6166
See [Converting Request Data into Entities](../orm/saving-data#converting-request-data-into-entities).
6267

68+
### Http
69+
70+
- Added PSR-13 Link implementation with `Cake\Http\Link\Link` and `Cake\Http\Link\LinkProvider`
71+
classes for hypermedia link support. Links added to responses are automatically emitted
72+
as HTTP `Link` headers. See [Hypermedia Links](../controllers/request-response#hypermedia-links).
73+
6374
### Utility
6475

6576
- Added `Cake\Utility\Fs\Finder` class for fluent file discovery with pattern matching,
6677
depth control, and custom filters. Added `Cake\Utility\Fs\Path` for cross-platform
6778
path manipulation.
6879

80+
### Collection
81+
82+
- Added [`keys()`](../core-libraries/collections#keys) and [`values()`](../core-libraries/collections#values) methods for extracting keys or re-indexing values.
83+
- Added [`implode()`](../core-libraries/collections#implode) method to concatenate elements into a string.
84+
- Added [`when()`](../core-libraries/collections#when) and [`unless()`](../core-libraries/collections#unless) methods for conditional method chaining.
85+
6986
### View
7087

7188
- Added `{{inputId}}` template variable to `inputContainer` and `error` templates

docs/en/controllers/components.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,47 @@ class MyFlashComponent extends FlashComponent
9898
The above would *alias* `MyFlashComponent` to `$this->Flash` in your
9999
controllers.
100100

101+
### Component Alias Conflicts
102+
103+
When a component alias matches the controller's default table name, accessing
104+
that property will return the table instead of the component. CakePHP triggers
105+
a warning when this conflict is detected:
106+
107+
```php
108+
class PaymentsController extends AppController
109+
{
110+
public function initialize(): void
111+
{
112+
parent::initialize();
113+
// Warning: Component alias `Payments` clashes with the default table name
114+
$this->loadComponent('Payments');
115+
}
116+
117+
public function index()
118+
{
119+
// This returns PaymentsTable, not PaymentsComponent!
120+
$this->Payments;
121+
}
122+
}
123+
```
124+
125+
To resolve this conflict, either use a different component alias:
126+
127+
```php
128+
$this->loadComponent('Payments', ['className' => 'Payments', 'alias' => 'PaymentService']);
129+
// Access via $this->PaymentService
130+
```
131+
132+
Or set `Controller::$defaultTable` to an empty string if the controller doesn't
133+
need a default table:
134+
135+
```php
136+
class PaymentsController extends AppController
137+
{
138+
protected ?string $defaultTable = '';
139+
}
140+
```
141+
101142
> [!NOTE]
102143
> Aliasing a component replaces that instance anywhere that component is used,
103144
> including inside other Components.

docs/en/controllers/request-response.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,61 @@ You can now use the convenience method
817817
`Cake\Http\Response::withLocation()` to directly set or get the
818818
redirect location header.
819819

820+
### Hypermedia Links
821+
822+
`method` Cake\\Http\\Response::**withLink**(LinkInterface $link): static
823+
824+
CakePHP implements [PSR-13](https://www.php-fig.org/psr/psr-13/) for hypermedia
825+
link support. You can add links to responses, and they will be automatically
826+
emitted as HTTP `Link` headers when the response is sent:
827+
828+
```php
829+
use Cake\Http\Link\Link;
830+
831+
// Add a simple link
832+
$response = $response->withLink(new Link('/api/users/1', 'self'));
833+
834+
// Add a link with multiple relations and attributes
835+
$response = $response->withLink(
836+
(new Link('/api/users?page=2'))
837+
->withRel('next')
838+
->withAttribute('type', 'application/json'),
839+
);
840+
841+
// Preload resources for performance
842+
$response = $response->withLink(
843+
(new Link('/css/app.css'))
844+
->withRel('preload')
845+
->withAttribute('as', 'style'),
846+
);
847+
```
848+
849+
The `Link` class implements `EvolvableLinkInterface` and provides these methods:
850+
851+
- `withHref(string $href)` - Set the link URI
852+
- `withRel(string $rel)` - Add a link relation
853+
- `withoutRel(string $rel)` - Remove a link relation
854+
- `withAttribute(string $name, $value)` - Add an attribute
855+
- `withoutAttribute(string $name)` - Remove an attribute
856+
857+
You can also work with multiple links using `LinkProvider`:
858+
859+
```php
860+
use Cake\Http\Link\Link;
861+
use Cake\Http\Link\LinkProvider;
862+
863+
$provider = new LinkProvider([
864+
new Link('/api/users/1', 'self'),
865+
new Link('/api/users?page=2', 'next'),
866+
]);
867+
868+
// Get the link provider from a response
869+
$links = $response->getLinks();
870+
871+
// Set a new link provider
872+
$response = $response->withLinkProvider($provider);
873+
```
874+
820875
### Setting the Body
821876

822877
`method` Cake\\Http\\Response::**withStringBody**(?string $string): static

docs/en/core-libraries/collections.md

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,17 @@ application as well.
6161
| `contains` | `countBy` | `each` |
6262
| `every` | `extract` | `filter` |
6363
| `first` | `firstMatch` | `groupBy` |
64-
| `indexBy` | `insert` | `isEmpty` |
65-
| `last` | `listNested` | `map` |
66-
| `match` | `max` | `median` |
67-
| `min` | `nest` | `prepend` |
68-
| `prependItem` | `reduce` | `reject` |
69-
| `sample` | `shuffle` | `skip` |
70-
| `some` | `sortBy` | `stopWhen` |
71-
| `sumOf` | `take` | `through` |
72-
| `transpose` | `unfold` | `zip` |
64+
| `implode` | `indexBy` | `insert` |
65+
| `isEmpty` | `keys` | `last` |
66+
| `listNested` | `map` | `match` |
67+
| `max` | `median` | `min` |
68+
| `nest` | `prepend` | `prependItem`|
69+
| `reduce` | `reject` | `sample` |
70+
| `shuffle` | `skip` | `some` |
71+
| `sortBy` | `stopWhen` | `sumOf` |
72+
| `take` | `through` | `transpose` |
73+
| `unfold` | `unless` | `values` |
74+
| `when` | `zip` | |
7375

7476
## Iterating
7577

@@ -1431,3 +1433,91 @@ foreach ($ages as $age) {
14311433
}
14321434
}
14331435
```
1436+
1437+
## Transforming Keys and Values
1438+
1439+
### keys()
1440+
1441+
`method` Cake\\Collection\\Collection::**keys**(): CollectionInterface
1442+
1443+
Returns a new collection containing only the keys from the original collection:
1444+
1445+
```php
1446+
$collection = new Collection(['a' => 1, 'b' => 2, 'c' => 3]);
1447+
$keys = $collection->keys()->toList(); // ['a', 'b', 'c']
1448+
```
1449+
1450+
### values()
1451+
1452+
`method` Cake\\Collection\\Collection::**values**(): CollectionInterface
1453+
1454+
Returns a new collection of values re-indexed with consecutive integers,
1455+
discarding the original keys:
1456+
1457+
```php
1458+
$collection = new Collection(['a' => 1, 'b' => 2, 'c' => 3]);
1459+
$values = $collection->values()->toList(); // [1, 2, 3]
1460+
```
1461+
1462+
## String Operations
1463+
1464+
### implode()
1465+
1466+
`method` Cake\\Collection\\Collection::**implode**(string $glue, callable|string|null $path = null): string
1467+
1468+
Concatenates all elements in the collection into a string, separated by
1469+
the given glue string. Optionally extract values using a path before joining:
1470+
1471+
```php
1472+
$collection = new Collection(['a', 'b', 'c']);
1473+
echo $collection->implode(', '); // 'a, b, c'
1474+
1475+
// With path extraction
1476+
$collection = new Collection([
1477+
['name' => 'Alice'],
1478+
['name' => 'Bob'],
1479+
['name' => 'Charlie'],
1480+
]);
1481+
echo $collection->implode(', ', 'name'); // 'Alice, Bob, Charlie'
1482+
1483+
// With a callback
1484+
$collection = new Collection([1, 2, 3]);
1485+
echo $collection->implode(' + ', fn($n) => $n * 2); // '2 + 4 + 6'
1486+
```
1487+
1488+
## Conditional Operations
1489+
1490+
### when()
1491+
1492+
`method` Cake\\Collection\\Collection::**when**(mixed $condition, callable $callback): CollectionInterface
1493+
1494+
Conditionally applies a callback to the collection when the condition is truthy.
1495+
This enables fluent conditional chaining without breaking the method chain:
1496+
1497+
```php
1498+
$collection = new Collection($items)
1499+
->when($shouldFilter, function ($collection) {
1500+
return $collection->filter(fn($item) => $item['active']);
1501+
})
1502+
->when($sortByName, function ($collection) {
1503+
return $collection->sortBy('name');
1504+
});
1505+
```
1506+
1507+
If the condition is falsy, the collection is returned unchanged.
1508+
1509+
### unless()
1510+
1511+
`method` Cake\\Collection\\Collection::**unless**(mixed $condition, callable $callback): CollectionInterface
1512+
1513+
The inverse of `when()`. Conditionally applies a callback to the collection
1514+
when the condition is falsy:
1515+
1516+
```php
1517+
$collection = new Collection($items)
1518+
->unless($hasDefaults, function ($collection) use ($defaults) {
1519+
return $collection->append($defaults);
1520+
});
1521+
```
1522+
1523+
If the condition is truthy, the collection is returned unchanged.

0 commit comments

Comments
 (0)