Problem/Motivation

The interface \Drupal\Core\TypedData\DataDefinitionInterface is missing the setConstraints() method that is defined in the \Drupal\Core\TypedData\DataDefinition::setConstraints even with the {@inheritdoc} tag. The method is present in the \Drupal\Core\Field\FieldConfigInterface::setConstraints for example, and I think it should be moved to the DataDefinitionInterface instead.

Allowing modules to overwrite the constraints of TypedData with the setConstraints method (instead of adding a constraint through addConstraint) seems like a valid use case.

An example of this is in \Drupal\Core\Field\FieldConfigBase

  /**
   * {@inheritdoc}
   */
  public function setPropertyConstraints($name, array $constraints) {
    $item_constraints = $this->getItemDefinition()->getConstraints();
    $item_constraints['ComplexData'][$name] = $constraints;
    $this->getItemDefinition()->setConstraints($item_constraints);
    return $this;
  }

Proposed resolution

Add the setConstraints method to \Drupal\Core\TypedData\DataDefinitionInterface.

Remaining tasks

Add the setConstraints method to \Drupal\Core\TypedData\DataDefinitionInterface.
Remove the setConstraints method from \Drupal\Core\Field\FieldConfigInterface::setConstraints

User interface changes

None

API changes

\Drupal\Core\TypedData\DataDefinitionInterface

Data model changes

None

Comments

Anonymous’s picture

ivanjaros created an issue. See original summary.

dawehner’s picture

Are you 100% sure about this? There is not a single setter defined on the DataDefinitionInterface

seanb’s picture

Version: 8.0.x-dev » 8.4.x-dev
Status: Active » Needs review
StatusFileSize
new1.16 KB

I just ran in to this. It makes sense. Besides the fact that \Drupal\Core\TypedData\DataDefinition::setConstraints already uses {@inheritdoc}, which could indicate that this was meant to be there all along, I found that the following interfaces contain a addConstraint() method:

  • \Drupal\Component\Plugin\Context\ContextDefinitionInterface
  • \Drupal\Core\Entity\EntityTypeInterface
  • \Drupal\Core\Field\FieldConfigInterface
  • \Drupal\Core\TypedData\DataDefinitionInterface

All these interfaces also contain a setConstraints() method, except \Drupal\Core\TypedData\DataDefinition. When having the option to add constraints, it makes sense to be able to add / override them.

Attached is a patch to add this.

seanb’s picture

Hope this comment gets the tests running...

seanb’s picture

Status: Needs review » Active
seanb’s picture

Status: Active » Needs review
seanb’s picture

StatusFileSize
new1.16 KB

Maybe a new upload...

phenaproxima’s picture

I see nothing wrong here. Looks like a good, solid (and originally intended) addition, although I question whether adding methods to existing interfaces constitutes a BC break.

seanb’s picture

StatusFileSize
new1.17 KB

Ah yes, excellent point. I checked core, but we don't know what contrib is doing. As discussed on IRC with phenaproxima I fixed the doc block and added a todo.

phenaproxima’s picture

Status: Needs review » Reviewed & tested by the community

I doubt that contrib is re-implementing DataDefinitionInterface, but who knows. In this case, better safe than sorry. I think this looks good.

phenaproxima’s picture

Issue tags: +API Documentation
alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/TypedData/DataDefinition.php
@@ -271,7 +271,23 @@ public function getConstraint($constraint_name) {
+   * @todo Needs to be added to \Drupal\Core\TypedData\DataDefinitionInterface
+   *   as mentioned in https://www.drupal.org/node/2824979.

Let's create a proper @todo. i.e. File a new issue to do this and link it here. Also if we add it to DataDefinitionInterface we can remove it from \Drupal\Core\Field\FieldConfigInterface()

Also the issue summary and title need updating for the new fix.

seanb’s picture

Version: 8.4.x-dev » 9.x-dev
Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new2.45 KB

I created #2852432: \Drupal\Core\TypedData\DataDefinition::setConstraints shouldn't use {@inheritdoc} to change the function doc comment for \Drupal\Core\TypedData\DataDefinition::setConstraints.

Attached is a new patch to fix this issue. I think the BC breaks means this will be postponed to 9.x.

alexpott’s picture

Status: Needs review » Needs work
  1. +++ b/core/lib/Drupal/Core/Field/FieldConfigInterface.php
    @@ -254,27 +254,4 @@ public function addPropertyConstraints($name, array $constraints);
    -   * NOTE: This will overwrite any previously set constraints. In most cases
    -   * FieldConfigInterface::addConstraint() should be used instead.
    -   *
    -   * Note that constraints added via this method are not stored in configuration
    -   * and as such need to be added at runtime using
    -   * hook_entity_bundle_field_info_alter().
    

    This documentation should move to be inlined in \Drupal\Core\Field\FieldConfigBase::setConstraints()

  2. +++ b/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php
    @@ -186,6 +186,24 @@ public function getSetting($setting_name);
    +   * Sets the array of validation constraints for the FieldItemList.
    

    The field item list is not relevant here now.

  3. Maybe one way around the Drupal 9 move is to introduce a ConstraintSomethingInterface or SomethingConstraintInterface... not sure what that something is atm... but it could have the following methods:
    • getConstraints()
    • getConstraint()
    • addConstraint()
    • setConstraints()

    And then both DataDefinition and ContextDefinitionInterface can implement/extend it. And the D9 issue can be to make DataDefinitionInterface extend the new interface. This way code can be written to be both D8 and D9 compatible if someone re-implements DataDefinition - though I'm not sure who is going to do that.

dawehner’s picture

Adding stuff do an interface is not necessarily a BC break, see https://www.drupal.org/node/2562903/

alexpott’s picture

I think given #15 going back to #7 is probably the best idea. I really don't think anyone is going to have re-implemented typed data in contrib - everyone is going to be extending from DataDefinition or FieldConfigBase. FieldConfigBase is the only other concrete class that implements DataDefinitionInterface without extending DataDefinition - and fortunately setConstraints is on FieldConfigInterface.

The remaining question is should we introduce an new interface to bring ContextDefinitionInterface and DataDefinitionInterface together?

seanb’s picture

Version: 9.x-dev » 8.4.x-dev
Status: Needs work » Needs review
StatusFileSize
new1.64 KB
new3.28 KB

Attached an updated patch addressing #14-1 and #14-2. Thanks dawehner for pointing out the BC policy!
Only remaining thing is possibly introducing a new interface as mentioned in #14-3. I guess this is a separate issue?

Moving back to 8.4.x and needs review..

phenaproxima’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +typed data

Patch looks great to me and it seems to conform to all the feedback thus far.

The remaining question is should we introduce an new interface to bring ContextDefinitionInterface and DataDefinitionInterface together?

I'm +1 for this idea. How about calling it ConstraintAcceptingInterface?

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/Field/FieldConfigBase.php
@@ -528,6 +528,12 @@ public function getConfig($bundle) {
+   *
+   * Note that constraints added via this method are not stored in configuration
+   * and as such need to be added at runtime using
+   * hook_entity_bundle_field_info_alter().
+   *
+   * @see hook_entity_bundle_field_info_alter()
    */
   public function setConstraints(array $constraints) {
     $this->constraints = $constraints;

Adding docs to @inheritdoc is not supported by api.drupal.org (or the standard). These docs can be just inline to the implementation since they are totally about how this specific implementation is used.

seanb’s picture

Status: Needs work » Needs review
StatusFileSize
new3.29 KB
new866 bytes

There are hundreds of places in core adding docs to @inheritdoc. Was this policy added later? What if the added documentation is important for api.drupal.org, should you just add a complete doc block (and possibly duplicate docs) and not use {@inheritdoc}? Just being curious :)

Anyway, a updated patch is attached.

phenaproxima’s picture

Status: Needs review » Reviewed & tested by the community

Looks pretty fine to me. Preemptively RTBC on the assumption that the tests will pass.

seanb’s picture

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 20: 2824979-20.patch, failed testing.

phenaproxima’s picture

Status: Needs work » Reviewed & tested by the community

The testbot doth protest too much.

xjm’s picture

Component: base system » typed data system
Priority: Minor » Normal
Status: Reviewed & tested by the community » Needs work
Issue tags: -API Documentation, -typed data +Needs change record

@seanB, the stuff for {@inheritdoc} has been a confusion for pretty much as long as we've used it. https://www.drupal.org/node/1354#inheritdoc says:

This must be the only line in the docblock.

Also see #1994890: Allow {@inheritdoc} and additional documentation.

  1. +++ b/core/lib/Drupal/Core/Field/FieldConfigBase.php
    @@ -530,6 +530,10 @@ public function getConfig($bundle) {
    +    // Note that constraints added via this method are not stored
    +    // in configuration and as such need to be added at runtime using
    +    // hook_entity_bundle_field_info_alter().
    

    Also wrapping too soon.

  2. +++ b/core/lib/Drupal/Core/TypedData/DataDefinitionInterface.php
    @@ -186,6 +186,27 @@ public function getSetting($setting_name);
    +   * NOTE: This will overwrite any previously set constraints.
    +   * In most cases DataDefinitionInterface::addConstraint() should be
    +   * used instead. See DataDefinitionInterface::getConstraints() for
    +   * details on how constraints are defined.
    

    This is wrapping too soon I think.

Method additions are allowed in minors per https://www.drupal.org/core/d8-bc-policy:

Interfaces that are not tagged with either @api or @internal can be safely used as type hints. No methods will be changed or removed from these interface in a breaking way.
However, we reserve the ability to add methods to these interfaces in minor releases to support new features. When implementing the interface, module authors are encouraged to either:
Where there is a 1-1 relationship between a class and an interface, inherit from the class. Where a base class or trait is provided, use those. This way your class should inherit new methods from the class or trait when they're added.
Where the interface is implemented directly for other reasons, be prepared to add support for new methods in minor releases

That said, I'm not sure that we've addressed the last part of #16? That sounded like a more BC solution to me. I think that exploring that rather than the interface break is worthwhile before we add the BC break. (Even if we do decide to go ahead with the method addition.)

Finally, either way, it will need a change record. Thanks!

seanb’s picture

Status: Needs work » Needs review
StatusFileSize
new11.25 KB
new10.36 KB

Here is a new patch implementing the new interface. Discussed this phenaproxima some time ago and he suggested ConstrainableDataDefinitionInterface().
Please let me know if this is what it should be, I will start writing the change records when there is consensus on the scope of this issue.

Status: Needs review » Needs work

The last submitted patch, 26: 2824979-26.patch, failed testing.

alexpott’s picture

Hmmm I missed that ContextDefinitionInterface is in component and that DataDefinitionInterface is in core. I definitely think that that means discussing this part in #2857651: Introduce new interface for objects accepting constraints makes more sense than trying to do that here.

Regarding BC. I think given we have classes DataDefinition and FieldConfigBase - both which implement setConstraints we are okay here. There is no alternate implementation of TypedData or the field system - especially an alternate implementation based only the interfaces. This is almost certainly impossible.

seanb’s picture

Status: Needs work » Needs review
StatusFileSize
new3.29 KB
new1.65 KB

Back to #20 and added the minor changes for #25.1 and #25.2.

Also added a change record: https://www.drupal.org/node/2864299

seanb’s picture

Issue tags: -Needs change record
dawehner’s picture

It would be nice to describe in the issue summary what the usecase is of setConstraints vs. just addConstrains. At least for me increasing an API surface is not necessarily the best idea.

tstoeckler’s picture

So as far as I can tell, this is basically the typed-data equivalent of #2346329: hook_entity_base_field_info_alter() and hook_entity_bundle_field_info_alter() are documented to get a parameter that doesn't implement an interface with setter methods. So would be nice to take that into account, so that we don't end up pursuing different directions in the two issues.

seanb’s picture

Issue summary: View changes

I've updated the summary and added a example of usage. The biggest difference between setConstraints and addConstraint is you can overwrite existing constraints through setConstraints. It is not used a lot though.

I found this while working on the media module. We are adding constraints on field/entity level when I noticed setConstraints was missing on the DataDefinitionInterface.
$this->get($source_field_name)->getDataDefinition()->setConstraints($source_field_constraints);

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

borisson_’s picture

While I agree with @dawehner, it increases our API surface. This is already implicitly part of the API surface since setConstraints is already implemented on both DataDefinition and FieldConfigBase.

About the patch:

Can we remove the setConstraints method from FieldConfigInterface? According to #25 it can't.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

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

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

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.

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.

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.

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

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Wondering if this is something still desired?

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative

This issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.

Should we deprecate the function out of FieldConfigInterface vs removing it?

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.