我有3个实体:公司,行业,类别 我想创建一个表单,用户可以在其中输入公司名称,然后从下拉列表中选择Industry。每个行业都有类别。当用户选择行业时,我想填充“类别”列表。我读过以下文章:http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data
我已经创建了表单,但是当触发ajax调用时,我收到以下错误:
Neither the property "categories" nor one of the methods "setCategories()", "__set()" or "__call()" exist and have public access in class "ebulucu\MainBundle\Entity\Company"
我现在已经很多天了,只是无法让它发挥作用。我希望有人能给我一些提示。我需要一个表单,其中包含一个输入字段用于公司名称,两个下拉列表行业和类别,其中类别取决于所选行业。公司与Category和Industry有很多关系,也有OneToMany关系。到目前为止,这是我的代码:
编辑: 我已尝试使用OneToMany代码,而不是公司和类别之间的ManyToMany关系。 这很好。但是,如果ManyToMany关系怎么办?如何管理加载和设置类别?
我的3个实体:
class Company
{
/**
* @var integer
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* @ORM\ManyToMany(targetEntity="Category", mappedBy="companies")
*/
private $categories;
/**
* Constructor
*/
public function __construct()
{
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
... setters and getters
class Industry
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=80)
* @Assert\NotBlank()
*/
private $name;
/**
* @var
*
* @ORM\OneToMany(targetEntity="Category",mappedBy="industry")
*/
private $categories;
public function __construct()
{
$this->categories = new ArrayCollection();
}
...setters and getters
class Category
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=80)
* @Assert\NotBlank()
*/
private $name;
/**
* @ORM\ManyToOne(targetEntity="Industry", inversedBy="categories");
* @ORM\JoinColumn(name="industry_id", referencedColumnName="id",nullable=false)
*/
private $industry;
/**
* @ORM\ManyToMany(targetEntity="Company", inversedBy="categories");
* @ORM\JoinTable(name="categories_companies")
*/
private $companies;
... setters and getters
我的公司表格类别:
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use ebulucu\MainBundle\Entity\Industry;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Doctrine\ORM\EntityRepository;
class CompanyRegistrationFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
$builder->add('industry', 'entity', array(
'mapped' => false,
'class' => 'ebulucuMainBundle:Industry',
'property' => 'name',
'empty_value' => 'Choose industry',
));
$formModifier = function(FormInterface $form, $industry_id) {
if($industry_id) {
$form->add('categories', 'entity', array(
'class' => 'ebulucuMainBundle:Category',
'query_builder' => function(EntityRepository $er) use ($industry_id) {
$query = $er->createQueryBuilder('i')
->select(array('i'))
->where('i.industry_id = :industry_id')
->setParameter('industry_id', $industry_id)
->orderBy('i.name', 'ASC');
return $query;
},
'empty_value' => 'Choose category'
)
);
}
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function(FormEvent $event) use ($formModifier) {
$formModifier($event->getForm(), null);
}
);
//** Checks for Industry that is submitted and adds categories based on industry selection **//
$builder->get('industry')->addEventListener(
FormEvents::POST_SUBMIT, function(FormEvent $event) use ($formModifier) {
$industry_id = $event->getData();
$formModifier($event->getForm()->getParent(), $industry_id);
}
);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'ebulucu\MainBundle\Entity\Company',
));
}
public function getName()
{
return 'company';
}
}
控制器:
use ebulucu\MainBundle\Entity\Company;
use ebulucu\MainBundle\Form\Type\CompanyRegistrationFormType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use ebulucu\MainBundle\Entity\Industry;
use ebulucu\MainBundle\Entity\Category;
use Symfony\Component\HttpFoundation\Request;
class MainController extends Controller
{
/**
* @Route("/", name="homepage")
* @Template()
*/
public function indexAction(Request $request)
{
$company = new Company();
$form = $this->createForm(new CompanyRegistrationFormType(), $company);
$form->handleRequest($request);
if ($form->isValid()) {
return $this->redirect($this->generateUrl('fos_user_security_login'));
}
return array(
'form' => $form->createView(),
);
}
/**
* @Route("/", name="loadIndustryCategories")
* @Template()
*/
public function loadIndustryCategories(Request $request)
{
$company = new Company();
$form = $this->createForm(new CompanyRegistrationFormType(), $company);
$form->handleRequest($request);
return array(
'form' => $form->createView(),
);
}
}
带有表单和ajax调用的Twig模板:
{% block content %}
<div>Homepage</div>
{{ form_start(form, {'attr': {'id': 'form_industry'}}) }}
{{ form_end(form) }}
{% endblock %}
{% block js%}
<script>
$('#company_industry').change( function() {
var postData = $("#form_industry").serializeArray();
var formURL = {{ path('loadIndustryCategories') }};
$.ajax(
{
url : formURL,
type: "POST",
data : postData,
success:function(data, textStatus, jqXHR)
{
//data: return data from server
},
error: function(jqXHR, textStatus, errorThrown)
{
//if fails
}
});
e.preventDefault(); //STOP default action
e.unbind(); //unbind. to stop multiple form submit.
});
</script>
{% endblock %}
答案 0 :(得分:0)
Company:categories
将是实体的集合,而不是单个实体,因此它不应该有setCategory
方法,否则您可能会无意中删除整个集合。相反,您将拥有addCategories
,removeCategories
和getCategories
(如果由于其“非复数化”而生成学说,则可以是addCategorie
和removeCategorie
。
要解决此问题,您需要将categories
表单元素更改为collection
类型,而不是entity
中的CompanyRegistrationFormType
。
如果公司有一个或多个类别,请检查一下?目前,您的代码似乎有点两者兼而有之?