gpt4 book ai didi

php - Symfony2 以 symfony 形式获取未映射的字段值

转载 作者:行者123 更新时间:2023-11-30 22:37:10 25 4
gpt4 key购买 nike

从事 symfony2 房地产项目,我需要弄清楚如何将提交的数据从动态创建的表单存储在数据库中。

这是我到目前为止所做的工作,我有一个带有一组预定义字段的房地产属性 addListings 表单,为此我从 options< 嵌入了一组附加字段 在里面。这些“附加字段”由管理员动态决定,他可以添加 x 个字段,并且可以在下拉列表、复选框或文本类型之间进行选择。

这是选项和类别表单类型,一切都很好,不用担心,只需将常规表单值提交给数据库

/**
* Inside OptionsType.php
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('value')
->add('submit', 'submit', ['label'=>'Create Option'])
;
}

/**
* Inside CategoriesType.php
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('required')
->add('isMultiple')
->add('isText')
->add('submit', 'submit',['label'=>'Create Category'])
;
}

这里是表示附加字段的实体 PropertyCategory.php 它有 getter 和 setter,不用担心这里

<?php
namespace path\to\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Table(name="property_category")
* @ORM\Entity
*/
class PropertyCategory {

/**
* @var type integer
*
* @ORM\ID
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**
* @ORM\ManyToOne(targetEntity="University", inversedBy="propertyCategory")
*/
protected $university;

/**
* @ORM\ManyToOne(targetEntity="Property", inversedBy="propertyCategory")
*/
protected $property;

/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="propertyCategory")
*/
protected $category;

/**
* @ORM\OneToOne(targetEntity="Options", inversedBy="propertyCategory")
*/
protected $options;

现在是真正的东西,在 PropertyCategoryType 中,Options 对象作为数组传递给此表单,数组的键成为标签,值成为表单字段的选项,忽略大部分内容并看看这一行

$builder->add($value->getCategory()->getName(), $type, $options);

这将创建一个 mapped=>false 字段。现在,如果您查看下面的 Controller AdditionalDetailsController,我有一个名为 propertyCategoryFormAction 的操作,这是我将用户选择的数据插入数据库的地方

所以问题是我如何动态获取未映射的字段名称,如 $form['fieldName']->getData() 以便我可以使用它来查询数据库并获取options_id 并将其保存到 propertyCategory 表中

namespace path\to\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class PropertyCategoryType extends AbstractType {

public function __construct($options) {
$this->options = $options;
}

/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) {

foreach ($this->options as $key => $value) {
if($value->getCategory()->getIsMultiple()){
$checkbox[$value->getCategory()->getName()][] = $value->getValue();
$type = 'choice';
$options = array('choices'=>$checkbox[$value->getCategory()->getName()],'multiple'=>true, "mapped"=>false, 'expanded' => true, 'required'=>$value->getCategory()->getRequired());


}elseif($value->getCategory()->getIsText()){
$type = 'text';
$options = array( "mapped"=>false, 'required'=>$value->getCategory()->getRequired());


}elseif($value->getCategory()->getIsText() == false && $value->getCategory()->getIsMultiple() == false){
$ddl[$value->getCategory()->getName()][] = $value->getValue();
$type = 'choice';
$options = array('choices'=>$ddl[$value->getCategory()->getName()],'multiple'=>false, "mapped"=>false, 'required'=>$value->getCategory()->getRequired());

}

$builder
->add($value->getCategory()->getName(), $type, $options);
}
$builder
->add('submit', 'submit', array('label'=>'submit', 'attr'=>array('class'=>'btn btn-danger')));
}


/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => path\to\PropertyCategory'
));
}


/**
* @return string
*/
public function getName()
{
return 'eduflats_bundle_eduflatsbundle_propertycategory';
}
}

这里是 Controller AdditionalDetailsController.php

class AdditionalDetailsController extends Controller
{
/**
* @Route("/AddCategory", name="addCategory")
* @Template()
*/
public function addCategoryAction(Request $request) {

$em = $this->getDoctrine()->getEntityManager();
$category = new Category();
$form = $this->createForm(new CategoryType(), $category);
$form->handleRequest($request);

if($form->isValid()){
$em->persist($category);
$em->flush();

return $this->redirect($this->generateUrl('addOption', array('id'=>$category->getId())));
}
return array('form'=>$form->createView());
}

/**
* @Route("/AddOption/{id}", name="addOption")
* @Template()
*/
public function addOptionAction(Request $request, $id){

$em = $this->getDoctrine()->getEntityManager();
$options = new Options();
$form = $this->createForm(new OptionsType(), $options);
$form->handleRequest($request);

if($form->isValid()){
$category = $this->getDoctrine()->getRepository('EduflatsBundle:Category')->findOneById($id);
$university = $this->getDoctrine()->getRepository('EduflatsBundle:University')->findOneById(siteConfig::$university_id);
$options->setCategory($category);
$options->setUniversity($university);
$em->persist($options);
$em->flush();

$this->get('session')->getFlashBag()->set('success', 'Your options have been saved Successfully');
return $this->redirect($this->generateUrl('addOption',array('id'=>$id)));
}
return array('form'=>$form->createView());

}

/**
* @Route("/form", name="form")
* @Template()
*/
public function propertyCategoryFormAction(Request $request) {

$options = $this->getDoctrine()->getRepository('EduflatsBundle:Options')->findAll();

$em = $this->getDoctrine()->getEntityManager();
$propertyCategory = new PropertyCategory();
$form = $this->createForm(new PropertyCategoryType($options), $propertyCategory);
$form->handleRequest($request);

if($form->isValid()){
$property = $this->getDoctrine()->getRepository('EduflatsBundle:Property')->findOneById(1);
$propertyCategory = new PropertyCategory();

$propertyCategory->setProperty($property);
$propertyCategory->setOptions();

$em->persist($propertyCategory);
$em->flush();
}
return array('form'=>$form->createView());
}
}

我希望我说得足够清楚,我可以在评论中澄清一些内容。

最佳答案

这是我的想法。我实际上有一份工作想做类似的事情,但我们当时最终放弃了它,因为这是一件很难管理的事情。但这就是我的计划。

从一个主实体开始

class Listing
{
protected $name;
protected $price;

//Your custom options (One-to-Many)
protected $options;

public function __construct()
{
$this->options = new ArrayCollection();
}

// Getters and Setters ...
}

然后我们有两个实体负责处理自定义选项。与列表相关的选项本身。

class Option
{
protected $name;
protected $fieldType;
protected $required;
// Other form options you may want...

//Related Values (One-to-many)
protected $optionValues;

// Many-to-one
protected $listings;

public function __construct()
{
$this->optionValues = new ArrayCollection();
}

// Getters and Setters ...
}

以及存储在数据库中的那个选项的值。

class OptionValues
{
protected $value;


// Many-to-one
protected $option;
}

然后我们为列表构建 are From。

class ListingType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name' , 'text')
->add('price', 'text');
//Your other standard fields...
foreach($options['extraFields'] as $field)
{
$builder->add($field->getName() , new OptionValueType(), array('mapped' => false, 'options' => array('field' => $field));
}
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setRequired('extraFields');

$resolver->addAllowedTypes(array(
'extraFields' => '\Doctrine\Common\Collections\Collection'
));

$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Listing',
'cascade_validation' => true
));
}

public function getName()
{
return 'listing';
}
}

我们要求您传递 $option['extraFields'],它应该是您从 $yourListing- 获得的 AppBundle\Entity\Option 的集合->getOptions() 在你的 Controller 中。然后我们可以遍历这些并创建一个新的未映射字段,将该字段的其余部分传递给 AppBundle\Entity\OptionValue 的表单,就像这样。

class OptionValueType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//Obviously do whatever other settings you need. The important part is remembering that this belongs in the $value
//of our OptionValue entity.
$builder->add('value' , $field->fieldType, array('required' => $field->getIsRequired()));
}

public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setRequired('field');

$resolver->addAllowedTypes(array(
'field' => '\AppBundle\Entity\Option'
));

$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\OptionValue',
'cascade_validation' => true
));
}

public function getName()
{
return '';
}
}

一些重要的注意事项。在这两种形式中,我们都使用 $resolver->setRequired()$resolver->setAddAllowedTypes() 来定义额外的选项字段,否则 Symfony 会抛出错误。此外,在 list 表单中,我们设置了 'cascade_validation' => true 以确保我们的子表单也得到验证,如果这是您想要的。您可能还需要进行一些疯狂的自定义验证,这是一整套技巧。

这最终允许在我们的 Controller 中使用的是限制疯狂的自定义表单操作的数量,相反,如果您正确设置持久化以在您的列表和选项实体中级联,您应该能够只持久化列表它将确保所有 Option 和 OptionValue 实体也持久保存到数据库中。只要你做对了一切。我遗漏了很多细节,因为要写的内容很多,但希望这能给您一些想法。

关于php - Symfony2 以 symfony 形式获取未映射的字段值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32227821/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com