2016-01-04 3 views
0

Во-первых, наилучшие пожелания всем за этот 2016 новый год!Silex - Symfony2: Формы автозаполненные для текстовых форм, а не для выбора

У меня возникла проблема, которую я не смог решить самостоятельно.

Я работаю над применением Silex (~1.3). Я закодировал простые CRUD на моих классах домена. Я также создал некоторые формы типов, чтобы иметь возможность изменять мои базовые классы домена. В этом случае я должен управлять понятием State в Country. Каждый из них является определенным классом, а State имеет один атрибут Country.

В моей форме я объявлял некоторые текстовые поля и поле Choice, чтобы иметь возможность выбрать страну (класс формы скопирован ниже).

Моя проблема заключается в том, что, когда я пытаюсь изменить существующий State со следующим контроллером, текстовые поля name, code, unloc заполнены данными из базы данных, но не выбор country ни hub (класс контроллера скопировано ниже).

Обратите внимание, что я НЕ использую Доктрину, но самодельный (и довольно простой) DAO.

Вот мой код и некоторая информация:

  1. Вид осуществляется с помощью прутик, с «стандартной» начальной загрузки примера, который можно найти здесь: Form Customization, используя Bootstrap layout и Form layout:

    {% extends 'layout.html.twig' %} {% block title %}{{ title }}{% endblock %} 
    {% block content %} 
        {% if form and is_granted('IS_AUTHENTICATED_FULLY') and is_granted('ROLE_ADMIN')%} 
         {% form_theme form 'bootstrap_3_layout.html.twig' %} {{ form_start(form) }} 
          <div class="form-group"> 
           {{ form_errors(form) }} 
           {{ form_widget(form) }} 
           <input type="submit" class="btn btn-primary" value={% if button is not defined %} "Save"{% else %}"{{ button }}"{% endif %} /> 
          </div> 
         {{ form_end(form) }} 
        {% else %} 
         <div> 
          <p>Ask an admin to add/modify information.</p> 
         </div> 
        {% endif %} 
    {% endblock %} 
    
  2. содержание composer.json:

    { 
        "require": { 
         "silex/silex": "~1.3", 
         "doctrine/dbal": "2.5.*", 
         "symfony/security": "2.7.*", 
         "twig/twig": "1.21.*", 
         "symfony/twig-bridge": "2.7.*", 
         "symfony/form": "2.7.*", 
         "symfony/translation": "2.7.*", 
         "symfony/config": "2.7.*", 
         "jasongrimes/silex-simpleuser": "*", 
         "twig/extensions": "1.3.*", 
         "symfony/validator": "2.*", 
         "phpoffice/phpexcel": "1.*" 
        }, 
        "require-dev": { 
         "phpunit/phpunit": "*", 
         "symfony/browser-kit": "*", 
         "symfony/css-selector": "*", 
         "silex/web-profiler": "*", 
         "symfony/monolog-bridge": "*" 
        }, 
        "autoload":{ 
         "psr-4":{"Easytrip2\\": "src"} 
        } 
    } 
    
  3. Код формы:

    содержание
    <?php 
    
    namespace Easytrip2\Form\Type; 
    
    use Easytrip2\DAO\CountryDAO; 
    use Easytrip2\DAO\GeopointDAO; 
    use Symfony\Component\Form\AbstractType; 
    use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList; 
    use Symfony\Component\Form\FormBuilderInterface; 
    use Symfony\Component\OptionsResolver\OptionsResolver; 
    
    class StateType extends AbstractType { 
        /** 
        * @CountryDAO 
        * \Easytrip2\DAO\CountryDAO 
        * allow to find the Country for the form. 
        */ 
        private $countryDAO; 
        /** 
        * @GeopointDAO 
        * \Easytrip2\DAO\GeopointDAO 
        * allow to find the Country for the form. 
        */ 
        private $geopointDAO; 
        /** 
        * 
        * {@inheritDoc} 
        * 
        * @see \Symfony\Component\Form\AbstractType::buildForm() 
        */ 
        public function buildForm(FormBuilderInterface $builder, array  $options) { 
         $builder->add ('name', 'text', array (
           'label' => 'State name' 
         )); 
         $builder->add ('code', 'text', array (
           'label' => 'State code' 
         )); 
         $builder->add ('unloc', 'text', array (
           'label' => 'State code' 
         )); 
         $countries = $this->countryDAO->findAll(); 
         $choices = array(); 
         $labels = array(); 
         foreach ($countries as $value) { 
          $choices [] = $value; 
          $labels [] = $value->getName(); 
         } 
         $builder->add ('country', 'choice', array (
           'choice_list' => new ChoiceList ($choices, $labels) 
         )); 
    
         $hubs = $this->geopointDAO->findAllHubs(); 
         $choices = array(); 
         $labels = array(); 
         foreach ($hubs as $value) { 
          $choices [] = $value; 
          $labels [] = $value->getName(); 
         } 
         $builder->add ('hub', 'choice', array (
           'choice_list' => new ChoiceList ($choices, $labels), 
           'required' => false 
         )); 
        } 
    
        /** 
        * 
        * {@inheritDoc} 
        * 
        * @see \Symfony\Component\Form\AbstractType::configureOptions() 
        */ 
        public function configureOptions(OptionsResolver $resolver) { 
         $resolver->setDefaults (array (
           'data_class' => 'Easytrip2\Domain\State' 
         )); 
        } 
    
        /** 
        * 
        * {@inheritDoc} 
        * 
        * @see \Symfony\Component\Form\FormTypeInterface::getName() 
        */ 
        public function getName() { 
         return 'state'; 
        } 
        /** 
        * allow use of a CountryDAO 
        */ 
        public function __construct(CountryDAO $countryDAO, GeopointDAO  $geopointDAO) { 
         $this->geopointDAO = $geopointDAO; 
         $this->countryDAO = $countryDAO; 
        } 
    } 
    
  4. Контроллер:

    public function stateUpdateByIdAction($id, Request $request, Application $app) { 
         if ($app ['security.authorization_checker']->isGranted ('IS_AUTHENTICATED_FULLY') and $app ['security.authorization_checker']->isGranted ('ROLE_ADMIN')) { 
          $obj = $app ['dao.state']->findById ($id); 
          $form = $app ['form.factory']->create (new StateType ($app ['dao.country'], $app ['dao.geopoint']), $obj); 
          $form->handleRequest ($request); 
          if ($form->isSubmitted() && $form->isValid()) { 
           if ($app ['dao.state']->save ($obj)) { 
            $app ['session']->getFlashBag()->add ('success', 'The state was succesfully updated.'); 
            return $app->redirect ($app ['url_generator']->generate ('state')); 
           } else { 
            $app ['session']->getFlashBag()->add ('error', 'Something went wrong...'); 
           } 
          } 
          return $app ['twig']->render ('form.html.twig', array (
            'form' => $form->createView(), 
            'title' => 'Edit states' 
          )); 
         } else { 
          $app ['session']->getFlashBag()->add ('error', 'Don\'t have the rights...'); 
          return $app->redirect ($app ['url_generator']->generate ('home')); 
         } 
        } 
    
+0

Я видел этот пост, но проблема немного отличается (это работает для меня для текстовых полей, а не для списков выбора, поскольку он вообще не работает в сообщении) https://stackoverflow.com/questions/20500115/symfony2-form-pre-fill-fields-with-data. Я все равно пытался, но проблема все еще существует. –

ответ

0

Мне удалось найти решение (возможно, не лучшее, но оно работает).

Я понимаю это так: мы даем объект как choices, использовать его в качестве значения, а затем использовать замыкание, чтобы получить ids и labels, вместо того, чтобы делать работу сами и давать «готовые к употреблению» данных к форма.

Есть ли более чистый способ сделать это?

$obj = $this->countryDAO->findAll(); 
$list = array(); 
foreach ($obj as $value) { 
    $list [$value->getId()] = $value; 
} 
$builder->add ('country', 'choice', array (
    'choices' => $list, 
    'choices_as_values' => true, 
    'choice_label' => function ($value) { 
     return $value->getName(); 
    }, 
    'choice_value' => function ($value) { 
    // you mightwant to check for null here, is your form concern 
    // a attribute that can be null, as the closure appear to be called 
    // on the attribute, and not only on the $obj contents; 
     return $value->getId(); 
    }, 
    'placeholder' => 'Select a country' 
)); 
0

Предположим, что выбор не заполнены данными из БД, так как страна и ступица идентификатор не передается список выбора

$choices = array(); 
foreach ($countries as $value) { 
    $choices[$value->getId()] = $value->getName(); 
} 
$builder->add('country', 'choice', array(
    'choices' => $choices 
)); 
+0

Хорошая идея! Я использую фабрику форм, хотя и получаю объект, который я создаю. Форма не получает объект напрямую. Вы знаете, как я могу передать связанные объекты на более низкие уровни моей формы? Я неправильно использую формы здесь? Спасибо ! –

+0

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

+0

Ах, ты прав, я не заметил изменений. Я просто попробовал, и теперь я понимаю, что Silex говорит мне, что «Выбор опции» не существует »и скажите мне, что это должен быть один из очень длинного списка, содержащий' 'choice_attr", "choice_label", " select_list "," choice_loader "," choice_name "," choice_translation_domain "," choice_value "," choice "," choice_as_values ​​"'. Если я изменю его, чтобы соответствовать 'choice', я получаю еще одну ошибку, которая говорит мне, что silex не смог загрузить тип' choice'. –

0

Добавьте эту строку в параметры выбора: 'choices_as_values' => true,

Это необходимо для активации нового типа выбора API http://symfony.com/doc/current/reference/forms/types/choice.html#example-usage

+0

Здравствуйте, я пробовал это раньше, и он работает (отображается правильно), но не заполняет данные объекта в форма в том случае, когда атрибут является объектом. Я предполагаю, что есть объект сравнения, который имеет место, когда нет замыкания, и это по какой-то причине не работает. –

Смежные вопросы