lundi 13 avril 2015

Symfony2: Form with image upload widgets creates new instances instead of keeping same image objects

I am still having issues with that Article form I have been asking about in the past few months. So to make it clear, my website articles are automatically created at beginning using DataFixtures. This is why I am only using an edit/update form. That ArticleType is based on Article object. It's got a complex three-tiered multi-nested collection in it.



$article->getComponents->getSections->getLinks()


$article got two child image objects that are instance of Picture entity Each $section has an $image attribute which is an instance of Image entity and each $link has an $image which is an instance of LinkImage All image entities extend an entity called File. The code to handle uploads and such is pretty classical. Inspired by the code provided on the Symfony website. A major difference is however that the Controller takes care of setting the folder names and more importantly it takes care of deleting old files when an image is replaced by a new one using the file upload inputs.


Everything is almost working as expected except that every time I update my article and hit "submit" new Image entries are saved into DataBase instead of updating an existing entry or living the existing entry alone because I am not changing anything in the form before hitting "submit"


I have tested the doctrine callbacks used in my "File" entity class definition file and it's clear that, as to be expected, the @preUpdate and postUpdate events are not guilty. Here the prePersist and postPersist events are called. I have no clue why new objects are persisted in database. My guess would be than since sections and links are in a collection and added dynamically they need to be persisted at creation. And maybe my form might persist this kind of thing systematically. However my form does not add new sections links and components on each flush. This part is working fine. Either the code in my controller that handles image functionalities somewhat does something wrong and create new instance or maybe there is something wrong with my doctrine annotations. But nowhere in my controller do I use the words "new" (except for ArrayCollections) or "persist" so I don't think it's the first option. Could be options in the formtype file that does it wrong.. I am going to post controller Code and more if requested.



Private function updateArticle(Request $request, $country, $topic)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('CountryBundle:Country')->getCountryAndArticle($country, $topic);

if (!$entity instanceof Country) {

throw new EntityNotFoundException();
}
$article = $entity->getArticle($topic);

$group = $em->getRepository('SiteBundle:LinkGroup')->findOneByName($topic);
if (!$group instanceof LinkGroup){
throw new \Exception($topic);
}

// On met en memoire les paths des anciens fichiers images
$oldFiles = new ArrayCollection();
foreach ($article->getPictures() as $picture)
{
if ($img = $picture->getImage()){
$oldFiles[] = $img->getAbsolutePath();
}
}
foreach ($article->getComponents() as $col)
{
foreach ($col->getSections() as $selection)
{
if($img = $selection->getImage()){
$oldFiles[] = $img->getAbsolutePath();
}
foreach ($selection->getLinks() as $link)
{
if ($img = $link->getImage()){
$oldFiles->add($img->getAbsolutePath()) ;
}
}
}
}

$editForm = $this->createEditArticleForm($article, $entity, $topic);
$editForm->handleRequest($request);

if ($editForm->isValid()) {

foreach($article->getPictures() as $picture){
if ($picture instanceof Picture and $picture->getImage()){
if (!$picture->getImage()->getFolder()){ // we set folder only once
$picture->getImage()->setFolder('country/'.$country.'/'.$topic);
}
}
}

foreach($article->getComponents() as $col){
foreach($col->getSections() as $section){
if ($section instanceof Section && $section->getImage()){

if ( !$section->getImage()->getFolder()){
$section->getImage()->setFolder('country/'.$country.'/'.$topic);
}
}
foreach($section->getLinks() as $link){
$link->setGroup($group);

if($link instanceof SectionLink && $link->getImage()){

if (!$link->getImage()->getFolder()){
$link->getImage()->setFolder('country/'.$country);
}
}
}
}
}

$em->flush();

// on compare les anciens fichiers images aux nouveaux et on supprime ceux qui ne sont plus utilises
$files = new ArrayCollection();
foreach($article->getPictures() as $picture){
if ($picture instanceof Picture and $picture->getImage()){
$files[] = $picture->getImage()->getAbsolutePath();
}
}
foreach($article->getComponents() as $col){
foreach($col->getSections() as $section){
if ($section instanceof Section && $section->getImage()){
$files->add($section->getImage()->getAbsolutePath());
}
foreach($section->getLinks() as $link){
if($link instanceof SectionLink && $link->getImage()){
$files->add($link->getImage()->getAbsolutePath());
}
}
}
}
foreach ($oldFiles as $file)
{
if (false === $files->contains($file)){
if (file_exists($file)){
unlink($file);
}
}
}

return $this->redirect($this->generateUrl($topic.'_show', array('country' => $entity)));
}

return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
);
}


Now the annotations for $image:



/**
* @var Image
*
* @ORM\OneToOne(targetEntity="AnyRoutes\SiteBundle\Entity\Image", cascade={"persist", "remove"})
*/
private $image;

Aucun commentaire:

Enregistrer un commentaire