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
| Comment | File | Size | Author |
|---|---|---|---|
| #29 | interdiff-20-29.txt | 1.65 KB | seanb |
| #29 | 2824979-29.patch | 3.29 KB | seanb |
| #26 | interdiff-20-26.txt | 10.36 KB | seanb |
| #26 | 2824979-26.patch | 11.25 KB | seanb |
| #20 | interdiff-17-20.txt | 866 bytes | seanb |
Comments
Comment #1
Anonymous (not verified) commentedivanjaros created an issue. See original summary.
Comment #2
dawehnerAre you 100% sure about this? There is not a single setter defined on the
DataDefinitionInterfaceComment #3
seanbI just ran in to this. It makes sense. Besides the fact that
\Drupal\Core\TypedData\DataDefinition::setConstraintsalready uses {@inheritdoc}, which could indicate that this was meant to be there all along, I found that the following interfaces contain a addConstraint() method: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.
Comment #4
seanbHope this comment gets the tests running...
Comment #5
seanbComment #6
seanbComment #7
seanbMaybe a new upload...
Comment #8
phenaproximaI 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.
Comment #9
seanbAh 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.
Comment #10
phenaproximaI doubt that contrib is re-implementing DataDefinitionInterface, but who knows. In this case, better safe than sorry. I think this looks good.
Comment #11
phenaproximaComment #12
alexpottLet'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.
Comment #13
seanbI 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.
Comment #14
alexpottThis documentation should move to be inlined in \Drupal\Core\Field\FieldConfigBase::setConstraints()
The field item list is not relevant here now.
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.
Comment #15
dawehnerAdding stuff do an interface is not necessarily a BC break, see https://www.drupal.org/node/2562903/
Comment #16
alexpottI 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?
Comment #17
seanbAttached 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..
Comment #18
phenaproximaPatch looks great to me and it seems to conform to all the feedback thus far.
I'm +1 for this idea. How about calling it ConstraintAcceptingInterface?
Comment #19
alexpottAdding 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.
Comment #20
seanbThere 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.
Comment #21
phenaproximaLooks pretty fine to me. Preemptively RTBC on the assumption that the tests will pass.
Comment #22
seanbAdded a separate issue to discuss the new interface #2857651: Introduce new interface for objects accepting constraints
Comment #24
phenaproximaThe testbot doth protest too much.
Comment #25
xjm@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:Also see #1994890: Allow {@inheritdoc} and additional documentation.
Also wrapping too soon.
This is wrapping too soon I think.
Method additions are allowed in minors per https://www.drupal.org/core/d8-bc-policy:
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!
Comment #26
seanbHere 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.
Comment #28
alexpottHmmm 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.
Comment #29
seanbBack to #20 and added the minor changes for #25.1 and #25.2.
Also added a change record: https://www.drupal.org/node/2864299
Comment #30
seanbComment #31
dawehnerIt would be nice to describe in the issue summary what the usecase is of
setConstraintsvs. justaddConstrains. At least for me increasing an API surface is not necessarily the best idea.Comment #32
tstoecklerSo 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.
Comment #33
seanbI've updated the summary and added a example of usage. The biggest difference between
setConstraintsandaddConstraintis you can overwrite existing constraints throughsetConstraints. 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);Comment #36
borisson_While I agree with @dawehner, it increases our API surface. This is already implicitly part of the API surface since
setConstraintsis already implemented on both DataDefinition and FieldConfigBase.About the patch:
Can we remove the
setConstraintsmethod fromFieldConfigInterface? According to #25 it can't.Comment #45
smustgrave commentedWondering if this is something still desired?
Comment #47
smustgrave commentedThis 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?