Handle computed fields in entity queries: throwing a helpful exception is better than a PHP fatal error

Created on 19 April 2018, over 6 years ago
Updated 23 April 2024, 8 months ago

Problem/Motivation

When writing an entity query it is possible to write conditions against all fields within an entity, however if the field is computed it will throw an error.

Proposed resolution

- Add a check within the entity query if a field is computed, and throw a better error than the one below.
- Create a follow up issue to allow computed fields to add something within the base field definition to know what table to join, how to join it, and which database field is the one to return or base conditions against.

Remaining tasks

User interface changes

API changes

Data model changes

Drupal\\Core\\Entity\\Query\\QueryException: 'moderation_state' not found in /app/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php:348\nStack trace:\n#0 /app/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php(241): Drupal\\Core\\Entity\\Query\\Sql\\Tables->ensureEntityTable('', 'moderation_stat...', 'INNER', NULL, 'base_table', 'nid', Array)\n#1 /app/core/lib/Drupal/Core/Entity/Query/Sql/Condition.php(44): Drupal\\Core\\Entity\\Query\\Sql\\Tables->addField('moderation_stat...', 'INNER', NULL)\n#2 /app/core/lib/Drupal/Core/Entity/Query/Sql/Condition.php(39): Drupal\\Core\\Entity\\Query\\Sql\\Condition->compile(Object(Drupal\\Core\\Database\\Query\\Condition))\n#3 /app/core/lib/Drupal/Core/Entity/Query/Sql/Query.php(163): Drupal\\Core\\Entity\\Query\\Sql\\Condition->compile(Object(Drupal\\Core\\Database\\Driver\\mysql\\Select))\n#4 /app/core/lib/Drupal/Core/Entity/Query/Sql/Query.php(74): Drupal\\Core\\Entity\\Query\\Sql\\Query->compile()\n#5 /app/modules/jsonapi/src/Controller/EntityResource.php(326): Drupal\\Core\\Entity\\Query\\Sql\\Query->execute()\n#6 [internal function]: Drupal\\jsonapi\\Controller\\EntityResource->getCollection(Object(Symfony\\Component\\HttpFoundation\\Request))\n#7 /app/modules/jsonapi/src/Controller/RequestHandler.php(145): call_user_func_array(Array, Array)\n#8 /app/core/lib/Drupal/Core/Render/Renderer.php(582): Drupal\\jsonapi\\Controller\\RequestHandler->Drupal\\jsonapi\\Controller\\{closure}()\n#9 /app/modules/jsonapi/src/Controller/RequestHandler.php(146): Drupal\\Core\\Render\\Renderer->executeInRenderContext(Object(Drupal\\Core\\Render\\RenderContext), Object(Closure))\n#10 [internal function]: Drupal\\jsonapi\\Controller\\RequestHandler->handle(Object(Symfony\\Component\\HttpFoundation\\Request), Object(Drupal\\jsonapi_extras\\ResourceType\\ConfigurableResourceType))\n#11 /app/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)\n#12 /app/core/lib/Drupal/Core/Render/Renderer.php(582): Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->Drupal\\Core\\EventSubscriber\\{closure}()\n#13 /app/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\\Core\\Render\\Renderer->executeInRenderContext(Object(Drupal\\Core\\Render\\RenderContext), Object(Closure))\n#14 /app/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)\n#15 /app/vendor/symfony/http-kernel/HttpKernel.php(151): Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->Drupal\\Core\\EventSubscriber\\{closure}()\n#16 /app/vendor/symfony/http-kernel/HttpKernel.php(68): Symfony\\Component\\HttpKernel\\HttpKernel->handleRaw(Object(Symfony\\Component\\HttpFoundation\\Request), 1)\n#17 /app/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\\Component\\HttpKernel\\HttpKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#18 /app/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\\Core\\StackMiddleware\\Session->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#19 /app/core/modules/page_cache/src/StackMiddleware/PageCache.php(99): Drupal\\Core\\StackMiddleware\\KernelPreHandle->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#20 /app/core/modules/page_cache/src/StackMiddleware/PageCache.php(78): Drupal\\page_cache\\StackMiddleware\\PageCache->pass(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#21 /app/modules/jsonapi/src/StackMiddleware/FormatSetter.php(40): Drupal\\page_cache\\StackMiddleware\\PageCache->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#22 /app/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\\jsonapi\\StackMiddleware\\FormatSetter->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#23 /app/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(50): Drupal\\Core\\StackMiddleware\\ReverseProxyMiddleware->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#24 /app/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\\Core\\StackMiddleware\\NegotiationMiddleware->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#25 /app/core/lib/Drupal/Core/DrupalKernel.php(664): Stack\\StackedHttpKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#26 /app/index.php(19): Drupal\\Core\\DrupalKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request))\n#27 {main}\n\nNext Symfony\\Component\\HttpKernel\\Exception\\HttpException: 'moderation_state' not found in /app/modules/jsonapi/src/EventSubscriber/DefaultExceptionSubscriber.php:43\nStack trace:\n#0 [internal function]: Drupal\\jsonapi\\EventSubscriber\\DefaultExceptionSubscriber->onException(Object(Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent), 'kernel.exceptio...', Object(Drupal\\Component\\EventDispatcher\\ContainerAwareEventDispatcher))\n#1 /app/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func(Array, Object(Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent), 'kernel.exceptio...', Object(Drupal\\Component\\EventDispatcher\\ContainerAwareEventDispatcher))\n#2 /app/vendor/symfony/http-kernel/HttpKernel.php(228): Drupal\\Component\\EventDispatcher\\ContainerAwareEventDispatcher->dispatch('kernel.exceptio...', Object(Symfony\\Component\\HttpKernel\\Event\\GetResponseForExceptionEvent))\n#3 /app/vendor/symfony/http-kernel/HttpKernel.php(79): Symfony\\Component\\HttpKernel\\HttpKernel->handleException(Object(Drupal\\Core\\Entity\\Query\\QueryException), Object(Symfony\\Component\\HttpFoundation\\Request), 1)\n#4 /app/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\\Component\\HttpKernel\\HttpKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#5 /app/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\\Core\\StackMiddleware\\Session->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#6 /app/core/modules/page_cache/src/StackMiddleware/PageCache.php(99): Drupal\\Core\\StackMiddleware\\KernelPreHandle->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#7 /app/core/modules/page_cache/src/StackMiddleware/PageCache.php(78): Drupal\\page_cache\\StackMiddleware\\PageCache->pass(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#8 /app/modules/jsonapi/src/StackMiddleware/FormatSetter.php(40): Drupal\\page_cache\\StackMiddleware\\PageCache->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#9 /app/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\\jsonapi\\StackMiddleware\\FormatSetter->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#10 /app/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(50): Drupal\\Core\\StackMiddleware\\ReverseProxyMiddleware->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#11 /app/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\\Core\\StackMiddleware\\NegotiationMiddleware->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#12 /app/core/lib/Drupal/Core/DrupalKernel.php(664): Stack\\StackedHttpKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#13 /app/index.php(19): Drupal\\Core\\DrupalKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request))\n#14 {main}
πŸ› Bug report
Status

Needs work

Version

11.0 πŸ”₯

Component
EntityΒ  β†’

Last updated about 2 hours ago

Created by

πŸ‡ΊπŸ‡ΈUnited States Snugug

Live updates comments and jobs are added and updated live.
  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡¨πŸ‡ΎCyprus EliasPapa

    Is there any chance this issue gets traction again?
    Trying to filter by moderation state using JSON:API and I would highly appreciate the proposal from #11.

  • πŸ‡ΊπŸ‡ΈUnited States owenbush Denver, CO

    I'm pretty sure this is a similar issue that is plaguing the Recurring Events module.

    In that case there's an entity type eventinstance which actually inherits it's title from a parent eventseries entity. So the title field is computed. This causes issues when using an entity reference field to reference an eventinstance, the entity query fails because the title field does not actually exist.

    Drupal\Core\Entity\Query\QueryException: 'title' not found in Drupal\Core\Entity\Query\Sql\Tables->ensureEntityTable()

    ✨ Unable to reference event instances Active

Production build 0.71.5 2024