首页 文章

Symfony2依赖下拉ManyToMany

提问于
浏览
0

我有3个实体:公司,行业,类别我想创建一个表单,用户可以在其中输入公司名称,然后从下拉列表中选择行业 . 每个行业都有类别 . 当用户选择行业时,我想填充“类别”列表 . 我读过以下文章: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 %}

1 回答

  • 0

    Company:categories 将是实体的集合,而不是单个实体,因此它不应该有 setCategory 方法,否则您可能会无意中删除整个集合 . 相反,你将有一个 addCategoriesremoveCategoriesgetCategories (如果由于'un-pluralization'而产生了学说,那么这可能是 addCategorieremoveCategorie ) .

    要解决此问题,您需要将 categories 表单元素更改为 collection 类型,而不是 CompanyRegistrationFormType 中的 entity .

    如果公司有一个或多个类别,只需检查一下?目前,您的代码似乎有点两者兼而有之?

相关问题