Php symfony 4创建多对多关系和嵌入表单无法正常工作

Php symfony 4创建多对多关系和嵌入表单无法正常工作,php,symfony,many-to-many,symfony4,formbuilder,Php,Symfony,Many To Many,Symfony4,Formbuilder,我创建了两个实体。第一类员额和第二类员额。该实体具有多对多关系。 我从帖子中创建表单,并添加使用ChoiceType的嵌入表单类别。 该表单工作正常,我可以为每个帖子添加多达多个类别。 但是在数据库orm中创建一个posts\u categories当我查看它的数据时,posts\u id是正确的,并且来自posts表,但是我不知道categories\u id来自哪里 我是指未保存在posts\u categories表中的类别的真实id。这个身份证从哪里来?我如何配置表上保存的真实id Ap

我创建了两个实体。第一类员额和第二类员额。该实体具有多对多关系。 我从帖子中创建表单,并添加使用ChoiceType的嵌入表单类别。 该表单工作正常,我可以为每个帖子添加多达多个类别。 但是在数据库orm中创建一个posts\u categories当我查看它的数据时,posts\u id是正确的,并且来自posts表,但是我不知道categories\u id来自哪里

我是指未保存在posts\u categories表中的类别的真实id。这个身份证从哪里来?我如何配置表上保存的真实id

App\Entity\Posts.php

    <?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\PostsRepository")
 */
class Posts
{
    public $newFormTitle = 'Add New Post';
    public $editFormTitle = 'Edit Post';
    public $listFormTitle = 'Posts List';
    public $adminList = 'postList';




    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=200)
     */
    private $title;

    /**
     * @ORM\Column(type="text")
     */
    private $content;

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Categories" , orphanRemoval=true, cascade={"persist"})
     */
    private $categories;

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

    public function getId()
    {
        return $this->id;
    }

    public function getTitle(): ?string
    {
        return $this->title;
    }

    public function setTitle(string $title): self
    {
        $this->title = $title;

        return $this;
    }

    public function getContent(): ?string
    {
        return $this->content;
    }

    public function setContent(?string $content): self
    {
        $this->content = $content;

        return $this;
    }

    /**
     * @return Collection|Categories[]
     */
    public function getCategories(): Collection
    {
        return $this->categories;
    }

    public function addCategory(Categories $category): self
    {
        if (!$this->categories->contains($category)) {
            $this->categories[] = $category;
        }

        return $this;
    }

    public function removeCategory(Categories $category): self
    {
        if ($this->categories->contains($category)) {
            $this->categories->removeElement($category);
        }

        return $this;
    }
}
<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\CategoriesRepository")
 */
class Categories
{
    public $newFormTitle = 'Add New Post';
    public $editFormTitle = 'Edit Post';
    public $listFormTitle = 'Categories List';
    public $adminList = 'categoriesList';


    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $name;

    public function __construct()
    {
    }

    public function getId()
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }
}
<?php

namespace App\Form;

use App\Entity\Posts;
use App\Form\CategoriesPostsType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;

class PostsType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {


        $builder
            ->add('title', null, [
                'attr' => ['autofocus' => true ,'class'=>'form-control'],
                'label' => 'label.title',
                'label_attr' => ['class'=>'label-control'],
            ])
            ->add('content', null, [
                'attr' => ['rows' => 8 ,'class'=>'form-control'],
                'label' => 'label.content',
                'label_attr' => ['class'=>'label-control'],
            ])
        ;
        /*
        $builder->add('categories', CollectionType::class, array(
            'entry_type' => CategoryType::class,
            'entry_options' => array('label' => false),
            'allow_add' => true,
        ));
        */
        $builder->add('categories', CollectionType::class, array(
            'entry_type' => CategoriesPostsType::class,
            'entry_options' => array('label' => false),
            'allow_add' => true,
            'allow_delete' => true,
            'by_reference' => true,
            'label' => false,
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Posts::class,
        ]);
    }
}
<?php

namespace App\Form;

use App\Entity\Categories;
use App\Form\Type\CategoryInputType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use App\Repository\CategoriesRepository;

class CategoriesPostsType extends AbstractType
{
    private $categories;
    public function __construct(CategoriesRepository $category)
    {
        $categories = $category->findAll();
        $choise = array();
        foreach ($categories as $key => $value)
            //$choise[] = new Categories($categories[$key]->getId();
            $choise[$categories[$key]->getName()] = $categories[$key]->getId();
        $this->categories = $choise;
    }

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name', ChoiceType::class, [
                'attr' => ['autofocus' => true ,'class'=>'form-detail-control formChoiceType'],
                'label' => false,
                'label_attr' => ['class'=>'label-control'],
                'choices'  => $this->categories,
            ])
          /*  ->add('category', CategoryInputType::class, [
                'label' => 'label.category',
                'required' => false,
            ])*/
        ;

    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => Categories::class,
        ]);
    }
}

为什么要“配置”生成的类别id?您在类别实体中指定了@ORM\GeneratedValue()。因此,您的数据库会生成id(例如,如果MySQL使用自动增量),我不想生成id?我希望在我的表中,为我创建多对多关系的类别插入正确的类别id。我不知道该id是如何生成的,它保存在哪里,我再次担心我的答案。它是由DBMS生成的,因为您在类别实体中指定了@ORM\GeneratedValue()。因此,例如MySQL使用自动增量在category表中为您的类别生成id。完成后,它将使用posts\u categories表中的id添加关系。
{% extends 'theme/basickTheme/form.html.twig' %}

{% block body_id 'content_new_posts' %}

{% block defaultFormHeader  entity.newFormTitle  %}

{% block defaultFormBody %}
<div class="row">
    <div class="col-12">
        {{ form_start(form) }}
        <div class="col-12">
            {{ form_errors(form) }}
        </div>
        <div class="col-12">
            {{ form_row(form.title) }}
        </div>
        <div class="col-12">
            {{ form_row(form.content) }}
        </div>
        <div class="col-12 form-group">
            <h3>Categories</h3>
        </div>
        <div class="col-12">
            <button type="button" class="btn add-detail-botton" onclick="addCategoriesForm(1)">
                <img src="{{ asset('img/custum-icon/add-small.png') }}">
                <i class="fa fa-save" aria-hidden="true"></i> {{ button_label|default('categories.label.add.category'|trans) }}
            </button>
            <ol class="detail-list" data-prototype="{{ form_widget(form.categories.vars.prototype)|e('html_attr') }}">
                {# iterate over each existing tag and render its only field: name #}
                {% for Category in form.categories %}
                    <li>{{ form_widget(Category.name) }}</li>
                {% endfor %}
            </ol>
            <button type="button" class="btn add-detail-botton" onclick="addCategoriesForm(2)">
                <img src="{{ asset('img/custum-icon/add-small.png') }}">
                <i class="fa fa-save" aria-hidden="true"></i> {{ button_label|default('categories.label.add.category'|trans) }}
            </button>

        </div>
        <div class="col-12 form-footer-botton">
                <button type="submit" class="btn btn-primary">
                    <i class="fa fa-save" aria-hidden="true"></i> {{ button_label|default('Label.save'|trans) }}
                </button>

                <a href="{{ backUrl }}" class="btn btn-primary">
                    <i class="fa fa-list-alt" aria-hidden="true"></i> {{ 'Label.back.to.list'|trans }}
                </a>
        </div>
        {{ form_end(form) }}
    </div>
</div>
{% endblock %}

    {% block javascripts %}`
        <script>
            var $collectionHolder;
            jQuery(document).ready(function() {


                // Get the ul that holds the collection of tags
                $collectionHolder = $('ol.detail-list');

                $collectionHolder.find('li').each(function() {
                    addCategoriesFormDeleteLink($(this));
                });

                // count the current form inputs we have (e.g. 2), use that as the new
                // index when inserting a new item (e.g. 2)
                $collectionHolder.data('index', $collectionHolder.find(':input').length);
            });
            function addCategoriesForm( $appendType = 1) {
                var $collectionHolder = $('ol.detail-list');

                // Get the data-prototype explained earlier
                var prototype = $collectionHolder.data('prototype');

                // get the new index
                var index = $collectionHolder.data('index');

                var newForm = prototype;
                // You need this only if you didn't set 'label' => false in your tags field in TaskType
                // Replace '__name__label__' in the prototype's HTML to
                // instead be a number based on how many items we have
                // newForm = newForm.replace(/__name__label__/g, index);

                // Replace '__name__' in the prototype's HTML to
                // instead be a number based on how many items we have
                newForm = newForm.replace(/__name__/g, index);
                newForm = newForm.replace(/form-detail-control/g, 'form-detail-control-new');

                // increase the index with one for the next item
                $collectionHolder.data('index', index + 1);

                // Display the form in the page in an li, before the "Add a tag" link li
                var $newFormLi = $('<li class="prototye"></li>').prepend(newForm);
                if($appendType == 1)
                    $collectionHolder.prepend($newFormLi);
                else
                    $collectionHolder.append($newFormLi);
                //$newLinkLi.before($newFormLi);
                addCategoriesFormDeleteLink($newFormLi);

            }

            function addCategoriesFormDeleteLink($tagFormLi) {
                //var $removeFormButton = $('<button type="button" class="detailDeleteButton">Delete</button>');
                var $removeFormButton = $('<button type="button" class="btn delte-detail-botton"><img src="{{ asset('img/custum-icon/delete-smal.png') }}"><i class="fa fa-save" aria-hidden="true"></i>{{ button_label|default('categories.label.delete.category'|trans) }}</button>');
                $tagFormLi.append($removeFormButton);

                $removeFormButton.on('click', function(e) {
                    // remove the li for the tag form
                    $tagFormLi.remove();
                });
            }

        </script>
    {% endblock %}