Argument 1 passed to Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer::isInternalResourceType() must implement interface Drupal\Core\Entity\EntityInterface, null given.

I have got picture base field definition with cardinality 1 on custom entity, most of them are nulls, suppose EntityReferenceFieldNormalizer lacks checking if entity is not null on line 128.

Comments

olexyy.mails@gmail.com’s picture

StatusFileSize
new38.68 KB

Looks like logic does not includes custom entity ref implementation, where entityr ref is not in separate table but in one main table of entity and is null.

olexyy.mails@gmail.com’s picture

StatusFileSize
new1.27 KB
olexyy.mails@gmail.com’s picture

This additional check in patch make it for me.

olexyy.mails@gmail.com’s picture

Assigned: Unassigned » olexyy.mails@gmail.com
olexyy.mails@gmail.com’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, 3: patch_3014380.patch, failed testing. View results

olexyy.mails@gmail.com’s picture

Patch applied by composer...

Gathering patches for dependencies. This might take a minute.
  - Installing drupal/jsonapi (2.0.0-rc1): Loading from cache
  - Applying patches for drupal/jsonapi
    patches/jsonapi/patch_3014380.patch (Issue #3014380 Handle null entity reference)
olexyy.mails@gmail.com’s picture

Status: Needs work » Needs review
olexyy.mails@gmail.com’s picture

StatusFileSize
new1.27 KB
olexyy.mails@gmail.com’s picture

StatusFileSize
new1.27 KB

The last submitted patch, 10: patch_3014380.patch, failed testing. View results

olexyy.mails@gmail.com’s picture

Status: Needs review » Needs work

The last submitted patch, 11: patch_3014380.patch, failed testing. View results

olexyy.mails@gmail.com’s picture

Well , I did it through `git diff`, composer applies it, so anyone who suffers, have soution...

olexyy.mails@gmail.com’s picture

Status: Needs work » Needs review
wim leers’s picture

Status: Needs review » Postponed (maintainer needs more info)
Issue tags: +API-First Initiative, +Needs steps to reproduce

Thanks for reporting this problem and even working on a patch already! 🙏 👌

I have got picture base field definition with cardinality 1 on custom entity, most of them are nulls, suppose EntityReferenceFieldNormalizer lacks checking if entity is not null on line 128.

Can you share this base field definition? I'd love to reproduce this locally :)

olexyy.mails@gmail.com’s picture

    $fields['picture'] = BaseFieldDefinition::create('image')
      ->setLabel(t('User picture'))
      ->setDescription(t('User picture item.'))
      ->setSetting('alt_field_required', FALSE)
      ->setSetting('title_field_required', FALSE)
      ->setDisplayOptions('view', [
        'type' => 'image',
        'settings' => [
          'image_style' => 'thumbnail',
        ],
      ])
      ->setDisplayConfigurable('view', TRUE)
      ->setDisplayConfigurable('form', TRUE);

This emulates picture like on D7 user (no separate field|table)

olexyy.mails@gmail.com’s picture

Cardinality is 1 by default.

olexyy.mails@gmail.com’s picture

StatusFileSize
new1.26 KB
olexyy.mails@gmail.com’s picture

Tell me why patch is not applies, I followed naming convention, this is strict copy of `git diff`, composer installs it ...

gabesullice’s picture

@olexyy.mails@gmail.com, did you generate the patch from the latest code on the JSON:API 8.x-2.x-dev branch? Perhaps you used the 1.x branch by accident?

keesee’s picture

I am also have this issue. Tried both 8.2.0.x (rc2) and the dev release

I have one custom entity referencing another. The referenced entity has a carnality of -1. both are generated with drupal generate:entity:content

any patches out there for this issue yet?

TypeError: Argument 1 passed to Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer::isInternalResourceType() must implement interface Drupal\Core\Entity\EntityInterface, null given, called in /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/Normalizer/EntityReferenceFieldNormalizer.php on line 128 in Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer->isInternalResourceType() (line 149 of /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/Normalizer/EntityReferenceFieldNormalizer.php) #0 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/Normalizer/EntityReferenceFieldNormalizer.php(128): Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer->isInternalResourceType(NULL) #1 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/vendor/symfony/serializer/Serializer.php(143): Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer->normalize(Object(Drupal\file\Plugin\Field\FieldType\FileFieldItemList), 'api_json', Array) #2 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/Serializer/Serializer.php(58): Symfony\Component\Serializer\Serializer->normalize(Object(Drupal\file\Plugin\Field\FieldType\FileFieldItemList), 'api_json', Array) #3 [internal function]: Drupal\jsonapi\Serializer\Serializer->normalize(Object(Drupal\file\Plugin\Field\FieldType\FileFieldItemList), 'api_json', Array) #4 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi_extras/src/SerializerDecorator.php(67): call_user_func_array(Array, Array) #5 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi_extras/src/SerializerDecorator.php(102): Drupal\jsonapi_extras\SerializerDecorator->relay('normalize', Array) #6 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/Normalizer/EntityNormalizer.php(230): Drupal\jsonapi_extras\SerializerDecorator->normalize(Object(Drupal\file\Plugin\Field\FieldType\FileFieldItemList), 'api_json', Array) #7 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/Normalizer/EntityNormalizer.php(124): Drupal\jsonapi\Normalizer\EntityNormalizer->serializeField(Object(Drupal\file\Plugin\Field\FieldType\FileFieldItemList), Array, 'api_json') #8 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/vendor/symfony/serializer/Serializer.php(143): Drupal\jsonapi\Normalizer\EntityNormalizer->normalize(Object(Drupal\zxlms_courses\Entity\Course), 'api_json', Array) #9 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/Serializer/Serializer.php(61): Symfony\Component\Serializer\Serializer->normalize(Object(Drupal\zxlms_courses\Entity\Course), 'api_json', Array) #10 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php(209): Drupal\jsonapi\Serializer\Serializer->normalize(Object(Drupal\zxlms_courses\Entity\Course), 'api_json', Array) #11 [internal function]: Drupal\jsonapi\Normalizer\JsonApiDocumentTopLevelNormalizer->Drupal\jsonapi\Normalizer\{closure}(Object(Drupal\zxlms_courses\Entity\Course)) #12 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php(210): array_map(Object(Closure), Array) #13 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/vendor/symfony/serializer/Serializer.php(143): Drupal\jsonapi\Normalizer\JsonApiDocumentTopLevelNormalizer->normalize(Object(Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel), 'api_json', Array) #14 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/Serializer/Serializer.php(58): Symfony\Component\Serializer\Serializer->normalize(Object(Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel), 'api_json', Array) #15 [internal function]: Drupal\jsonapi\Serializer\Serializer->normalize(Object(Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel), 'api_json', Array) #16 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi_extras/src/SerializerDecorator.php(67): call_user_func_array(Array, Array) #17 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi_extras/src/SerializerDecorator.php(102): Drupal\jsonapi_extras\SerializerDecorator->relay('normalize', Array) #18 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/EventSubscriber/ResourceResponseSubscriber.php(117): Drupal\jsonapi_extras\SerializerDecorator->normalize(Object(Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel), 'api_json', Array) #19 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/EventSubscriber/ResourceResponseSubscriber.php(82): Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber->renderResponseBody(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\jsonapi\ResourceResponse), Object(Drupal\jsonapi_extras\SerializerDecorator), 'api_json') #20 [internal function]: Drupal\jsonapi\EventSubscriber\ResourceResponseSubscriber->onResponse(Object(Symfony\Component\HttpKernel\Event\FilterResponseEvent), 'kernel.response', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher)) #21 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func(Array, Object(Symfony\Component\HttpKernel\Event\FilterResponseEvent), 'kernel.response', Object(Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher)) #22 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/vendor/symfony/http-kernel/HttpKernel.php(191): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.response', Object(Symfony\Component\HttpKernel\Event\FilterResponseEvent)) #23 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/vendor/symfony/http-kernel/HttpKernel.php(173): Symfony\Component\HttpKernel\HttpKernel->filterResponse(Object(Drupal\jsonapi\ResourceResponse), Object(Symfony\Component\HttpFoundation\Request), 1) #24 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/vendor/symfony/http-kernel/HttpKernel.php(68): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1) #25 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/simple_oauth/src/HttpMiddleware/BasicAuthSwap.php(67): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #26 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Drupal\simple_oauth\HttpMiddleware\BasicAuthSwap->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #27 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #28 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(99): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #29 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(78): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true) #30 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/modules/contrib/jsonapi/src/StackMiddleware/FormatSetter.php(41): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #31 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\jsonapi\StackMiddleware\FormatSetter->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #32 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(52): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #33 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #34 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/core/lib/Drupal/Core/DrupalKernel.php(665): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true) #35 /mnt/c/Users/corpx/Projects/Drupal/drupal-builder/web/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request)) #36 {main}.

keesee’s picture

the referenced entity. I mentioned in #23


namespace Drupal\zxlms_objectives\Entity;

use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\RevisionableContentEntityBase;
use Drupal\Core\Entity\RevisionableInterface;
use Drupal\Core\Entity\EntityChangedTrait;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\user\UserInterface;

/**
 * Defines the Objective entity.
 *
 * @ingroup zxlms_objectives
 *
 * @ContentEntityType(
 *   id = "objective",
 *   label = @Translation("Objective"),
 *   handlers = {
 *     "storage" = "Drupal\zxlms_objectives\ObjectiveStorage",
 *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
 *     "list_builder" = "Drupal\zxlms_objectives\ObjectiveListBuilder",
 *     "views_data" = "Drupal\zxlms_objectives\Entity\ObjectiveViewsData",
 *     "translation" = "Drupal\zxlms_objectives\ObjectiveTranslationHandler",
 *
 *     "form" = {
 *       "default" = "Drupal\zxlms_objectives\Form\ObjectiveForm",
 *       "add" = "Drupal\zxlms_objectives\Form\ObjectiveForm",
 *       "edit" = "Drupal\zxlms_objectives\Form\ObjectiveForm",
 *       "delete" = "Drupal\zxlms_objectives\Form\ObjectiveDeleteForm",
 *     },
 *     "access" = "Drupal\zxlms_objectives\ObjectiveAccessControlHandler",
 *     "route_provider" = {
 *       "html" = "Drupal\zxlms_objectives\ObjectiveHtmlRouteProvider",
 *     },
 *   },
 *   base_table = "objective",
 *   data_table = "objective_field_data",
 *   revision_table = "objective_revision",
 *   revision_data_table = "objective_field_revision",
 *   translatable = TRUE,
 *   admin_permission = "administer objective entities",
 *   entity_keys = {
 *     "id" = "id",
 *     "revision" = "vid",
 *     "label" = "title",
 *     "uuid" = "uuid",
 *     "uid" = "user_id",
 *     "langcode" = "langcode",
 *     "status" = "status",
 *   },
 *   links = {
 *     "canonical" = "/admin/structure/objective/{objective}",
 *     "add-form" = "/admin/structure/objective/add",
 *     "edit-form" = "/admin/structure/objective/{objective}/edit",
 *     "delete-form" = "/admin/structure/objective/{objective}/delete",
 *     "version-history" = "/admin/structure/objective/{objective}/revisions",
 *     "revision" = "/admin/structure/objective/{objective}/revisions/{objective_revision}/view",
 *     "revision_revert" = "/admin/structure/objective/{objective}/revisions/{objective_revision}/revert",
 *     "revision_delete" = "/admin/structure/objective/{objective}/revisions/{objective_revision}/delete",
 *     "translation_revert" = "/admin/structure/objective/{objective}/revisions/{objective_revision}/revert/{langcode}",
 *     "collection" = "/admin/structure/objective",
 *   },
 *   field_ui_base_route = "objective.settings"
 * )
 */
class Objective extends RevisionableContentEntityBase implements ObjectiveInterface {

  use EntityChangedTrait;

  /**
   * {@inheritdoc}
   */
  public static function preCreate(EntityStorageInterface $storage_controller, array &$values) {
    parent::preCreate($storage_controller, $values);
    $values += [
      'user_id' => \Drupal::currentUser()->id(),
    ];
  }

  /**
   * {@inheritdoc}
   */
  protected function urlRouteParameters($rel) {
    $uri_route_parameters = parent::urlRouteParameters($rel);

    if ($rel === 'revision_revert' && $this instanceof RevisionableInterface) {
      $uri_route_parameters[$this->getEntityTypeId() . '_revision'] = $this->getRevisionId();
    }
    elseif ($rel === 'revision_delete' && $this instanceof RevisionableInterface) {
      $uri_route_parameters[$this->getEntityTypeId() . '_revision'] = $this->getRevisionId();
    }

    return $uri_route_parameters;
  }

  /**
   * {@inheritdoc}
   */
  public function preSave(EntityStorageInterface $storage) {
    parent::preSave($storage);

    foreach (array_keys($this->getTranslationLanguages()) as $langcode) {
      $translation = $this->getTranslation($langcode);

      // If no owner has been set explicitly, make the anonymous user the owner.
      if (!$translation->getOwner()) {
        $translation->setOwnerId(0);
      }
    }

    // If no revision author has been set explicitly, make the objective owner the
    // revision author.
    if (!$this->getRevisionUser()) {
      $this->setRevisionUserId($this->getOwnerId());
    }
  }

  /**
   * {@inheritdoc}
   */
  public function getName() {
    return $this->get('title')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setName($name) {
    $this->set('title', $name);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getCreatedTime() {
    return $this->get('created')->value;
  }

  /**
   * {@inheritdoc}
   */
  public function setCreatedTime($timestamp) {
    $this->set('created', $timestamp);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function getOwner() {
    return $this->get('user_id')->entity;
  }

  /**
   * {@inheritdoc}
   */
  public function getOwnerId() {
    return $this->get('user_id')->target_id;
  }

  /**
   * {@inheritdoc}
   */
  public function setOwnerId($uid) {
    $this->set('user_id', $uid);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function setOwner(UserInterface $account) {
    $this->set('user_id', $account->id());
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public function isPublished() {
    return (bool) $this->getEntityKey('status');
  }

  /**
   * {@inheritdoc}
   */
  public function setPublished($published) {
    $this->set('status', $published ? TRUE : FALSE);
    return $this;
  }

  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
    $fields = parent::baseFieldDefinitions($entity_type);

    $fields['title'] = BaseFieldDefinition::create('string')
      ->setRequired(TRUE)
      ->setLabel(t('Title'))
      ->setDescription(t('The objective title.'))
      ->setRevisionable(TRUE)
      ->setDefaultValue('')
      ->setSettings([ 'max_length' => 50, 'text_processing' => 0 ])
      ->setDisplayOptions('view', [ 'label' => 'above', 'type' => 'string', 'weight' => -4 ])
      ->setDisplayOptions('form', [ 'type' => 'string_textfield', 'weight' => -4 ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    $fields['text'] = BaseFieldDefinition::create('string_long')
      ->setLabel(t('Description'))
      ->setDescription(t('Main text content for the course'))
      ->setDefaultValue('')
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE)
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // References ///////////////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    $fields['user_id'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Authored by'))
      ->setDescription(t('The user ID of author of the Objective entity.'))
      ->setRevisionable(TRUE)
      ->setSetting('target_type', 'user')
      ->setSetting('handler', 'default')
      ->setTranslatable(TRUE)
      ->setDisplayOptions('view', [
        'label' => 'hidden',
        'type' => 'author',
        'weight' => 0,
      ])
      ->setDisplayOptions('form', [
        'type' => 'entity_reference_autocomplete',
        'weight' => 5,
        'settings' => [
          'match_operator' => 'CONTAINS',
          'size' => '60',
          'autocomplete_type' => 'tags',
          'placeholder' => '',
        ],
      ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    $fields['on_lists'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Show on Lists'))
      ->setDescription(t('Show on marketing and summary lists'))
      ->setDefaultValue(TRUE)
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);



    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Flags ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    $fields['status'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Publishing Status'))
      ->setDescription(t('A boolean indicating whether the Course is published.'))
      ->setRevisionable(TRUE)
      ->setDefaultValue(TRUE)
      ->setDisplayOptions('form', [ 'type' => 'boolean_checkbox', 'weight' => -3 ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Timestamps ///////////////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    $fields['created'] = BaseFieldDefinition::create('created')
      ->setLabel(t('Created'))
      ->setDescription(t('The time that the entity was created.'));

    $fields['changed'] = BaseFieldDefinition::create('changed')
      ->setLabel(t('Changed'))
      ->setDescription(t('The time that the entity was last edited.'));

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Revisions ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    $fields['revision_translation_affected'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Revision translation affected'))
      ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
      ->setReadOnly(TRUE)
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE);


    return $fields;
  }

}

wim leers’s picture

Assigned: olexyy.mails@gmail.com » wim leers
Status: Postponed (maintainer needs more info) » Active
Issue tags: -Needs steps to reproduce

Reproduced using #20!

wim leers’s picture

Title: Argument 1 passed to Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer::isInternalResourceType() must implement interface Drupal\Core\Entity\EntityInterface, null given » EntityReference base fields that are optional are not empty, but its sole item is empty, causing EntityReferenceFieldNormalizer to fail
Status: Active » Needs review
Issue tags: +Entity Field API
StatusFileSize
new12.81 KB
new858 bytes

The root cause is that in this case, there is a FileFieldItemList containing one value, a ImageItem object whose isEmpty() returns TRUE, yet it does contain a value:

[
  'target_id' => NULL,
  'alt' => NULL,
  'title' => NULL,
  'width' => NULL,
  'height' => NULL,
]

This matches what's stored in the database:

Whereas configurable entity reference fields in general end up with FieldItemList::$list = [].

So this appears to be a bug in how base fields versus configurable fields are handled. Core doesn't have any base entity reference fields that are optional. If the field was required, this wouldn't be a problem (then the value wouldn't be empty).

On the one hand I want to write test coverage for this, on the other hand it's so much overhead for something that is as trivial to fix as this.

wim leers’s picture

StatusFileSize
new1.03 KB
new1.36 KB

This then actually allows a slight simplification in the loop's body.

wim leers’s picture

Assigned: wim leers » Unassigned

Also: it's pretty cool to see that there are some people out there writing custom entity types! 🤘 🎉

lawxen’s picture

3014380-27.patch works for me, Thanks.

The bug happened on request commerce module's entity: commerce_order /jsonapi/commerce_order/default .
Because all our commerce_order's field billing_profile is empty (We post commerce_order by rest, and get commerce_order by jsonapi).

The field billing_profile's definition is here: https://cgit.drupalcode.org/commerce/tree/modules/order/src/Entity/Order... .

    $fields['billing_profile'] = BaseFieldDefinition::create('entity_reference_revisions')
      ->setLabel(t('Billing information'))
      ->setDescription(t('Billing profile'))
      ->setSetting('target_type', 'profile')
      ->setSetting('handler', 'default')
      ->setSetting('handler_settings', ['target_bundles' => ['customer']])
      ->setTranslatable(TRUE)
      ->setDisplayOptions('form', [
        'type' => 'commerce_billing_profile',
        'weight' => 0,
        'settings' => [],
      ])
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayConfigurable('view', TRUE);
wim leers’s picture

@caseylau Woot, thank you so much for confirming this! 🎉

I'm pretty sure that @gabesullice or @e0ipso will now be happy to RTBC and commit this.

gabesullice’s picture

Status: Needs review » Reviewed & tested by the community

@olexyy.mails@gmail.com, can you confirm that this fixes the problem for you? If so, mark this as RTBC and I'll commit it :)

Welp! @caseylau just did exactly what I needed! LGTM!

  • gabesullice committed eddec9a on 8.x-2.x authored by Wim Leers
    Issue #3014380 by olexyy.mails@gmail.com, Wim Leers, keesee, caseylau:...
gabesullice’s picture

Status: Reviewed & tested by the community » Fixed
wim leers’s picture

npralhad’s picture

StatusFileSize
new811 bytes
gabesullice’s picture

@npralhad, this issue has already been marked "Fixed". Can you open a new issue (a "followup" if need be) and explain your patch? Thank you!

wim leers’s picture

Uncrediting @npralhad (uploading a patch to a fixed issue automatically grants credit).

wim leers’s picture

@npralhad apparently just re-uploaded their patch from #3019329-2: 500 error is thrown while pushing the node creation here.

mstef’s picture

Is there a patch or fix for 1.x?

mstef’s picture

StatusFileSize
new1023 bytes

Here's a patch that applies against 1.24, in case any one needs it.

mstef’s picture

Status: Fixed » Active

Do you want to get my last patch in for 1.x? If not, you can re-close this.

wim leers’s picture

Status: Active » Patch (to be ported)

Pinged @e0ipso and @gabesullice to get their thoughts. In any case, we strongly recommend you to update to JSON:API 2.x — but we understand this is not always possible given project constraints.

gabesullice’s picture

I have no objections to backporting this. I have a slight preference for waiting until we have a few issues to commit so that it makes sense to make another release. That'd discourage running the dev branch in production. Composer makes it easy to automatically apply the patch in #40 until that time.

wim leers’s picture

Version: 8.x-2.x-dev » 8.x-1.x-dev
gerzenstl’s picture

I can confirm patch from #38 works

My setup:
Drupal: 8.6.9
jsonapi: 1.24
jsonapi_extras: 2.15

Given project constraints we're looking for a good way to upgrade to JSON:API 2.x.

wim leers’s picture

Version: 8.x-1.x-dev » 8.x-2.x-dev
Status: Patch (to be ported) » Fixed

At this point, we want people to move over to Drupal core's JSON:API. This is not even a critical bugfix, so backporting is hard to justify by now.

Status: Fixed » Closed (fixed)

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