教义Manytomany与额外的领域

时间:2017-11-12 00:10:17

标签: symfony doctrine-orm many-to-many

我在任何地方都搜索可以帮助我解决这个问题并且找不到。

我有关系:

表A ---一对多---表AB ---多对一---表B

错误尝试调用newAction方法时得到的结果:

Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "AppBundle\Entity\Line#$buttons", got "AppBundle\Entity\Button" instead.

我认为我已经尝试了所有内容并且仍然遇到同样的错误。

行实体

    namespace AppBundle\Entity;

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

    /**
     * Line
     *
     * @ORM\Table(name="lines")
     * @ORM\Entity(repositoryClass="AppBundle\Repository\LineRepository")
     */
    class Line
    {
        /**
         * @var int
         *
         * @ORM\Column(name="id", type="integer")
         * @ORM\Id
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;

        /**
         * @var string
         *
         * @ORM\Column(name="line_name", type="string", length=255)
         */
        private $lineName;

        /**
         * @ORM\OneToMany(targetEntity="AppBundle\Entity\ButtonsState", mappedBy="line", cascade={"all"})
         */
        private $buttons;

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

        /**
         * Get id
         *
         * @return int
         */
        public function getId()
        {
            return $this->id;
        }

        /**
         * Set lineName
         *
         * @param string $lineName
         *
         * @return Line
         */
        public function setLineName($lineName)
        {
            $this->lineName = $lineName;

            return $this;
        }

        /**
         * Get lineName
         *
         * @return string
         */
        public function getLineName()
        {
            return $this->lineName;
        }

        /**
         * Get buttons
         *
         * @return int
         */
        public function getButtons()
        {
            return $this->buttons;
        }

        public function addButton(Button $button)
        {
            if ($this->buttons->contains($button)) {
                return;
            }

            $this->buttons->add($button);
        }

    }

按钮实体

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Button
 *
 * @ORM\Table(name="buttons")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ButtonRepository")
 */
class Button
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="button_name", type="string", length=255)
     */
    private $buttonName;

    /**
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\ButtonsState", mappedBy="button", cascade={"all"})
     */
    private $lines;


    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Get buttonName
     *
     * @return string
     */
    public function getButtonName()
    {
        return $this->buttonName;
    }

    /**
     * Set buttonName
     *
     * @param string $buttonName
     *
     * @return Button
     */
    public function setButtonName($buttonName)
    {
        $this->buttonName = $buttonName;
    }

}

ButtonsState实体

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * ButtonsState
 *
 * @ORM\Table(name="lines_buttons")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\ButtonStateRepository")
 */
class ButtonsState
{
    /**
     * @ORM\Id()
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Line", inversedBy="buttons", cascade={"PERSIST"})
     * @ORM\JoinColumn(name="line_id", referencedColumnName="id")
     */
    private $line;

    /**
     * @ORM\Id()
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Button", inversedBy="line", cascade={"PERSIST"})
     * @ORM\JoinColumn(name="button_id", referencedColumnName="id")
     */
    private $button;

    /**
     * @var int
     *
     * @ORM\Column(name="state", type="integer")
     */
    private $state;

    /**
     * @return int
     */
    public function getState()
    {
        return $this->state;
    }

    /**
     * @param int $state
     */
    public function setState($state)
    {
        $this->state = $state;
    }  

}

LineController

/**
     * Creates a new line entity.
     *
     * @Route("/new", name="line_new")
     * @Method({"GET", "POST"})
     */
    public function newAction(Request $request)
    {
        $line = new Line();
        $form = $this->createForm('AppBundle\Form\LineType', $line);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {

            $em = $this->getDoctrine()->getManager();

            foreach ($line->getButtons() as $button) {
                $line->addButton($button);
            }

            $em->persist($line);
            $em->flush();

            return $this->redirectToRoute('line_index', array('id' => $line->getId()));
        }

        return $this->render('line/new.html.twig', array(
            'line' => $line,
            'form' => $form->createView(),
        ));
    }

线型

namespace AppBundle\Form;

use AppBundle\Entity\Button;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class LineType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('lineName', null, array(
                'label' => 'Line name',
            ))
            ->add('buttons', EntityType::class, array(
                'class' => Button::class,
                'choice_label' => 'buttonName',
                'multiple' => true,
                'expanded' => true,
            ));
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'AppBundle\Entity\Line'
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'appbundle_line';
    }


}

2 个答案:

答案 0 :(得分:0)

在控制器的第51行,您正在调用方法addButtons

foreach ($line->getButtons() as $button) {
    $line->addButtons($button);
}

尝试将其更改为addButton,因为这是实体中定义的方法。

如果这没有帮助,请提供相应的堆栈跟踪。

修改

再看一遍,我已经看到了问题所在。

你将ButtonsState Entity视为m到m之间关系的表,因为它上面有一个额外的属性。

在表单类型中,你说在Line实体的按钮属性后面有按钮。这是错的。在这个属性后面有ButtonsState实体。

所以改变你的代码如下:

表格类型:

// ...
->add('buttonsToAdd', EntityType::class, array(
    'class' => Button::class,
    'choice_label' => 'buttonName',
    'multiple' => true,
    'expanded' => true,
    'mapped' => false,
))
// ...

控制器:

// ...
$em->persist($line);
foreach ($form->get('buttonsToAdd')->getData() as $button) {
    $state = new \UserBundle\Entity\ButtonsState();
    $state->setLine($line);
    $state->setButton($button);
    $state->setState(0);

    $line->addButton($state);
}

$em->flush();
// ...

像这样你有一个额外的(未映射的)属性,可以使用窗体上的按钮转换为控制器中的ButtonsState实例。

还有一个提示:使用命令bin/console doctrine:generate:entities AppBundle:ButtonsState在您的实体中生成getter和setter,因为它们在某些地方是wronc / incomplete。

答案 1 :(得分:0)

添加'在这之后:

<强>从

class ButtonsState
{
    /**
     * @ORM\Id()
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Button", inversedBy="line", cascade={"PERSIST"})
     * @ORM\JoinColumn(name="button_id", referencedColumnName="id")
     */
    private $button;
}

class ButtonsState
{
    /**
     * @ORM\Id()
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Button", inversedBy="lines", cascade={"PERSIST"})  // added a 's' behind line
     * @ORM\JoinColumn(name="button_id", referencedColumnName="id")
     */
    private $button;
}

下次检查你的关系:

  

bin / console doctrine:schema:validate