CreatedItem and ChangedItem are missing TimestampItem's Range constraint

Created on 24 April 2025, 22 days ago

Problem/Motivation

Timestamp fields have a range constraint so that no value outside of the range of the database storage can be saved. The changed and created field types extend the timestamp field type but are missing that constraint. That means that invalid created or changed values that enter the system via a migration or JSON:API, for example, are not properly validated and may cause exceptions when being saved.

Steps to reproduce

$node = Node::create([
  'title' => 'Back to the future',
  'type' => 'article',
  // This is not a 32-bit integer.
  'created' => 2147483649
]);
// This yields 0, thus no violation is recorded.
$node->validate()->count();
// Brace for SQL exception.
$node->save();

Proposed resolution

Copy the constraints over from TimestampItem to CreatedItem and ChangedItem.

Remaining tasks

User interface changes

-

Introduced terminology

-

API changes

-

Data model changes

-

Release notes snippet

-

🐛 Bug report
Status

Active

Version

11.0 🔥

Component

field system

Created by

🇩🇪Germany tstoeckler Essen, Germany

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @tstoeckler
  • Pipeline finished with Failed
    18 days ago
    Total: 95s
    #484476
  • Pipeline finished with Success
    18 days ago
    Total: 641s
    #484485
  • 🇩🇪Germany tstoeckler Essen, Germany

    Thanks for picking this up @annmarysruthy!

    Looks perfect.

    This will need some test coverage to go in, though. I looked around a bit and found \Drupal\KernelTests\Core\Entity\EntityValidationTest::checkValidation. I think it would make sense to add some checks to that as that already tests various field-type-specific constraints. All the tested entity types should also have a created field, so just adding a test for that should work fine. And for the changed field you can check if the entity type implements EntityChangedInterface as only a couple entity types have that.

    Marking needs work for that.

  • 🇮🇳India prabha1997

    I am working on this issue

  • 🇮🇳India prabha1997

    I tried to add validation for the ChangedItem field as shown below, but I am not getting the expected validation failure for the invalid changed timestamp.

     if ($entity instanceof \Drupal\Core\Entity\EntityChangedInterface && $entity->hasField('changed')) {
          // This entity has a 'changed' field. You can now safely test it.
          $test_entity = clone $entity;
          $test_entity->set('changed', -2147483649);  // Invalid timestamp (below min range)
          // Validate the entity.
          $violations = $test_entity->validate();
          $this->assertEquals(1, $violations->count(), 'Validation failed for invalid changed timestamp.');
          $this->assertEquals('The changed timestamp is out of the valid range.', $violations[0]->getMessage());
    
          // Valid 'changed' timestamp.
          $test_entity->set('changed', 1234567890);  // Valid timestamp
          $violations = $test_entity->validate();
          $this->assertEquals(0, $violations->count(), 'Valid changed timestamp passed validation.');
        }
  • Pipeline finished with Success
    17 days ago
    Total: 922s
    #484673
  • 🇩🇪Germany tstoeckler Essen, Germany

    Nice work with the test coverage.

    Ahh, how annoying. I think that is because one of the test entities uses the changed_test item (i.e. \Drupal\entity_test\Plugin\Field\FieldType\ChangedTestItem) instead of the regular changed. I had missed that initially when looking into this. I guess we could also add the constraint to the test field type one, but that then kind of feels like testing the test coverage. Alternatively we could check that $entity->get('changed')->getFieldDefinition()->getType() is in fact changed (and not changed_test). I guess I like the latter solution a bit better, but also open to what you think.

  • Pipeline finished with Running
    17 days ago
    #484717
  • 🇮🇳India prabha1997

    I've updated the test to include a check for the actual field type, so it now only runs if the changed field uses the real 'changed' type (not the changed_test).

  • 🇩🇪Germany tstoeckler Essen, Germany

    Thanks for sticking with this @prabha1997!

    I tried it out locally and I guess my suggestion above was not really great. Turns out the inside of the if is reached. I had seen that the entity_test_constraints entity type has an actual changed field, but unfortunately that is not one of the entity types used in the test. (See \Drupal\entity_test\EntityTestHelper::getEntityTypes().) All of this is a bit of a mess, but not one we will have to fix here, I hope. So I looked into how to get an actual changed field into the entity types being tested without rewriting the entire test and found that the test entity types support adding base field definitions via state. I wasn't sure whether that actually worked as intended so I tried it out to be sure. And since I already had it then I went ahead and pushed it to the branch, I hope that was OK.

    Maybe you can take a look and see if you agree with those changes, thanks!

Production build 0.71.5 2024