fieldset with multiple elements for recurrent code in forms using ZF2 and Doctrine2

491 Views Asked by At

I am new to ZF2 and Doctrine2.

I am wondering, can I use Fieldsets for simillar elements repeating in Forms. There are might be several simillar elements in the same form, and there are many simillar forms.

These elements are mapped to regular fields in entities (no one-to-many or many-to-one relationships ), and there are more fields in the same entities.

If it is possible, how do I set the objects for a fieldset like that?

I am getting the following error:

Zend\Hydrator\Exception\BadMethodCallException

File:

    D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-hydrator\src\ArraySerializable.php:26

Message:

    Zend\Hydrator\ArraySerializable::extract expects the provided object to implement getArrayCopy()

Stack trace:

    #0 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-form\src\Fieldset.php(631): Zend\Hydrator\ArraySerializable->extract(Object(OnlineFieldEvaluation\Entity\CompetencyDemonstrateEthicalAndProfessionalBehavior))
    #1 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-form\src\Form.php(944): Zend\Form\Fieldset->extract()
    #2 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-form\src\Form.php(303): Zend\Form\Form->extract()
    #3 D:\wamp\www\onlinefieldevaluation\module\OnlineFieldEvaluation\src\OnlineFieldEvaluation\Controller\TabsController.php(170): Zend\Form\Form->bind(Object(OnlineFieldEvaluation\Entity\CompetencyDemonstrateEthicalAndProfessionalBehavior))
    #4 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-mvc\src\Controller\AbstractActionController.php(82): OnlineFieldEvaluation\Controller\TabsController->editTabAction()
    #5 [internal function]: Zend\Mvc\Controller\AbstractActionController->onDispatch(Object(Zend\Mvc\MvcEvent))
    #6 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-eventmanager\src\EventManager.php(490): call_user_func(Array, Object(Zend\Mvc\MvcEvent))
    #7 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-eventmanager\src\EventManager.php(263): Zend\EventManager\EventManager->triggerListeners('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
    #8 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-mvc\src\Controller\AbstractController.php(118): Zend\EventManager\EventManager->triggerEventUntil(Object(Closure), Object(Zend\Mvc\MvcEvent))
    #9 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-mvc\src\Controller\Plugin\Forward.php(143): Zend\Mvc\Controller\AbstractController->dispatch(Object(Zend\Http\PhpEnvironment\Request), Object(Zend\Http\PhpEnvironment\Response))
    #10 D:\wamp\www\onlinefieldevaluation\module\OnlineFieldEvaluation\src\OnlineFieldEvaluation\Controller\OnlineFieldEvaluationController.php(845): Zend\Mvc\Controller\Plugin\Forward->dispatch('OnlineFieldEval...', Array)
    #11 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-mvc\src\Controller\AbstractActionController.php(82): OnlineFieldEvaluation\Controller\OnlineFieldEvaluationController->showStudentEvaluationAction()
    #12 [internal function]: Zend\Mvc\Controller\AbstractActionController->onDispatch(Object(Zend\Mvc\MvcEvent))
    #13 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-eventmanager\src\EventManager.php(490): call_user_func(Array, Object(Zend\Mvc\MvcEvent))
    #14 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-eventmanager\src\EventManager.php(263): Zend\EventManager\EventManager->triggerListeners('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
    #15 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-mvc\src\Controller\AbstractController.php(118): Zend\EventManager\EventManager->triggerEventUntil(Object(Closure), Object(Zend\Mvc\MvcEvent))
    #16 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-mvc\src\DispatchListener.php(114): Zend\Mvc\Controller\AbstractController->dispatch(Object(Zend\Http\PhpEnvironment\Request), Object(Zend\Http\PhpEnvironment\Response))
    #17 [internal function]: Zend\Mvc\DispatchListener->onDispatch(Object(Zend\Mvc\MvcEvent))
    #18 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-eventmanager\src\EventManager.php(490): call_user_func(Array, Object(Zend\Mvc\MvcEvent))
    #19 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-eventmanager\src\EventManager.php(263): Zend\EventManager\EventManager->triggerListeners('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
    #20 D:\wamp\www\onlinefieldevaluation\vendor\zendframework\zend-mvc\src\Application.php(340): Zend\EventManager\EventManager->triggerEventUntil(Object(Closure), Object(Zend\Mvc\MvcEvent))
    #21 D:\wamp\www\onlinefieldevaluation\public\index.php(27): Zend\Mvc\Application->run()
    #22 {main}

Here is what I tried so far:

Example for Factory

<?php

class FIGradeFSFactory implements FactoryInterface
{

    protected $options = array();

    protected $name;


    public function __construct( array $options = array())
    {
        $this->options = $options['options'];
        $this->name = $options['name'];
    }

    public function createService(ServiceLocatorInterface $formElementManager)
    {

        $elementName = $this->options["select_element_name"];
        $name = $this->getName();
        $options = $this->getOptions();
        return new FIGradeFS($name, $options);
    }

    .......... Getters and Setters


}

Example of Fieldset

<?php
namespace OnlineFieldEvaluation\Form;

class FIGradeFS extends Fieldset implements ObjectManagerAwareInterface, InputFilterProviderInterface, EventManagerAwareInterface
{

    protected $objectManager;
    protected $name;
    protected $commentName;
    protected $options;
    protected $events;
    protected $entityName;


    /**
     * @param ObjectManager $objectManager
     */
    public function __construct($name = null, $options = array())
    {
        $this->name = $name;

        $fsName = $name."FS";

        parent::__construct($fsName, $options);

        $this->commentName = $name . "Comment";
        $this->options = $options;

        $this->entityName = $options['allowed_object_binding_class'];

    }


    /**
     *
     */
    public function init()
    {

        $figrade = $this->name;

        $figradeComment = $figrade . 'Comment';

        $om = $this->getObjectManager();

        $hydrator = new DoctrineHydrator($om, $this->entityName);

        $hydrator->addStrategy($figrade , new FiGradeFSStrategy($figrade, $this->entityName));

        $hydrator->addStrategy($figradeComment , new FiGradeFSStrategy($figradeComment, $this->entityName));

        $this->setHydrator($hydrator)->setObject( new $this->entityName());

        $options = $this->getOptions();
        $tabPosition = $options["tabPosition"];
        $qtnLetter = $options["qtnLetter"];
        $isNA = $options["isNA"];

        $this->add(array(
            'name' => $figrade,
//            'type' => 'Zend\Form\Element\Select',
            'type' => 'DoctrineModule\Form\Element\ObjectSelect',
            'attributes' => array(
                'required' => 'required',
                'class' => 'fi-grade',
            ),
            'options' => array(
                'label' => 'Field Instructor Grade',
                'object_manager'  => $om,
                'target_class'    => $this->entityName,
                'disable_inarray_validator' => true,
                'property'        => $figrade,
                'value_options' => $this->getOptionsForSelect($isNA, $tabPosition, $qtnLetter),
            ),
        ));

        //Comment popup

        $this->add(array(
            'type' => 'Zend\Form\Element\Textarea',

            'name' => $figradeComment,
            'attributes' => array(
                'id' => $figradeComment,
            ),
            'options' => array(
                'label' => 'FI Comment',
            ),
        ));


    }

    /**
     * @return array
     */
    public function getInputFilterSpecification()
    {
        return array(
            $this->name => array(
                'required' => false,
            ),

            $this->commentName => array(
                'required' => false,
            ),
        );
    }


  ............... other methods..........................
}

Example of entity:

<?php
/**
 * OnlineFieldEvaluation - ${FILE_NAME}
 *
 * Initial version by: Viktor
 * Initial version created on: 4/23/15
 */

namespace OnlineFieldEvaluation\Entity;


// Add these import statements
use Doctrine\ORM\Mapping as ORM;

/**
 * An Identity Information.
 *
 * @ORM\Entity
 * @ORM\Table(name="form_comp_advance_rights_justice")
 *
 **/
class CompetencyAdvanceHumanRightsAndJustice extends CompetencyBase
{
    /**
     * @ORM\Column(type="string", length=10)
     */
    protected $applJusticeFIGrade;
    /**
     * @ORM\Column(type="string", length=1000)
     */
    protected $applJusticeFIGradeComment;

    /**
     * @ORM\Column(type="string", length=10)
     */
    protected $applJusticeSSGrade;

    /**
     * @ORM\Column(type="string", length=10)
     */
    protected $engageJusticeFIGrade;
    /**
     * @ORM\Column(type="string", length=1000)
     */
    protected $engageJusticeFIGradeComment;

    /**
     * @ORM\Column(type="string", length=10)
     */
    protected $engageJusticeSSGrade;


    /**
     * CompetencyAdvanceHumanRightsAndJustice constructor.
     */
    public function __construct()
    {
        //calculate summary grade
//        $this->calculateFiSummaryGrade();
    }

    public function getAllFiGrades()
    {
        $fiGrades[] = null;
        if ($this->applJusticeFIGrade != null)
            $fiGrades[] = $this->applJusticeFIGrade;
        if ($this->getEngageJusticeFIGrade() != null)
            $fiGrades[] = $this->engageJusticeFIGrade;

        return $fiGrades;
    }


    ...... setters and getters


}

Example of form:

<?php
/**
 * OnlineFieldEvaluation - ${FILE_NAME}
 *
 * Initial version by: Viktor
 * Initial version created on: 4/23/15
 */
namespace OnlineFieldEvaluation\Form;

use Zend\Captcha;
use Zend\Form\Element;


class CompetencyAdvanceHumanRightsAndJusticeForm extends BaseCompetencyForm
{


    /**
     * @param null $name
     * @param null $options
     */
    public function __construct($name = null, $options = null)
    {
        parent::__construct($name, $options);

    }

    /**
     * needs to be set in init(), because constructor won't be aware of objectmanager
     */
    public function init()
    {


        $this->setAttribute('method', 'post');



        $this->getBaseCompetencyFormElements();


        $this->add($this->getCaptionElement('applJustice'));

        // Add the a fieldset for FI grade of appJustice
        $this->addFIGrade('applJusticeFIGrade', $this->getTabPosition(), 'a', 'OnlineFieldEvaluation\Entity\CompetencyAdvanceHumanRightsAndJustice');

        $this->add(array(
            'name' => 'applJusticeSSGrade',
            'type' => 'Zend\Form\Element\Select',
            'attributes' => array(
                'required' => 'required',
            ),
            'options' => array(
                'label' => 'Student Self Grade',
                'disable_inarray_validator' => true,
                'value_options' => $this->getOptionsForSelect($this->getSemester(), $this->getTabPosition(), 'a'),
            ),
        ));


        $this->add($this->getExampleText('applJusticeFBExample'));


        $this->add($this->getExampleText('applJusticeVFPExample'));

        $this->add($this->getCaptionElement('engageJustice'));

        //Add FIGrade
        $this->addFIGrade('engageJusticeFIGrade', $this->getTabPosition(), 'b', 'OnlineFieldEvaluation\Entity\CompetencyAdvanceHumanRightsAndJustice');


        $this->add(array(
            'name' => 'engageJusticeSSGrade',
            'type' => 'Zend\Form\Element\Select',
            'attributes' => array(
                'required' => 'required',
            ),
            'options' => array(
                'label' => 'Student Self Grade',
                'disable_inarray_validator' => true,
                'value_options' => $this->getOptionsForSelect($this->getSemester(), $this->getTabPosition(), 'b'),
            ),
        ));


        $this->add($this->getExampleText('engageJusticeFBExample'));


        $this->add($this->getExampleText('engageJusticeVFPExample'));

        parent::init();

    }

    public function getAllCompetencyNamesForForm()
    {
        return array(
            'applJustice',
            'engageJustice',
        );
    }


}

BaseCompetencyForm :

<?php
/**
 * OnlineFieldEvaluation - formFileName
 *
 * Initial version by: Viktor
 * Initial version created on: 7/16/15
 */

namespace OnlineFieldEvaluation\Form;

use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Persistence\ObjectManagerAwareInterface;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use OnlineFieldEvaluation\Strategy\FIGradeFSStrategy;
use Zend\Form\Element;
use Zend\Form\Form;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;


abstract class BaseCompetencyForm extends Form implements ObjectManagerAwareInterface, ServiceLocatorAwareInterface, SignatureAwareInterface
{

    protected $captionService;
    /**
     * @var
     */
    private $semester;

    /**
     *
     * @var
     */
    protected $serviceLocator;

    /**
     * @var \Doctrine\ORM\EntityManager
     */
    private $objectManager;

    private $name;

    private $buildName;

    private $tabName;

    private $tabPosition;

    protected $options;

    protected $isSigned;

    protected $isNA;

    protected $role;

    /**
     * @param null $name
     * @param null $options
     */
    public function __construct($name = null, $options = null)
    {
        $this->name = $name;

        $this->options = $options;

        parent::__construct($name, $options);

        $this->semester = $options['semester'];

        $this->buildName = $options['buildName'];

        $this->tabPosition = $options['tabPosition'];

        $this->tabName = $options['tabName'];

        $this->isSigned= $options['isSigned'];

        $this->isNA = $options['isNA'];

        $this->role = $options['role'];

    }

    /**
     *
     */
    public function init()
    {

        $om = $this->getObjectManager();

        $this->setAttribute('name', $this->getName());

        $this->setAttribute('class', 'competency-form');

        $hydrator = new DoctrineHydrator($om);
//        $hydrator->setObject($this->getEntityInstanceFromBuildName($this->buildName));

//        $hydrator->addStrategy('applJusticeFIGradeFS', new FiGradeFSStrategy());

        $entityName = 'OnlineFieldEvaluation\Entity\\' . $this->buildName;

        foreach ($this->getAllCompetencyNamesForForm() as $compName) {
            $figrade = $compName . 'FIGrade';

            $figradeComment = $figrade . 'Comment';

//            $hydrator->addStrategy($figrade, new FiGradeFSStrategy($figrade, $entityName));

//            $hydrator->addStrategy($figradeComment, new FiGradeFSStrategy($figradeComment, $entityName));

//            TODO: Here Apply captionService
//            $competencyCaption = $compName.'Caption';
//
//            $hydrator->addStrategy($competencyCaption, new AssignCaptionsStrategy($competencyCaption, $entityName));

        }

//        $this->setHydrator($hydrator);

        // disable elements if the form is signed
        if($this->isSigned)
        {
            $this->disableElements($this->getIterator());
        }

    }

    /**
     * @param $formElements
     */
    protected function disableElements($formElements)
    {


        foreach ($formElements as $elementOrFieldset) {

            if ($elementOrFieldset instanceof \Zend\Form\FieldsetInterface) {

                $fsElements = $elementOrFieldset->getIterator();

                $this->disableElements($fsElements);

            } else {

                $elementOrFieldset->setAttribute('disabled', 'disabled');

            }

        }
    }


    /**
     * @param $name
     * @return mixed
     */
    protected function getCaptionElement($name)
    {
        $formElementManager = $this->serviceLocator;

        $options = [
            'name' => $name,
            'type' => 'CompetencyElementCaption',
            'shared' => false,
            'attributes' => array(
                'class' => 'competency-task',
                'disabled' => 'disabled',
                'required' => 'required',
            ),
            'options' => array(
                'label' => 'test label'
            ),
        ];

        $captionElement = $formElementManager->get('CompetencyElementCaption', $options);
//        $captionElement->setOptions($options);

        return $captionElement;
    }

    /**
     * @param $name
     * @return mixed
     */
    protected function getExampleText($name)
    {
        $formElementManager = $this->serviceLocator;

        $options = [
            'name' => $name,
            'type' => 'CompetencyExampleText',
            'shared' => false,
            'attributes' => array(
                'class' => 'competency-task',
                'disabled' => 'disabled',
                'required' => 'required',
            ),
            'options' => array(
                'label' => 'test label'
            ),
        ];

        $exampleTextElement = $formElementManager->get('CompetencyExampleText', $options);
//        $captionElement->setOptions($options);

        return $exampleTextElement;
    }


    /**
     *
     */
    private function getEntityInstanceFromBuildName($buildName)
    {
        $entityName = 'OnlineFieldEvaluation\Entity\\' . $buildName;
        return new $entityName();
    }

    /**
     *
     */
    public function getBaseCompetencyFormElements()
    {

        $this->add(array(
            'name' => 'id',
//            'type' => 'Hidden',
            'options' => array(
                'label' => 'ID',
            ),

        ));

        $this->add(array(
            'type' => 'Hidden',
            'name' => 'tabName',
            'attributes' => array(
                'value' => $this->tabName
            )
        ));

        $this->add(array(
            'type' => 'Hidden',
            'name' => 'buildName',
            'attributes' => array(
                'class' => 'build-name',
                'value' => $this->buildName
            )
        ));

        $this->add(array(
            'type' => 'Hidden',
            'name' => 'semester',
            'attributes' => array(
                'value' => $this->semester
            )
        ));


        $this->add(array(
            'type' => 'Hidden',
            'name' => 'tabPosition',
            'attributes' => array(
                'value' => $this->tabPosition,
            ),
        ));

        $this->add(array(
            'type' => 'Hidden',
            'name' => 'isSigned',
            'attributes' => array(
                'value' => $this->isSigned,
            ),
        ));



        $this->add(array(
            'name' => 'studEvalId',
            'type' => 'Hidden',
            'options' => array(
                'label' => 'Student Evaluation ID',
            ),
        ));

        $this->add(array(
            'type' => 'Hidden',
            'name' => 'fiSummaryGrade',
            'attributes' => array(
                'class' => 'grades-summary',
                'label' => 'FI Summary Grade',
            )
        ));

        $this->add(array(
            'name' => 'csrf',
            'type' => 'Zend\Form\Element\Csrf',
            'options' => array(
                'csrf_options' => array(
                    'timeout' => 7200
                )
            )
        ));

        $this->add(array(
            'name' => 'submitbutton',
            'type' => 'Submit',
            'attributes' => array(
                'value' => 'Save',
                'id' => 'submitbutton',
            ),
            'options' => array(
                'label' => 'Save It',
            ),
        ));
    }

    /**
     * @param mixed $semester
     */
    public function setSemester($semester)
    {
        $this->semester = $semester;
    }

    /**
     * @return mixed
     */
    public function getSemester()
    {
        return $this->semester;
    }

    /**
     * @param $semester
     * @return array
     */
    public function getOptionsForSelect($semester, $tabPosition, $qtnLetter)
    {
        $question = ($tabPosition - 1) . $qtnLetter;

        $naQuestions = array('3a', '3b', '4b', '5a', '5b', '5c', '8c', '9a', '9b', '9c');

        $valueOptions = null;

//        if ($semester === 1 && in_array($question, $naQuestions)) {
        if ($this->isNA === true && in_array($question, $naQuestions)) {
            $valueOptions = array(
                'na' => 'N/A',
                '0' => '0',
                '1' => '1',
                '2' => '2',
                '3' => '3',
                '4' => '4',
                '5' => '5',
                '6' => '6',
                '7' => '7',
                '8' => '8',
                '9' => '9',
                '10' => '10',
            );

        } else {
            $valueOptions = array(

                '0' => '0',
                '1' => '1',
                '2' => '2',
                '3' => '3',
                '4' => '4',
                '5' => '5',
                '6' => '6',
                '7' => '7',
                '8' => '8',
                '9' => '9',
                '10' => '10'
            );
        }


        return $valueOptions;
    }

    /**
     * @return mixed
     */
    public function getObjectManager()
    {
        return $this->objectManager;
    }

    /**
     * @param ObjectManager $objectManager
     * @return $this
     */
    public function setObjectManager(ObjectManager $objectManager)
    {
        $this->objectManager = $objectManager;
//        return $this;
    }


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

    /**
     * @return mixed
     */
    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }

    /**
     * @param null $name
     * @param null $bindingClass
     * @return mixed
     */
    protected function addFIGrade($name = null, $tabPosition = null, $qtnLetter = null, $bindingClass = null)
    {
//        $options = $this->getFIFieldSetOptions($name, $this->getSemester(), $tabPosition, $qtnLetter, $bindingClass);
        $isNA = $this->getIsNA();
        $options = $this->getFIFieldSetOptions($name, $isNA, $tabPosition, $qtnLetter, $bindingClass);

        $formElementManager = $this->serviceLocator;
        $fieldset = $formElementManager->get('FIGradeFS', array('name' => $name, 'options' => $options));

        $this->add($fieldset);
    }

    /**
     * @param null $name
     * @param array $options
     */
    protected function getFIFieldSetOptions($name = null, $isNA = 0, $tabPosition = null, $qtnLetter = null, $bindingClass = null)
    {
        return array(
            'use_as_base_fieldset' => false,
            'object_manager' => $this->getObjectManager(),
            'disable_inarray_validator' => true,
            'allowed_object_binding_class' => $bindingClass,
            'select_element_name' => $name,
//            'semester' => $semester,
            'isNA' => $isNA,
            'tabPosition' => $tabPosition,
            'qtnLetter' => $qtnLetter
        );
    }

    /**
     * @param null $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @return null
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param null $options
     */
    public function setOptions($options)
    {
        $this->options = $options;
    }

    /**
     * @return null
     */
    public function getOptions()
    {
        return $this->options;
    }

    /**
     * @param mixed $buildName
     */
    public function setBuildName($buildName)
    {
        $this->buildName = $buildName;
    }

    /**
     * @return mixed
     */
    public function getBuildName()
    {
        return $this->buildName;
    }

    /**
     * @param mixed $tabPosition
     */
    public function setTabPosition($tabPosition)
    {
        $this->tabPosition = $tabPosition;
    }

    /**
     * @return mixed
     */
    public function getTabPosition()
    {
        return $this->tabPosition;
    }


    /**
     * Order matters in this function
     */
    abstract public function getAllCompetencyNamesForForm();

    /**
     * @param $isSigned
     */
    public function setIsSigned($isSigned)
    {
        $this->isSigned = $isSigned;

    }

    /**
     * @return mixed
     */
    public function getIsSigned()
    {
        return $this->isSigned;
    }

    /**
     * @return mixed
     */
    public function getIsNA()
    {
        return $this->isNA;
    }

    /**
     * @param mixed $isNA
     */
    public function setIsNA($isNA)
    {
        $this->isNA = $isNA;
    }


}
0

There are 0 best solutions below