php - fields - Symfony Generator Forms, Doctrine y M: N Relationships
symfony form querybuilder (2)
Hace aproximadamente 10 meses tuve problemas similares con las relaciones M: N y los metadatos en la tabla de unión.
¡Encontré esas entradas de blog de Melikedev muy útiles! Esto no es exactamente lo mismo que su caso de uso, pero podría darle algunas pistas:
http://melikedev.com/2009/12/09/symfony-w-doctrine-saving-many-to-many-mm-relationships/
http://melikedev.com/2009/12/06/symfony-sfformextraplugin-select-double-list-maintain-order/
http://melikedev.com/2010/04/06/symfony-saving-metadata-during-form-save-sort-ids/
Tengo una configuración M: N básica con tres tablas: candidato, posición y candidate_position.
Aquí hay una captura de pantalla del ERD de MySQL Workbench
Ahora, pasando de eso, hablemos de formas. En el mundo predeterminado del generador de Symfony, tendrías una interfaz CRUD separada para las tres de estas tablas. Sin embargo, no quiero tener una interfaz CRUD para candidate_position
.
Lo que quiero es que las acciones de creación y edición de la interfaz candidata contengan un campo de opción múltiple (lista de selección, matriz de casillas, lo que sea) que crearía los registros CandidatePosition como parte de las acciones candidatas.
En el código
config / doctrine / schema.yml (Nota: el no es el esquema completo.yml, sino solo las tablas que se tratan aquí)
---
detect_relations: true
options:
type: InnoDB
candidate:
columns:
id:
type: integer(4)
primary: true
unsigned: true
notnull: true
autoincrement: true
first_name:
type: string(45)
notnull: true
last_name:
type: string(45)
notnull: true
created_at:
type: integer(4)
unsigned: true
relations:
Positions:
class: Position
refClass: CandidatePosition
local: candidate_id
foreign: position_id
position:
columns:
id:
type: integer(4)
primary: true
unsigned: true
notnull: true
autoincrement: true
name:
type: string(45)
relations:
Candidates:
class: Candidate
refClass: CandidatePosition
local: position_id
foreign: candidate_id
candidatePosition:
tableName: candidate_position
columns:
candidate_id:
type: integer(4)
primary: true
unsigned: true
notnull: true
position_id:
type: integer(4)
primary: true
unsigned: true
notnull: true
indexes:
fk_candidate_position_candidate1:
fields: [candidate_id]
fk_candidate_position_position1:
fields: [position_id]
aplicaciones / backend / modules / candidate / config / generator.yml
generator:
class: sfDoctrineGenerator
param:
model_class: Candidate
theme: admin
non_verbose_templates: true
with_show: false
singular: ~
plural: ~
route_prefix: candidate
with_doctrine_route: true
actions_base_class: sfActions
config:
actions: ~
fields:
first_name: { label: First Name }
last_name: { label: Last Name }
created_at: { label: Created On }
candidate_positions: {label: Positions}
list:
sort: [last_name, asc]
filter: ~
form:
display:
"User": [first_name, last_name]
"Applying For": [candidate_positions]
fields :
hide: [created_at]
edit: ~
new: ~
lib / form / doctrine / candidateForm.class.php
class candidateForm extends BasecandidateForm
{
public function configure()
{
unset( $this[''created_at''] );
$this->widgetSchema[''candidate_positions''] = new sfWidgetFormDoctrineChoice(
array( ''multiple'' => true, ''model'' => ''Position'', ''renderer_class'' => ''sfWidgetFormSelectCheckbox'' )
);
$this->validatorSchema[''candidate_positions''] = new sfValidatorDoctrineChoice(
array( ''multiple'' => true, ''model'' => ''Position'', ''min'' => 1 )
);
}
}
Todo esto funciona, excepto cuando se trata de guardar los datos. Este es el punto donde me quedo atascado.
Claramente necesito hacer algo para crear / editar / eliminar los registros CandidatePosition, pero no estoy seguro por dónde empezar a trabajar. En candidateActions
? Anular Basecandidate::save()
?
Avíseme si hay otros datos que pueda necesitar ver.
- PHP 5.2.x
- Symfony 1.4.3
antes que nada, puedo sugerir una actualización de la versión de Symfony; utilizo 1.4.11 donde tendrás esta funcionalidad funcionando desde cero.
Si esto no es posible en su caso, el mejor lugar para esto será anular el método base doSave () en candidateForm así:
protected function doSave($con = null)
{
$existing = $this->object->Position->getPrimaryKeys();
$values = $this->getValue(''candidate_positions'');
$unlink = array_diff($existing, $values);
$this->object->unlink(''Position'', array_values($unlink));
$link = array_diff($values, $existing);
$this->object->link(''Position'', array_values($link));
parent::doSave($con);
}
y también es probable que necesite establecer manualmente el objeto de enlace seleccionado en la carga de formulario de esta manera:
public function updateDefaultsFromObject()
{
parent::updateDefaultsFromObject();
if (isset($this->widgetSchema[''candidate_positions'']))
{
$this->setDefault(''candidate_positions'', $this->object->Position->getPrimaryKeys());
}
}
Esto debería funcionar.
ACTUALIZAR
Creo que dado que la actualización a la 1.4.11 no ayuda, hay un problema con la definición del esquema y mi suposición es que debe agregar la definición de relación a la tabla de enlace ''candidatePosition'' de esta manera:
relations:
Candidate:
class: Candidate
local: candidate_id
foreign: id
foreignAlias: Candidates
Position:
class: Position
local: position_id
foreign: id
foreignAlias: Positions
Espero que esto ayude.
Saludos.