2015-05-10 7 views
0

Я в ситуации, когда хочу иметь возможность динамически устанавливать опцию required=true/false или поле формы array(...other stuff..., 'class' => ' hidden').Symfony2 динамически назначает attr в поле формы

Контекст следующий: существует сущность «Проект» с некоторыми полями. Когда я создаю другие объекты с формами, я хочу проверить некоторые атрибуты объекта Project и принять решения о видимости/необходимости определенных полей создаваемого объекта.

Например, если проект имеет атрибут «timePressure = high», тогда поле данной сущности не требуется (но является видимым). Если есть другие условия, он становится невидимым и т. Д.

Так что в основном я надеялся вызвать функцию внутри каждого конструктора форм, чтобы выплюнуть соответствующие части (например, эта функция вернет строку с обязательным = true "или другой, относящийся к скрытому классу). Дело в том, что функция должна принимать в качестве аргументов: projectID (ok, это может быть передано как параметры конструктора форм), класс и поле, о котором мы говорим, чтобы решить. Я предполагая что-то вроде:

->add('background', 'textarea', array('attr' => array('rows' => 4, functionToDecideIfInvisible($projectId)), functionToDecideRequiredness($projectId))) 

Обе функции возвратит строку 'class' => ' hidden' и required=true (или ложные)

Я хотел бы, чтобы избегать того, чтобы указать имя поля (в данном случае background) чтобы избежать повторения кода.

Можно ли это сделать?

Другие предложения о том, как решить эту проблему?

Спасибо!

SN

ответ

2

Что вам нужно, Форма События: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-underlying-data

Они позволяют изменять свою форму на основе ваших данных.

Вы создаете проецирование формы в контроллере:

$form = $this->createForm(new ProjectType(), $project, array(
    'action' => $this->generateUrl('project.edit'), 
    'method' => 'POST', 
)); 

Затем добавьте FormEvents :: PRE_SET_DATA слушатель:

public function buildForm(FormBuilderInterface $builder, array $options) 
{ 
    $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { 
     $project = $event->getData(); 
     $form = $event->getForm(); 

     // check timePressure on the Project object 
     if ('high' === $project->timePressure) { 
      $form->add('timePressure', 'text', array(
       'required' => false 
      ); 
     } 
    }); 
} 
+0

Это интересная особенность, которую я не знаю ... но я мог бы достичь того же без слушателя событий, если я хочу, чтобы вставить логика там. Я мог бы просто проверить поле проекта и добавить поле так или иначе. Но то, что я искал, - это способ запросить БД, где у меня есть список всех возможных полей и всех полей проекта. Я бы хотел вызвать функцию внутри «add», и функция: 1) получить форму поля, которую она вызвала, 2) проверить DB, вернуть желаемый атрибут/класс. Возможно ли это? –

+2

@ Серхионегри, я думаю, что ваш подход неправильный. Вы не можете вызвать свою функцию внутри «добавить». Вместо этого вы должны вызывать функцию «добавить» внутри прослушивателя событий с разными атрибутами/классами. – SpartakusMd

+0

Ок, спасибо, жаль, что этого не может быть сделано :(! –

-1

Я нашел способ сделать это.

Моя надстройка будет, как:

->add('background', 'textarea', array_merge($this->vr->fieldReq(get_class($this), 
'background', $projectID), array('attr' => array_merge(array('rows' => 4,), 
$this->vr->fieldCssClass(get_class($this), 'background', $projectID))))) 

Для этого я должен был определить форму как сервис, плюс я создал еще один класс в качестве сервиса (тот, который содержит два метода, которые мне нужно).

Это класс:

class FieldReqAndCssClass 
{ 
public function fieldReq($parentEntity, $field, $projectID) 
    { 
    $required = array(); 
    $required['required'] = false; //do stuff on the database instead of setting it to false hardcoded 
    return $required; 
    } 

public function fieldCssClass($parentEntity, $field, $projectID) 
    { 
    $cssClass= array(); 
    //do stuff on the database instead of setting the class as hidden hardcoded 
    //$cssClass['class'] = ' hidden'; 
    $cssClass['class'] = ''; 
    return $cssClass; 
    } 
} 

Конечно, в моей форме я должен был:

public function __construct(\AppBundle\Util\FieldReqAndCssClass $fieldReqAndCssClass) 
{ 
$this->vr = $fieldReqAndCssClass; // vr stands for visibility and requiredness 
} 

И эти две услуги:

app_bundle.field_req_and_css_class: 
    class: AppBundle\Util\FieldReqAndCssClass 
    arguments: [] 

app_bundle.form.type.projectdetail: 
    class: AppBundle\Form\Type\ProjectDetailFormType 
    arguments: [@app_bundle.field_req_and_css_class] 
    tags: 
     - { name: form.type, alias: ProjectDetail } 

Конечно здесь первой услуге мне нужно будет добавить диспетчер сущностей и добавить его в конструкцию и, возможно, также в службу формы, но Основной скелет работает :)

Я счастливый человек :)

EDIT Единственная проблема вышеперечисленное является то, что он делает скрытый виджет, но не ярлык. Чтобы это исправить:

->add('background', 'textarea', array_merge($vr->fieldReq($myClass, 
'background', $project), array('label_attr' => $vr->fieldCssClass($myClass, 
'background', $project),'attr' => array_merge(array('rows' => 4,), 
$vr->fieldCssClass($myClass, 'background', $project))))) 

Очевидно, прежде чем я должен заявить:

$myClass = get_class($this); 
$vr = $this->vr; 
Смежные вопросы