TypeError: FormsSteps::getFirstStep(): Return value must be of type Drupal\forms_steps\StepInterface

Created on 7 February 2025, 6 months ago

Problem/Motivation

TypeError: Drupal\forms_steps\Entity\FormsSteps::getFirstStep(): Return value must be of type Drupal\forms_steps\StepInterface, false returned in Drupal\forms_steps\Entity\FormsSteps->getFirstStep() (line 409 of /app/public/modules/contrib/forms_steps/src/Entity/FormsSteps.php).

Steps to reproduce

- Install / setup clean Drupal without any content type
- go config/workflow/forms_steps
- create workflow
- add step(s) without content type because you dont have any
- check that your form steps are showing on forms step listing
- create a new content type
- now go again config/workflow/forms_steps
- now you see error

🐛 Bug report
Status

Active

Version

1.7

Component

Code

Created by

🇫🇮Finland tvalimaa

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @tvalimaa
  • Merge request !19allow null getFirstStep return → (Open) created by tvalimaa
  • 🇺🇸United States markwk

    I hit the same issue. The issue occurs because:

    1. FormsStepsListBuilder::getDefaultOperations() calls getFirstStep() to determine if a "View" operation should be shown
    2. FormsSteps::getFirstStep() uses reset($steps) which returns FALSE when the array is empty
    3. The method signature requires a StepInterface return type, but FALSE is returned instead

    The fix involves:
    1. Modifying getFirstStep() and getLastStep() to throw a descriptive exception when no steps exist
    2. Updating FormsStepsListBuilder to catch this exception gracefully.

    diff --git a/src/Builder/FormsStepsListBuilder.php b/src/Builder/FormsStepsListBuilder.php
    index c932430..5c16ea9 100644
    --- a/src/Builder/FormsStepsListBuilder.php
    +++ b/src/Builder/FormsStepsListBuilder.php
    @@ -47,18 +47,23 @@ class FormsStepsListBuilder extends ConfigEntityListBuilder {
       public function getDefaultOperations(EntityInterface $entity): array {
         /** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $entity */
         $operations = parent::getDefaultOperations($entity);
    -    $first_step = $entity->getFirstStep();
    +    
    +    try {
    +      $first_step = $entity->getFirstStep();
    +      // View action is only displayed when the forms steps has at least one step.
    +      if ($first_step) {
    +        $uri = $first_step->url();
     
    -    // View action is only displayed when the forms steps has at least one step.
    -    if ($first_step) {
    -      $uri = $first_step->url();
    -
    -      $operations['display'] = [
    -        'title' => $this->t('View'),
    -        'weight' => 20,
    -        'url' => Url::fromUri("internal:$uri"),
    -      ];
    +        $operations['display'] = [
    +          'title' => $this->t('View'),
    +          'weight' => 20,
    +          'url' => Url::fromUri("internal:$uri"),
    +        ];
    +      }
    +    } catch (\InvalidArgumentException $e) {
    +      // No steps available, so no View operation will be shown.
         }
    +    
         return $operations;
       }
     
    diff --git a/src/Entity/FormsSteps.php b/src/Entity/FormsSteps.php
    index 4ca1eb2..4b62d96 100644
    --- a/src/Entity/FormsSteps.php
    +++ b/src/Entity/FormsSteps.php
    @@ -406,7 +406,11 @@ class FormsSteps extends ConfigEntityBase implements FormsStepsInterface {
         if ($steps === NULL) {
           $steps = $this->getSteps();
         }
    -    return reset($steps);
    +    $first_step = reset($steps);
    +    if ($first_step === FALSE) {
    +      throw new \InvalidArgumentException('No steps available to get first step.');
    +    }
    +    return $first_step;
     
       }
     
    @@ -417,7 +421,11 @@ class FormsSteps extends ConfigEntityBase implements FormsStepsInterface {
         if ($steps === NULL) {
           $steps = $this->getSteps();
         }
    -    return end($steps);
    +    $last_step = end($steps);
    +    if ($last_step === FALSE) {
    +      throw new \InvalidArgumentException('No steps available to get last step.');
    +    }
    +    return $last_step;
     
       }
     
    
  • 🇺🇸United States markwk

    Attaching fix that addresses the InvalidArgumentException issue by:
    - Adding proper exception handling in getFirstStep() and getLastStep() methods when no steps are available
    - Catching the exception in the list builder to prevent crashes when displaying the operations

Production build 0.71.5 2024