Complex application rules in CakePHP3

I had a pretty interesting task recently. We have profiles that must implement certain constraints depending on what kind of profile / product the client purchased. So a profile can have a specific number of languages depending on the constraints. This means we need to validate the number of languages an user has picked by a value from another database table that needs to be picked up somehow at runtime.

Why a validation rule won’t can’t do the job

Validation rules are stateless. They are intended to operate in a stateless way. They are best leveraged to ensure that the shape, data types and format of data is correct.

Application rules are stateful, so they are best leveraged to check stateful properties of your entities. For example, validation rules could ensure that an email address is valid, while an application rule could ensure that the email address is unique.

When validation rules are applied the entity has not yet been marshalled, in other words the entity has not yet really been constructed and processed, the data is still a simple array.

So when you inspect the $context, the 2nd arg of a validation rule, you’ll notice that the `data` key of the array just contains what you’ve passed, but not the whole entity!

Application rules will do it

An application rule will run after the entity object was built by the marshaller and you’ll have all data available you need that was passed and merged if you used patchEntity() for example.

See the “Creating custom rule objects” section of the official documentation on how to create your own rule objects.

Conclusion

Application rules are a nice thing to work with in CakePHP3 even the fact they might not be that easy to understand by a first quick look. You can implement more complex requirements that require you to work on the DB level to validate the integrity of your requirement and database as application rules.

CakePHP 3.0 i18n – language inside the URL

In CakePHP 2.x it was pretty cumbersome to get the language across all pages into the URL. With CakePHP 3 it is just awesome and easy. You can now create persistent URL parameters.

This is basically all you need for the most basic implementation inside your config/routes.php. The code is mostly the same as in the previous link to the persistent URL parameters page but I’ve added the default language so  that it is always present. If you don’t want a default language to be always present just remove the elseif part. Notice that you’ll have to add routes into the /:language/* scope to inject it.

If you now want to change the URL to something else by a simple click on a flag for example you can use a simple link like this to change it:

If you don’t want the language to be part of the URL but still detect the language somehow you can use the LocaleSelector dispatcher filter that will get it from the client. This is straight taken from the CakePHP book:

By using the LocaleSelectorFilter in your application, CakePHP will automatically set the locale based on the current user: