Проблема в заполнении подчиненной формы в Zend Framework - PullRequest
2 голосов
/ 16 марта 2011

Я строю абстрактную форму в Zend Framework. Это делается путем создания динамических элементов формы из базы данных (таблицы со значениями ключ / значение). Большинство из них работает нормально, за исключением функции setDefault / populate формы. Позвольте мне объяснить.

У меня есть основная форма с 3 подчиненными формами (форма в стиле мастера). 3-й шаг формы имеет 5 или более динамических элементов. (например: свойства серверной стойки).
Форма на шаге 3 может быть клонирована с помощью ajax. (Таким образом, вы сможете добавить 4 серверных стойки одновременно). При отправке формы функция preValidation () проверит все новые поля и добавит их в подчиненную форму. Так хорошо, так хорошо. Теперь проблемы начинаются.

При добавлении полей в подчиненную форму я использую фабричный способ создания элементов формы =>

$subForm->addElement($presentation_type,'fixedField'. $key.'_'.$formStep, 
array('label' => $label.':',
'required'     => $is_mandatory,
'filter'       => $filters,
'value'        => $value,
'description'  => $unit .' '. $description,
'validators'   => $validators));

Это прекрасно работает при запуске новой неподтвержденной формы, но не может установить параметр-значение при отправке формы, он не заполняет параметр-значение (остальные параметры в той же функции работают нормально). Я обновил Zend Framework до последней версии. Попытался найти мою проблему на Google и форумах, но безуспешно.

Я пришлю вам бельгийское пиво, если вы решите это :) Искал 3 дня сейчас.

Также пытались использовать функцию setDefault и функцию заполнения.

Странная вещь, когда я делаю "echo $ subForm-> getElement ('xxxxxx') -> getValue ();" я получаю правильный вывод. Похоже, что Zend просто не будет отображать значение внутри элемента.

Код контроллера:

<code><?php
class TestController extends Zend_Controller_Action {
    protected $_form;
    protected $_namespace = 'TestController';
    protected $_session;

    /**
     * Gets the add/edit form for the current object
     *
     * @access public
     * @return object|void
     * @param boolean $search_form Set to true if you want the search form object to be returned
     */
    public function getForm()
    {
        if (null === $this->_form) {
            $action = $this->getRequest()->getActionName();
            $this->_form = new Application_Form_Test();

        }
        return $this->_form;
    }

    /**
     * Action for the new page
     *
     * @access public
     * @return void
     */
    public function newAction (){


        //Store the parent object in a session, this way we can use the var in the 3th form step
        $this->getSessionNamespace();

        // Either re-display the current page, or grab the "next"
        // (first) sub form
        if (!$form = $this->getCurrentSubForm()) {
            $form = $this->getNextSubForm();
        }

        $this->view->form = $this->getForm()->prepareSubForm($form);

    }

     /**
     * Action to process the multi step form
     *
     * @access public
     * @return mixed
     */
    public function processAction(){

        //No form is set
        if (!$form = $this->getCurrentSubForm()) {
            return $this->_forward('new');
        }

        if (!$this->subFormIsValid($form, $this->getRequest()->getPost())) {
            $this->view->form = $this->getForm()->prepareSubForm($form);
            return $this->render('new');
        }

        if (!$this->formIsValid()) {
            $form = $this->getNextSubForm();
            $this->view->form = $this->getForm()->prepareSubForm($form);
            return $this->render('new');
        }

        // Valid form!
        // Let's save everything
        //......

        // All done, clear the sessions
        Zend_Session::namespaceUnset($this->_namespace);
        //$this->render('index');
        $this->_forward('index');
    }

    /**
     * Ajax action that returns the dynamic form field for step3 in the form
     */
    public function newajaxformAction() {

      if(!$this->getRequest()->isXmlHttpRequest()) throw new Zend_Controller_Action_Exception("This isn't a Ajax request !", 404);

      $ajaxContext = $this->_helper->getHelper('AjaxContext');
      $ajaxContext->addActionContext('newfield', 'html')->initContext();

      //Disable view
      $this->_helper->viewRenderer->setNoRender();
      $this->_helper->layout()->disableLayout();

      $id = $this->_getParam('id', null);
      $amount = $this->_getParam('amount', null);

      $fieldsKeys = $_POST['key'];
      $fieldsValues = $_POST['value'];

      //This one adds multiple objects on one page
      $po = new Test_Partial($id,$amount,$fieldsKeys,$fieldsValues);

      echo $po->__toString();
    }

    /**
     * Get the session namespace we're using
     *
     * @access public
     * @return Zend_Session_Namespace
     */
    public function getSessionNamespace()
    {
        if (null === $this->_session) {
            $this->_session = new Zend_Session_Namespace($this->_namespace);
        }

        return $this->_session;
    }

    /**
     * Get a list of forms already stored in the session
     *
     * @access public
     * @return array
     */
    public function getStoredForms()
    {
        $stored = array();
        foreach ($this->getSessionNamespace() as $key => $value) {
            $stored[] = $key;
        }

        return $stored;
    }

    /**
     * Get list of all subforms available
     *
     * @access public
     * @return array
     */
    public function getPotentialForms()
    {
        return array_keys($this->getForm()->getSubForms());
    }

    /**
     * What sub form was submitted?
     *
     * @access public
     * @return false|Zend_Form_SubForm
     */
    public function getCurrentSubForm()
    {
        $request = $this->getRequest();
        if (!$request->isPost()) {
            return false;
        }

        foreach ($this->getPotentialForms() as $name) {
            if ($data = $request->getPost($name, false)) {
                if (is_array($data)) {
                    return $this->getForm()->getSubForm($name);
                    break;
                }
            }
        }

        return false;
    }

    /**
     * Get the next sub form to display
     *
     * @return Zend_Form_SubForm|false
     * @access public
     */
    public function getNextSubForm()
    {
        $storedForms    = $this->getStoredForms();
        $potentialForms = $this->getPotentialForms();

        foreach ($potentialForms as $name) {
            if (!in_array($name, $storedForms)) {
                return $this->getForm()->getSubForm($name);
            }
        }

        return false;
    }

    /**
     * Is the sub form valid?
     *
     * @param  Zend_Form_SubForm $subForm
     * @param  array $data
     * @return bool
     */
    public function subFormIsValid(Zend_Form_SubForm $subForm,array $data)
    {
        $name = $subForm->getName();

        echo '<br />Submitted data(Send from Controller) = <pre>';
            print_r($data);
        echo '
'; if ($ subForm-> isValid ($ data)) { $ this-> getSessionNamespace () -> $ name = $ subForm-> getValues ​​(); вернуть истину; } вернуть ложь; } / ** * Действительна ли полная форма? * * @return bool * @ доступ общественности * / публичная функция formIsValid () { $ data = array (); foreach ($ this-> getSessionNamespace () как $ key => $ info) { $ data [$ key] = $ info [$ key]; } return (count ($ this-> getStoredForms ()) getPotentialForms ()))? false: $ this-> getForm () -> isValid ($ data); } } ?> Код формы: <? PHP Класс Application_Form_Test extends Zend_Form { публичная функция init () { // Установить несколько фильтров для полей $ This-> setElementFilters (массив ( 'StringTrim')); // Давайте создадим несколько подформ => каждая подформа будет на другой странице //Шаг 1 $ step1 = new Zend_Form_SubForm (); $ step1-> addElement ('select', 'test', array ('label' => 'Save in:', 'multiOptions' => array ('choose' => 'Choose one ...', 'a' => 'a', 'b' => 'b'), 'required' => false, 'игнорировать' => правда, 'значение' => массив ('выбрать'), 'validators' => array (array ('InArray', false, array (array_keys (array ('Choose' => 'Choose one ...', 'a' => 'a', 'b' => 'b) «))))))); // Шаг 3 $ step2 = new Zend_Form_SubForm (); // Добавить кнопку удаления и добавления для динамических форм $ step2-> addElement ('text', 'addFormAmount', array ('label' => '', 'required' => false, 'игнорировать' => правда, 'значение' => 1, 'description' => 'objects.', 'order' => 99992 )); $ step2-> addElement ('button', 'addForm', array ('label' => 'Add', 'order' => 99991 )); $ step2-> getElement ('addForm') -> setAttrib ('onClick', 'ajaxAddForm ();');// Добавить скрытое поле идентификатора, таким образом, мы можем использовать идентификатор в javascript для подсчета количества полей $ step2-> addElement ('hidden', 'id', array ('value' => 1));$ this-> addAbstractField ($ step2, '', 1, 'test value');// тест, давайте поместим нашу предварительную проверку в конец объекта формы $ this-> preValidation ($ step2, $ _ POST);// Наконец, присоединяем вложенные формы к главной форме $ this-> addSubForms (array ('step1' => $ step1, 'step2' => $ step2));} / ** * Создание медленной строки для форм или любой другой связанной с URI строки * * @return mixed * @access public * @param mixed $ array * / защищенная функция getSlug ($ string) {$ slug = trim ($ string);// обрезать строку $ slug = preg_replace ('/ [^ a-zA-Z0-9 -] /', '', $ slug);// принимаем только буквенно-цифровые символы, но сохраняем также пробелы и тире… $ slug = str_replace ('', '-', $ slug);// заменить пробелы тире $ slug = strtolower ($ slug);// сделать его строчным. return $ slug;} / ** * Подготовка формы для отображения * * @param string | Zend_Form_SubForm $ spec * @return Zend_Form_SubForm * / открытая функция prepareSubForm ($ spec) {if (is_string ($ spec)) {$ subForm = $ this->{$} спецификации;} elseif ($ spec instanceof Zend_Form_SubForm) {$ subForm = $ spec;} else {throw new Exception ('Недопустимый аргумент, переданный'. __FUNCTION__. '()');} $ this-> setSubFormDefaultDecorators ($ subForm) -> addSubmitButton ($ subForm) -> addSubFormActions ($ subForm);вернуть $ subForm;} / ** * Добавление декораторов формы к отдельной подформе * * @param Zend_Form_SubForm $ subForm * @return My_Form_Registration * / открытая функция setSubFormDefaultDecorators (Zend_Form_SubForm $ subForm) {$ subForm-> setDecorators (array ('FormElements', массивHtmlTag ', array (' tag '=>' dl ',' class '=>' zend_form ')),' Form ',));вернуть $ this;} / ** * Добавить кнопку отправки в отдельную суб-форму * * @param Zend_Form_SubForm $ subForm * @return My_Form_Registration * / открытая функция addSubmitButton (Zend_Form_SubForm $ subForm) {$ subForm-> addElement (новый массив Zend_Form_Element_Submit (сохранить)('label' => 'Сохранить и продолжить', 'required' => false, 'ignore' => true, 'order' => 99999)));$ subForm-> getElement ('save') -> setAttrib ('onClick', 'ajaxController (); $ ("# processing_alert"). css ("display", "block");');вернуть $ this;} / ** * Добавление действия и метода в подформу * * @param Zend_Form_SubForm $ subForm * @return My_Form_Registration * / открытая функция addSubFormActions (Zend_Form_SubForm $ subForm) {$ subForm-> setAction ('/ test / process') -> setMethod('post') -> setEnctype (Zend_Form :: ENCTYPE_MULTIPART);вернуть $ this;} / ** * После публикации, ловушка предварительной проверки * * Находит все поля, в которых name включает 'newField', и использует addNewField для добавления * их к объекту формы * * @param array $ data $ _GET или $ _POST * / public function preValidation(Zend_Form_SubForm $ subForm, массив $ data) {// функция обратного вызова array_filter findFields ($ field) {// вернуть имена полей, которые включают 'newField' if (strpos ($ field, 'newField')! == false) {return $поле;}} // Поиск $ data для динамически добавляемых полей с использованием обратного вызова findFields $ newFields = array_filter (array_keys ($ data), 'findFields');foreach ($ newFields as $ fieldName) {// убрать номер идентификатора из имени поля и использовать его для установки нового порядка $ ex1 = explode ('newField', $ fieldName);$ ex2 = взорваться ('_', $ ex1 [1]);$ key = $ ex2 [0];$ order = $ ex2 [1];$ this-> addAbstractField ($ subForm, $ key, $ order, $ data [$ fieldName]); // echo 'order:'. $ order. "и ключ". $ key. "
"; тест хорошо } } / ** * Добавляет новые поля для динамического формирования * * @param string $ name * @param string $ value * @param int $ order * @param object $ subForm * * / публичная функция addAbstractField (Zend_Form_SubForm $ subForm, $ key, $ formStep = null, $ value) { $ subForm-> addElement ('text', 'fixedField'. $ key .'_ '. $ formStep, array (' label '=>' Test label: ', 'required' => 'true', 'value' => $ value, 'description' => 'описание теста')); echo '
Добавлен элемент в подчиненную форму (метод Send from Form) key = "fixedField". $ key .'_'. $ formStep. '"and value"'. $ value. '"
'; вернуть $ this; } } ?> Форма Частичный код: <? PHP class Test_Partial { защищенный $ id; публичная функция __construct ($ id, $ amount = 1, $ fieldsKeys = array (), $ fieldsValues ​​= array ()) { $ this-> id = $ id; $ this-> amount = is_int ((int) $ amount)? сумма в долларах: 1; $ this-> fields = array (); // Позволяет объединить оба массива в один foreach ($ fieldsKeys как $ key => $ value) { $ ex = explode ('fixedField', $ value); $ ex2 = взорваться ('_', $ ex [1]); $ this-> fields [$ ex2 [0]] = $ fieldsValues ​​[$ key]; } } публичная функция get () { $ result_array = array (); $ amount_counter = 1; while ($ amount_counter <= $ this-> amount) { $ result_array [] = new Zend_Form_Element_Text ('newField'. $ keyvalue ['id'] .'_ '. ($ this-> id + $ amount_counter), массив (' label '=>' test: ', 'required' => true, 'value' => 'эти данные будут потеряны')); $ tikk = new Zend_Form_Element_Button ('removeForm'. ($ this-> id + $ amount_counter), массив ('label' => 'Remove')); $ tikk-> setAttrib ('onClick', 'ajaxRemoveForm ('. ($ this-> id + $ amount_counter). ')'); $ result_array [] = $ tikk; ++ $ amount_counter; } return $ result_array; } публичная функция __toString () { return implode ('', $ this-> get ()); } / ** * Создать медлительную строку для форм или любую другую строку, связанную с URI * * @return смешанный * @ доступ общественности * @param mixed $ array * / защищенная функция getSlug ($ string) { $ slug = trim ($ string); // обрезать строку $ slug = preg_replace ('/ [^ a-zA-Z0-9 -] /', '', $ slug); // принимаем только буквенно-цифровые символы, но сохраняем также пробелы и тире ... $ slug = str_replace ('', '-', $ slug); // заменить пробелы тире $ slug = strtolower ($ slug); // сделать его строчным вернуть $ slug; } } ?> Посмотреть: function getLastSubId () { var maxc = 0; // Удалить все элементы с определенным субидидом $ ('*'). each (function () { num = parseInt (this.id.split ("_") [1], 10); if (num> maxc) { maxc = num; } }); возврат maxc; } // Получить html нового элемента из контроллера действий function ajaxAddForm (amount) { // Diplay обработка сообщений $ ("# processing_alert"). css ("display", "block"); // Получить значение id - целое число, добавляемое к динамическим именам полей и идентификаторам var id = $ ("# step2-id"). val (); if (typeof amount == 'undefined') { var amount = $ ("# step2-addFormAmount"). val (); } var fields = ''; // Собираем все ключи и значения полей и включаем их в запрос ajax. $ ('* [id * = step2-fixedField]: visible'). each (function () {var key = $ (this) .attr ('id'); var value = $ (this) .attr ('value'); поля + = '& key [] =' + key + '& value [] =' + value; }); $ .Ajax ( { тип: "POST", url: "<? php echo $ this-> url (array ('action' => 'newAjaxForm'));?>", данные: "id =" + id + "& amount =" + amount + fields, асинхронный: ложный, success: function (newForm) { // Вставляем новый элемент перед кнопкой Добавить var counter = parseInt (id) + parseInt (amount); $ ( "# AddForm-метка") перед (NEWFORM). . $ ( "# Step2-ID") Вал (счетчик); } } ); // Отключить обработку сообщения $ ("# processing_alert"). css ("display", "none"); } function ajaxRemoveForm (id) { // Diplay обработка сообщений $ ("# processing_alert"). css ("display", "block"); // Удалить кнопку "удалить", которую мы только что нажали + метка $ ( "# RemoveForm" + ID + "- метка") удалить (). $ ( "# RemoveForm" + + идентификатор "- элемент") удалить (). // Удалить все элементы с определенным субидидом $ ('* [id * = _' + id + '-]: visible'). each (function () { $ (Это) .remove (); }); // Отключить обработку сообщения $ ("# processing_alert"). css ("display", "none"); } <? php echo $ this-> form; ?>

1 Ответ

0 голосов
/ 09 мая 2011

Я работаю над той же проблемой на Маврикии:)

Я полагаю, вы основали свои дополнительные поля, сгенерированные ajax, на уроке Джереми Кендалла:

http://www.jeremykendall.net/2009/01/19/dynamically-adding-elements-to-zend-form/

Мне потребовалось много времени, чтобы заставить это работать.

Я изменил его урок следующим образом:

В своем основном определении формы я получил функцию preValidation и addNewExperience (я работаю над CV в режиме онлайн).

public function preValidation(array $data) {

        // array_filter callback
        function findSubForms($subForms) {
            // return field names that include 'newName'
            if (strpos($subForms, 'experience') !== false) {
                return $subForms;
            }
        }

        // Search $data for dynamically added fields using findFields callback
        $newSubForms = array_filter(array_keys($data), 'findSubForms');

        foreach ($newSubForms as $subForm) {
            // strip the id number off of the field name and use it to set new order

            $order = ltrim($subForm, 'experience') + 3;
            $this->addNewExperience($subForm, $data[$subForm], $order);

        }
    }



public function addNewExperience($name, $value, $order) {

        $mysubForm = new Application_Form_Experience();
        $this->addSubForm($mysubForm, $name, $order);
    }

Итак,

либо проходит проверку формы, и в этом случае она отправляется в модель и вставляется в БД, либо проверка завершается неудачно, и форма должна отображаться с введенными значениями.

В этом случае запускается предварительное подтверждение, вновь добавленные подформы повторно отображаются с новыми добавленными значениями.

Это полностью работает для меня. И я думаю, что мне даже не нужно $ value в addNewExperience (он не используется в функции). Zend хорошо умеет находить, где значения принадлежат, когда ваш массив заполнен.

Я борюсь с форматированием формы в таблицу: / Структура немного хрупкая. Если я слегка коснусь декораторов, форма перестанет заполняться правильно.

Не совсем уверен, что происходит, и, как вы узнали, мало кто из нас занимается такими вещами в Интернете.

...