Problem/Motivation

Creating an entity reference field referencing 'Contact message' causes a fatal error.

Steps to reproduce

1) Create new Content Type (if using existing CT, skip to next step)
2) Add a new field -> Reference -> Other
3) Type of item to reference -> Contact Message -> Save Field Settings
4) Try to access admin/content - same error
5) Try to delete the field - same error, can't be deleted

Full error:

Error: Call to a member function getType() on null in Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::propertyDefinitions() (line 73 of /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php)
#0 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php(118): Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::propertyDefinitions(Object(Drupal\field\Entity\FieldStorageConfig))
#1 /var/lib/tugboat/stm/web/core/modules/field/src/Entity/FieldStorageConfig.php(453): Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::schema(Object(Drupal\field\Entity\FieldStorageConfig))
#2 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php(2311): Drupal\field\Entity\FieldStorageConfig->getSchema()
#3 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php(1540): Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema->getDedicatedTableSchema(Object(Drupal\field\Entity\FieldStorageConfig))
#4 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php(1521): Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema->createDedicatedTableSchema(Object(Drupal\field\Entity\FieldStorageConfig), NULL)
#5 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php(1725): Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema->performFieldSchemaOperation('create', Object(Drupal\field\Entity\FieldStorageConfig))
#6 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php(1521): Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema->updateDedicatedTableSchema(Object(Drupal\field\Entity\FieldStorageConfig), Object(Drupal\field\Entity\FieldStorageConfig))
#7 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php(703): Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema->performFieldSchemaOperation('update', Object(Drupal\field\Entity\FieldStorageConfig), Object(Drupal\field\Entity\FieldStorageConfig))
#8 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php(1527): Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema->onFieldStorageDefinitionUpdate(Object(Drupal\field\Entity\FieldStorageConfig), Object(Drupal\field\Entity\FieldStorageConfig))
#9 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php(1572): Drupal\Core\Entity\Sql\SqlContentEntityStorage->Drupal\Core\Entity\Sql\{closure}()
#10 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php(1530): Drupal\Core\Entity\Sql\SqlContentEntityStorage->wrapSchemaException(Object(Closure))
#11 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Field/FieldStorageDefinitionListener.php(104): Drupal\Core\Entity\Sql\SqlContentEntityStorage->onFieldStorageDefinitionUpdate(Object(Drupal\field\Entity\FieldStorageConfig), Object(Drupal\field\Entity\FieldStorageConfig))
#12 /var/lib/tugboat/stm/web/core/modules/field/src/Entity/FieldStorageConfig.php(385): Drupal\Core\Field\FieldStorageDefinitionListener->onFieldStorageDefinitionUpdate(Object(Drupal\field\Entity\FieldStorageConfig), Object(Drupal\field\Entity\FieldStorageConfig))
#13 /var/lib/tugboat/stm/web/core/modules/field/src/Entity/FieldStorageConfig.php(297): Drupal\field\Entity\FieldStorageConfig->preSaveUpdated(Object(Drupal\field\FieldStorageConfigStorage))
#14 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(494): Drupal\field\Entity\FieldStorageConfig->preSave(Object(Drupal\field\FieldStorageConfigStorage))
#15 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php(449): Drupal\Core\Entity\EntityStorageBase->doPreSave(Object(Drupal\field\Entity\FieldStorageConfig))
#16 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php(263): Drupal\Core\Entity\EntityStorageBase->save(Object(Drupal\field\Entity\FieldStorageConfig))
#17 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Entity/EntityBase.php(339): Drupal\Core\Config\Entity\ConfigEntityStorage->save(Object(Drupal\field\Entity\FieldStorageConfig))
#18 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Config/Entity/ConfigEntityBase.php(591): Drupal\Core\Entity\EntityBase->save()
#19 /var/lib/tugboat/stm/web/core/modules/field_ui/src/Form/FieldStorageConfigEditForm.php(224): Drupal\Core\Config\Entity\ConfigEntityBase->save()
#20 [internal function]: Drupal\field_ui\Form\FieldStorageConfigEditForm->save(Array, Object(Drupal\Core\Form\FormState))
#21 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Form/FormSubmitter.php(113): call_user_func_array(Array, Array)
#22 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Form/FormSubmitter.php(51): Drupal\Core\Form\FormSubmitter->executeSubmitHandlers(Array, Object(Drupal\Core\Form\FormState))
#23 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Form/FormBuilder.php(593): Drupal\Core\Form\FormSubmitter->doSubmitForm(Array, Object(Drupal\Core\Form\FormState))
#24 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Form/FormBuilder.php(321): Drupal\Core\Form\FormBuilder->processForm('field_storage_c...', Array, Object(Drupal\Core\Form\FormState))
#25 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Controller/FormController.php(73): Drupal\Core\Form\FormBuilder->buildForm(Object(Drupal\field_ui\Form\FieldStorageConfigEditForm), Object(Drupal\Core\Form\FormState))
#26 /var/lib/tugboat/stm/web/core/modules/layout_builder/src/Controller/LayoutBuilderHtmlEntityFormController.php(39): Drupal\Core\Controller\FormController->getContentResult(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Routing\RouteMatch))
#27 [internal function]: Drupal\layout_builder\Controller\LayoutBuilderHtmlEntityFormController->getContentResult(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Routing\RouteMatch))
#28 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)
#29 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/Render/Renderer.php(573): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#30 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure))
#31 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)
#32 /var/lib/tugboat/stm/vendor/symfony/http-kernel/HttpKernel.php(158): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#33 /var/lib/tugboat/stm/vendor/symfony/http-kernel/HttpKernel.php(80): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1)
#34 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#35 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#36 /var/lib/tugboat/stm/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(106): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#37 /var/lib/tugboat/stm/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(85): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#38 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#39 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(52): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#40 /var/lib/tugboat/stm/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#41 /var/lib/tugboat/stm/web/core/lib/Drupal/Core/DrupalKernel.php(705): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#42 /var/lib/tugboat/stm/web/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#43 {main}

---

When going back to the field management page, it appears as though the field is properly created with the "entity reference" as the widget. However, when clicking on the link for "entity reference", you are then presented with the error: The website encountered an unexpected error. Please try again later. (I'm thinking it might be an issue with simplytest.me?)

If you try to delete the field, it gives you the same error, but it does appear to properly delete the field when backing up to the field management page.

Proposed resolution

The problem is due to the fact that contact messages don't have an ID key -- intentionally, apparently -- but entity reference fields, quite reasonably, expect their targeted entity type to have an ID. Therefore, it shouldn't be possible to create an entity reference field that targets an entity type that hasn't got an ID key.

We need to fix this from two angles:

  • When creating an entity reference field in the UI, you should not be able to choose an ID-less entity type as the target entity type. Those entity types should not even be presented as options.
  • At the API level, upon creation of a new entity reference field storage, we should check that the target entity type has an ID key and throw an exception if it doesn't.

Remaining tasks

  • Write a test to ensure that ID-less entity types are not presented in the UI as options when creating a new entity reference field. Done!
  • Write a test to ensure that we throw an exception when programmatically creating an entity reference field that targets an ID-less entity type. Done!
  • Review and commit the merge request!

API changes

None.

UI changes

Some options will no longer be available in the Field UI, but good friggin' riddance: choosing those options causes an exception.

Data model changes

None.

Release notes snippet

TBD

Issue fork drupal-2608750

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:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

philsward created an issue. See original summary.

philsward’s picture

Issue summary: View changes
philsward’s picture

Title: Fatal error Referencing Contact Form » Fatal error Referencing Contact Message Form
larowlan’s picture

Why not use admin>config>search>URL aliases to add a pretty path to the existing form?

larowlan’s picture

Are you referencing contact form or contact message? Either way it won't do what you want.

gopagoninarsing’s picture

Able to replicate the issue with the steps provided.Here is the error log message which might helps in investigating/fixing the issue.

Uncaught PHP Exception Drupal\\Core\\Database\\DatabaseExceptionWrapper: "SQLSTATE[42S02]: Base table or view not found: 1146 Table 'drupal_8_rc3.node_revision__field_contact' doesn't exist: SELECT 1 AS expression\nFROM \n{node_revision__field_contact} t\nWHERE ( (field_contact_target_id IS NOT NULL ) )\nLIMIT 1 OFFSET 0; Array\n(\n)\n at /drupal-8-rc3/core/lib/Drupal/Core/Database/Connection.php line 676,

philsward’s picture

@larowlan thanks for the suggestion. I didn't get that far to think of doing that. I assumed that a contact form by nature would be more straight forward to access from the outside, than manually adding a URL alias somewhere else... Guess there's no "URL field" in D8 to convert any entity into a URL page? (Thinking aloud)

The next logical thought was to reference the contact entity on a node, which is where the error is produced. Thanks for confirming it @gopagoninarsing

fietserwin’s picture

Version: 8.0.0-rc3 » 8.1.1
FileSize
308.33 KB

Still occurring in 8.1.1,see attached detailed error page.

larowlan’s picture

FWIW contact_storage in contrib makes this possible - it adds a view builder so you can reference a form and use 'rendered entity' to embed the form

Clemence.Blazy’s picture

I got the problem with the same steps, with an "SQLSTATE[42S02]: Base table or view not found". The problem is that the table really doesn't exist in the DB, and I get a fatal error on my drupal install and can't access either front or back office anymore. Not sure yet how I'm going to get my site back...
If this action really doesn't work (and worse get sites to crash), why keep it? Either it should work or disappear.

praveenmoses61’s picture

Version: 8.1.1 » 8.6.12
Priority: Normal » Critical
FileSize
24.66 KB
5.4 KB

This issue was also in Drupal 8.6.12. refer the image attachments.

catch’s picture

Title: Fatal error Referencing Contact Message Form » Contact forms are offered as an option for entity reference fields, but selecting leads to a fatal error
Version: 8.6.12 » 8.8.x-dev
Component: field system » contact.module
Priority: Critical » Major

Re-titling to try to make it clearer what's going on. Moving to contact module because it's likely an issue there (unless we're missing a mechanism to prevent entity types from being referencable).

Also downgrading to major per https://www.drupal.org/core/issue-priority

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

pameeela’s picture

Title: Contact forms are offered as an option for entity reference fields, but selecting leads to a fatal error » Contact messages are offered as an option for entity reference fields, but selecting leads to a fatal error
Issue summary: View changes
Issue tags: +Bug Smash Initiative

Updating because this works fine when you try to reference a contact *form*, it only errors if you try to reference a contact *message*.

I'm bumping this down to normal as it's hard to fathom intentionally referencing a contact message? It's not clear what that would even be since contact messages are not stored without contact storage?

Updating the IS too because it's a little confusing that it references contact forms before the STR specify contact message.

pameeela’s picture

Priority: Major » Normal

Doh.

pameeela’s picture

Priority: Normal » Major
Issue summary: View changes

Bumping this back to major because I've just realised (and #10 points out) the field can't be deleted through the UI, and it leads to a fatal at admin/content or when viewing any node of the type with this field.

So it may even be critical? A workaround might be to change the yml to reference a different entity type and import the updated config? Haven't tried this as simplytest doesn't support config import.

It's possible you could do this by accident, as Contact message sits between comment and content in the entity reference type list.

larowlan’s picture

The fix here is to change \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::storageSettingsForm to filter out entity types that don't have an ID key

pameeela credited Sid_omp.

pameeela’s picture

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

larowlan’s picture

Component: contact.module » entity system

Per #18 this is not related to the contact module per-se

larowlan’s picture

Issue tags: +Novice, +Needs tests

Tagging for Novice, happy to mentor someone on this

akhoury’s picture

Shriaas’s picture

@larowlan I wrote a small snippet to filter types which do not have id in their entity_keys

$options = \Drupal::service('entity_type.repository')->getEntityTypeLabels(TRUE);
    foreach ($options as $group => $option) {
      foreach ($option as $label => $value) {
        $entity_type = \Drupal::service('entity_type.manager')->getDefinition($label);
        if (!$entity_type->hasKey('id')) {
            unset($options[$group][$label]);
        }
      }
    }
    $element['target_type']['#options'] = $options;

However filtering types in storageSettingsForm using entity_type.manager seems like an overkill to me since the getEntityTypeLabels method itself used entity_type.manager to get the labels of types. So instead it would be better if we create a different method in EntityTypeRepository class to only fetch entity types which have id, or we can add a parameter in the getEntityTypeLabels to accept a filter key and return only the matching types

larowlan’s picture

I think having a filter param which accepted an optional callable that could be passed to array_filter would probably be the cleanest approach, but let me poll the other framework managers first

larowlan’s picture

@shriaas2898 I discussed this with alexpott and we agreed that filtering it in the settings form is fine.

Thanks

Shriaas’s picture

So should I create a patch with snippet suggested in #25 ?

Shriaas’s picture

Status: Active » Needs review
FileSize
1.76 KB

Adding patches with changes, I have added a function to check if the entity type has id key and used it to filter the options array. Also I don't think we can use array_intersect_key here because the getDefinition() function returns an object of \Drupal\Core\Entity\EntityTypeInterface not an array. Please check if this looks fine.

Abhijith S’s picture

FileSize
38.27 KB
42.37 KB

Applied patch #29 and it removes the Contact Message option from type of item to reference.

Before patch:
before

After patch:
after

renatog’s picture

Removing unnecessary line and using single quotes

andypost’s picture

+++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
@@ -353,16 +353,20 @@ class EntityReferenceItem extends FieldItemBase implements OptionsProviderInterf
+    $options = \Drupal::service('entity_type.repository')->getEntityTypeLabels(TRUE);

is there a way to inject the service?

KapilV’s picture

Assigned: Unassigned » KapilV
KapilV’s picture

KapilV’s picture

Assigned: KapilV » Unassigned
sulfikar_s’s picture

FileSize
21.02 KB
20.43 KB
31.44 KB

Hi, I applied the patch, and is working fine!

I'm attaching the screenshots below,

Before,
before-patch.png

After,
after-patch.png

Considering the below change,
patch-change.png

.. I think the previous documentation was better as it is more meaningful! Otherwise RTBC!

guilhermevp’s picture

Issue summary: View changes
Status: Needs review » Needs work
FileSize
34.75 KB

Updated patch works as intended.
Comment #32 asks for dependency injection. Should it be done here and be the only DI of the whole class, or should it be another issue altogether?
Also, patch works moving forward, but user who had used contact message fields will have their sites entirely broken, should we fix that (if possbile) ?
Still needs tests so I'm moving it back to needs work.

Shriaas’s picture

is there a way to inject the service?

@guilhermevp I think adding DI should be a separate issue since other methods of the class will needed to be changed too. Need maintainers suggestion on this.

Also, patch works moving forward, but user who had used contact message fields will have their sites entirely broken, should we fix that (if possbile) ?

Well the issue here was exactly that users are not able to use contact messages as entity reference, so I don't understand how they could have existing field for contact messages 🤔 am I missing something?

guilhermevp’s picture

I think adding DI should be a separate issue since other methods of the class will needed to be changed too. Need maintainers suggestion on this.

I fully agree! Just opened the question because I'm new here, and I think someone more experienced should comment on the matter, since it is a core issue.

I missing something?

No, it's just that I notice that the comment #10 could happened to more people. But then again, I believe that we should move forward on the issue.

guilhermevp’s picture

Issue summary: View changes
Shriaas’s picture

Status: Needs work » Needs review

phenaproxima made their first commit to this issue’s fork.

phenaproxima’s picture

Issue tags: -Needs tests

I hope y'all don't mind that I converted this to a merge request :) They're just so much easier to review in GitLab. (For the record, anybody can push changes to the issue fork; just click the green "Get push access" button at the bottom of the issue summary, then "Show commands" to see how to set up your local git to work with the issue fork. Further documentation about how to work with merge requests on drupal.org can be found at https://www.drupal.org/docs/develop/git/using-git-to-contribute-to-drupa....)

I also wrote a kernel test to make sure this is fixed. However, the most recent patch (#34) does NOT appear to fix the underlying bug; it does fix it when creating fields in the UI, but not when creating fields programmatically (which is what the test covers, and therefore implicitly covers it for the UI too). So the actual fix might need some reworking. However, now that there is low-level test coverage, I leave that task to the rest of you smart people. :)

phenaproxima’s picture

Status: Needs review » Needs work

Oops, forgot to set this to "needs work" to rework the proposed fix to get the test passing.

phenaproxima’s picture

Hiding the previous patch so that committers don't accidentally review it.

phenaproxima’s picture

So I discussed this issue with @larowlan in Slack. We reached the following conclusions:

  • The fundamental nature of this bug is that it is possible to create an entity reference field to entity types which don't have an ID. You can do this in the UI, or programmatically. Either way will result in brokenness. That's not good. I'm not sure if Contact is the only example in core, but it should not be allowed for any ID-less entity type.
  • The UI and the API should be consistent -- creating an entity reference field to an entity type without an ID should always be disallowed. In the UI, ID-less entity types should not be presented as options when creating an entity reference field. Programmatically, trying to create a field to an ID-less entity type should throw an exception.
  • We should fix this in a consistent way, not just for contact messages.

So, with that in mind, I think we need to re-title this issue, rewrite the issue summary, and widen the scope. I think we should still use the code from patch #34 (which I've already added to the issue fork), with a test to ensure that contact messages are not presented as an option in the UI when creating an entity reference field. This is probably no longer novice material, sadly, so I'm removing that tag.

phenaproxima’s picture

Title: Contact messages are offered as an option for entity reference fields, but selecting leads to a fatal error » It is possible to create entity reference fields targeting entity types without an ID
Issue tags: -Needs title update
phenaproxima’s picture

Title: It is possible to create entity reference fields targeting entity types without an ID » Exception when creating an entity reference field targeting an entity type without an ID

Re-titled again to make it clearer what the actual problem is.

phenaproxima’s picture

Updated the issue summary to reflect the new understandings and scope.

mohit_aghera made their first commit to this issue’s fork.

mohit_aghera’s picture

Status: Needs work » Needs review

Write a test to ensure that ID-less entity types are not presented in the UI as options when creating a new entity reference field.

Added the above test case.

Write a test to ensure that we throw an exception when programmatically creating an entity reference field that targets an ID-less entity type.

This seems to be already there in form of Kernel tests.

@phenaproxima, Please confirm if these tests are sufficient. After that I'll remove the "Needs tests" tag.

phenaproxima’s picture

Issue summary: View changes
Issue tags: -Needs tests

That looks great, @mohit_aghera! Removing the tag and updating the issue summary.

phenaproxima’s picture

Regarding this question from #37:

Comment #32 asks for dependency injection. Should it be done here and be the only DI of the whole class, or should it be another issue altogether?

I think adding dependency injection here is out of scope. EntityReferenceItem has at least one other non-static method which uses \Drupal, and I've seen it elsewhere in the field system too. Fixing all that would be nice, but it doesn't affect the actual bug we're trying to squash in this issue. So if we're using \Drupal now -- in code that was previously using \Drupal, to be clear -- then there's no need to add dependency injection now.

guilhermevp’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
3.35 MB
285.99 KB

Moving to RTBC. It has tests and as stated in comments #36, #37 patch works as intended.
Re-adding evidence.

Error:
1

Proposed resolution:
2

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

larowlan’s picture

I think adding dependency injection here is out of scope. EntityReferenceItem ...

Typed data plugins don't support DI, so this is moot #2053415: Allow typed data plugins to receive injected dependencies

larowlan’s picture

left one minor optimisation/question

phenaproxima’s picture

I discussed this issue with @webchick to see if she could think of any edge cases or things I might have missed with this fix. The only questions that came up were:

  1. How does this surface to end users?
  2. What happens if, somehow, you have some invalid configuration somewhere and you try to import it into your site?

This will surface to end users if they try to interact with a reference field that, for some reason, references an entity type without an ID. I could see this happening if, say, they installed the contrib Contact Storage module (which adds an ID field to contact messages), made a reference field to contact messages, and then later uninstalled Contact Storage without removing the field. That would go kaboom, with a fatal error about "cannot call getType() on null", as you see in the issue summary.

In a case like that, this fix will not solve the problem of the invalid field, but it WILL make the error message quite a bit more useful and friendly by actually naming the offending field, and stating the reason why it's hosed.

The same thing will happen if you try to import an invalid field config. I tested this locally by:

  1. Creating a legit reference field, targeting nodes.
  2. Exporting config.
  3. Altering the field config so it would point to contact messages.
  4. Running drush si --existing-config.

Without the patch, I got the same terrifying error as in the issue summary. With it, I got the much more readable and helpful exception. (Although, in the interest of full disclosure, the exception was repeated many times. But I don't know if that's something we can address in this issue.)

So although this will not actually fix existing broken configuration, it does improve the status quo somewhat by a) producing a much more useful error, and b) making it a lot harder, if not impossible, to create broken configuration in the UI.

webchick’s picture

Awesome. That indeed sounds far better than the status quo. And in terms of the overall solution, agreed that filtering these invalid options out of the available ones to choose from seems like a good approach.

However, it seems like @larowlan has his paws all over this one, so not pressing the Big Green Button™ just yet. :) Thanks for looking into my one potential concern, @phenaproxima!

larowlan’s picture

Adding issue credits

larowlan’s picture

Going to merge this locally because the MR is against 9.2, but this needs to go into 9.3 first

  • larowlan committed cf80690 on 9.3.x
    Issue #2608750 by phenaproxima, shriaas2898, KapilV, mohit_aghera,...

  • larowlan committed 87bdf2c on 9.1.x
    Issue #2608750 by phenaproxima, shriaas2898, KapilV, mohit_aghera,...
  • larowlan committed fdb10cc on 9.2.x
    Issue #2608750 by phenaproxima, shriaas2898, KapilV, mohit_aghera,...
larowlan’s picture

Version: 9.3.x-dev » 9.1.x-dev

Committed cf80690 and pushed to 9.3.x. Thanks!

As there is minimal risk of disruption here and this is a major bug, backported to 9.2.x and 9.1.x

Thanks all 🐛

phenaproxima’s picture

Status: Reviewed & tested by the community » Fixed

Nice to see this one fixed! Thanks all.

  • larowlan committed 2e9d478 on 9.3.x
    Revert "Issue #2608750 by phenaproxima, shriaas2898, KapilV,...
  • larowlan committed 3eebb1b on 9.3.x
    Issue #2608750 by phenaproxima, shriaas2898, KapilV, mohit_aghera,...

  • larowlan committed 9d8a004 on 9.1.x
    Revert "Issue #2608750 by phenaproxima, shriaas2898, KapilV,...
  • larowlan committed e57b4e1 on 9.1.x
    Issue #2608750 by phenaproxima, shriaas2898, KapilV, mohit_aghera,...
  • larowlan committed aed9f63 on 9.2.x
    Revert "Issue #2608750 by phenaproxima, shriaas2898, KapilV,...
  • larowlan committed f3227f4 on 9.2.x
    Issue #2608750 by phenaproxima, shriaas2898, KapilV, mohit_aghera,...
larowlan’s picture

I had to re-do the commits here.

I used https://git.drupalcode.org/project/drupal/-/merge_requests/614.patch locally to apply the changes.

However, that's not the same as https://git.drupalcode.org/project/drupal/-/merge_requests/614.diff, which has the correct changes.

I've redone using the later

jibran’s picture

Issue tags: +DER issue

We might have to fix this for DER as well so tagging.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.