Не удается получить дополнительные поля формы при отправке формы

Мой автоматически сгенерированный базовый класс формы выглядит следующим образом:

abstract class BaseGestorForm extends BaseFormDoctrine {
    public function setup() {
        $this->setWidgets(array(
            'persona_fk' => new sfWidgetFormInputHidden(),
            'unitat_fk'  => new sfWidgetFormInputHidden(),
            'baixa'      => new sfWidgetFormDateTime(),
        ));
        $this->setValidators(array(
            'persona_fk' => new sfValidatorChoice(array('choices' => array($this->getObject()->get('persona_fk')), 'empty_value' => $this->getObject()->get('persona_fk'), 'required' => false)),
            'unitat_fk'  => new sfValidatorChoice(array('choices' => array($this->getObject()->get('unitat_fk')), 'empty_value' => $this->getObject()->get('unitat_fk'), 'required' => false)),
            'baixa'      => new sfValidatorDateTime(array('required' => false)),
            ));  
        $this->widgetSchema->setNameFormat('gestor[%s]');
        $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);   
        $this->setupInheritance();
        parent::setup();
    }

    public function getModelName() {
        return 'Gestor';
    }
}    

В форму я добавил два дополнительных поля (totes_unitats и unitats_a_gestionar). Первое поле представляет собой раскрывающийся список, в котором пользователи выбирают один или несколько вариантов, и с помощью jquery, когда пользователь нажимает кнопку, выбранные параметры добавляются в раскрывающийся список unitats_a_gestionar. При этом эти опции удаляются из списка totes_unitats.

class GestorForm extends BaseGestorForm {   
    public function configure() {
        unset($this['baixa']);

        $this->widgetSchema['persona_fk'] = new sfWidgetFormChoice(array(
            'choices' => UsuariLdap::getAllUsuaris()
        ));

        $this->widgetSchema['totes_unitats'] = new sfWidgetFormChoice(array(
            'choices' => UnitatTable::findAllUnitatsPerOrdreArray(),
            'multiple' => true
        ));

        $this->widgetSchema['unitats_a_gestionar'] = new sfWidgetFormChoice(array(
            'choices' => array(),
            'multiple' => true
        ));

        $this->widgetSchema->setLabels(array(
            'persona_fk' => 'Gestor',
            'unitat_fk' => 'Unitat',
            'totes_unitats' => 'Totes les unitats',
            'unitats_a_gestionar' => 'Unitats a gestionar'
        ));

        $this->validatorSchema->setOption('allow_extra_fields', true);

        $this->validatorSchema['persona_fk'] = new sfValidatorString(array('required' => true), array('required' => 'Requerit'));
    }   
}    

Где я нахожу проблему, так это в файле действий. Прежде всего, я вызываю метод executeNouGestor, который отрисовывает форму. Затем, когда пользователь нажимает кнопку «Продолжить» и создает объект Gestor, он вызывает executeValidaGestor, который проверяет форму. Этот последний метод вызывает processFormGestor, где нет возможности получить дополнительное поле unitats_a_gestionar.

public function executeNouGestor(sfWebRequest $request) {
    $this->gestorForm = new GestorForm();
}

public function executeValidaGestor(sfWebRequest $request) {
    $this->forward404Unless($request->isMethod(sfRequest::POST));
    $this->gestorForm = new GestorForm();   
    $this->processFormGestor($request, $this->gestorForm);
    $this->setTemplate('nouGestor');
}

protected function processFormGestor(sfWebRequest $request, sfForm $gestorForm) {
    $gestorForm->bind($request->getParameter($gestorForm->getName()), $request->getFiles($gestorForm->getName()));
    if ($gestorForm->isValid()) { 
        var_dump($_POST);
        var_dump($request->getParameterHolder()->getAll());
        ...
    }
}

Эти два var_dump показывают мне следующую информацию:

var_dump($_POST):

array(2) {
  ["gestor"]=>
  array(2) {
    ["persona_fk"]=>
    string(3) "330"
    ["_csrf_token"]=>
    string(32) "91e18aa0570bfc7558d21ebb4b98f512"
  }
  ["Desar"]=>
  string(5) "Desar"
}

var_dump($request->getParameterHolder()->getAll()):

array(4) {
  ["gestor"]=>
  array(2) {
    ["persona_fk"]=>
    string(3) "330"
    ["_csrf_token"]=>
    string(32) "91e18aa0570bfc7558d21ebb4b98f512"
  }
  ["Desar"]=>
  string(5) "Desar"
  ["module"]=>
  string(13) "administracio"
  ["action"]=>
  string(12) "validaGestor"
}

Итак, как видите, в ["gestor"] нет трека ни totes_unitats, ни unitats_a_gestionar дополнительных полей формы. Понятия не имею почему. Я показываю поля формы в шаблоне как обычно:

<?php echo $gestorForm['persona_fk']->renderLabel(); ?>
<div class="input"><?php echo $gestorForm['persona_fk']->render(); ?></div>
<div class="error-input"><?php echo $gestorForm['persona_fk']->renderError(); ?></div>

<?php echo $gestorForm['totes_unitats']->renderLabel(); ?>
<div class="input multiple"><?php echo $gestorForm['totes_unitats']->render(); ?></div>
<div class="error-input"><?php echo $gestorForm['totes_unitats']->renderError(); ?></div>

<?php echo $gestorForm['unitats_a_gestionar']->renderLabel(); ?>
<div class="input multiple"><?php echo $gestorForm['unitats_a_gestionar']->render(); ?></div>
<div class="error-input"><?php echo $gestorForm['unitats_a_gestionar']->renderError(); ?></div>

Я также добавляю код jquery, который управляет добавленными или удаленными параметрами между двумя раскрывающимися списками с множественным выбором:

function afegirTreureUnitats() {
  var boto_afegir = $("#btn-multiple-afegir");
  var boto_treure = $("#btn-multiple-treure");
  boto_afegir.click(function() {
    var selectedItems = $("#gestor_totes_unitats option:selected");
    var output = [];
    $.each(selectedItems, function(key, e)
    {
      output.push('<option value="' + e.value + '">' + e.text + '</option>');

    });
    $("#gestor_unitats_a_gestionar").append(output.join(""));
    ordenaOptionsSelect("gestor_unitats_a_gestionar");
    selectedItems.remove();
  });  
  boto_treure.click(function() {
    var selectedItems = $("#gestor_unitats_a_gestionar option:selected");
    var output = [];
    $.each(selectedItems, function(key, e)
    {
      output.push('<option value="' + e.value + '">' + e.text + '</option>');
    });
    $("#gestor_totes_unitats").append(output.join(""));
    ordenaOptionsSelect("gestor_totes_unitats");
    selectedItems.remove();
  });
}

function ordenaOptionsSelect(idSelect)
{
  var options = $('#' + idSelect + ' option');
  options.sort(function(a, b)
  {
    if (a.text > b.text)
      return 1;
    else if (a.text < b.text)
      return -1;
    else
      return 0;
  });
  $('#' + idSelect).empty().append(options);
}

$(document).ready(function() {
  afegirTreureUnitats();
});

Отображаемая форма имеет следующий вид:

https://drive.google.com/file/d/0B0Mz720p9Q_DN1RnYWIyR0pXOTQ/edit?usp=sharing

Я также обнаружил любопытный факт. Если я выбираю один из вариантов в раскрывающемся списке, либо totes_unitats, либо unitats_a_gestionar, они отправляются методом POST, но только один (если я выбираю более одного, я могу получить только один из выбранных вариантов).


person dsolemorera    schedule 12.06.2014    source источник
comment
Можете ли вы вставить обработанный HTML-код, используемый для отображения списков?   -  person Michal Trojanowski    schedule 12.06.2014
comment
Вы имеете в виду интерфейс, не так ли? Сделанный.   -  person dsolemorera    schedule 13.06.2014


Ответы (1)


Когда вы используете <select> элементы в форме или <input> типа radio или checkbox, браузер будет отправлять их значения при отправке формы, только если в полях выбраны какие-либо параметры.

Список опций в теге <select> не отправляется обратно на сервер. Только значения опций, которые фактически выбраны.

Вы можете решить свою проблему двумя способами:

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

  2. Другой вариант — добавить два скрытых поля, в которых будут храниться списки параметров, и изменять эти списки вместе с полями <select>.

person Michal Trojanowski    schedule 13.06.2014