Skip to content
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

EZP-32256: GraphQL field validation throws exception without 'eng-GB' language #93

Merged
merged 1 commit into from
Jan 11, 2021
Merged

EZP-32256: GraphQL field validation throws exception without 'eng-GB' language #93

merged 1 commit into from
Jan 11, 2021

Conversation

ITernovtsii
Copy link
Contributor

@ITernovtsii ITernovtsii commented Dec 29, 2020

Jira ticket: https://issues.ibexa.co/browse/EZP-32256

Shortly, this PR address 3 issues with validation

  • $fieldErrors['eng-GB'] is not an array, but single error
  • use translated message text instead of Value for required field definition '%identifier%' with language '%code%' is empty"
  • undefined index 'eng-GB' if no such language in the system

STR:

  1. On clean install, replace eng-GB language to eng-US. You can use SQL to speed it up (instead of doing it manually in admin):
UPDATE `ezcontentclass`
SET `serialized_name_list` = REPLACE(`serialized_name_list`, "eng-GB", "eng-US")
WHERE `serialized_name_list` LIKE "%eng-GB%";

UPDATE `ezcontentclass`
SET `serialized_description_list` = REPLACE(`serialized_description_list`, "eng-GB", "eng-US")
WHERE `serialized_description_list` LIKE "%eng-GB%";

UPDATE `ezcontentclass_attribute`
SET `serialized_name_list` = REPLACE(`serialized_name_list`, "eng-GB", "eng-US")
WHERE `serialized_name_list` LIKE "%eng-GB%";

UPDATE `ezcontentclass_attribute`
SET `serialized_description_list` = REPLACE(`serialized_description_list`, "eng-GB", "eng-US")
WHERE `serialized_description_list` LIKE "%eng-GB%";

UPDATE `ezcontentclass_name`
SET `language_locale` = "eng-US"
WHERE `language_locale`="eng-GB";

UPDATE ezcontentobject_attribute
SET `language_code` = "eng-US"
WHERE `language_code`="eng-GB";

UPDATE ezcontentobject_attribute
SET `data_text` = REPLACE(`data_text`, "eng-GB", "eng-US")
WHERE `data_text` LIKE "%eng-GB%";

UPDATE ezcontentobject_name
SET `content_translation`="eng-US", `real_translation`="eng-US"
WHERE `content_translation`="eng-GB";

UPDATE `ezcontent_language`
SET `locale` ="eng-US", `name`="English (American)"
WHERE `locale`="eng-GB";
  1. Regenerate graphql schema
  2. Send graphql request with invalid field, for example:
mutation createUser {
  createUser(parentLocationId: 2, language: eng_US, input: {
    firstName: ""
    lastName: "test l"
    userAccount: "test@test.test"
  }) {
    id
  }
}

AR:
PHP Notice message returned:

"errors": [
    {
      "debugMessage": "Notice: Undefined index: eng-GB",
      "message": "Internal server Error",

ER:
Message about field validation fails returned:

"errors": [
    {
      "message": "Field 'first_name' failed validation: Value for required field definition 'first_name' with language 'eng-US' is empty",

Comment on lines 280 to 281
$fieldErrorsList = $fieldErrors['eng-GB'] ?? reset($fieldErrors);
$fieldErrorsList = is_array($fieldErrorsList) ? $fieldErrorsList : [$fieldErrorsList];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your patch is correct, however the root cause of the issue is hard-coded eng-GB language code, which shouldn't happen here 😞

Can we change renderFieldValidationErrors  implementation to:

    private function renderFieldValidationErrors(RepositoryExceptions\ContentFieldValidationException $e, API\Values\ContentType\ContentType $contentType)
    {
        $errors = [];
        foreach ($e->getFieldErrors() as $fieldDefId => $fieldErrorsByLanguage) {
            $fieldDefinition = $contentType->getFieldDefinitions()->filter(
                static function (FieldDefinition $fieldDefinition) use ($fieldDefId) {
                    return $fieldDefinition->id === $fieldDefId;
                }
            )->first();

            foreach ($fieldErrorsByLanguage as $fieldErrors) {
                foreach ($fieldErrors as $fieldError) {
                    // depending on error instance, values injected in Plural::__toString or Message::__toString
                    $errors[] = sprintf("Field '%s' failed validation: %s",
                        $fieldDefinition->identifier,
                        (string)$fieldError->getTranslatableMessage()
                    );
                }
            }
        }

        return $errors;
    } 

// cc @ezsystems/php-dev-team @bdunogier

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adamwojs
Looks like no, as I see $fieldErrors is not an array, but a single field error.
But I agree that keeping hardcoded language in place is not a good part, I just kept it as I wasn't sure why it was like this initially.

I would change this line if you can confirm it's okay.
$fieldErrorsList = $fieldErrors['eng-GB'] ?? reset($fieldErrors);
to
$fieldErrorsList = reset($fieldErrors);
So error (or errors if there is some other flow that I didn't test) from first available language will be used.
Let me know if it's not okay.

debug info based on your variant:

var_dump($fieldErrorsByLanguage);

array(1) {
  'eng-US' =>
  class eZ\Publish\Core\FieldType\ValidationError#7473 (4) {
    protected $singular =>
    string(90) "Value for required field definition '%identifier%' with language '%languageCode%' is empty"
    protected $plural =>
    NULL
    protected $values =>
    array(2) {
      '%identifier%' =>
      string(10) "first_name"
      '%languageCode%' =>
      string(6) "eng-US"
    }
    protected $target =>
    string(5) "empty"
  }
}

// so, we can't iterate here
foreach ($fieldErrorsByLanguage as $fieldErrors) { // $fieldErrors is instance of ValidationError
                foreach ($fieldErrors as $fieldError) { // this iteration will do nothing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, I rechecked the flow again and I think we don't need to support array in $fieldErrors at all.
$e->getFieldErrors() should return this structure:
https://github.com/ezsystems/ezpublish-kernel/blob/master/eZ/Publish/Core/Base/Exceptions/ContentFieldValidationException.php#L26

What do you think about variant I just pushed?

Copy link
Member

@bdunogier bdunogier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, and thank you very much for your PR Ivan.

While we must still get rid of the hardcoded eng-GB, your patch is a good improvement for the time being.

@micszo micszo self-assigned this Jan 11, 2021
Copy link
Member

@micszo micszo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduced and retested on Ibexa Experience 3.2.3 with diff.

@micszo micszo removed their assignment Jan 11, 2021
@lserwatka lserwatka merged commit 9531abd into ezsystems:2.2 Jan 11, 2021
@lserwatka
Copy link
Member

@bdunogier could you merge it up?

@bdunogier
Copy link
Member

@lserwatka done for master and 3.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

5 participants