2013-06-07 16 views
8

Ho un problema con SonataAdminBunle in combinazione con symfony 2.2. Ho un progetto un'entità e un'entità ProjectImage e specificata una relazione uno-a-molti tra questi due in questo modo:Sonata Admin Bundle Relazione uno-a-molti che non salva ID esterno

class Project 
{ 
    /** 
    * @ORM\OneToMany(targetEntity="ProjectImage", mappedBy="project", cascade={"all"}, orphanRemoval=true) 
    */ 
    private $images; 
} 

class ProjectImage 
{ 

    /** 
    * @ORM\ManyToOne(targetEntity="Project", inversedBy="images") 
    * @ORM\JoinColumn(name="project_id", referencedColumnName="id") 
    */ 
    private $project; 
} 

Ho configurato il ProjectAdmin e ProjectImageAdmin:

class ProjectAdmin extends Admin 
{ 
    protected function configureFormFields(FormMapper $formMapper) 
    { 
     $formMapper 
      ->add('title') 
      ->add('website') 
      ->add('description', 'textarea') 
      ->add('year') 
      ->add('tags') 
      ->add('images', 'sonata_type_collection', array(
          'by_reference' => false 
      ), array(
          'edit' => 'inline', 
          'inline' => 'table', 
          'sortable' => 'id', 
      )) 
      ; 
    } 
} 

class ProjectImageAdmin extends Admin 
{ 
    protected function configureFormFields(FormMapper $formMapper) 
    { 
     $formMapper 
      ->add('file', 'file', array(
          'required' => false 
      )) 
      ; 
    } 
} 

Il problema è che nella tabella project_image nel database non viene salvato project_id, mentre tutti gli altri dati sono e anche l'immagine viene salvata. Non ho trovato una risposta funzionante da nessun'altra parte.

+0

Hai provato a rimuovere by_reference? –

+0

Sì, l'ho provato. Purtroppo nessun risultato. –

+0

Sono presenti i metodi setImages, addImage, removeImage e getImages nell'entità Progetto? –

risposta

23

anche se estranei, sarei leggermente tweak il vostro uno-a-molti nota:

class Project 
{ 
    /** 
    * @ORM\OneToMany(targetEntity="ProjectImage", mappedBy="project", cascade={"persist"}, orphanRemoval=true) 
    * @ORM\OrderBy({"id" = "ASC"}) 
    */ 
    private $images; 
} 

Torna in pista, le annotazioni e le forme Sonata Admin guardare bene, quindi sono abbastanza sicuro che ti manca uno di questi metodi nel progetto classe di entità:

public function __construct() { 
    $this->images = new \Doctrine\Common\Collections\ArrayCollection(); 
} 

public function setImages($images) 
{ 
    if (count($images) > 0) { 
     foreach ($images as $i) { 
      $this->addImage($i); 
     } 
    } 

    return $this; 
} 

public function addImage(\Acme\YourBundle\Entity\ProjectImage $image) 
{ 
    $image->setProject($this); 

    $this->images->add($image); 
} 

public function removeImage(\Acme\YourBundle\Entity\ProjectImage $image) 
{ 
    $this->images->removeElement($image); 
} 

public function getImages() 
{ 
    return $this->Images; 
} 

E nella classe Admin:

public function prePersist($project) 
{ 
    $this->preUpdate($project); 
} 

public function preUpdate($project) 
{ 
    $project->setImages($project->getImages()); 
} 
+0

Questo mi ha salvato da un forte mal di testa ... grazie mille! –

+0

Questo pacchetto Sonata diventa un po 'peloso. Il suggerimento 'prePersist()' | 'preUpdate()' mi ha aiutato ... ma ho dovuto fare qualcosa di leggermente diverso. Vedere il succo - https://gist.github.com/justinpfister/9634619 – JustinP

+1

Forse dovresti farlo 'foreach' in' setEntries', invece? Sembra strano farlo in 'preUpdate' –

1

Passa attraverso questo link http://sonata-project.org/bundles/doctrine-orm-admin/master/doc/reference/form_field_definition.html#advanced-usage-many-to-one questo collegamento ti aiuterà molto sulla mappatura delle associazioni in bundle di amministrazione sonata.

+4

Si noti che [risposte solo per collegamento] (http://meta.stackoverflow.com/tags/link-only-answers/info) sono scoraggiate, quindi le risposte dovrebbero essere la fine- punto di una ricerca di una soluzione (rispetto a un'altra sosta di riferimenti, che tendono a diventare obsoleti nel tempo). Si prega di considerare l'aggiunta di una sinossi autonoma qui, mantenendo il collegamento come riferimento. – kleopatra

+0

Grazie a kleopatra per aver segnalato il mio errore. Mi prenderò cura del tuo suggerimento la prossima volta. –

0

Un modo per risolvere il problema era impostare manualmente tutte le associazioni del lato inverso tramite un gestore di modelli di Sonata personalizzato.

<?php 

namespace Sample\AdminBundle\Model; 

class ModelManager extends \Sonata\DoctrineORMAdminBundle\Model\ModelManager 
{ 
    /** 
    * {@inheritdoc} 
    */ 
    public function create($object) 
    { 
     try { 
      $entityManager = $this->getEntityManager($object); 
      $entityManager->persist($object); 
      $entityManager->flush(); 
      $this->persistAssociations($object); 
     } catch (\PDOException $e) { 
      throw new ModelManagerException('', 0, $e); 
     } 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function update($object) 
    {  
     try { 
      $entityManager = $this->getEntityManager($object); 
      $entityManager->persist($object); 
      $entityManager->flush(); 
      $this->persistAssociations($object); 
     } catch (\PDOException $e) { 
      throw new ModelManagerException('', 0, $e); 
     } 
    } 

    /** 
    * Persist owning side associations 
    */ 
    public function persistAssociations($object) 
    {  
     $associations = $this 
      ->getMetadata(get_class($object)) 
      ->getAssociationMappings(); 

     if ($associations) { 
      $entityManager = $this->getEntityManager($object); 

      foreach ($associations as $field => $mapping) { 
       if ($mapping['isOwningSide'] == false) { 
        if ($owningObjects = $object->{'get' . ucfirst($mapping['fieldName'])}()) { 
         foreach ($owningObjects as $owningObject) { 
          $owningObject->{'set' . ucfirst($mapping['mappedBy']) }($object); 
          $entityManager->persist($owningObject); 
         } 
         $entityManager->flush(); 
        } 
       } 
      } 
     } 
    } 
} 

Assicurarsi di definire questo come un nuovo servizio nel file services.yml:

services: 
    sample.model.manager: 
     class: Sample\AdminBundle\Model\ModelManager 
     arguments: [@doctrine] 


    sample.admin.business: 
     class: Sample\AdminBundle\Admin\BusinessAdmin 
     tags: 
      - { name: sonata.admin, manager_type: orm, group: "Venues", label: "Venue" } 
     arguments: [~, Sample\AppBundle\Entity\Business, ~] 
     calls: 
      - [ setContainer, [@service_container]] 
      - [ setModelManager, [@sample.model.manager]] 
2

È ca farlo direttamente nella funzione PreUpdate

public function prePersist($societate) 
{ 
    $this->preUpdate($societate); 
} 

public function preUpdate($societate) 
{ 
    $conturi = $societate->getConturi(); 
    if (count($conturi) > 0) { 
     foreach ($conturi as $cont) { 
      $cont->setSocietate($societate); 
     } 
    } 
} 
+0

Penso che questa dovrebbe essere la risposta corretta. – StockBreak

5

Dal momento che alcune cose hanno cambiato con la raccolta di moduli Symfony ora aggiungendo il addChild() e removeChild() con il by_reference l'opzione impostata su false interrompe automaticamente la raccolta e imposta l'ID sul lato inverso come previsto.

Ecco una versione funzionante completa: https://gist.github.com/webdevilopers/1a01eb8c7a8290d0b951

protected function configureFormFields(FormMapper $formMapper) 
{ 
    $formMapper 
     ->add('childs', 'sonata_type_collection', array(
      'by_reference' => false 
     ), array(
      'edit' => 'inline', 
      'inline' => 'table' 
     )) 
    ; 
} 

Il addChild) Metodo (deve contenere il setter per il genitore sul bambino:

public function addChild($child) 
{ 
    $child->setParent($this); // !important 
    $this->childs[] = $child; 
    return $this; 
} 
0
public function prePersist($user) 
{ 
    $this->preUpdate($user); 
} 

public function preUpdate($user) 
{ 
    $user->setProperties($user->getProperties()); 
} 

Questo ha perfettamente risolto il problema per me grazie!

Problemi correlati