Introduce a new cache tags aware prop shape repository, so changes affecting prop shape calculation can force the re-invoke of hook_canvas_storable_shape_prop_alter
>>> [!note] Migrated issue
<!-- Drupal.org comment -->
<!-- Migrated from issue #3547579. -->
Reported by: [wim leers](https://www.drupal.org/user/99777)
Related to !145 !298
>>>
<h3 id="overview">Overview</h3>
<p><em>Identified at <a href="https://git.drupalcode.org/project/canvas/-/merge_requests/23#note_590788">https://git.drupalcode.org/project/canvas/-/merge_requests/23#note_590788</a> on <span class="drupalorg-gitlab-issue-link drupalorg-gitlab-link-wrapper"><a href="https://git.drupalcode.org/project/canvas/-/work_items/3544604" class="drupalorg-gitlab-link">https://git.drupalcode.org/project/canvas/-/work_items/3544604</a></span>.</em></p>
<p><code>hook_storage_prop_shape_alter()</code> is basically the only PHP API that Canvas offers.</p>
<p>However, the results of this method may need to be re-evaluated based on external changes that Canvas is unaware of. </p>
<h4>Example
</h4><p><code>\Drupal\canvas\Hook\ShapeMatchingHooks::mediaLibraryStoragePropShapeAlter()</code> implements this hook on behalf of the <code>media_library</code> module.</p>
<ol>
<li>✅ A module getting installed in Drupal automatically rebuilds caches. So the hook is executed automatically. Which means <code>Component</code> config entities are updated automatically with the field type+widget that should be used for "image"-shaped props. <em>If</em> there are >=1 <code>MediaType</code>s using the <code>image</code> <code>MediaSource</code> plugin. If there's zero, Canvas sticks to its default that is guaranteed to work (the image field type+widget).
</li><li>🐛 However, if there were 0 such <code>MediaType</code>s the first time it ran, and then the user creates their first such <code>MediaType</code>, then the site incorrectly stays "stuck" on using the image field type, rather than switching to the media library widget!
</li><li>💡 What's missing is the ability for <code>hook_storage_prop_shape_alter()</code> to convey what cache tags cause its results/conclusions to change. In the case of <code>ShapeMatchingHooks::mediaLibraryStoragePropShapeAlter()</code> that's the <code>config:media_type_list</code> cache tag. But this won't cause component config entities to be regenerated for the JsComponent source plugin - it only updates when the JavascriptComponent entity is saved
</li><li>💡 We can listen for changes to media source fields using <code>hook_field_config_insert</code> and <code>hook_field_config_update</code> and use that to invalidate discovered SDC components and resave any JavascriptComponents that have props referencing image or video objects. But that requires taking care of each use case one by one, which won't scale when contrib chimes in: there are multiple reasons the shape might need to change</li>
</ol>
<h3 id="proposed-resolution">Proposed resolution</h3>
<ol>
<li> 🤓 Make <code>Component</code> config generation/updates predictable (in <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-7"><a href="https://www.drupal.org/project/canvas/issues/3556327" title="Status: Closed (fixed)">#3556327: Don't save `Component` config entities unnecessarily</a></span>)</li>
<li>Introduce a prop shape repository as a cache collector (TBD) with associated cacheability metadata for each one.</li>
<li>If any prop shape changes, the prop shape repository can invalidate the shapes and ask the required component source manager to update the relevant components:
<ol>
<li>Invalidate discovered SDC components and </li>
<li>resave any JavascriptComponents that have props affected.</li>
</ol>
</li>
</ol>
<h3 id="ui-changes">User interface changes</h3>
<p>See the example above: the 🐛 would disappear.</p>
> Related issue: [Issue #3544604](https://www.drupal.org/node/3544604)
> Related issue: [Issue #3556320](https://www.drupal.org/node/3556320)
> Related issue: [Issue #3556327](https://www.drupal.org/node/3556327)
> Related issue: [Issue #3526045](https://www.drupal.org/node/3526045)
issue