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

[BUG]: form entity isn't passed to validator #15567

Closed
stijn1989 opened this issue Jul 1, 2021 · 6 comments · Fixed by #15568
Closed

[BUG]: form entity isn't passed to validator #15567

stijn1989 opened this issue Jul 1, 2021 · 6 comments · Fixed by #15568
Labels
5.0 The issues we want to solve in the 5.0 release bug A bug report

Comments

@stijn1989
Copy link
Contributor

When setting an entity to a form on construction and calling isValid($data), the entity isn't passed to the validator. The only entity that is passed, is the entity that is passed with isValid($data, $entity). But you shouldn't do this, because you already pass this entity to the form on construction.

To Reproduce

Steps to reproduce the behavior:

Person.php

<?php
class Person extends \Phalcon\Mvc\Model
{
    public $name;

    public function validation(): bool
    {
        return $this-validate(new PersonValidator());
    }
}

PersonValidator.php

<?php
class PersonValidator extends \Phalcon\Validation
{

    public function __construct()
    {
        parent::__construct([
            'name' => [
                new \Phalcon\Validation\Validator\Uniqueness(['message' => "Person name must be unique!"])
            ]
        ]);
    }

}

PersonForm.php

<?php
class PersonForm extends \Phalcon\Forms\Form
{

    public function initalize($entity = null, $options = []): 
    {
        $name = new \Phalcon\Forms\Element\Text('name');
        $name->setLabel('Name');

        $this->add($name);
        $this->setValidation(new PersonValidator());
    }

}

Provide minimal script to reproduce the issue

PersonController.php

<?php
class PersonController extends \Phalcon\Mvc\Controller
{

    public function editAction($name)
    {
        $person = Person::findByName($name);
        $form = new PersonForm($person);

        if($this->request->isPost()) {
            if($form->isValid($this->request->getPost()) {
                $person->save();
                $this->flash->success('Person saved!');
            } else {
                $this->flash->error( implode('<br>', $form->getMessages());
            }
        }

        $this->view->form = $form;
    }

}

Expected behavior
If you run this edit action and just hit save and don't change anything. It should produce the success message Person saved!.
But it doesn't. It gives the error message Person name must be unique!.

If you change the isValid() line to the line below, it works.

....
if($form->isValid($this->request->getPost(), $person) {
....

Details

  • Phalcon version: 4.1
  • PHP Version: 7.4
  • Operating System: Debian
  • Installation type: Installing from PECL.
  • Zephir version (if any):
  • Server: Nginx
@wurst-hans
Copy link

Shouldn't the validator be attachted to field instead?
Try to use $name->addValidator(new PersonValidator());

@stijn1989
Copy link
Contributor Author

Shouldn't the validator be attachted to field instead?
Try to use $name->addValidator(new PersonValidator());

No, because you set validators for the field in PeronValidator. It's better to separate validation rules in a class. That way you can use that validation everywhere like in Forms and Models.

@wurst-hans
Copy link

wurst-hans commented Jul 15, 2021

I see. Slightly different behavior here on 4.1.0. I've created a validation class and attached it to a form and to the related model.

No problems on adding a new (non-existing) name. But funny thing is, I can't update the freshly created object. On save() object the validation fails.

@stijn1989
Copy link
Contributor Author

Adding is not a problem because the entity is in TRANSIENT state. Fetch an existing one and don't change the name and submit the form. Then it doesn't validate.

And that's the problem, because the form object doesn't pass his entity to the validation. And the Uniqueness validator checks on the state of the entity.

@wurst-hans
Copy link

wurst-hans commented Jul 15, 2021

BTW: I would use public function initialize() instead of overwriting constructor for extended validation class.

But as the problem happens in model validation, does it really depends on form? I mean, form validation passes and in isValid() the data is bound to entity. Can you try if this also fails, when getting object from database and save() it immediately without using a form?

Edit:
You are right. In code one can see, that only $entity of isValid() is passed, but not $this->entity of form itself. Not very neat, but one might solve it this way:

class MyForm extends Form {
    public function initialize($entity = null, array $options = []): void
    {
        [...]
        $validation = new CustomValidation();
        if ($entity instanceof ModelInterface) {
            $validation->setEntity($entity);
        }
        $this->setValidation($validation);
    }
}

@niden niden linked a pull request Aug 12, 2021 that will close this issue
5 tasks
@niden
Copy link
Member

niden commented Aug 12, 2021

Resolved in #15568

@niden niden closed this as completed Aug 12, 2021
@Jeckerson Jeckerson added 5.0 The issues we want to solve in the 5.0 release and removed status: unverified Unverified labels Aug 12, 2021
@niden niden moved this to Released in Phalcon v5 Aug 25, 2022
@niden niden added this to Phalcon v5 Aug 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
5.0 The issues we want to solve in the 5.0 release bug A bug report
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

4 participants