We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Form messages seem spoiled

Hi again, I try to use Form component but I can't. First case, when form is valid:

$form->getMessages()->appendMessage(new Message('general message')); //nothing
$form->get('email')->appendMessage(new Message('emai invalid 1')); //ok (add message to field property)
$form->getMessages(); //return empty object

Second case, form is invalid:

$form->isValid(['email' => 'invalid email']); //ensure is invalid
$form->getMessages()->appendMessage(new Message('general message')); //ok
$form->getMessages()->appendMessage(new Message('general message 2')); //ok
$form->get('email')->appendMessage(new Message('emai invalid 1')); //ok (add message to field property)
$form->get('email')->appendMessage(new Message('email invalid 2')); //ok as above
$form->getMessages(); //show messages, but not all (email messages are ignored)

To my thinking base problems are two:

  • different behaviour when form is valid/invalid (or maybe messages are empty)
  • isValid method, it seems to copy messages from fields to form messages property, but only first message (when I have more validators I'd like to show all messages) and overwrite messages list

So I want:

  • to show messages from all validators
  • to have possibility to add custom messages


8.3k
edited Feb '18

I came up a workaround, first You have to extend Form class and:

Add special field (it would be also used to check whether form is submitted), You can perform it manually, by initialize, constructor or even add "_f" in template

    public function addIsSubmittedField(){
        $f = new Hidden('_f');
        $this->add($f);
    }

Next adding message, firstly it's required to set messages object, secondly ensure that form doesn't pass a validation test (we presume that form is invalid when has at least one message)

   public function addMessage($message){
        $refObject = new \ReflectionObject($this);
        $refProperty = $refObject->getProperty('_messages');
        $refProperty->setAccessible(true);
        $val = $refProperty->getValue($this);
        if ($val === null) {
            $val = new \Phalcon\Validation\Message\Group();
            $val->appendMessage(new Message($message));
        } else {
            $val->appendMessage(new Message($message));
        }
        $refProperty->setValue($this, $val);
        $refProperty->setAccessible(false);
        if ($this->has('_f')) {
            $this->get('_f')->addValidator(new AlwaysFalseValidator(['message' => $message]));
        }
    }

Finally we need validator who always returns false:

class AlwaysFalseValidator extends Validator
{

    /**
     * Workaround - form messages
     *
     * @param Validation $validator
     * @param string     $attribute
     * @return boolean
     */
    public function validate(Validation $validator, $attribute)
    {
        $validator->appendMessage(
            new Message($this->getOption('message'), $attribute)
        );

        return false;
    }
}

Now we can use it like below:

        $form = new TestRenderForm();
        // test1 $form->addMessage('Your (|) is leaking here!');
        if ($this->request->isPost()) {
            // test2 $form->addMessage('Your (|) is leaking here!');
            if ($form->isValid($this->request->getPost())) {
                // test3 $form->addMessage('Your (|) is leaking here!');
                $this->getToolbarLog()->notice('Form is valid!');
            } else {
                // test4 $form->addMessage('Your (|) is leaking here!');
                $this->getToolbarLog()->error('Form is invalid!');
            }
            //test5 $form->addMessage('Your (|) is leaking here!');
        }
        //test6 $form->addMessage('Your (|) is leaking here!');

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