-
Notifications
You must be signed in to change notification settings - Fork 824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NEW Show more information in ValidationException message #11562
base: 6.0
Are you sure you want to change the base?
NEW Show more information in ValidationException message #11562
Conversation
e148ac2
to
2a63e66
Compare
2a63e66
to
89727e1
Compare
6b90450
to
53569d9
Compare
53569d9
to
dd52956
Compare
c433cf9
to
263d324
Compare
263d324
to
adf3ca1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't tested locally yet - but the below stick out to me
* @param $value The value to validate | ||
* @param Constraint|Constraint[] $constraints a constraint or array of constraints to validate against | ||
* @param string $fieldName The field name the value relates to, if relevant | ||
* @param $fieldName The field name the value relates to, if relevant |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@param
must always include the type. IDEs (and probably our API docs) don't know what to do with a non-typed param and they treat the param name as the type and the first word of the description as the name.
So @param $value The value to validate
makes IDEs think $value
is the type, and The
is the name.
Either remove the @param
entirely or revert the change. Personally I'd just remove the $value
and $fieldName
@param
s as they're self-explanatory, and only keep the $constraints
@param
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This applies to any other PHPDoc changes in this PR.
if ($this->doShowAdditionalInfo()) { | ||
if ($message['fieldName']) { | ||
$exceptionMessage .= ' - fieldName: ' . $message['fieldName']; | ||
} | ||
$dataClass = $result->getDataClass(); | ||
if (is_subclass_of($dataClass, DataObject::class, true)) { | ||
$exceptionMessage .= ', recordID: ' . $result->getRecordID(); | ||
$exceptionMessage .= ', dataClass: ' . $dataClass; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there ever a reason not to include this additional info in the exception message? e.g. where ValidationException
gets thrown for a CMS form submission and $result
is a ValidationResult
, the actual message isn't parsed by the UI - instead the validation result's individual messages are included in JSON in the response and are used appropriately.
$exceptionMessage .= ', recordID: ' . $result->getRecordID(); | ||
$exceptionMessage .= ', dataClass: ' . $dataClass; | ||
} | ||
} | ||
break; | ||
} | ||
} elseif (is_string($result)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, where only a string is provided and no ValidationResult
, seems to be where the conditional $this->doShowAdditionalInfo()
should be used.
We should definitely be adding this extra context here when it's appropriate.
// e.g. dev/build | ||
if (is_a(Controller::curr(), DevelopmentAdmin::class)) { | ||
return true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why specifically that controller? I feel like it makes more sense to have a configurable deny list, and say "If the controller is in the deny list, return false" (e.g. LeftAndMain
and maybe even up to FormSchemaController
should be in the deny list, but if the current controller is front-end or custom, we should assume the extra context is needed unless developers say otherwise)
@@ -16,6 +17,7 @@ | |||
class ValidationResult | |||
{ | |||
use Injectable; | |||
use Configurable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why add configurable here?
/** | ||
* The record ID of the object being validated. | ||
*/ | ||
private int $recordID = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In various places we allow mixed
for ID (e.g. see the recent updated to SS_List
and related, which have mixed $id
for the byID()
method). We should do the same here - there's no guarantee that all projects use numeric IDs for all of their models.
Someone might have a model (not a subclass of DataObject
) that integrates with a third-party service and uses a GUID - and they may want to use a ValidationResult
with that model.
private int $recordID = 0; | |
private mixed $recordID = null; |
Please also update the constructor, setter, and getter.
protected array $messages = []; | ||
|
||
/** | ||
* The class of the DataObject being validated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* The class of the DataObject being validated. | |
* The class of the model being validated. |
if ($thisDataClass === '' && $otherDataClass !== '') { | ||
$this->setDataClass($otherDataClass); | ||
} elseif ($thisDataClass !== '' && $otherDataClass === '') { | ||
$other->setDataClass($thisDataClass); | ||
} | ||
if ($thisRecordID === 0 && $otherRecordID !== 0) { | ||
$this->setRecordID($otherRecordID); | ||
} elseif ($thisRecordID !== 0 && $otherRecordID === 0) { | ||
$other->setRecordID($thisRecordID); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be altering $other
.
if ($thisDataClass === '' && $otherDataClass !== '') { | |
$this->setDataClass($otherDataClass); | |
} elseif ($thisDataClass !== '' && $otherDataClass === '') { | |
$other->setDataClass($thisDataClass); | |
} | |
if ($thisRecordID === 0 && $otherRecordID !== 0) { | |
$this->setRecordID($otherRecordID); | |
} elseif ($thisRecordID !== 0 && $otherRecordID === 0) { | |
$other->setRecordID($thisRecordID); | |
} | |
if ($thisDataClass === '' && $otherDataClass !== '') { | |
$this->setDataClass($otherDataClass); | |
} | |
if ($thisRecordID === 0 && $otherRecordID !== 0) { | |
$this->setRecordID($otherRecordID); | |
} |
@@ -1257,7 +1257,7 @@ public function forceChange() | |||
*/ | |||
public function validate(): ValidationResult | |||
{ | |||
$result = ValidationResult::create(); | |||
$result = ValidationResult::create(get_class($this), $this->ID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the only place this gets set in core right now?
What about if I call validate()
on a form, and the form belongs to a specific model? E.g. I could conceivably set up a PHP Form
for some record that can be submitted from CLI using the fancy symfony console IO functionality.
Personally I think that scenario is likely to contain all the relevant context already, but want to get your thoughts and make sure that sort of thing has been considered.
Issue #11423
Also added in a bunch of strong typing while was doing it, removed nullable params and instead use blank string to denote "nothing", and changing a string|bool param param to just string