问题
There are 3 tables: shelf, section and shelf_has_section intermediate table to support n-m relation. The schema build from symfony doctrine:build-schema looks as following.
Simply,
shelf(id, position)
section(id, name)
shelf_has_section(shelf_id, section_id, number_of_books)
The schema.
Shelf:
connection: doctrine
tableName: shelf
columns:
id:
type: integer(4)
fixed: false
unsigned: true
primary: true
autoincrement: true
position:
type: string(255)
primary: false
notnull: true
autoincrement: false
relations:
ShelfHasSection:
local: id
foreign: shelf_id
type: many
Section:
connection: doctrine
tableName: section
columns:
id:
type: integer(1)
primary: true
autoincrement: false
name:
type: string(20)
primary: false
notnull: true
relations:
ShelfHasSection:
local: id
foreign: section_id
type: many
ShelfHasSection:
connection: doctrine
tableName: shelf_has_section
columns:
shelf_id:
type: integer(4)
primary: true
autoincrement: false
section_id:
type: integer(1)
primary: true
autoincrement: false
number_of_books:
type: integer(4)
primary: false
notnull: false
autoincrement: false
relations:
Shelf:
local: shelf_id
foreign: id
type: one
Section:
local: section_id
foreign: id
type: one
I managed to show Sections as a check box list through adding the following relation to Shelf in the schema. I also need to display a text field infront of section check box in order to enter number of books.
Sections:
class: Section
refClass: ShelfHasSection
local: shelf_id
Simply it's like checking the list of checkboxes for available sections and add the number of books for section checked.
I tried to make it through embedRelation() etc, but lack of my symfony knowledge doesn't get me there. Any help highly appreciated.
回答1:
Theoretically speaking, if an n-m relation table has it own field, it becomes an entity itself, so the doctrine model for n-m relation doesn't match this problem... but: - First, you must to redefine your schema to add foreignAliases to n-m entity:
ShelfHasSection:
connection: doctrine
tableName: shelf_has_section
columns:
shelf_id:
type: integer(4)
primary: true
autoincrement: false
section_id:
type: integer(1)
primary: true
autoincrement: false
number_of_books:
type: integer(4)
primary: false
notnull: false
autoincrement: false
relations:
Shelf:
local: shelf_id
foreign: id
type: one
**foreignAlias: ShelfHasSections**
Section:
local: section_id
foreign: id
type: one
**foreignAlias: ShelfHasSections**
If your are trying to make it work on a generated module, your checkboxes idea has no solution. I'll suggest you to use the ahDoctrineEasyEmbeddedRelationsPlugin, and embed the relation ShelfHasSections to your shelf form. The ShelfHasSectionForm embed by the plugin may have an autocomplete field for the section, and the input for the number of books. So, when you want to relate some shelf to one section, add one form (using the plugin) and select the values. The latest problem become on how to avoid duplicate sections.... I guess you should apply some javascript filter to remember witch section are already related and send it with the autocomplete query, so the doctrine query could exclude this sections.... Sounds very nasty, and it is, but it's the only one solution I can figure out.
If you not using a generator, but some custom actions/template, I guess the problem become easier: Embed 1 CustomShelfHasSectionForm to your Shelf Form (one for each section). Then, add one checkbox widget (maybe with sfWidgetFormInputCheckbox) it each form to select the relation or not. Them, processing the form remove those embedded form wich no checkbox selected. Somethig like:
class CustomShelfHasSectionForm extends ShelfHasSectionForm {
public function configure() {
unset($this['shelf_id']);
$this->widgetSchema['selected'] = new sfWidgetFormInputCheckbox();
$this->validatorSchema['selected'] = new sfValidatorBoolean(array('required' => false));
}
}
class CustomShelfForm extends ShelfForm {
private $unselected_sections = array();
public function configure() {
$sections = Doctrine::getTable('Section')->findAll();
foreach($sections as $section) {
$shelfHasSection = new ShelfHasSection();
$shelfHasSection->setShefl($this->getObject());
$shelfHasSection->setSection($section);
$this->embedForm('section_'.$section->getId(), new CustonShelfHasSectionForm($shelfHasSection));
}
}
public function doBind(array $values) {
$sections = Doctrine::getTable('Section')->findAll();
foreach($sections as $section) {
// Do some debug with print_r($values) to find something like
...
if(empty($values['section_'.$section->getId()]['selected']) {
$this->unselected_sections[] = $section->getId();
}
}
return parent::doBind($values);
}
public function doSave($con = null) {
foreach($this->unselected_sections as $section_id) {
// disembed form, something like
unset($this->embeddedForms["section_".$section->getId()]);
}
}
}
Then, in your action.class.php
$shelfObject = ....
$this->form = new CustomShelfForm($shelfObject);
if(....) {
$this->form->bind...
if($this->form->isValid()) {
$this->form->save();
}
}
This is all "on the air" code, so probably something doesn't work so well. Maybe you can try one of this solutions an let us know how it works for you. I hope this can helpyou.
回答2:
You're not the first one to ask such a behavior. Sadly, symfony isn't designed to handle an extra field in the relation table.
I did it once in the past but I can't find source code about it. But I remember that this is kind of hack which is hard to handle with embedRelation.
I found few topics around the web that might help you (at least for a starting point):
- Form for many-to-many relation with extra field
- Extra Field on Doctrine Many-to-Many Relationship Table
- (might be too old) Intermediary Tables Question
In the first link, it seems that johandouma has a suitable solution but didn't post it. You might contact him to see if he remember the solution..
来源:https://stackoverflow.com/questions/12597786/symfony-1-4-doctrine-many-to-many-relationship-with-extra-field-in-intermediat