Skip to content

[6.x] Bard server-side performance improvements - #15258

Merged
jasonvarga merged 4 commits into
6.xfrom
bard-php-perf
Aug 24, 2026
Merged

[6.x] Bard server-side performance improvements#15258
jasonvarga merged 4 commits into
6.xfrom
bard-php-perf

Conversation

@jasonvarga

Copy link
Copy Markdown
Member

Split out of #15158.

Generate the asset field's meta once

preload() called meta() twice on the same throwaway asset field, once for container and once for columns. Each call builds the entire Assets preload payload — container lookup, five permission checks, blueprint columns — so half of that work was thrown away.

Resolve link data without a full preload payload

linkDataForType() called preload() on a nested field just to read ['data'][0]. Relationship and Assets both build that data from getItemData(), so it can come straight from there, skipping the selection URLs, columns, creatables and container permissions that were being built and discarded once per link in the content.

It's also a bug fix. When a Bard field has an asset link in its content but no configured container, the old path went through Assets::preload()container(), which throws UndefinedContainerException and 500s the publish form. The new path returns the usual invalid-item marker instead.

The fast path is guarded with instanceof rather than a method_exists('getItemData') check. Dictionary::getItemData() is private and returns a plain array, so duck-typing would fatal on a link type using it, where today it harmlessly resolves to null.

Cache the toolbar's link types for the request

Every Bard field rebuilt the toolbar's link types from scratch, generating a full preload payload per link type. A page with several Bard fields — or a Replicator whose sets each contain one — repeated that per field. Blink is request-scoped, so there's no cross-request staleness.

The key includes the current site and user as well as the field config, because the payload embeds both. An entry link type with no configured collections falls back to the collections routable in Site::current(), and the asset link type's meta carries the current user's container permissions. Keying on the config alone serves one context's toolbar to another — with blog routable in en only and actus in fr only, the second site got the first site's collections.

Return $this from the DataAwareRule's setData()

The interface declares a $this return. Removes the corresponding PHPStan baseline entry.

The interface declares a $this return. Removes the corresponding PHPStan
baseline entry.
preload() called meta() twice on the same throwaway asset field, generating
the whole Assets preload payload — container lookup, permission checks and
blueprint columns — twice over.
Relationship and Assets both build their preload 'data' from getItemData(),
so link data can be resolved directly from it. The rest of the payload —
selection URLs, columns, creatables, container permissions — was being built
and thrown away once per link in the content.

Also fixes a 500 when a Bard field contains an asset link but has no
container configured: the old path went through Assets::preload(), which
throws UndefinedContainerException.
Every Bard field rebuilt the toolbar's link types from scratch, generating a
full preload payload per link type. A page with several Bard fields — or a
Replicator whose sets each contain one — repeated that work per field.

Keyed on the current site and user as well as the field config, because the
payload embeds both: an entry link type with no configured collections falls
back to the current site's routable collections, and the asset link type's
meta carries the current user's container permissions.
@jasonvarga
jasonvarga merged commit 9bfb6ab into 6.x Aug 24, 2026
65 checks passed
@jasonvarga
jasonvarga deleted the bard-php-perf branch August 24, 2026 22:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant