0
votes

I'm struggling to get a simple form working in a Symfony 1.4 backend module.

The idea is to create an embedded form (One to many relation, Inschrijvingen -> Danser). Each embedded form has one many to many relation. (Lessen) The forms displays correctly but doesn't save the lessen_list. (Many to many relation)

The DanserForm I'm embedding does work on its own. But doesn't work when embedding this into InschrijvingenForm.

I tried the following tutorial. but that didn't work for me: http://inluck.net/Blog/Many-to-many-relations-in-embedded-form-in-Symfony-1_4

My schema.yml

Inschrijving:
  actAs:
    Timestampable: ~
  columns:
    voornaam: { type: string(100), notnull: true, minlength: 2 }
    achternaam: { type: string(100), notnull: true, minlength: 2 }
    straat: { type: string(100), notnull: true, minlength: 2 }
    nr: { type: string(5) }
    postcode: { type: int(9), notnull: true, minlength: 4 }
    gemeente: { type: string(100), notnull: true, minlength: 2 }
    land: { type: string(2), notnull: true, default: 'BE' }
    telefoon: { type: string(100), notnull: true, minlength: 8 }
    email:  { type: string(100), notnull: true, minlength: 4, nospace: true }
    gestructureerde_mededeling: { type: string(20) }
    interne_opmerking: { type: string(1000) }
    gebruiker_id: { type: int(9) }
    is_gearchiveerd:  { type: boolean, default:false }
  relations:
    Danser:
      local: id
      foreign: inschrijving_id
      type: many
      onDelete: CASCADE
      foreignAlias: Dansers

Danser:
  columns:
    voornaam: { type: string(100), notnull: true, minlength: 2 }
    achternaam: { type: string(100), notnull: true, minlength: 2 }
    geboortedatum: { type: date(), notnull: true }
    email:  { type: string(100), notnull: true, minlength: 4, nospace: true }
    medische_opmerkingen: { type: string(2000) }
    inschrijving_id: { type: int(9), notnull: true }
    is_verzekering_ok: { type: boolean, default:false }
  relations:
    Inschrijving:
      local: inschrijving_id
      foreign: id
      type: one
      onDelete: CASCADE
      foreignAlias: Inschrijvingen
    Lessen:
      class:              Lessen
      refClass:           LessenVanDanser
      local:              danser_id
      foreign:            lessen_id

LessenVanDanser:
  columns:
    lessen_id:             { primary: true, type: integer }
    danser_id:            { primary: true, type: integer }
  relations:
    Lessen:                { onDelete: CASCADE, local: lessen_id, foreign: id ,class: Lessen}
    Danser:          { onDelete: CASCADE, local: danser_id, foreign: id, class: Danser }

Lessen:
  actAs:
    Timestampable: ~
  columns:
    naam: { type: string(100), notnull: true, minlength: 2 }
    leeftijd_van: { type: string(3) }
    leeftijd_tot: { type: string(3) }
    dag:  { type: enum(),values: ['Maandag','Dinsdag','Woensdag','Donderdag','Vrijdag','Zaterdag'],default: Maandag }
    van: { type: time() }
    tot: { type: time() }
    beschrijving: { type: string(5000) }
    max_aantal_deelnemers: { type: int(9) }    
    lesgever_id: { type: int(9), notnull: true }
    locatie_id: { type: int(9), notnull: true }
    lessenreeks_id: { type: int(9), notnull: true }
  relations:
    Danser:
      class:              Danser
      refClass:           LessenVanDanser
      local:              lessen_id
      foreign:            danser_id

InschrijvingenForm.class.php

<?php
class InschrijvingForm extends BaseInschrijvingForm
{
  public function configure()
  {
      unset(
      $this['created_at'], $this['updated_at'],$this['gestructureerde_mededeling']
      );

      $choices = CountryCodes::get();
      $this->widgetSchema['land'] = new sfWidgetFormChoice(array('choices' => $choices));

      $choice_keys = array();
      foreach ($choices as $choice) {
          $choice_keys = array_merge($choice_keys,array_keys($choice));
      }

      $this->setValidator('land', new sfValidatorChoice(array('choices'=>$choice_keys,'required'=>true)));
      $this->setDefault('land','BE');

      //Many to many relations
      $data = $this->getObject();
      $data_count = @count($_POST['inschrijving']['danser']);
      $data_count = $data_count > 0 ? $data_count:1;

        $subForm = new sfForm();

        for ($i = 0; $i < $data_count; $i++){
            if($data['Danser'][$i]){
                $subForm->embedForm($i, new DanserForm($data['Danser'][$i]));
            }else{
                $subForm->embedForm($i, new DanserForm());
            }
        }
        $this->embedForm('danser', $subForm);
  }

  public function saveEmbeddedForms($con = null, $forms = null) {
        if (null === $forms){
            $en_forms = $this->getEmbeddedForm('danser');

            foreach ($en_forms as $name => $form){
                if ($form instanceof sfFormObject){
                    $form->getObject()->setInschrijvingId($this->getObject()->getId());
                    $form->getObject()->save($con);
                }
            }
        }
          return parent::saveEmbeddedForms($con, $forms);
    }
}

DanserForm.class.php

<?php

/**
 * Danser form.
 *
 * @package    dansschool
 * @subpackage form
 * @author     Ilias Barthelemy
 * @version    SVN: $Id: sfDoctrineFormTemplate.php 23810 2009-11-12 11:07:44Z Kris.Wallsmith $
 */
class DanserForm extends BaseDanserForm
{
  public function configure()
  {
      unset(
      $this['inschrijving_id']
      );

      $years = range(((int) date('Y'))-70, ((int) date('Y'))-3);
      $years_list = array_combine($years, $years);

      //$this->setWidget('geboortedatum', new sfWidgetFormDate(array('format' => '%day%/%month%/%year%','years' => $years_list)));
      $user = sfContext::getInstance()->getUser();
      $inschrijving = $user->getAttribute( 'dansers_form.inschrijving',null,'admin_module' );

      if(!is_null($inschrijving)){
          $this->widgetSchema['inschrijving_id']->setDefault($inschrijving['inschrijving_id']);
      }

      $this->setWidget('geboortedatum',new sfWidgetFormJQueryDate(array(
        'date_widget' => new sfWidgetFormDate(array('format' => '%day%/%month%/%year%','years' => $years_list))
      )));

      $this->widgetSchema['lessen_list'] = new sfWidgetFormDoctrineChoice(array(
      'multiple' => true,
      'model' => 'Lessen',
      'renderer_class' => 'sfWidgetFormSelectDoubleList',
      'renderer_options' => array(
        'label_unassociated' => 'Beschikbare lessen',
        'label_associated' => 'Actief'
    )));

  }

    public function bind(array $taintedValues = null, array $taintedFiles = null)
    {
        if($this->getObject()->getId()>0){
            $taintedValues['id']=$this->getObject()->getId();
            $this->isNew = false;
        }
        parent::bind($taintedValues, $taintedFiles);
    }
}
1

1 Answers

0
votes

Is lessen_list a field in your BaseDanserForm and BaseInchrijvingForm class? Symfony usually provides a widget for managing many-to-many relationships like the one you have in your base class. I just thought it would be named lessenvandanser_list.

I don't think you're embedding your Danser forms correctly. Try something similar to what I've done below, where you assign the Danser objects to the Inschrijving object, before instantiating the embedded forms with those Danser objects. What I've done is create a new DanserCollectionForm class to handle this logic (see below).

// lib\form\DanserCollectionForm.class.php
class DanserCollectionForm extends sfForm
{
    if (!$inschrijving = $this->getOption('inschrijving')) {
        throw new InvalidArgumentException(sprintf("%s must be provided with inschrijving object", get_class($this)));
    }

    // Get all danser objects associated with this inschrijving
    $dansers = $inschrijving->getDansers();

    // If no dansers, then creat a new danser
    if (!$dansers) {
        $danser = new Danser();
        // Assign the danser to the inschrijving
        $danser->Inschrijving = $inschrijving;
        $dansers = array($danser);
    }

    // Embed Danser forms
    foreach ($dansers as $key => $danser) {
        $this->embedForm($key, new DanserForm($danser));
    }
}

Then in your InschrijvingForm class

// lib\form\InschrijvingForm.class.php 
class InschrijvingForm extends BaseInschrijvingForm
{
    public function configure()
    {
        unset(
            $this['created_at'],
            $this['updated_at'],
            $this['gestructureerde_mededeling']
        );

        $choices = CountryCodes::get();
        $this->widgetSchema['land'] = new sfWidgetFormChoice(array('choices' => $choices));

        $choice_keys = array();
        foreach ($choices as $choice) {
                $choice_keys = array_merge($choice_keys,array_keys($choice));
        }

        $this->setValidator('land', new sfValidatorChoice(array('choices' => $choice_keys, 'required' => true)));
        $this->setDefault('land','BE');

        $collectionForm = new DanserCollectionForm(null, array('inschrijving' => $this->getObject()));
        $this->embedForm('dansers', $collectionForm);
    }

    public function saveEmbeddedForms($con = null, $forms = null)
    {
        if (null === $forms) {
            $dansers = $this->getValue('dansers');
            $forms = $this->embeddedForms;

            foreach ($this->embeddedForms['dansers'] as $name => $form) {
                $deleteDanser = // Put logic of whether to ignore/delete danser forms here
                if ($deleteDanser) {
                    unset($forms['dansers'][$name]);
                    $form->getObject()->delete();
                }
            }
        }

        return parent::saveEmbeddedForms($con, $forms);
    }
}