diff --git a/docs/en/appendices/6-0-migration-guide.md b/docs/en/appendices/6-0-migration-guide.md index 65bdc6c837..42d4306bb4 100644 --- a/docs/en/appendices/6-0-migration-guide.md +++ b/docs/en/appendices/6-0-migration-guide.md @@ -22,6 +22,11 @@ deprecation warnings. allowing listeners to register providers used by `Validator::add()`. Listeners that inspect rules added by `validationDefault()` must account for this order. +- Calling behavior methods directly on the table instance is now opt-in. + Behaviors no longer expose their public methods as mixin methods on the + table unless they are attached with the `implementedMethods` configuration + set to `true`, a map of `alias => method` pairs, or a list of method names. + ## Breaking Changes ### Renamed Methods diff --git a/docs/en/orm/behaviors.md b/docs/en/orm/behaviors.md index 93d51285d2..81136914c8 100644 --- a/docs/en/orm/behaviors.md +++ b/docs/en/orm/behaviors.md @@ -96,44 +96,60 @@ Public methods on behaviors can be called as normal methods: $articles->getBehavior('Sluggable')->slug($value); ``` -Public methods defined on behaviors are also added as 'mixin' methods on the -table object they are attached to. If you attach two behaviors that provide the -same methods an exception will be raised. If a behavior provides the same method -as a table class, the behavior method will not be callable from the table. -Behavior mixin methods will receive the exact same arguments that are provided -to the table. For example, if our SluggableBehavior defined the following -method: +Public methods defined on behaviors can also be exposed as 'mixin' methods on +the table object they are attached to, so they can be called directly on the +table. For example, if our SluggableBehavior defined the following method: ```php public function slug(string $value): string { - return Text::slug($value, $this->_config['replacement']); + return Text::slug($value, $this->getConfig('replacement')); } ``` -It could be invoked using: +::: info Changed in version 6.0 +Exposing behavior methods on the table instance is opt-in. In 5.x all public +behavior methods were proxied by default. In 6.0 nothing is proxied until you +set the `implementedMethods` configuration key when attaching the behavior. +::: + +To proxy all of a behavior's public methods, set `implementedMethods` to +`true` when adding the behavior: + +```php +// In a table's initialize() method. +$this->addBehavior('Sluggable', [ + 'implementedMethods' => true, +]); +``` + +The method could then be invoked using: ```php $slug = $articles->slug('My article'); ``` -::: info Deprecated in version 5.3.0 -Calling behavior methods as mixin methods is deprecated -::: +If you attach two behaviors that provide the same method an +exception will be raised. If a behavior provides the same method as a table +class, the behavior method will not be callable from the table. #### Limiting or Renaming Exposed Mixin Methods -When creating behaviors, there may be situations where you don't want to expose -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: +When creating behaviors, there may be situations where you don't want to +expose all public methods as mixin methods. Instead of setting +`implementedMethods` to `true`, you can provide an array that maps the mixin +method name to the behavior method it proxies. Providing an array both +enables proxying and decides which methods are exposed. For example if we +wanted to prefix our slug() method we could do the following when adding the +behavior to a table: ```php -protected array $_defaultConfig = [ +// In a table's initialize() method. +$this->addBehavior('Sluggable', [ 'implementedMethods' => [ 'superSlug' => 'slug', ] -]; +]); ``` Applying this configuration will make `slug()` not callable, however it will @@ -141,17 +157,13 @@ add a `superSlug()` mixin method to the table. Notably if our behavior implemented other public methods they would **not** be available as mixin 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: +The array can also be a numerically indexed list of method names, in which +case each method is proxied under its own name, so +`'implementedMethods' => ['slug']` is equivalent to +`'implementedMethods' => ['slug' => 'slug']`. -```php -// In a table's initialize() method. -$this->addBehavior('Sluggable', [ - 'implementedMethods' => [ - 'superSlug' => 'slug', - ] -]); -``` +Method names are matched case-insensitively, and setting +`implementedMethods` to an empty array disables mixin methods entirely. ### Defining Event Listeners @@ -173,7 +185,7 @@ use Cake\Utility\Text; class SluggableBehavior extends Behavior { - protected array $_defaultConfig = [ + protected array $defaultConfig = [ 'field' => 'title', 'slug' => 'slug', 'replacement' => '-', @@ -247,7 +259,7 @@ or exclude finder methods. For example if we wanted to rename our `find(slug)` method we could do the following: ```php -protected array $_defaultConfig = [ +protected array $defaultConfig = [ 'implementedFinders' => [ 'slugged' => 'findSlug', ] @@ -317,6 +329,10 @@ $table->behaviors()->has('CounterCache'); // Get a loaded behavior // Remember to omit plugin prefixes $table->behaviors()->get('CounterCache'); + +// Check if any loaded behavior exposes a mixin method. +// Only methods enabled through the `implementedMethods` config match. +$table->behaviors()->hasMethod('slug'); ``` ### Re-configuring Loaded Behaviors diff --git a/docs/en/orm/behaviors/tree.md b/docs/en/orm/behaviors/tree.md index b94da5f361..094b8d3386 100644 --- a/docs/en/orm/behaviors/tree.md +++ b/docs/en/orm/behaviors/tree.md @@ -66,9 +66,15 @@ already holding some rows: ```php // In a controller $categories = $this->getTableLocator()->get('Categories'); -$categories->recover(); +$categories->getBehavior('Tree')->recover(); ``` +> [!NOTE] +> `recover()` is a method provided by the `TreeBehavior`. Behavior methods are +> only callable on the table instance when the behavior has been attached with +> the `implementedMethods` configuration enabled, see +> [Calling behavior methods](../../orm/behaviors#calling-behavior-methods). + You can verify it works by getting any row from the table and asking for the count of descendants it has: diff --git a/docs/en/orm/validation.md b/docs/en/orm/validation.md index 24e7e3af45..ea5aad688a 100644 --- a/docs/en/orm/validation.md +++ b/docs/en/orm/validation.md @@ -201,8 +201,10 @@ contain the validation rules declared in the `default` set. Validation rules can use functions defined on any known providers. By default CakePHP sets up a few providers: -1. Methods on the table class or its behaviors are available on the `table` - provider. +1. Methods on the table class are available on the `table` provider. Methods + provided by behaviors are available on this provider as well, but only + when the behavior is attached with the `implementedMethods` configuration + enabled, see [Calling behavior methods](../orm/behaviors#calling-behavior-methods). 2. The core `Cake\Validation\Validation` class is setup as the `default` provider.