Resource type policy attachments are stored under the yoyaku_order third party key
Moves a resource type's constraint policy attachments from the yoyaku_order
third-party key to yoyaku, and derives each policy's settings schema from the
attached plugin id.
Why
The engine owns the constraint policy system and ships a policy of its own
(transaction_quantity_limit), but the key the attachments sat under, and the
only schema describing them, belonged to yoyaku_order. Two consequences:
- Attaching any policy to a type produced configuration with no schema unless
yoyaku_orderhappened to be installed. A kernel test installing onlyyoyakuand attaching the engine's own policy failed withSchemaIncompleteException. - One flat mapping enumerated the settings of three different modules, so every
policy-shipping module had to name its settings in a file it did not control.
The
minimum_agesettings had no schema at all.
What changed
yoyaku.schema.ymldescribes the attachment once (yoyaku.constraint_policy_attachment) and resolves the settings type from the attached plugin id, following core'simage.effect.[%parent.id]pattern. A module shipping a policy now declaresyoyaku.constraint_policy.<plugin_id>, extendingyoyaku.constraint_policy_settingsand naming only what it adds.yoyaku_orderandyoyaku_orchestra_exampleeach declare their own policies' settings. The flat mapping is gone, not deprecated: there is no fallback read of the old key and no legacy schema left behind.ConstraintPolicyResolvergains aPROVIDERconstant and uses it for both the read and the write.
Deliberately not added: a PluginExists constraint on the stored id. An
attachment naming a plugin that has gone must stay storable, because the manager
keeps it, logs the host and answers it with the broken stand-in that refuses.
Rejecting it in schema would turn that loud fail-closed into a resource type
nobody can save. A test pins this.
Upgrade step, and it is not optional
The key is stored data, so the code change alone would leave existing
attachments where nothing reads them. That fails open and silently:
typePolicies() returns an empty list, ceilingFor() returns NULL, and a
resource configured to allow one booking at a time quietly starts allowing every
one. This is the failure mode of [#3614349].
scripts/migrate-policy-key.php moves the data. Pre 1.0 there are no update
hooks, so run it once per site with drush php:script followed by
drush cache:rebuild. With no fallback read, the caps of any type not yet moved
do not apply, so do the deploy and the script inside one maintenance window.
The script is idempotent and reports every type it moved.
Behaviour change worth noting
A type carrying policies no longer declares a module dependency on
yoyaku_order — ConfigEntityBase::addDependency() skips the entity type's own
provider. That is the safer direction: a config entity is deleted along with a
module it depends on, so a type carrying the engine's own limit used to be one
yoyaku_order uninstall away from disappearing. Uninstalling the module that
ships an attached policy now leaves the attachment naming a plugin nothing
defines, which the existing fail-closed path already handles.
Tests
PolicyAttachmentStorageTestinstalls onlyyoyaku. It is the class that reproduced the reported failure: all five methods errored withthird_party_settings.yoyaku_order.policies missing schemabefore the fix, 0 assertions reached. It also pins the storage key, the absent dependency, that emptying a type's policies leaves it with none, and that an unknown plugin id is still storable.ShippedPolicySettingsSchemaTestsweeps every policy from the plugin manager rather than listing them, asks each for its own default settings, and saves each on a resource type under strict schema. Removing theyoyaku_orchestra_exampleschema file makes it fail namingmin_ageandfield, so it is known to bite. A second method asserts the sweep actually covers the five shipped policies, since the same test would pass over an empty list.
Docs and the French translation are updated in the same commit.