Problem/Motivation

WebformAccessBreadcrumbBuilder::applies() passes the result of
RouteMatchInterface::getRouteName() straight to str_contains().
That method is documented to return string|null — "NULL if no route is matched" —
and passing NULL to a string parameter has been deprecated since PHP 8.1. Every enabled breadcrumb
builder is asked whether it applies, so on a route-less match sites with webform_access
enabled log:

Deprecated function: str_contains(): Passing null to parameter #1 ($haystack) of type string is deprecated

This is the unfinished half of
#3158332.
That issue
(fixed in 2020, commit 9863ce8) reported this exact builder blowing up during Solr
search indexing, because entities were being rendered in a context with no route. The fix added:

if (!$route_match->getRouteObject()) {
  return FALSE;
}

…but placed it after the route-name check rather than before it. On PHP 7 that
ordering was harmless, since strpos(NULL, ...) simply worked. Once PHP 8.1 deprecated
passing NULL to a string parameter, the very first line — the one #3158332 did not touch —
started emitting a deprecation in precisely the scenario #3158332 documented. The guard is one line
too late.

The sibling WebformBreadcrumbBuilder::applies() already has the correct form,
if (!$route_name || !str_contains($route_name, 'webform')), and
WebformBreadcrumbBuilderTest::providerTestApplies() already covers the NULL route name
case (its first data set, [FALSE], relies on the ?string $route_name = NULL
default). The access variant was never brought in line.

Steps to reproduce

Any render of an entity without a route match will do — search indexing is the real-world
case documented in #3158332. Minimal deterministic reproduction:

  1. Install Drupal 11.4 on PHP 8.3 and enable webform and webform_access.
  2. Build a route match that matched no route and ask the builder whether it applies:
    $request = \Symfony\Component\HttpFoundation\Request::create('/this-path-does-not-exist');
    $route_match = \Drupal\Core\Routing\RouteMatch::createFromRequest($request);
    // getRouteName() is NULL here.
    \Drupal::service('webform_access.breadcrumb')->applies($route_match);
  3. Observe the deprecation notice. It also appears in dblog on ordinary 404 responses.

Proposed resolution

Guard the route name before the str_contains() call, using exactly the same
expression the sibling WebformBreadcrumbBuilder already uses:

if (!$route_name || !str_contains($route_name, 'webform_access')) {

A NULL or empty route name can never contain webform_access, so the method still
returns FALSE and behaviour is unchanged for every route that previously matched.

Remaining tasks

  • Review the merge request.
  • Optional: add a unit test for WebformAccessBreadcrumbBuilder mirroring
    WebformBreadcrumbBuilderTest::testApplies(); webform_access currently
    has no breadcrumb test coverage at all. A [FALSE] data set (NULL route name) would
    have caught this.

AI-Generated: Yes (used to draft the fix and this issue summary, reviewed and tested by me.)

Issue fork webform-3623528

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

vas-alyfantis created an issue. See original summary.

vas-alyfantis’s picture

Status: Active » Needs review
liam morland’s picture

Status: Needs review » Active

The merge request contains no proposed changes to review.

vas-alyfantis’s picture

Apologies, the branch is now updated and contains the suggested proposed fix

vas-alyfantis’s picture

Status: Active » Needs review