0
votes

I've this schema.yml:

SdrivingMaquina:
  connection: doctrine
  tableName: sdriving_maquina
  actAs: [Timestampable]
  columns:
    idmaquina: { type: integer(8), fixed: false, unsigned: false, primary: true, autoincrement: true }
    idempresa: { type: integer(4), fixed: false, unsigned: true, primary: true, autoincrement: false }
    patente: { type: string(12), fixed: false, unsigned: false, primary: false, notnull: true, autoincrement: false }
  relations:
    Empresa: { local: idempresa, class: SdrivingEmpresa, type: one, foreignType: one, foreignAlias: MaquinaEmpresa, onDelete: CASCADE, onUpdate: CASCADE }
SdrivingMaquinaEmisor:
  connection: doctrine
  tableName: sdriving_maquina_emisor
  actAs: [Timestampable]
  columns:
    idmaquinaemisor: { type: integer(8), fixed: false, unsigned: false, primary: true, autoincrement: true }
    idmaquina: { type: integer(8), fixed: false, unsigned: false, primary: true, autoincrement: false }
    idemisor: { type: integer(8), fixed: false, unsigned: false, primary: true, autoincrement: false }
  relations:
    SdrivingEmisor: { onDelete: CASCADE, local: idemisor, foreign: idemisor, type: one }
    SdrivingMaquina: { onDelete: CASCADE, local: idmaquina, foreign: idmaquina, type: one }

And this is the configure() method for the form associated:

public function configure() {
    $this->current_user = sfContext::getInstance()->getUser()->getGuardUser();

    unset($this['updated_at'], $this['created_at']);

    $this->widgetSchema['idempresa'] = new sfWidgetFormInputHidden();
    $id_empresa = $this->current_user->getSfGuardUserProfile()->getIdempresa();
    $this->setDefault('idempresa', $id_empresa);

    $this->widgetSchema['no_emisor'] = new sfWidgetFormDoctrineChoice(array('model' => 'SdrivingEmisor', 'add_empty' => 'Seleccione un Emisor', 'table_method' => 'fillChoice'));
    $this->validatorSchema['idempresa'] = new sfValidatorPass();
    $this->validatorSchema['no_emisor'] = new sfValidatorPass();
}

I'm trying after save the main maquina then save the data for the relation SdrivingMaquinaEmisor() but don't know and didn't find (after some Google and Stackoverflow research) the proper way to get the latest ID of SdrivingMaquina object.

This is what I'm doing in my save() method (in the same Form):

public function save($con = null) {
    $new_machine = parent::save($con);

    $relation = new SdrivingMaquinaEmisor();
    $relation->setIdmaquina($new_machine->getIdmaquina());
    $relation->setIdemisor($this->values['no_emisor']);
    $relation->save();

    return $new_machine;
}

But setIdmaquina() never gets a value so it breaks my application and cause a CONSTRAINT error, can any point me in the right direction?

1

1 Answers

1
votes

You don't have to do that, the id is not needed. If the form is correct and the required fields (idempresa) are in the form, then the relations will be save automatically.

It's not an exact full answer (it depends a lot of things) to your question but some advices I can give you (I hope you don't mind).

Let's try to simplify some things:

SdrivingMaquina:
  actAs:
    Timestampable: ~
  columns:
    empresa_id: { type: integer(4), unsigned: true, primary: true }
    patente: { type: string(12), notnull: true }
  relations:
    Empresa: { class: SdrivingEmpresa, type: one, foreignType: one, foreignAlias: MaquinaEmpresa, onDelete: CASCADE, onUpdate: CASCADE }
SdrivingMaquinaEmisor:
  actAs:
    Timestampable: ~
  columns:
    maquina_id: { type: integer, notnull: true  }
    emisor_id: { type: integer, notnull: true }
  relations:
    SdrivingEmisor: { onDelete: CASCADE, local: emisor_id, type: one }
    SdrivingMaquina: { onDelete: CASCADE, local: maquina_id, type: one }

Primary keys (like idmaquina) is not required to declare explicitly... a primary key will be added automatically and for simplicity it will be (and should be) named id. Doctrine not really good at handling compound keys so you should use only one field. If you want to ensure uniqueness add a unique index.

You should name foreign keys like empresa_id not idempresa because it will simplify some things as well.

And in the form (I don't know this form belongs to which table):

/** @var sfDoctrineGuardUser */
protected $user; 

public function configure()
{
    // user comes as an option e.g. in an action new SomeForm(null, array('user' => $this->getUser()));
    $this->user = $this->getOption('user');
    if ($this->user instanceof sfDoctrineGuard)
    {
      throw new InvalidArgumentException('A sfDoctrineGuard object is required as "user" option in '.__METHOD__);
    }

    // use useFields instead of unset
    $this->useFields(array(
      'empersa_id',
      'no_emisor',
      // ...
    ));

    // this should be done automatically by symfony in the base class
    //$this->widgetSchema['idempresa'] = new sfWidgetFormInputHidden();
    //$id_empresa = $this->current_user->getSfGuardUserProfile()->getIdempresa();
    //$this->setDefault('idempresa', $id_empresa);

    // do not recreate widgets if not needed (I don't know if no_emisor is in the schema or not), just modify them
    $this->getWidget('no_emisor')->setOption('table_method', 'fillChoice');
    $this->getWidget('no_emisor')->setOption('add_empty', 'Seleccione un Emisor');
}

If the schema is correct and a foreign key field like empresa_id is in the form symfony will create a select widget for it and the selected value will be saved automatically. If you don't want that widget in the form you should not put it in (or unset it) and set the field value empresa_id in code. You should override the doUpdateObject method:

protected function doUpdateObject($values)
{
  parent::doUpdateObject($values);

  // thats it... link objects together and doctrine will figure out the id 
  $this->getObject()->setEmpresa($this->user);
}

You should follow conventions and best practices (get them from the documentation) in general. Not just because your code will be much more readable and understandable for other people but it will make your life much easier. I know it takes a lot of time to learn complex things like symfony, but you should read all the documentation (for symfony and doctrine as well) and then read symfony's code itself to know how it works under the hood. Use a framework to simplify your work not to complicate it.

UPDATE:

This is how you can link objects together before save (use this or something like this instead of your save method):

protected function doUpdateObject($values)
{
  parent::doUpdateObject($values);

  if (isset($this['no_emisor']))
  {
    if ($this->isNew())
    {
      $sdrivingMaquinaEmisor = new SdrivingMaquinaEmisor();
      $this->getObject()->setSdrivingMaquinaEmisor($sdrivingMaquinaEmisor);
    }
    else
    {
      $sdrivingMaquinaEmisor = $this->getObject()->getSdrivingMaquinaEmisor();
    }

    $sdrivingMaquinaEmisor->setIdemisor($this->values['no_emisor']);
  }
}