Fix LogicException on component instance updates and config schema validation errors on fallback components
## Problem/Motivation Since upgrading the `canvas` module from `1.4.1` to `1.5.1`, two related issues prevent content templates from being loaded or saved: 1. Loading a template throws a `LogicException: Missing the keys expression.` 2. Accepting config updates triggers multiple schema validation errors (e.g., `'width' is not a supported key.`, `'columns' is not a supported key.`) on fallback components (e.g., components defined in disabled themes or uninstalled modules). NOTE: My PHP skills are pretty much non-existent, so I had the AI help me look into this issues and generate the patch. ### Error 1: LogicException Traceback ``` LogicException: Missing the keys expression. in Drupal\canvas\PropSource\EntityFieldPropSource::parse() (line 91 of /var/www/html/public_html/modules/contrib/canvas/src/PropSource/EntityFieldPropSource.php). #0 /var/www/html/public_html/modules/contrib/canvas/src/PropSource/PropSource.php(114): Drupal\canvas\PropSource\EntityFieldPropSource::parse() #1 /var/www/html/public_html/modules/contrib/canvas/src/Plugin/Canvas/ComponentSource/JsonSchemaPropsComponentSourceBase.php(1526): Drupal\canvas\PropSource::parse() #2 /var/www/html/public_html/modules/contrib/canvas/src/Plugin/Canvas/ComponentSource/JsonSchemaPropsComponentSourceBase.php(609): Drupal\canvas\Plugin\Canvas\ComponentSource\JsonSchemaPropsComponentSourceBase->uncollapse() ... ``` ### Error 2: Configuration Validation Violations ``` - [component_tree.241bbe4f-0d9a-4efb-9ab1-4c422caf7282.inputs.width] 'width' is not a supported key. - [component_tree.241bbe4f-0d9a-4efb-9ab1-4c422caf7282.inputs.columns] 'columns' is not a supported key. ... ``` --- ## Causes ### Cause 1: LogicException in Cardinality Slicing In `JsonSchemaPropsComponentInstanceUpdater::update()`, a loop truncates array inputs exceeding new cardinality limits: ```php foreach ($to_props as $prop_name => $def) { ... if (!isset($inputs[$prop_name]) || !\is_array($inputs[$prop_name]) || \count($inputs[$prop_name]) <= $new_cardinality) { continue; } $inputs[$prop_name] = \array_slice($inputs[$prop_name], 0, $new_cardinality); } ``` Dynamic prop sources (like `entity-field` inputs) are stored as associative PHP arrays (e.g., `['sourceType' => 'entity-field', 'expression' => '...']`), so they satisfy `\is_array()`. Slicing them down to the cardinality limit (which is `1` for single-value properties) drops critical keys like `'expression'`, triggering `LogicException`. ### Cause 2: Validation Errors on Fallback Components When a theme/module containing component definitions is disabled, `canvas` converts those component instances to `active version = fallback`. The `Fallback` component source plugin uses `FallbackComponentInstanceInputsConfigSchemaGenerator` to generate the config schema mapping of its inputs. Since `Fallback::getDefaultExplicitInput()` returns `[]`, `getConfigSchemaMapping()` returns an empty array `[]`. Thus, the config schema definition for the inputs of a fallback component is completely empty. When the template gets validated/saved during update checks, Drupal's strict configuration validator flags all existing properties (like `width`, `columns`, `variant`) as unsupported keys. --- ## Proposed Resolutions ### Fix 1: Skip Slicing on Single Prop Sources Modify the cardinality check in `JsonSchemaPropsComponentInstanceUpdater` to ignore/skip array slicing for associative arrays representing a single prop source (i.e. those containing the key `'sourceType'`). ```php if ( !isset($inputs[$prop_name]) || !\is_array($inputs[$prop_name]) || \array_key_exists('sourceType', $inputs[$prop_name]) || \count($inputs[$prop_name]) <= $new_cardinality ) { continue; } ``` ### Fix 2: Dynamically Map Fallback Inputs Modify `FallbackComponentInstanceInputsConfigSchemaGenerator::refineForInstance()` to append any keys present in the instance's actual inputs as `type: ignore` to prevent validation errors while preserving existing configuration data. ```php public function refineForInstance(array $mapping, array $actual_inputs, string $component_id, string $component_version): array { foreach (\array_keys($actual_inputs) as $key) { if (!isset($mapping[$key])) { $mapping[$key] = [ 'type' => 'ignore', 'requiredKey' => FALSE, ]; } } return $mapping; } ``` --- ## Remaining Tasks - Review patch. - Apply patch and verify. [canvas-missing-expression.patch](/uploads/4fbeb9faa923ddd51ed296b8bcdd8dce/canvas-missing-expression.patch)
issue