0
votes

Experiencing some serious problems in getting a OneToMany relationship to work. The error happens when trying to add "Children" to Beauties in Sonata Admin.

Using:

Symfony2 Doctrine Sonata Admin

Been trying to follow the guide at: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-many-bidirectional

and

http://sonata-project.org/bundles/doctrine-orm-admin/2-2/doc/reference/form_field_definition.html

Error:

"CRITICAL - Uncaught PHP Exception Doctrine\ORM\ORMInvalidArgumentException: "A new entity was found through the relationship 'Beautify\BeautiesBundle\Entity\Beauty#children' that was not configured to cascade persist operations for entity: Beautify\BeautiesBundle\Entity\Children@000000000eff91d5000000017f8ca53b. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'Beautify\BeautiesBundle\Entity\Children#__toString()' to get a clue." at /Users/gmf/symfony/vendor/doctrine/orm/lib/Doctrine/ORM/ORMInvalidArgumentException.php line 91 "

. .

BeautyAdmin.php


<?php
// src/Beautify/BeautiesBundle/Admin/BeautyAdmin.php

namespace Beautify\BeautiesBundle\Admin;

use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;

use Knp\Menu\ItemInterface as MenuItemInterface;

use Beautify\CategoryBundle\Entity\Category;
use Beautify\CategoryBundle\Entity\Children;

class BeautyAdmin extends Admin
{
    // Fields to be shown on create/edit forms
    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
            ->with('General')
                ->add('name', 'text', array('label' => 'Name'))
                ->add('content', 'textarea', array('label' => 'Content'))
                ->add('imageFile', 'file', array('label' => 'Image file', 'required' => false))
            ->end()
            ->with('Category')
                ->add('category', 'sonata_type_model', array('expanded' => true))
            ->end()
            ->with('Children')

                ->add('children', 'sonata_type_collection', array(), array(
                'edit' => 'inline',
                'inline' => 'table',
                'sortable'  => 'position'
            ))

            ->end()




        ;
    }



    // Fields to be shown on filter forms
    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    {
        $datagridMapper
            ->add('name')
            ->add('content')
            ->add('category')


        ;
    }

    // Fields to be shown on lists
    protected function configureListFields(ListMapper $listMapper)
    {
        $listMapper
            ->addIdentifier('name')
            ->add('content')
            ->add('category')
            ->add('imageName')
            ->add('_action', 'actions', array(
                'actions' => array(
                    'show' => array(),
                    'edit' => array(),
                    'delete' => array(),
                )
            ))
        ;
    }
}

Beauty.php Entity


<?php

// src/Beautify/BeautiesBundle/Entity/Beauty.php

namespace Beautify\BeautiesBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Doctrine\Common\Collections\ArrayCollection;

/** 
* @ORM\Entity
* @ORM\Table(name="beauties")
* @ORM\HasLifecycleCallbacks
* @Vich\Uploadable
*/

 class Beauty
 {

     /**
     * @ORM\OneToMany(targetEntity="Children", mappedBy="beauties")
     **/
    private $children;

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





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

    /**
    * @ORM\Column(type="string", length=100)
    */

    protected $name;

    /**
    * @ORM\Column(type="text")
    */

    protected $content;  



    /**
     * @Vich\UploadableField(mapping="beauty_image", fileNameProperty="imageName")
     * @var File $imageFile
     */
    protected $imageFile;

    /**
     * @ORM\Column(type="string", length=255, nullable=true, name="image_name")
     * @var string $imageName
     */
    protected $imageName;



    /**
    * @ORM\ManyToOne(targetEntity="Category", inversedBy="beauties")
    * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
    */
    protected $category;





/**
     * If manually uploading a file (i.e. not using Symfony Form) ensure an instance
     * of 'UploadedFile' is injected into this setter to trigger the  update. If this
     * bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
     * must be able to accept an instance of 'File' as the bundle will inject one here
     * during Doctrine hydration.
     *
     * @param File|\Symfony\Component\HttpFoundation\File\UploadedFile
     */
    public function setImageFile(File $image = null)
    {
        $this->imageFile = $image;

        if ($image) {
            // It is required that at least one field changes if you are using doctrine
            // otherwise the event listeners won't be called and the file is lost
            $this->updatedAt = new \DateTime('now');
        }
    }

    /**
     * @return File
     */
    public function getImageFile()
    {
        return $this->imageFile;
    }

    /**
     * @param string $imageName
     */
    public function setImageName($imageName)
    {
        $this->imageName = $imageName;
    }

    /**
     * @return string
     */
    public function getImageName()
    {
        return $this->imageName;
    }






    public function __toString()
    {
    return ($this->getName()) ? : '';
    }

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

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

        return $this;
    }

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

    /**
     * Set content
     *
     * @param string $content
     * @return Beauty
     */
    public function setContent($content)
    {
        $this->content = $content;

        return $this;
    }

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

    /**
     * Set category
     *
     * @param \Beautify\BeautiesBundle\Entity\Category $category
     * @return Beauty
     */
    public function setCategory(\Beautify\BeautiesBundle\Entity\Category $category = null)
    {
        $this->category = $category;

        return $this;
    }

    /**
     * Get category
     *
     * @return \Beautify\BeautiesBundle\Entity\Category 
     */
    public function getCategory()
    {
        return $this->category;
    }



    /**
     * Set children
     *
     * @param \Beautify\BeautiesBundle\Entity\Children $children
     * @return Beauty
     */
    public function setChildren(\Beautify\BeautiesBundle\Entity\Children $children = null)
    {
        $this->children = $children;

        return $this;
    }

    /**
     * Get children
     *
     * @return \Beautify\BeautiesBundle\Entity\Children 
     */
    public function getChildren()
    {
        return $this->children;
    }




    /**
     * Add children
     *
     * @param \Beautify\BeautiesBundle\Entity\Children $children
     * @return Beauty
     */
    public function addChild(\Beautify\BeautiesBundle\Entity\Children $children)
    {
        $this->children[] = $children;

        return $this;
    }

    /**
     * Remove children
     *
     * @param \Beautify\BeautiesBundle\Entity\Children $children
     */
    public function removeChild(\Beautify\BeautiesBundle\Entity\Children $children)
    {
        $this->children->removeElement($children);
    }
}

Children.php Entity


<?php



namespace Beautify\BeautiesBundle\Entity;

use Doctrine\ORM\Mapping as ORM;


/**
 * Children
 *
* @ORM\Table(name="children")
 * @ORM\Entity
 */
class Children
{

    /**
     * @ORM\ManyToOne(targetEntity="Beauty", inversedBy="children")
     * @ORM\JoinColumn(name="beauty_id", referencedColumnName="id")
     **/

    private $beauties;


    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

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

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

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


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

    /**
     * Set image
     *
     * @param string $image
     * @return Children
     */
    public function setImage($image)
    {
        $this->image = $image;

        return $this;
    }

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

    /**
     * Set content
     *
     * @param string $content
     * @return Children
     */
    public function setContent($content)
    {
        $this->content = $content;

        return $this;
    }

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

    /**
     * Set priority
     *
     * @param integer $priority
     * @return Children
     */
    public function setPriority($priority)
    {
        $this->priority = $priority;

        return $this;
    }

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

    /**
     * Set parentId
     *
     * @param integer $parentId
     * @return Children
     */
    public function setParentId($parentId)
    {
        $this->parentId = $parentId;

        return $this;
    }

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





    /**
     * Set beauties
     *
     * @param \Beautify\BeautiesBundle\Entity\Beauty $beauties
     * @return Children
     */
    public function setBeauties(\Beautify\BeautiesBundle\Entity\Beauty $beauties = null)
    {
        $this->beauties = $beauties;

        return $this;
    }

    /**
     * Get beauties
     *
     * @return \Beautify\BeautiesBundle\Entity\Beauty 
     */
    public function getBeauties()
    {
        return $this->beauties;
    }
}

Very thankful for any help...

1

1 Answers

2
votes

The error says it all. You need to add cascade="persist" to the children property.

/**
 * @ORM\OneToMany(targetEntity="Children", mappedBy="beauties", cascade={"persist"})
 **/
private $children;

See http://doctrine-orm.readthedocs.org/en/latest/reference/working-with-associations.html#transitive-persistence-cascade-operations