Problem/Motivation

When a user name field has a preferred_field_reference or alternative_field_reference configured, the realname integration resolves those components via AdditionalComponentService::collectRenderedValues(), which renders the referenced field item and catches \Exception around the render call. Outside a render context, Renderer::render() throws LogicException, which is caught and treated as "no value" — the component is silently dropped.

UserHooks::userLoad() runs on every user entity load, and many loads happen with no render context active: drush, cron, queue workers, mail building, and the early phases of ordinary page requests (routing and access checks run before HtmlRenderer wraps the page build in executeInRenderContext()). In those cases $account->realname — and therefore the altered display name — is computed without the preferred/alternative component. Because realname is statically cached per request, the same user can show different names depending on where in the request they were first loaded, and a stale render context left on the renderer's stack can make the bug vanish intermittently — which may be why it is hard to pin down in the wild.

The same silent fallback affects any other caller of the service without an active render context; we first noticed it via a site computing display names in preSave().

A contributing factor: the existing AdditionalComponentServiceTest covers _self, _self_property_* and a missing field, but not a real field reference — so resolveField()/collectRenderedValues(), the only path that renders, currently has no test coverage.

Steps to reproduce

  1. On the user entity, add a name field and a plain string field (e.g. "Nickname"). Confirm name.settings user_preferred now holds the name field's machine name (creating the field sets this automatically; note it must be the field name, not a format id).
  2. In the name field's settings, set the preferred source to the nickname field, and set the field's override_format to a format whose pattern uses the preferred token with a fallback, e.g. (Gp~Gg)+iGf.
  3. Create a user with name "Lucinda Cooper" and nickname "Cindy".
  4. Probe without a render context: drush php:eval '$u = \Drupal\user\Entity\User::load(UID); print $u->getDisplayName();' → "Lucinda Cooper".
  5. Probe the same load inside \Drupal::service('renderer')->executeInRenderContext(new \Drupal\Core\Render\RenderContext(), …) (separate drush invocation, to avoid the per-request realname static cache) → "Cindy Cooper".

Proposed resolution

Wrap the viewFieldItem()/render() call in collectRenderedValues() in executeInRenderContext(new RenderContext(), …) — or equivalently use $this->renderer->renderInIsolation($renderable) — so resolution works identically in all calling contexts. No signature or behaviour changes otherwise.

Two adjacent observations we're deliberately leaving out of scope for 1.x, as they'd be behaviour changes in a stable branch: the access('view') check makes computed names viewer-dependent, and the mid-computation render discards cacheability metadata.

Remaining tasks

User interface changes

None.

API changes

None.

Data model changes

None.

Issue fork name-3614450

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

jonathanshaw created an issue. See original summary.

jonathanshaw’s picture

Issue summary: View changes
bluegeek9’s picture

Issue summary: View changes
bluegeek9’s picture

I will look into ways we might be able to fix this. In 2.0.x the preferred and alternative name will be field settings.

#3031696: Refactor preferred and alternative as computed properties

jonathanshaw’s picture

My suggestion for the 2.x solution for this issue would be #3614726: Add NameItem::getComponents() and NameItem::format() to make name resolution available outside the formatter. In sense this issue is the 1.x bug manifestation of that broader API weakness.