Verified Commit 6e88a2d4 authored by Dave Long's avatar Dave Long
Browse files

fix: #3205577 Form handlers should throw exception when not implementing EntityFormInterface

By: @joachim
By: @acbramley
(cherry picked from commit 9976cfec)
parent c967b591
Loading
Loading
Loading
Loading
Loading
+0 −30
Original line number Diff line number Diff line
@@ -49197,36 +49197,6 @@
	'count' => 1,
	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityResolverManagerTest.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\Tests\\\\Core\\\\Entity\\\\TestEntityForm\\:\\:getBaseFormId\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
	'count' => 1,
	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityTypeManagerTest.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\Tests\\\\Core\\\\Entity\\\\TestEntityForm\\:\\:getFormId\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
	'count' => 1,
	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityTypeManagerTest.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\Tests\\\\Core\\\\Entity\\\\TestEntityForm\\:\\:setEntity\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
	'count' => 1,
	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityTypeManagerTest.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\Tests\\\\Core\\\\Entity\\\\TestEntityForm\\:\\:setEntityTypeManager\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
	'count' => 1,
	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityTypeManagerTest.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\Tests\\\\Core\\\\Entity\\\\TestEntityForm\\:\\:setOperation\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
	'count' => 1,
	'path' => __DIR__ . '/tests/Drupal/Tests/Core/Entity/EntityTypeManagerTest.php',
];
$ignoreErrors[] = [
	'message' => '#^Method Drupal\\\\Tests\\\\Core\\\\Entity\\\\TestEntityFormInjected\\:\\:create\\(\\) has no return type specified\\.$#',
	'identifier' => 'missingType.return',
+3 −0
Original line number Diff line number Diff line
@@ -212,6 +212,9 @@ public function getFormObject($entity_type_id, $operation) {
    }

    $form_object = $this->classResolver->getInstanceFromDefinition($class);
    if (!$form_object instanceof EntityFormInterface) {
      throw new InvalidPluginDefinitionException($entity_type_id, sprintf('The "%s" form handler of the "%s" entity type specifies a class "%s" that does not extend "%s".', $operation, $entity_type_id, $class, EntityFormInterface::class));
    }

    return $form_object
      ->setStringTranslation($this->stringTranslation)
+44 −45
Original line number Diff line number Diff line
@@ -9,14 +9,16 @@
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityHandlerBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Exception\InvalidLinkTemplateException;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Tests\UnitTestCase;
use PHPUnit\Framework\Attributes\CoversClass;
@@ -294,6 +296,23 @@ public function testGetFormObjectInvalidOperation(string $entity_type_id, string
    $this->entityTypeManager->getFormObject($entity_type_id, $operation);
  }

  /**
   * Tests the getFormObject() method with an invalid class.
   *
   * @legacy-covers ::getFormObject
   */
  public function testGetFormObjectInvalidClass(): void {
    $donkey = $this->prophesize(EntityTypeInterface::class);
    $donkey->getFormClass('default')->willReturn(TestNotAnEntityForm::class);

    $this->setUpEntityTypeDefinitions([
      'donkey' => $donkey,
    ]);
    $this->expectException(InvalidPluginDefinitionException::class);
    $this->expectExceptionMessage('The "default" form handler of the "donkey" entity type specifies a class "Drupal\Tests\Core\Entity\TestNotAnEntityForm" that does not extend "Drupal\Core\Entity\EntityFormInterface".');
    $this->entityTypeManager->getFormObject('donkey', 'default');
  }

  /**
   * Tests the getHandler() method.
   *
@@ -465,7 +484,7 @@ public function setDiscovery(DiscoveryInterface $discovery): void {
/**
 * Provides a test entity form.
 */
class TestEntityForm extends EntityHandlerBase {
class TestEntityForm extends EntityForm {

  /**
   * {@inheritdoc}
@@ -477,49 +496,6 @@ class TestEntityForm extends EntityHandlerBase {
   */
  public $stringTranslation;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * {@inheritdoc}
   */
  public function getBaseFormId() {
    return 'the_base_form_id';
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'the_form_id';
  }

  /**
   * {@inheritdoc}
   */
  public function setEntity(EntityInterface $entity) {
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function setOperation($operation) {
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function setEntityTypeManager(EntityTypeManagerInterface $entity_type_manager) {
    $this->entityTypeManager = $entity_type_manager;
    return $this;
  }

}

/**
@@ -553,6 +529,29 @@ public static function create(ContainerInterface $container) {

}

/**
 * Provides a test entity form that doesn't extend EntityForm.
 */
class TestNotAnEntityForm extends FormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'not_an_entity_form';
  }

  public function buildForm(array $form, FormStateInterface $form_state) {
    // No-op.
    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state): void {
    // No-op.
  }

}

/**
 * Provides a test entity route provider.
 */