Problem/Motivation

ERItem adds EntityType constraint on entity property in ERItem::propertyDefinitions because $settings['target_type'] exists in field storage of ER field but DERItem can't add EntityType constraint on entity property in DERItem::propertyDefinitions because DER field can reference multiple entity types. Also, ERItem::getConstraints() adds bundle constraint to entity property whereas there is no bundle constraint on DERItem entity.
Add EntityType and bundle constraint on entity property of DER.

Proposed resolution

DERItem can't add EntityType constraint on entity property because we don't have target_type value until DERItem entity property is created so add it in DynamicEntityReferenceFieldItemList like #2577963: Let entity_ref Selection handlers be in charge of the field validation.

Remaining tasks

  • Complete ValidDynamicReferenceConstraintValidator.
    • Validate new entities
    • Validate target_ids
    • Validate bundles
  • Fix the failing tests and add new asserts about bundle and entity type constraints
  • Review the patch, address the valid points from #18.
  • Verify that EntityType and Bundle constraint exists and works fine on DER entity property.
  • User interface changes

    None.

    API changes

    None

    Data model changes

    Adds EntityType and bundle constraint on entity property of DER.

    Original report by @jibran

    Follow-up to #2365331-28: Update DynamicEntityReferenceItem according to EntityReferenceItem

    1. +++ b/src/Plugin/Field/FieldType/DynamicEntityReferenceItem.php
      @@ -80,30 +87,18 @@ class DynamicEntityReferenceItem extends ConfigurableEntityReferenceItem {
      -      // $properties['entity']->getTargetDefinition()->addConstraint('Bundle', $settings['target_bundle']);
      

      We can add this constraint in setValue(). Do you think it is worth it? If yes we can discuss this in follow up.

    Comments

    larowlan’s picture

    Status: Active » Needs review
    StatusFileSize
    new4.04 KB

    Status: Needs review » Needs work

    The last submitted patch, 1: validate-stuff.patch, failed testing.

    jibran’s picture

    We also need validation tests for each class i.e. DynamicEntityReference, DynamicEntityReferenceItem and DynamicEntityReferenceFieldItemList.

    +++ b/src/Plugin/DataType/DynamicEntityReference.php
    @@ -61,4 +61,13 @@ class DynamicEntityReference extends EntityReference {
    +    $this->definition->addConstraint('Bundle', ['bundle' => $this->parent->parent->getSetting($this->parent->getValue()['target_type'])['handler_settings']['target_bundles']]);
    

    There should be some better way to do this.

    larowlan’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new1.29 KB
    new4.54 KB

    Status: Needs review » Needs work

    The last submitted patch, 4: validate-stuff.2.patch, failed testing.

    larowlan’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new2.99 KB
    new6.23 KB
    jibran’s picture

    1. +++ b/src/DynamicEntityReferenceFieldItemList.php
      @@ -131,4 +131,20 @@ class DynamicEntityReferenceFieldItemList extends EntityReferenceFieldItemList {
      +   * {@inheritdoc}
      
      +++ b/src/Plugin/DataType/DynamicEntityReference.php
      @@ -61,4 +61,25 @@ class DynamicEntityReference extends EntityReference {
      +   * {@inheritdoc}
      
      +++ b/src/Plugin/Field/FieldType/DynamicEntityReferenceItem.php
      @@ -472,4 +472,13 @@ class DynamicEntityReferenceItem extends ConfigurableEntityReferenceItem {
      +   * {@inheritdoc}
      

      We should add some additional documents to explain this.

    2. +++ b/src/Plugin/Validation/Constraint/ValidDynamicReferenceConstraint.php
      @@ -26,6 +26,7 @@ class ValidDynamicReferenceConstraint extends Constraint {
      +  public $wrongIDMessage = 'The referenced entity (%type: %id) does not exist.';
      +  public $wrongTypeMessage = 'The referenced entity (%type: %id) is not allowed for this field.';
      

      Can we please improve these messages? So that user can understand which value is not correct.

    We still have this @todo left

        // @todo Implement a test case for invalid bundle references.
    

    perhaps we should have to add test for entities which don't have the bundles.

    larowlan’s picture

    StatusFileSize
    new6.73 KB
    new7.91 KB

    fixes

    Status: Needs review » Needs work

    The last submitted patch, 8: validate-stuff.4.patch, failed testing.

    jibran’s picture

    Thanks for the fixes. Some more nitpicks :P

    1. +++ b/src/Tests/DynamicEntityReferenceFieldTest.php
      @@ -119,16 +128,21 @@ class DynamicEntityReferenceFieldTest extends EntityUnitTestBase {
      +    $dud_referenced_entity = entity_create($this->referencedEntityType, array('type' => 'dud'));
      

      We can use EntityTest::create here.

    2. +++ b/src/DynamicEntityReferenceFieldItemList.php
      @@ -131,4 +131,24 @@ class DynamicEntityReferenceFieldItemList extends EntityReferenceFieldItemList {
      +      if (!$return) {
      ...
      +      else {
      

      Can we please explain this if/else as well?

    3. +++ b/src/Plugin/DataType/DynamicEntityReference.php
      @@ -61,4 +61,29 @@ class DynamicEntityReference extends EntityReference {
      +    $field = $this->parent->parent;
      

      Can we please add /* @var \.. $field */ here for better understanding?

    4. +++ b/src/Tests/DynamicEntityReferenceFieldTest.php
      @@ -78,13 +78,22 @@ class DynamicEntityReferenceFieldTest extends EntityUnitTestBase {
      -    FieldConfig::create(array(
      +    FieldConfig::create([
      

      This is fine here. Let's use @grom358's script in a follow up issue and fix it for whole module.

    Status: Needs work » Needs review

    jibran queued 8: validate-stuff.4.patch for re-testing.

    Status: Needs review » Needs work

    The last submitted patch, 8: validate-stuff.4.patch, failed testing.

    fago’s picture

    +++ b/src/DynamicEntityReferenceFieldItemList.php
    @@ -131,4 +131,24 @@ class DynamicEntityReferenceFieldItemList extends EntityReferenceFieldItemList {
    +  public function validate() {
    +    $return = NULL;
    +    foreach ($this->list as $item) {
    +      if (!$return) {
    

    I've no idea why you are doing that? It propagates down on its own anyway?

    1. +++ b/src/Plugin/DataType/DynamicEntityReference.php
      @@ -61,4 +61,29 @@ class DynamicEntityReference extends EntityReference {
      +      if (isset($target_type_settings['handler_settings']['target_bundles'])) {
      +        // Add the constraint to limit the bundles of this item.
      +        $this->definition->addConstraint('Bundle', ['bundle' => $target_type_settings['handler_settings']['target_bundles']]);
      

      Would it be possible to add that constraint as part of the property definitions already or does it depend on FieldConfig settings? If so, adding it here makes sense to me.

    2. +++ b/src/Plugin/Field/FieldType/DynamicEntityReferenceItem.php
      @@ -472,4 +472,17 @@ class DynamicEntityReferenceItem extends ConfigurableEntityReferenceItem {
      +  public function validate() {
      +    $return = parent::validate();
      +    $return->addAll($this->get('entity')->validate());
      +    return $return;
      

      Again, no need for that?

    larowlan’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new7.14 KB
    new8.7 KB

    Couldn't get the getConstraints method to be called. Then realized, we already have our own validator, so lets just use that.

    Status: Needs review » Needs work

    The last submitted patch, 14: der-bundle-validation.patch, failed testing.

    jibran’s picture

    larowlan’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new9.08 KB
    new3.73 KB
    jibran’s picture

    Title: Add bundle constraint to entity property of DynamicEntityReferenceItem » Add EntityType and Bundle constraint on entity property of DynamicEntityReferenceItem
    Issue summary: View changes
    Status: Needs review » Needs work
    Related issues: +#2064191: Fix the 'target_bundle' field setting - 'target_bundles' are not validated when entity_reference is enabled, +#1978714: Entity reference doesn't update its field settings when referenced entity bundles are deleted, +#2578249: Some e_r fields get the wrong Selection handler

    @larowlan thank you so much for fixing this. Patch looks good. Let me update IS and ping @fago for opinion.

    1. +++ b/src/Plugin/Validation/Constraint/ValidDynamicReferenceConstraintValidator.php
      @@ -46,10 +47,54 @@ class ValidDynamicReferenceConstraintValidator extends ConstraintValidator {
      +          '%bundles' => implode(', ', $target_type_settings['handler_settings']['target_bundles']),
      

      Isn't this the disclosure of information?

    2. +++ b/src/Plugin/Validation/Constraint/ValidDynamicReferenceConstraintValidator.php
      @@ -46,10 +47,54 @@ class ValidDynamicReferenceConstraintValidator extends ConstraintValidator {
      +  public function getConstraints() {
      

      I think it is not suppose to be here.

    3. +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
      @@ -154,6 +148,28 @@ public static function schema(FieldStorageDefinitionInterface $field_definition)
      +  public function getConstraints() {
      +    $constraints = parent::getConstraints();
      +    list($current_handler) = explode(':', $this->getSetting('handler'), 2);
      +    if ($current_handler === 'default') {
      +      $handler_settings = $this->getSetting('handler_settings');
      +      if (!empty($handler_settings['target_bundles'])) {
      +        $constraint_manager = \Drupal::typedDataManager()->getValidationConstraintManager();
      +        $constraints[] = $constraint_manager->create('ComplexData', [
      +          'entity' => [
      +            'Bundle' => [
      +              'bundle' => $handler_settings['target_bundles'],
      +            ],
      +          ],
      +        ]);
      +      }
      +    }
      +    return $constraints;
      +  }
      

      @larowlan have you this seen from #2064191: Fix the 'target_bundle' field setting - 'target_bundles' are not validated when entity_reference is enabled.
      Do you think we should accommodate/bypass this hunk in DER? I believe this is not same for DERItem.

    4. +++ b/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php
      @@ -15,6 +15,13 @@
      +    $constraints[] = $constraint_manager->create('ValidReference', []);
      
      +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/EntityReferenceItem.php
      @@ -33,8 +30,7 @@
      - *   constraints = {"ValidReference" = {}}
      

      Also #2577963: Let entity_ref Selection handlers be in charge of the field validation removes ValidReference from ERItem and moves it to ERItemList. Should we also consider that in follow up when #2577963: Let entity_ref Selection handlers be in charge of the field validation is fixed.

    5. +++ b/core/lib/Drupal/Core/Entity/Plugin/EntityReferenceSelection/SelectionBase.php
      @@ -111,7 +111,10 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
      -      'target_bundles' => array(),
      +      // For the 'target_bundles' setting, a NULL value is equivalent to "allow
      +      // entities from any bundle to be referenced" and an empty array value is
      +      // equivalent to "no entities from any bundle can be referenced".
      +      'target_bundles' => NULL,
      

      FYI after #1978714: Entity reference doesn't update its field settings when referenced entity bundles are deleted NULL means all bundles and empty array means no bundle so following is the wrong assumption in the patch

      +++ b/src/Plugin/Validation/Constraint/ValidDynamicReferenceConstraintValidator.php
      @@ -46,10 +47,54 @@ class ValidDynamicReferenceConstraintValidator extends ConstraintValidator {
      +    // No bundles selected = all bundles are valid.
      
    6. Also, I believe we are missing EntityType constraint for entity property in DERItem we should add it in DERItem::getConstraints(). I have updated IS to accommodate that case.

    • jibran committed 35fffa1 on 8.x-1.x
      [#2405467] Avoid ajax tests for now.
      
    jibran’s picture

    StatusFileSize
    new8.47 KB
    new14.7 KB

    #2577963: Let entity_ref Selection handlers be in charge of the field validation is in so I pushed a fix for the failing tests 5df5af3. Here is a reroll and WIP patch. Please feel free to pick this up.

    james.williams’s picture

    StatusFileSize
    new9.8 KB

    Here's another re-rolled patch that should at least apply, since I found the previous one didn't any more. Still needs review, and not all of the points from comment 18 above have been addressed yet.

    james.williams’s picture

    StatusFileSize
    new9.94 KB

    Fixed constraints not actually causing a form validation error when submitting an invalid reference in a field widget :-)

    jibran’s picture

    Status: Needs work » Needs review

    Status: Needs review » Needs work

    The last submitted patch, 22: der-constraints-2405467-22.patch, failed testing.

    The last submitted patch, 22: der-constraints-2405467-22.patch, failed testing.

    The last submitted patch, 22: der-constraints-2405467-22.patch, failed testing.

    jibran’s picture

    There are proper tests for each use case if you'd like to complete it then you just need to fix the fails and add new asserts about bundle and entity type constraints. Please provide the interdiff for reviewer. Thanks.

    james.williams’s picture

    Issue summary: View changes

    Yes, sorry, I'd forgotten the interdiffs. I don't believe all the points in comment 18 have been addressed yet either anyway, so I was fully aware that the patch still needed work. Remaining tasks updated in issue summary.

    jibran’s picture

    Priority: Normal » Major

    • jibran committed 35fffa1 on 8.x-2.x
      [#2405467] Avoid ajax tests for now.
      
    larowlan’s picture

    Its been so long, I'm not sure what we need to do here to finish this off, I'll talk with Jibran about it today.

    jibran’s picture

    Issue summary: View changes
    Issue tags: -Needs issue summary update

    Updated the issue summary.

    jibran’s picture

    Issue summary: View changes
    Status: Needs work » Needs review
    StatusFileSize
    new1.39 KB
    new7.42 KB
    new9.09 KB

    Reroll and some clean up.

    Status: Needs review » Needs work

    The last submitted patch, 33: add_entitytype_and-2405467-33.patch, failed testing.

    jibran’s picture

    Issue tags: +ER feature parity
    thenchev’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new9.94 KB
    new865 bytes

    Started looking into it.
    Here a fix to the fatal for generateSampleItems()

    Status: Needs review » Needs work

    The last submitted patch, 36: add_entitytype_and-2405467-36.patch, failed testing.

    thenchev’s picture

    Assigned: Unassigned » thenchev
    Status: Needs work » Needs review
    StatusFileSize
    new14.92 KB
    new8.24 KB

    Added more validations, started fixing tests.

    Status: Needs review » Needs work

    The last submitted patch, 38: add_entitytype_and-2405467-38.patch, failed testing.

    slashrsm’s picture

    1. Main thing that I noticed is that we're not consistent when it comes to behavior after a violation. In some cases we return from the validator as soon as a violation has occurred. In some other cases we try to continue and check other items too. We should be consistent.
    2. +++ b/src/Plugin/Validation/Constraint/ValidDynamicReferenceConstraint.php
      @@ -21,7 +21,30 @@ class ValidDynamicReferenceConstraint extends Constraint {
      +  public $wrongIDMessage = 'The referenced entity (%type: %id) does not exist.';
      +  public $wrongTypeMessage = 'The referenced entity type (%type) is not allowed for this field.';
      +  public $wrongBundleMessage = 'The entity bundle must be one of %bundles, the selected entity is of bundle %bundle.';
      

      Comments missing for those. Last one reads a bit strange.

    3. +++ b/src/Plugin/Validation/Constraint/ValidDynamicReferenceConstraintValidator.php
      @@ -2,50 +2,152 @@
      +      $target_id = $item->target_id;
      +      $target_type = $item->target_type;
      

      Do we really need this two extra variables? $item->target_id and $item->target_type seem compact enough to me.

    4. +++ b/src/Plugin/Validation/Constraint/ValidDynamicReferenceConstraintValidator.php
      @@ -2,50 +2,152 @@
      +        $valid_target_id = $handler->validateReferenceableEntities([$target_id]);
      +        if (!$valid_target_id) {
      

      Can this function call go into the condition to avoid an extra variable assignment?

    thenchev’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new21.48 KB
    new7.44 KB

    Worked only on tests. Will cover #40 in the next patch. Also tests for bundles are missing.

    jibran’s picture

    Status: Needs review » Needs work

    Thanks @Denchev for the patch and thanks @slashrsm for the review.

    +++ b/src/Plugin/Validation/Constraint/ValidDynamicReferenceConstraintValidator.php
    @@ -2,50 +2,153 @@
    +      $handler = $this->selectionManager->getSelectionHandler($value->getFieldDefinition(), NULL, $target_type);
    

    This $target_type can be NULL which we don't want.

    Here is how I thought we should proceed.

    1. Validate not NULL first for properties and return violationnullMessage if any field property is NULL.
    2. If the entity is new then keep them in an array$new_entities and validate them later cause we need to validate the entity type first.
    3. Validate target type this includes new entities as well. Keep adding the violations$wrongTypeMessage. Remove the new entities from new entities array.
    4. Now validate the new entities using validateReferenceableNewEntities. Keep adding the violationsinvalidAutocreateMessage.
    5. Validated target_id using validateReferenceableEntities. Keep adding the violations.

    See ValidReferenceConstraintValidator in core for more details.

    thenchev’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new26.33 KB
    new14.17 KB

    So i few things here:
    1. Now we go over every element and and get first validation that we find.

    2. $valid_type = empty($item->target_type) || (!empty($item->target_type) && in_array($item->target_type, $valid_target_types));
    used this code because it was already there. So we are allowing empty target type?

    3. Moved the check with validateReferenceableEntities at the end. If the bundle is not valid then the validateReferenceableEntities is not going to pass. Have to check first if ID has an existing entity so i can do the check for the bundle and have that specific message ('Referenced entity %label does not belong to one of the supported bundles (%bundles).')

    4. There is the case if the 'target_bundles' is an empty array (which means no bundles allowed) this does not quite work with the massage we have now for the bundle (Referenced entity %label does not belong to one of the supported bundles (%bundles)). Should i add a new message like "No bundle allowed for %entity_type" or change the message to something else?

    jibran’s picture

    Wow, nice update. Thanks for the patch. Here is the answer to your questions:

    1. This is perfect.
    2. Yeah
    3. That's alright.
    4. Yeah, sure.

    Can you please upload this path for 8.x-2.x and test it againest that branch?

    thenchev’s picture

    StatusFileSize
    new26.83 KB
    new3.03 KB

    Thanks for the quick answers. Added new message for no bundle allowed.

    Status: Needs review » Needs work

    The last submitted patch, 45: add_entitytype_and-2405467-45.patch, failed testing.

    jibran’s picture

    Status: Needs work » Needs review

    It is green for 8.x-1.x.

    jibran’s picture

    StatusFileSize
    new26.82 KB

    Re-roll for 8.x-2.x.

    jibran’s picture

    Assigned: thenchev » larowlan

    Thanks! @Denchev. I think this is ready. I asked @larowlan to review this so assigning it to him now. Meanwhile, if @Berdir would be able to have a look at it then it'd be great.

    larowlan’s picture

    Status: Needs review » Reviewed & tested by the community

    This looks ready to me, thanks @Denchev!

    • jibran committed 30f7654 on 8.x-1.x
      Issue #2405467 by larowlan, Denchev, jibran, james.williams, fago,...

    • jibran committed 3c17efb on 8.x-2.x
      Issue #2405467 by larowlan, Denchev, jibran, james.williams, fago,...
    jibran’s picture

    Status: Reviewed & tested by the community » Fixed

    Thank you. Committed and pushed to both branches.

    jibran’s picture

    jibran’s picture

    Assigned: larowlan » Unassigned

    Status: Fixed » Closed (fixed)

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