Я пытаюсь сгенерировать тип формы, в частности «ProductLanguageType».
Я хочу сгенерировать ProductLanguageType столько раз, сколько текущих чисел существующих языков в таблице Language.
Например, если у меня есть (английский, французский, русский, китайский) в таблице «Язык», на той же странице будет сгенерирована форма 4 ProductLanguageType.
Я хотел бы знать, как запросить таблицу языков и создать несколько форм одного типа на одной и той же странице, способен ли это сделать конструктор форм или есть другой обходной путь? В течение некоторого времени у нас были некоторые проблемы с этим, и мы были бы рады найти хорошее решение для этого.
ProductLanguageType:
class ProductLanguageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options){
$builder->add('id_language', 'entity', array(
'class' => 'AdminBundle:Language',
'data_class' => 'Main\AdminBundle\Entity\Language',
'property' => 'language'
)
)
->add('name', 'text')
->add('description', 'ckeditor', array(
'config_name' => 'admin',
'config' => array(
'filebrowser_image_browse_url' => array(
'route' => 'elfinder',
'route_parameters' => array('instance' => 'default'),
),
)
))
->add('short_description', 'text');
}
public function getName(){
return 'productLanguage';
}
}
ProductType (здесь указывается ProductLanguageType):
class ProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options){
$builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'));
$builder->add('productLanguage', new ProductLanguageType())
->add('id_seller','text')
->add('price','text')
->add('cost_price','text')
->add('retail_price','text')
->add('hot', 'checkbox')
->add('featured', 'checkbox')
->add('new', 'checkbox')
->add('free_shipping', 'checkbox')
->add('status','text') //active or inactive, to be decided if hidden or visible
->add('Add', 'submit');
}
}
Надеюсь, это кому-нибудь поможет.
Надлежащим способом будет использование службы form.factory Symfony для создания именованного компоновщика и, в свою очередь, создания формы из этого. Я рекомендую создать функцию для процесса создания формы, так как (как я понимаю, исправьте меня, если я ошибаюсь) каждый экземпляр FormBuilder должен отличаться для создания другой формы.
Так же, как объяснение цели кода:
Мне нужно было показать список открытых заявок в справочной системе с возможностью назначения человека (авторизованного без входа в систему) на основе его токена для входа в заявку. Для этого необходимо отобразить N форм на одной странице, которые будут уникальными, но сгенерированы из одного «шаблона» или Type, если хотите.
Этот код достиг этого без каких-либо взломов. Просто не существует сокращенного метода createForm с определенным идентификатором (именем) из контроллера AFAIK.
ех.
public function generateFormForTicketAssignment(Ticket $ticket) {
$ticketAssignType = new TicketAssignInvokeType();
$ticketAssignType->setNameSuffix($ticket->getId());
/**
* @var Symfony\Component\Form\FormBuilderInterface
*/
$builder = $this->get('form.factory')->createNamedBuilder($ticketAssignType->getName(), $ticketAssignType );
$builder->setAutoinitialize(true);
$formTicket = $builder->getForm();
$formTicket->get('ticket')->setData($ticket);return $formTicket;
}
И (это важная часть) ticketAssignInvokeType выглядит следующим образом:
class TicketAssignInvokeType extends AbstractType {
private $nameSuffix = null;
private $name = 'ticket_assign_invoke';
public function __constructor(string $suffix = null) {
//parent::__construct();
$this->nameSuffix = $this->generateNameSuffix();
}
private function generateNameSuffix() {
if ($this->nameSuffix == null || $this->nameSuffix == '') {
$generator = new SecureRandom();
//change data to alphanumeric string
return bin2hex($generator->nextBytes(10));
}
return $this->nameSuffix;
}
/**
*
* @param string $suffix When set suffix added to form will use selected
* string (note it should be unique for all forms on a page).
*/
public function setNameSuffix($suffix){
$this->nameSuffix = $suffix;
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('loginToken',new AuthenticateTokenType())
->add('ticket',new TicketIDType())
->add('save', 'submit', array('label' => 'form.button.assign'))
;
}
public function getName() {
if ($this->nameSuffix == null || $this->nameSuffix == "" ) {
$this->nameSuffix = $this->generateNameSuffix();
}
return $this->name .'_'. $this->nameSuffix;
}
public function configureOptions(OptionsResolver $resolver) {
// ...
}
}
Это несколько чрезмерно сложная логика и проверка суффикса имени, но в какой-то момент я не мог понять, почему все, что мне нужно — это имя формы без суффикса, отсюда и сложность.
PS. Я создал формы как сервисы и позже проверим, можно ли использовать сервис, а это было моим первым намерением.
PS2. Я не уверен насчет setAutoinitialize
метода пока нет, но проверим и его.
Теперь в Symfony 3.0 они изменили createNamedBuilder, так что это можно решить, только вызвав:
use AppBundle\Form\ShippingTrackCodeReturnType;
$uniqueForm = $this->get('form.factory')->createNamedBuilder('ship_form_'.$orderRecord->getId(), ShippingTrackCodeReturnType::class, $orderRecord)->getForm();
Итак, вам просто нужно выполнить цикл для отображения и сохранения их:
foreach ($invoice->getOrderRecords() as $key => $orderRecord)
{
// creates the forms with different names
$returnShipTrackCodeForm = $this->get('form.factory')->createNamedBuilder('ship_form_'.$orderRecord->getId(), ShippingTrackCodeReturnType::class, $orderRecord)->getForm();
$returnShipTrackCodeForm->handleRequest($request);
if ($returnShipTrackCodeForm->isSubmitted() && $returnShipTrackCodeForm->isValid())
{
// flush object
}
$returnForms[$orderRecord->getId()] = $returnShipTrackCodeForm;
}