$form->isValid says it is invalid, but my form does not show any error message - Zend Framework 2
Asked Answered
E

3

8

Im having a problem with the addAction in my CRUD application. On the controller the logic does not pass the $form->isValid() verification but the form does not show any error message.

I tried with this (Thanks Sam):

foreach($form->get('product')->getElements() as $el)
{
    echo $el->getName()." = ".$el->getValue()." > ".$el->getMessages()." <br/>";
}

That only show the name and value of the field, but not the error message.

I've tried letting the form totally blank and it fire "Value is required and can't be empty" error messages, but then, i fill each field one by one until i don't get more error messages but the form still invalid.

My form has a Product Fieldset as a base fieldset and a submit button. Inside Product Fieldset i have an ID field, a name field, a price field and a Brand Fieldset. Inside my Brand Fieldset i have a id field. Like this:

ProductForm:

class ProductForm extends Form
{

    public function init()
    {
        // we want to ignore the name passed
        parent::__construct('product');
        $this->setName('product');
        $this->setAttribute('method', 'post');

        $this->add(array(
               'name' => 'product',
                'type' => 'Administrador\Form\ProductFieldset',
                'options' => array(
                        'use_as_base_fieldset' => true
                ),
        ));
        $this->add(array(
                'name' => 'submit',
                'type' => 'Submit',
                'attributes' => array(
                        'value' => 'Add',
                        'id' => 'submitbutton',
                ),
        ));
    }
}

ProductFieldset:

class ProductFieldset extends Fieldset implements ServiceLocatorAwareInterface
{

    protected $serviceLocator;

    function __construct($name = null)
    {
        parent::__construct('product_fieldset');

        $this->setHydrator(new ArraySerializableHydrator());
        $this->setObject(new Product());
    }

    public function init()
    {

        $this->add(array(
                'name' => 'id',
                'type' => 'Hidden',
        ));
        $this->add(array(
                'name' => 'name',
                'type' => 'Text',
                'options' => array(
                        'label' => 'Name',
                ),
        ));
        $this->add(array(
                'name' => 'price',
                'type' => 'Text',
                'options' => array(
                        'label' => 'Price',
                ),
        ));
        $this->add(array(
                'name' => 'brand',
                'type' => 'BrandFieldset',
        ));
    }


    public function setServiceLocator(ServiceLocatorInterface $sl)
    {
        $this->serviceLocator = $sl;
    }

    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }
}

BrandFieldset:

class BrandFieldset extends Fieldset
{
    function __construct(BrandTable $brandTable)
    {
        parent::__construct('brand_fieldset');

        //$this->setHydrator(new ClassMethodsHydrator(false))->setObject(new Brand());

        $this->setHydrator(new ArraySerializableHydrator());
        $this->setObject(new Brand());

        $brandSelectOptionsArray = $brandTable->populateSelectBrand();
        $this->add(array(
                'name' => 'id',
                'type' => 'Select',
                'options' => array(
                        'label' => 'Brand',
                        'empty_option' => 'Please select a brand',
                        'value_options' => $brandSelectOptionsArray,
                ),
        ));
    }
}

This is my new Form statement in the addAction:

$formManager = $this->serviceLocator->get('FormElementManager');
$form = $formManager->get('Administrador\Form\ProductForm');

Inside my model 'Product' i have the inputFilters, required filter for 'id' field, required filter for 'name' field. And for the Brand field i created other inputFilter and added it to the main inputFilter:

$brandFilter->add($factory->createInput(array(
'name'     => 'id',
'required' => true,
'filters'  => array(
    array('name' => 'Int'),
),
)));
$inputFilter->add($brandFilter, 'brand');

The weird behavior is that my editAction works fine and has the same logic.

Is it there any form of echoing an internal error message from the form, something that helps me to understand WHY the form is not valid.

EDIT 2013-06-01

Here is my full Controller:

class ProductController extends AbstractActionController
{

    protected $productTable;
    protected $brandTable;

    public function indexAction()
    {
        return new ViewModel(array(
            'products' => $this->getProductTable()->fetchAll(),
        ));
    }

    public function addAction()
    {
        $formManager = $this->serviceLocator->get('FormElementManager');
        $form = $formManager->get('Administrador\Form\ProductForm');
        $form->get('submit')->setValue('Add');

        $request = $this->getRequest();
        if ($request->isPost()) {
            $product = new Product();
            $product->brand = new Brand();
            $form->setInputFilter($product->getInputFilter());
            $form->setData($request->getPost());

            if ($form->isValid()) {
                $product->exchangeArray($form->getData());
                $this->getProductTable()->saveProduct($product);

                // Redirect to list of products
                return $this->redirect()->toRoute('product');
            }
        }
        return new ViewModel(array(
            'form' => $form,
        ));
    }

    public function editAction()
    {
        $id = (int) $this->params()->fromRoute('id', 0);
        if (!$id) {
            return $this->redirect()->toRoute('product', array(
                    'action' => 'add'
            ));
        }

        // Get the Product with the specified id.  An exception is thrown
        // if it cannot be found, in which case go to the index page.
        try {
            $product = $this->getProductTable()->getProduct($id);
        }
        catch (\Exception $ex) {
            return $this->redirect()->toRoute('product', array(
                    'action' => 'index'
            ));
        }
        $formManager = $this->serviceLocator->get('FormElementManager');
        $form = $formManager->get('Administrador\Form\ProductForm');
        $brand = $this->getBrandTable()->getBrand($product->brand);
        $product->brand = $brand;
        $form->bind($product);
        $form->get('submit')->setAttribute('value', 'Edit');

        $request = $this->getRequest();
        if ($request->isPost()) {
            $form->setInputFilter($product->getInputFilter());
            $form->setData($request->getPost());

            if ($form->isValid()) {
                $this->getProductTable()->saveProduct($form->getData());

                // Redirect to list of products
                return $this->redirect()->toRoute('product');
            }
        }

        return array(
                'id' => $id,
                'form' => $form,
        );
    }

    public function deleteAction()
    {
        $id = (int) $this->params()->fromRoute('id', 0);
        if (!$id) {
            return $this->redirect()->toRoute('product');
        }

        $request = $this->getRequest();
        if ($request->isPost()) {
            $del = $request->getPost('del', 'No');

            if ($del == 'Yes') {
                $id = (int) $request->getPost('id');
                $this->getProductTable()->deleteProduct($id);
            }

            // Redirect to list of products
            return $this->redirect()->toRoute('product');
        }

        return array(
                'id'    => $id,
                'product' => $this->getProductTable()->getProduct($id)
        );
    }


    public function getProductTable()
    {
        if (!$this->productTable) {
            $sm = $this->getServiceLocator();
            $this->productTable = $sm->get('Administrador\Model\ProductTable');
        }
        return $this->productTable;
    }

    public function getBrandTable()
    {
        if (!$this->brandTable) {
            $sm = $this->getServiceLocator();
            $this->brandTable = $sm->get('Administrador\Model\BrandTable');
        }
        return $this->brandTable;
    }
}
Elison answered 31/5, 2013 at 23:44 Comment(2)
Please provide full controller methods involved.Wollongong
OK, I'll provide the controller's add and edit action.Elison
E
0

Well, I got the answer :D

This is how the addAction should be:

public function addAction()
{
    $formManager = $this->serviceLocator->get('FormElementManager');
    $form = $formManager->get('Administrador\Form\ProductForm');
    $form->get('submit')->setValue('Add');

    $product = new Product();
    $product->brand = new Brand();

    $form->bind($product);  // I need to bind the product to the form to pass the isValid() validation

    $request = $this->getRequest();
    if ($request->isPost()) {
        $form->setInputFilter($product->getInputFilter());
        $form->setData($request->getPost());

        if ($form->isValid()) {
            $product = $form->getData();
            $this->getProductTable()->saveProduct($product);

            // Redirect to list of products
            return $this->redirect()->toRoute('product');
        }
    }
    return new ViewModel(array(
        'form' => $form,
    ));
}

Apparently i needed to bind and empty product object to the form to be able to pass the isValid() validation. After that i retrieve a product object from the $form->getData().

Elison answered 3/6, 2013 at 21:9 Comment(0)
P
1

My case was I passed wrong input filter. isValid returns false, but $form->getMessages() is empty. Form OrderForm had the following:

$form->setInputFilter(new \Application\Form\UserInputFilter($er));

When I changed UserInputFilter to OrderInputFilter it works.

Pioneer answered 29/7, 2015 at 0:22 Comment(0)
E
0

Well, I got the answer :D

This is how the addAction should be:

public function addAction()
{
    $formManager = $this->serviceLocator->get('FormElementManager');
    $form = $formManager->get('Administrador\Form\ProductForm');
    $form->get('submit')->setValue('Add');

    $product = new Product();
    $product->brand = new Brand();

    $form->bind($product);  // I need to bind the product to the form to pass the isValid() validation

    $request = $this->getRequest();
    if ($request->isPost()) {
        $form->setInputFilter($product->getInputFilter());
        $form->setData($request->getPost());

        if ($form->isValid()) {
            $product = $form->getData();
            $this->getProductTable()->saveProduct($product);

            // Redirect to list of products
            return $this->redirect()->toRoute('product');
        }
    }
    return new ViewModel(array(
        'form' => $form,
    ));
}

Apparently i needed to bind and empty product object to the form to be able to pass the isValid() validation. After that i retrieve a product object from the $form->getData().

Elison answered 3/6, 2013 at 21:9 Comment(0)
A
0

You can also do: $form->setBindOnValidate(false);

Armindaarming answered 19/1, 2015 at 15:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.