2013-08-10 25 views
15

Prima di tutto, non sono sicuro che si tratti di un problema di Sonata o di Symfony2, questa è la prima volta che lavoro con i moduli Sf2 per modificare un relazione.Arresta SonataAdmin/Symfony2 dalla creazione di oggetti vuoti con gli amministratori incorporati sonata_type_admin

Ecco il problema:

Ho due classi, chiamiamoli i favoriti anziani: Car e Wheel. L'auto ha una relazione uno-a-uno opzionale con Wheel (è per l'esempio, seguitela ...). Ho impostato SonataAdmin con una classe CarAdmin che incorpora unutilizzando sonata_type_admin e provo a creare un'auto senza immettere dati per Wheel.

Tuttavia, su submit (da qualche parte in $ form-> bind()/$ form-> submit() per quanto posso rintracciare) Symfony e/o Sonata sta creando un'istanza di una ruota e cercando di mantenerla (con tutto i suoi valori come null). Poiché la ruota presenta alcuni vincoli non nulli, ciò genera un'eccezione DBALE che lamenta che non è possibile INSERIRE una ruota con vla null.

Questo è cattivo e vorrei fermarlo. Se non inserisco alcun dettaglio per la ruota, non voglio che una ruota fantasma minacci il mio codice e il mio database. Quello che mi aspetto è che se non inserisco alcun dato non c'è nulla da inserire/persistere quindi è lasciato in pace. Ma questo non è quello che sta succedendo ... qualche idea su come domare questo in qualcosa di sensato?


Ecco la versione lunga, con blocchi di codice e tutto il resto:

Le definizioni ORM prima:

# MyNS\MyBundle\Resources\Config\Doctrine\Car.orm.yml 
MyNS\MyBundle\Entity\Car: 
    type: entity 
    repositoryClass: MyNS\MyBundle\Entity\Repositories\CarRepository 
    table: test_cars 
    id: 
    id: 
     type:      integer 
     generator:    { strategy: AUTO } 
    fields: 
    color: 
     type:      string 
     length:     50 
    owner: 
     type:      string 
     length:     50 
     nullable:     true 
    oneToOne: 
    leftFrontWheel: 
     targetEntity:    Wheel 
     cascade:     [ persist ] 
     joinColumn: 
     name:     leftFrontWheelId 
     referencedColumnName: id 


# MyNS\MyBundle\Resources\Config\Doctrine\Wheel.orm.yml 
MyNS\MyBundle\Entity\Wheel: 
    type: entity 
    repositoryClass: MyNS\MyBundle\Entity\Repositories\WheelRepository 
    table: test_wheels 
    id: 
    id: 
     type:      integer 
     generator:    { strategy: AUTO } 
    fields: 
    diameter: 
     type:      integer 
     length:     5 

Poi le classi SonataAdmin:

namespace MyNS\MyBundle\Admin 

use ... 

class CarAdmin extends Admin 
{ 
    protected function configureFormFields(FormMapper $formMapper) 
    { 
     $formMapper 
      ->add('color',    null, array('required' => true)) 
      ->add('owner',    null, array('required' => false)) 
      ->add('leftFrontWheel',  'sonata_type_admin', array('delete' => false)) 
     ; 
    } 

    protected function configureListFields(ListMapper $listMapper) { ... } 
} 

e

namespace MyNS\MyBundle\Admin; 

use ... 

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

    protected function configureListFields(ListMapper $listMapper) { ... } 
} 

e, infine, le voci admin.yml:

services: 
    sonata.admin.car: 
     class: MyNS\MyBundle\Admin\CarAdmin 
     tags: 
      - { name: sonata.admin, manager_type: orm, label: "Car" } 
     arguments: 
      - ~ 
      - MyNS\MyBundle\Entity\Car 
      - 'SonataAdminBundle:CRUD' 
     calls: 
      - [ setTranslationDomain, [MyNS\MyBundle]] 
    sonata.admin.wheel: 
     class: MyNS\MyBundle\Admin\WheelAdmin 
     tags: 
      - { name: sonata.admin, manager_type: orm, label: "Wheel" } 
     arguments: 
      - ~ 
      - MyNS\MyBundle\Entity\Wheel 
      - 'SonataAdminBundle:CRUD' 
     calls: 
      - [ setTranslationDomain, [MyNS\MyBundle]] 

atteso/comportamento richiesto:

  • visualizzare un modulo con tre campi:

    • car.color (richiesto)
    • car.owner (opzionale)
    • car.wheel.diameter (opzionale)
  • se car.wheel.diameter viene lasciato vuoto quindi non ruota deve essere creato e test_cars.leftFrontWheelId dovrebbe rimanere null nel database

  • se car.wheel.diametro viene inserita poi una rotella dovrebbe essere creato e collegato al Car (questo sembra funzionare bene con la configurazione esistente)

La domanda: Come faccio ad avere questo sistema si comporti come sopra?

+4

Penso di essere riuscito a creare una soluzione alternativa per questo, ma ci deve essere un modo migliore! (In CarAdmin ho aggiunto i metodi prePersist() e preUpdate() che controllano se a una ruota manca il diametro. Se è (cioè non è valido) allora '' $ car-> setLeftFrontWheel (null) '' cancella la relazione e smette di cercare di mantenere una ruota vuota.) – caponica

+0

Sonata è soggetta a bug che appaiono casualmente, ma ragionevolmente spesso. Prova a provare una nuova versione, perché il comportamento che descrivi non si verifica nella mia (vecchia) versione. In bocca al lupo! – likeitlikeit

+0

Bene, sto usando la versione più recente (dev-master) di SonataAdmin quindi non penso che ce ne sia una nuova :) Non ancora abbastanza esperto con Symfony per sapere se si tratta di un problema di Symfony o di Sonata, quando so per certo che solleverò la questione appropriata. – caponica

risposta

0

Potrebbe essere causato da uno 'required' => false mancante, no?

protected function configureFormFields(FormMapper $formMapper) { 
    $formMapper 
     ->add('color',    null, array('required' => true)) 
     ->add('owner',    null, array('required' => false)) 
     ->add('leftFrontWheel',  'sonata_type_admin', array('required' => false, 'delete' => false)) 
    ; 
} 
0

Cambia vostro campo Wheel modulo per qualcosa di simile:

$formMapper 
    // ... 
    ->add('leftFrontWheel', 'sonata_type_admin', array(
     'delete' => false, 
     'by_reference => true, 
     'required' => false, 
    )) 
    // ... 

Vedi by_referencedocumentation

Se non è sufficiente utilizzare un gancio prePersist nel vostro genitore classe di amministratore e gestire quale campo di memorizzare . Ad esempio:

// Fire on submit, before the object persisting 
public function prePersist($object) 
    if ($wheel = $object->getLeftFrontWheel()) { 
     if (!$wheel->getYourNonNullableField()) { 
      $object->setLefTFrontWheel(null); 
     } 
    } 
}