symfony: разве мы не можем иметь скрытое поле сущности?
Я рендеринг формы с полем сущности в symfony.
Он хорошо работает, когда я выбираю регулярное поле сущности.
$builder
->add('parent','entity',array(
'class' => 'AppBundle:FoodAnalyticsRecipe',
'attr' => array(
'class' => 'hidden'
)
))
он выдает следующую ошибку, когда я выбираю - >add ('parent', 'hidden'):
ожидается, что данные представления формы будут скалярного типа, массива или экземпляр ArrayAccess, но является экземпляром класса AppBundleEntityFoodAnalyticsРецепт. Вы можете избежать этой ошибки установка параметра "data_class для формы" для "AppBundleEntityFoodAnalyticsRecipe" или путем добавления представления трансформатор, преобразующий экземпляр класса AppBundleEntityFoodAnalyticsRecipe для скаляра, массива или экземпляра из интерфейса ArrayAccess. 500 Внутренняя Ошибка Сервера-LogicException
мы не можем иметь скрытые поля ?? Почему бы и нет? Обязан ли я поместить другое скрытое поле для получения идентификатора сущности?
изменить :
в основном, то, что я пытаюсь сделать, это увлажнить форму до отображение его, но запретить пользователю изменять одно из его полей (родитель здесь). Это потому, что мне нужно передать идентификатор в качестве параметра, и я не могу сделать это в виде URL-адреса действия.
4 ответов
только что сделал это на Symfony 3 и понял, что это немного отличается от того, что уже опубликовано здесь, так что я решил, что стоит поделиться.
Я только что сделал общий преобразователь данных, который может быть легко повторно использован во всех ваших типах форм. Вы просто должны пройти в своем типе, виде и все. Нет необходимости создавать пользовательский тип формы.
прежде всего, давайте взглянем на трансформаторе данные:
<?php
namespace AppBundle\Form;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
/**
* Class EntityHiddenTransformer
*
* @package AppBundle\Form
* @author Francesco Casula <fra.casula@gmail.com>
*/
class EntityHiddenTransformer implements DataTransformerInterface
{
/**
* @var ObjectManager
*/
private $objectManager;
/**
* @var string
*/
private $className;
/**
* @var string
*/
private $primaryKey;
/**
* EntityHiddenType constructor.
*
* @param ObjectManager $objectManager
* @param string $className
* @param string $primaryKey
*/
public function __construct(ObjectManager $objectManager, $className, $primaryKey)
{
$this->objectManager = $objectManager;
$this->className = $className;
$this->primaryKey = $primaryKey;
}
/**
* @return ObjectManager
*/
public function getObjectManager()
{
return $this->objectManager;
}
/**
* @return string
*/
public function getClassName()
{
return $this->className;
}
/**
* @return string
*/
public function getPrimaryKey()
{
return $this->primaryKey;
}
/**
* Transforms an object (entity) to a string (number).
*
* @param object|null $entity
*
* @return string
*/
public function transform($entity)
{
if (null === $entity) {
return '';
}
$method = 'get' . ucfirst($this->getPrimaryKey());
// Probably worth throwing an exception if the method doesn't exist
// Note: you can always use reflection to get the PK even though there's no public getter for it
return $entity->$method();
}
/**
* Transforms a string (number) to an object (entity).
*
* @param string $identifier
*
* @return object|null
* @throws TransformationFailedException if object (entity) is not found.
*/
public function reverseTransform($identifier)
{
if (!$identifier) {
return null;
}
$entity = $this->getObjectManager()
->getRepository($this->getClassName())
->find($identifier);
if (null === $entity) {
// causes a validation error
// this message is not shown to the user
// see the invalid_message option
throw new TransformationFailedException(sprintf(
'An entity with ID "%s" does not exist!',
$identifier
));
}
return $entity;
}
}
Итак, идея в том, что вы звоните это путем передачи диспетчера объектов, сущности, которую вы хотите использовать, а затем имени поля для получения идентификатора сущности.
в основном так:
new EntityHiddenTransformer(
$this->getObjectManager(),
Article::class, // in your case this would be FoodAnalytics\Recipe::class
'articleId' // I guess this for you would be recipeId?
)
Давайте теперь все вместе. Нам просто нужен тип формы и немного конфигурации YAML, а затем мы хорошо идем.
<?php
namespace AppBundle\Form;
use AppBundle\Entity\Article;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Class JustAFormType
*
* @package AppBundle\CmsBundle\Form
* @author Francesco Casula <fra.casula@gmail.com>
*/
class JustAFormType extends AbstractType
{
/**
* @var ObjectManager
*/
private $objectManager;
/**
* JustAFormType constructor.
*
* @param ObjectManager $objectManager
*/
public function __construct(ObjectManager $objectManager)
{
$this->objectManager = $objectManager;
}
/**
* @return ObjectManager
*/
public function getObjectManager()
{
return $this->objectManager;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('article', HiddenType::class)
->add('save', SubmitType::class);
$builder
->get('article')
->addModelTransformer(new EntityHiddenTransformer(
$this->getObjectManager(),
Article::class,
'articleId'
));
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\MyEntity',
]);
}
}
и затем в :
app.form.type.article:
class: AppBundle\Form\JustAFormType
arguments: ["@doctrine.orm.entity_manager"]
tags:
- { name: form.type }
и в вашем контроллере:
$form = $this->createForm(JustAFormType::class, new MyEntity());
$form->handleRequest($request);
вот именно :-)
быстрое решение whitout создание новых классов трансформатора и типа. Если вы хотите предварительно заполнить Связанный объект из БД.
// Hidden selected single group
$builder->add('idGroup', 'entity', array(
'label' => false,
'class' => 'MyVendorCoreBundle:Group',
'query_builder' => function (EntityRepository $er) {
$qb = $er->createQueryBuilder('c');
return $qb->where($qb->expr()->eq('c.groupid', $this->groupId()));
},
'attr' => array(
'class' => 'hidden'
)
));
это приводит к одному скрытому выбору, как:
<select id="mytool_idGroup" name="mytool[idGroup]" class="hidden">
<option value="1">MyGroup</option>
</select>
Но да, я согласен, что с немного большим усилием, используя DataTransformer
вы можете достичь что-то вроде:
<input type="hidden" value="1" id="mytool_idGroup" name="mytool[idGroup]"/>
этого можно достигнуть справедливо чисто с theming формы, используя стандарт hidden
тема поля вместо этого для сущности. Я думаю, что использование трансформаторов, вероятно, излишне, учитывая, что скрытые и выбранные поля дадут тот же формат.
{% block _recipe_parent_widget %}
{%- set type = 'hidden' -%}
{{ block('form_widget_simple') }}
{% endblock %}