Symfony3:将数据保存到数据库中时将值丢失到集合中

时间:2016-06-17 09:17:52

标签: sql forms entity symfony formcollection

我尝试为目录创建树结构。

首先,用户使用基本信息(名称,代码,有效期,类型等)创建目录。然后,我以另一种形式重定向用户以创建树结构。

目录可以有多个级别。 这些级别可以包含多个产品(在此处命名为“Model”)。

所以,在我的树形态中,我有一系列关卡。 在水平集合表格中,我有一系列模型。

换句话说,我有一个收集到另一个集合。

enter image description here

我无法将我的几个实体保存在数据库中。当我在控制器中执行$em->flush();时,它丢失了模型值(第二个集合)。我对CatalogModel实体的组合键(由级别ID和目录代码组成)有完整性约束违规。

但是,Catalog,CatalogLevel和CatalogModel很好地保留了。两者都填充了正确的数据。

所以我不明白我做错了什么......

目录实体:请注意,我不使用自动生成的ID。代码是id,用户在创建目录时提供。

/**
 * @ORM\Table(name="catalogue")
 * @ORM\Entity(repositoryClass="AppBundle\Entity\CatalogRepository")
 * @UniqueEntity(fields="code", message="Catalog code already exists")
 */
class Catalog
{
    /**
     * @ORM\Column(name="Catalogue_Code", type="string", length=15)
     * @ORM\Id
     * @Assert\NotBlank()
     * @Assert\Length(max=15, maxMessage="The code is too long ({{ limit }} characters max)")
     */
    private $code;

    /**
     * @ORM\OneToMany(targetEntity="CatalogLevel", mappedBy="catalog", cascade={"persist", "remove"})
     * @Assert\Valid
     */
    private $levels;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->levels = new ArrayCollection();
    }

   /**
    * Set code
    *
    * @param string $code
    *
    * @return Catalog
    */
    public function setCode($code)
    {
        $this->code = $code;

        return $this;
    }

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

    /**
     * Get levels
     *
     * @return ArrayCollection
     */
    public function getLevels()
    {
      return $this->levels;
    }

    /**
     * Add level
     *
     * @param \AppBundle\Entity\CatalogLevel $level
     *
     * @return Catalog
     */
    public function addLevel(\AppBundle\Entity\CatalogLevel $level)
    {
        $level->setCatalogCode($this->getCode());
        $level->setCatalog($this);

        if (!$this->getLevels()->contains($level)) {
            $this->levels->add($level);
        }

        return $this;
    }

    /**
     * Remove level
     *
     * @param \AppBundle\Entity\CatalogLevel $level
     */
   public function removeLevel(\AppBundle\Entity\CatalogLevel $level)
    {
        $this->levels->removeElement($level);
    }
}

CatalogLevel实体:我也不使用自动生成的ID。 Level作为由级别id和目录代码组成的复合键。当我使用表单中的添加按钮创建一个级别时,在JS中生成id。请记住,关卡是一种收集形式。

/**
 * @ORM\Table(name="catalogue_niveau")
 * @ORM\Entity(repositoryClass="AppBundle\Entity\CatalogLevelRepository")
 */
class CatalogLevel
{
    /**
     * @ORM\Column(name="Niveau_ID", type="string", length=15)
     * @ORM\Id
     */
    private $id;

    /**
     * @ORM\Column(name="Catalogue_Code", type="string", length=15)
     * @ORM\Id
     */
    private $catalogCode;

    /**
     * @ORM\Column(name="Niveau_Nom", type="string", length=40)
     * @Assert\NotBlank()
     */
    private $name;

    /**
     * @ORM\Column(name="Parent_ID", type="string", length=15, nullable=true)
     * @ORM\ManyToOne(targetEntity="CatalogLevel")
     * @ORM\JoinColumn(referencedColumnName="Niveau_ID", onDelete="CASCADE")
     */
    private $parent;

    /**
     * @ORM\Column(name="Niveau_Ordre", type="integer")
     */
    private $order;

    /**
     * @ORM\ManyToOne(targetEntity="Catalog", inversedBy="levels")
     * @ORM\JoinColumn(name="Catalogue_Code", referencedColumnName="Catalogue_Code")
     */
    private $catalog;

    /**
     * @ORM\OneToMany(targetEntity="CatalogModel", mappedBy="level", cascade={"persist", "remove"})
     * @Assert\Valid
     */
    private $models;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->order = 0;
        $this->models = new ArrayCollection();
    }

    /**
     * Set id
     *
     * @param string $id
     *
     * @return CatalogLevel
     */
    public function setId($id)
    {
        $this->id = $id;

        return $this;
    }

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

    /**
     * Set catalogCode
     *
     * @param string $catalogCode
     *
     * @return CatalogLevel
     */
    public function setCatalogCode($catalogCode)
    {
        $this->catalogCode = $catalogCode;

        return $this;
    }

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

    /**
     * Set name
     *
     * @param string $name
     *
     * @return CatalogLevel
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

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

    /**
     * Set parent
     *
     * @param string $parent
     *
     * @return CatalogLevel
     */
    public function setParent($parent)
    {
        $this->parent = $parent;

        return $this;
    }

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

    /**
     * Set order
     *
     * @param integer $order
     *
     * @return CatalogLevel
     */
    public function setOrder($order)
    {
        $this->order = $order;

        return $this;
    }

    /**
     * Get order
     *
     * @return integer
     */
    public function getOrder()
    {
        return $this->order;
    }

    /**
     * Set catalog
     *
     * @param \AppBundle\Entity\Catalog $catalog
     *
     * @return CatalogLevel
     */
    public function setCatalog(\AppBundle\Entity\Catalog $catalog = null)
    {
        $this->catalog = $catalog;

        return $this;
    }

    /**
     * Get catalog
     *
     * @return \AppBundle\Entity\Catalog
     */
    public function getCatalog()
    {
        return $this->catalog;
    }

     /**
     * Get models
     *
     * @return ArrayCollection
     */
    public function getModels()
    {
      return $this->models;
    }

    /**
     * Add model
     *
     * @param \AppBundle\Entity\CatalogModel $model
     *
     * @return CatalogLevel
     */
    public function addModel(\AppBundle\Entity\CatalogModel $model)
    {
        $model->setLevel($this);
        $model->setCatalog($this->getCatalog());

        if (!$this->getModels()->contains($model)) {
            $this->models->add($model);
        }

        return $this;
    }

    /**
     * Remove model
     *
     * @param \AppBundle\Entity\CatalogModel $model
     */
    public function removeModel(\AppBundle\Entity\CatalogModel $model)
    {
        $this->models->removeElement($model);
    }
}

CatalogModel实体:model也有一个复合键,由代码(Model实体的代码),目录代码和级别id组成。

/**
 * @ORM\Table(name="catalogue_rayon")
 * @ORM\Entity(repositoryClass="AppBundle\Entity\CatalogModelRepository")
 */
class CatalogModel
{
    /**
     * @ORM\Column(name="Modele_Code", type="string", length=20)
     * @ORM\Id
     */
    private $code;

    /**
     * @ORM\Column(name="Catalogue_Code", type="string", length=15)
     * @ORM\Id
     */
    private $catalogCode;

    /**
     * @ORM\Column(name="Niveau_ID", type="string", length=15)
     * @ORM\Id
     */
    private $levelId;

    /**
     * @ORM\Column(name="Modele_Ordre", type="integer")
     */
    private $order;

    /**
     * @ORM\ManyToOne(targetEntity="CatalogLevel", inversedBy="models")
     * @ORM\JoinColumn(name="Niveau_ID", referencedColumnName="Niveau_ID")
     */
    private $level;

    /**
     * @ORM\ManyToOne(targetEntity="Catalog")
     * @ORM\JoinColumn(name="Catalogue_Code", referencedColumnName="Catalogue_Code")
     */
    private $catalog;

    /**
     * @ORM\ManyToOne(targetEntity="Model")
     * @ORM\JoinColumn(name="Modele_Code", referencedColumnName="Modele_Code")
     */
    private $model;

    /**
     * @ORM\Column(name="Date_Debut", type="datetime", nullable=true)
     * @Assert\Date()
     */
    private $beginDate;

    /**
     * @ORM\Column(name="Date_Fin", type="datetime", nullable=true)
     * @Assert\Date()
     */
    private $endDate;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->order = 0;
    }

    /**
     * Set code
     *
     * @param string $code
     *
     * @return CatalogModel
     */
    public function setCode($code)
    {
        $this->code = $code;

        return $this;
    }

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

    /**
     * Set catalogCode
     *
     * @param string $catalogCode
     *
     * @return CatalogModel
     */
    public function setCatalogCode($catalogCode)
    {
        $this->catalogCode = $catalogCode;

        return $this;
    }

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

     /**
     * Set levelId
     *
     * @param integer $levelId
     *
     * @return CatalogModel
     */
    public function setLevelId($levelId)
    {
        $this->levelId = $levelId;

        return $this;
    }

    /**
     * Get levelId
     *
     * @return integer
     */
    public function getLevelId()
    {
        return $this->levelId;
    }

    /**
     * Set order
     *
     * @param integer $order
     *
     * @return CatalogModel
     */
    public function setOrder($order)
    {
        $this->order = $order;

        return $this;
    }

    /**
     * Get order
     *
     * @return integer
     */
    public function getOrder()
    {
        return $this->order;
    }

    /**
     * Set level
     *
     * @param \AppBundle\Entity\CatalogLevel $level
     *
     * @return CatalogModel
     */
    public function setLevel(\AppBundle\Entity\CatalogLevel $level = null)
    {
        $this->level = $level;

        return $this;
    }

    /**
     * Get level
     *
     * @return \AppBundle\Entity\CatalogLevel
     */
    public function getLevel()
    {
        return $this->level;
    }

     /**
     * Set catalog
     *
     * @param \AppBundle\Entity\Catalog $catalog
     *
     * @return CatalogModel
     */
    public function setCatalog(\AppBundle\Entity\Catalog $catalog = null)
    {
        $this->catalog = $catalog;

        return $this;
    }

    /**
     * Get catalog
     *
     * @return \AppBundle\Entity\Catalog
     */
    public function getCatalog()
    {
        return $this->catalog;
    }

     /**
     * Set beginDate
     *
     * @param \DateTime $beginDate
     *
     * @return CatalogModel
     */
    public function setBeginDate($beginDate)
    {
        $this->beginDate = $beginDate;

        return $this;
    }

    /**
     * Get beginDate
     *
     * @return \DateTime
     */
    public function getBeginDate()
    {
        return $this->beginDate;
    }

    /**
     * Set endDate
     *
     * @param \DateTime $endDate
     *
     * @return CatalogModel
     */
    public function setEndDate($endDate)
    {
        $this->endDate = $endDate;

        return $this;
    }

    /**
     * Get endDate
     *
     * @return \DateTime
     */
    public function getEndDate()
    {
        return $this->endDate;
    }

    /**
     * Set model
     *
     * @param \AppBundle\Entity\Model $model
     *
     * @return CatalogModel
     */
    public function setModel(\AppBundle\Entity\Model $model = null)
    {
        $this->model = $model;

        return $this;
    }

    /**
     * Get model
     *
     * @return \AppBundle\Entity\Model
     */
    public function getModel()
    {
        return $this->model;
    }
}

然后,形式:

CatalogTreeType

class CatalogTreeType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('levels',     CollectionType::class, array(
                'entry_type'    => CatalogLevelType::class,
                'entry_options'     => array('catalogCode' => $options['data']->getCode()),
                'allow_add'         => true,
                'allow_delete'      => true,
                'prototype'         => true,
                'label'             => false,
                'by_reference'  => false
            ))
            ->add('search',     TextType::class, array(
                'label'                 => false,
                'mapped'                => false,
                'required'          => false,
                'attr'              => array(
                    'class'             => 'search',
                    'size'          => 35,
                    'placeholder'   => 'Search for a model...'
                )
            ))
            ->add('save',       SubmitType::class, array(
                'attr'              => array('class' => 'button-link save'),
                'label'             => 'Validate'
            ))
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class'  => 'AppBundle\Entity\Catalog',
            // 'allow_extra_fields' => true
        ));
    }
}

CatalogLevelType (收藏)

class CatalogLevelType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name',           TextType::class, array(
                'label'                 => false,
                'attr'              => array(
                    'class'             => 'full level-name',
                    'size'          => 35,
                    'placeholder'   => 'Name of level'
                )
            ))

            ->add('id',             HiddenType::class, array(
                'attr'              => array('class' => 'level-id')
            ))
            ->add('parent',     HiddenType::class, array(
                'attr'              => array('class' => 'level-parent'),
                'required'          => false
            ))

            ->add('models',     CollectionType::class, array(
                'entry_type'    => CatalogModelType::class,
                'entry_options'     => array('catalogCode' => $options['catalogCode']),
                'allow_add'         => true,
                'allow_delete'      => true,
                'prototype'         => true,
                'prototype_name'    => '__model_name__',
                'label'             => false,
                'by_reference'  => false
            ))
        ;
    }

CatalogModelType (收藏)

class CatalogModelType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('code',           TextType::class, array(
                'label'                 => false,
                'attr'              => array(
                    'class'             => 'full model-field',
                    'readonly'      => true
                )
            ))
            ->add('beginDate',  DateType::class, array(
                'label'                 => 'Begins',
                'widget'            => 'single_text',
                'html5'                 => false,
                'attr'              => array('class' => 'full'),
                'format'            => 'yyyy-MM-dd',
                'data'              => new \DateTime('0000-00-00'),
                'required'          => false
            ))
            ->add('endDate',        DateType::class, array(
                'label'                 => 'Ends',
                'widget'            => 'single_text',
                'html5'                 => false,
                'attr'              => array('class' => 'full'),
                'format'            => 'yyyy-MM-dd',
                'data'              => new \DateTime('0000-00-00'),
                'required'          => false
            ))
            ->add('catalogCode',    HiddenType::class, array(
                'data'              => $options['catalogCode']
            ))
            ->add('levelId',        HiddenType::class, array(
                'attr'              => array('class' => 'model-level-id')
            ))
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class'    => 'AppBundle\Entity\CatalogModel',
            'catalogCode'   => null
        ));
    }
}

CatalogController

/**
* @Route("/catalogs/{code}/tree-structure", name="catalog_tree")
*/
public function treeAction($code, Request $request) {    
    // get catalog from database
  $em = $this->getDoctrine()->getManager();
  $catalog = $em->getRepository('AppBundle:Catalog')->find($code);

  // catalog doesn't exist
  if (!$catalog) {
     throw $this->createNotFoundException('No catalog found for code '. $code);
  }

    // build the form
    $form = $this->createForm(CatalogTreeType::class, $catalog);

    // Form posté et valide
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $em->persist($catalog);     // save the catalog

        // save the levels
        foreach($catalog->getLevels() as $level) {
            // var_dump($level);
            $em->persist($level);

            // save the models
            foreach($level->getModels() as $model) {
                // var_dump($model);
                $em->persist($model);
            }
        }

        // update database
        $em->flush();

        // success message
        $this->addFlash('notice', 'Catalog tree structure has been created successfully !');

        # redirection
        // return $this->redirectToRoute('catalog_tree_edit', array('code' => $code));
    }

    // show page
  return $this->render('catalogs/tree.html.twig', array(
     'h1_title'  => 'Tree structure of the catalog : ' . $catalog->getName() . ' (' . $catalog->getCode() . ')',
        'form'      => $form->createView(),
        'code'      => $catalog->getCode()
  ));
}

var_dump的结果:

// save the levels
foreach($catalog->getLevels() as $level) {
    // var_dump($level);
    $em->persist($level);

    // save the models
    foreach($level->getModels() as $model) {
        // var_dump($model);
        $em->persist($model);
    }
}

等级:

object(AppBundle\Entity\CatalogLevel)[2610]
  private 'id' => string 'NIV_1' (length=5)
  private 'catalogCode' => string 'CATEST' (length=6)
  private 'name' => string 'genou' (length=5)
  private 'parent' => null
  private 'order' => int 0
  private 'catalog' => 
    object(AppBundle\Entity\Catalog)[2493]
      private 'code' => string 'CATEST' (length=6)
      private 'name' => string 'Catalogue de test' (length=17)
      private 'type' => string 'Normal' (length=6)
      private 'promo' => null
      private 'tariff' => string 'F0' (length=2)
      private 'campaign' => string 'FTEST' (length=5)
      private 'beginDate' => 
        object(DateTime)[2495]
          public 'date' => string '2016-06-16 00:00:00.000000' (length=26)
          public 'timezone_type' => int 3
          public 'timezone' => string 'UTC' (length=3)
      private 'endDate' => 
        object(DateTime)[2496]
          public 'date' => string '2016-06-24 00:00:00.000000' (length=26)
          public 'timezone_type' => int 3
          public 'timezone' => string 'UTC' (length=3)
      private 'catalogSalesForce' => 
        object(Doctrine\ORM\PersistentCollection)[2473]
          private 'snapshot' => 
            array (size=2)
              ...
          private 'owner' => 
            &object(AppBundle\Entity\Catalog)[2493]
          private 'association' => 
            array (size=15)
              ...
          private 'em' => 
            object(Doctrine\ORM\EntityManager)[2086]
              ...
          private 'backRefFieldName' => string 'catalog' (length=7)
          private 'typeClass' => 
            object(Doctrine\ORM\Mapping\ClassMetadata)[2489]
              ...
          private 'isDirty' => boolean false
          protected 'collection' => 
            object(Doctrine\Common\Collections\ArrayCollection)[2484]
              ...
          protected 'initialized' => boolean true
      private 'forces' => null
      private 'levels' => 
        object(Doctrine\ORM\PersistentCollection)[2459]
          private 'snapshot' => 
            array (size=0)
              ...
          private 'owner' => 
            &object(AppBundle\Entity\Catalog)[2493]
          private 'association' => 
            array (size=15)
              ...
          private 'em' => 
            object(Doctrine\ORM\EntityManager)[2086]
              ...
          private 'backRefFieldName' => string 'catalog' (length=7)
          private 'typeClass' => 
            object(Doctrine\ORM\Mapping\ClassMetadata)[2468]
              ...
          private 'isDirty' => boolean true
          protected 'collection' => 
            object(Doctrine\Common\Collections\ArrayCollection)[2442]
              ...
          protected 'initialized' => boolean true
  private 'models' => 
    object(Doctrine\Common\Collections\ArrayCollection)[2708]
      private 'elements' => 
        array (size=1)
          0 => 
            object(AppBundle\Entity\CatalogModel)[2735]

型号:

object(AppBundle\Entity\CatalogModel)[2735]
  private 'code' => string 'BARACCBA' (length=8)
  private 'catalogCode' => string 'CATEST' (length=6)
  private 'levelId' => string 'NIV_1' (length=5)
  private 'order' => int 0
  private 'level' => 
    object(AppBundle\Entity\CatalogLevel)[2610]
      private 'id' => string 'NIV_1' (length=5)
      private 'catalogCode' => string 'CATEST' (length=6)
      private 'name' => string 'genou' (length=5)
      private 'parent' => null
      private 'order' => int 0
      private 'catalog' => 
        object(AppBundle\Entity\Catalog)[2493]
          private 'code' => string 'CATEST' (length=6)
          private 'name' => string 'Catalogue de test' (length=17)
          private 'type' => string 'Normal' (length=6)
          private 'promo' => null
          private 'tariff' => string 'F0' (length=2)
          private 'campaign' => string 'FTEST' (length=5)
          private 'beginDate' => 
            object(DateTime)[2495]
              ...
          private 'endDate' => 
            object(DateTime)[2496]
              ...
          private 'catalogSalesForce' => 
            object(Doctrine\ORM\PersistentCollection)[2473]
              ...
          private 'forces' => null
          private 'levels' => 
            object(Doctrine\ORM\PersistentCollection)[2459]
              ...
      private 'models' => 
        object(Doctrine\Common\Collections\ArrayCollection)[2708]
          private 'elements' => 
            array (size=1)
              ...
  private 'catalog' => null
  private 'model' => null
  private 'beginDate' => 
    object(DateTime)[2722]
      public 'date' => string '1905-05-05 00:00:00.000000' (length=26)
      public 'timezone_type' => int 1
      public 'timezone' => string '+00:00' (length=6)
  private 'endDate' => 
    object(DateTime)[2772]
      public 'date' => string '1905-05-05 00:00:00.000000' (length=26)
      public 'timezone_type' => int 1
      public 'timezone' => string '+00:00' (length=6)

请求详细信息:

"START TRANSACTION"
Parameters: { } 

INSERT INTO catalogue_niveau (Niveau_ID, Catalogue_Code, Niveau_Nom, Parent_ID, Niveau_Ordre) VALUES (?, ?, ?, ?, ?)
Parameters: { 1: NIV_1, 2: CATEST, 3: genou, 4: null, 5: 0 } 

INSERT INTO catalogue_rayon (Modele_Code, Catalogue_Code, Niveau_ID, Modele_Ordre, Date_Debut, Date_Fin) VALUES (?, ?, ?, ?, ?, ?)
Parameters: { 1: null, 2: null, 3: NIV_1, 4: 0, 5: '1905-05-05 00:00:00', 6: '1905-05-05 00:00:00' } 

我不明白为什么模型值丢失了......请帮忙!

PS:如果我在树中创建只有级别,没有模型,则会将级别保存在数据库中。没错。所以,我的模型有问题。

0 个答案:

没有答案