I've got a little problem with many to many relations on the same table using Symfony 1.4 with the Propel ORM. My schema.yml looks like this:
propel:
item:
_attributes: { phpName: Item }
id: { phpName: Id, type: INTEGER, size: '10', primaryKey: true, autoIncrement: true, required: true }
type_id: { phpName: TypeId, type: INTEGER, size: '11', required: true, foreignTable: type, foreignReference: id, onDelete: RESTRICT, onUpdate: RESTRICT }
owner_id: { phpName: OwnerId, type: INTEGER, size: '11', required: true, foreignTable: owner, foreignReference: id, onDelete: RESTRICT, onUpdate: RESTRICT }
place_id: { phpName: PlaceId, type: INTEGER, size: '11', required: true, foreignTable: place, foreignReference: id, onDelete: RESTRICT, onUpdate: RESTRICT }
picture_id: { phpName: PictureId, type: INTEGER, size: '11', required: false, foreignTable: picture, foreignReference: id, onDelete: RESTRICT, onUpdate: RESTRICT }
supplier_id: { phpName: SupplierId, type: INTEGER, size: '11', required: false, foreignTable: supplier, foreignReference: id, onDelete: RESTRICT, onUpdate: RESTRICT }
name: { phpName: Name, type: VARCHAR, size: '255', required: true }
amount: { phpName: Amount, type: INTEGER, size: '11', required: true }
wished_amount: { phpName: WishedAmount, type: INTEGER, size: '11', required: true }
costs: { phpName: Costs, type: DECIMAL, size: '7', scale: '2', required: true }
description: { phpName: Description, type: LONGVARCHAR, required: false }
use_until: { phpName: UseUntil, type: DATE, required: false }
last_used: { phpName: LastUsed, type: TIMESTAMP, required: false }
last_updated: { phpName: LastUpdated, type: TIMESTAMP, required: false }
_indexes: { item_FI_1: [type_id], item_FI_2: [owner_id], item_FI_3: [place_id], item_FI_4: [picture_id], item_FI_5: [supplier_id] }
item_has_item:
item_id: { type: INTEGER, required: true, foreignTable: item, foreignAlias: item, foreignReference: id, primaryKey: true}
parent_item_id: { type: INTEGER, required: true, foreignTable: item, foreignAlias: parent_item, foreignReference: id, primaryKey: true}
_indexes: { item_has_item_FKIndex1: [item_id], item_has_item_FKIndex2: [parent_item_id] }
However, the needed admin_double_list in the admin generator does not appear automatically. It does, when the second foreignTable is adjusted to another table, for example sf_guard_user. I've read that this could be fixed in Propel 1.3, but I don't know which Propel version is included with Symfony 1.4.
I hope I gave enough information for my problem to be solved by you guys. Otherwise I will have to make another table which holds the items that have child item, like this:
Item <---- Item_has_item <---- Combined_item
EDIT AFTER REACTION FROM j0k
After the reaction from j0k, I did update the sfPropelORMPlugin, and it did recognise the relation. However, I still got an error while saving (only when a relation is made):
Unable to execute INSERT statement [INSERT INTO `item_has_item` (`ITEM_ID`) VALUES (:p0)]
[wrapped: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a
child row: a foreign key constraint fails (`SI/item_has_item`, CONSTRAINT
`item_has_item_FK_1` FOREIGN KEY (`parent_item_id`) REFERENCES `item` (`id`))]
I have found, after a long extensive search, that the form generator fails to correctly understand the many-to-many relation on the same table. In the function saveItemHasItemList($con = null):
$c = new Criteria();
$c->add(ItemHasItemPeer::ITEM_ID, $this->object->getPrimaryKey());
ItemHasItemPeer::doDelete($c, $con);
$values = $this->getValue('item_has_item_list');
if (is_array($values))
{
foreach ($values as $value)
{
$obj = new ItemHasItem();
$obj->setItemId($this->object->getPrimaryKey());
$obj->setItemId($value);
$obj->save();
}
}
As you can see, the ItemId is twice set, while the ParentItemId is not set, hence the constraint value. It should be generated as:
$c->add(ItemHasItemPeer::ITEM_ID, $this->object->getPrimaryKey());
$c->add(ItemHasItemPeer::PARENT_ITEM_ID, $this->object->getPrimaryKey());
&&
$obj->setParentItemId($this->object->getPrimaryKey());
$obj->setItemId($value);
This solves the saving problem, however, it still does not show the already selected relations. To solve that, you should also change the updateDefaultsFromObject():
foreach ($this->object->getItemHasItemsRelatedByItemId() as $obj)
Should be:
foreach ($this->object->getItemHasItemsRelatedByParentItemId() as $obj)
Remember, these functions are located in form/base/BaseItemForm.class.php, but the functions should be overwritten in /form/ItemForm.class.php.
I believe this is an Propel bug, so I will post it tomorrow on the Propel TRAC.
If you are using the last symfony 1.4, it uses Propel 1.4.2.
You should try to use a new version of the Propel Plugin. It uses Propel 1.6.
I'm looking to create fixtures file for the following schema (Movies library):
VodProgram:
actAs: { Timestampable: ~ }
columns:
title: { type: string(255), notnull: true }
year: { type: smallint }
...
relations:
VodPersons:
class: VodPerson
refClass: VodCasting
local: program_id
foreign: person_id
foreignAlias: VodPrograms
VodPerson:
columns:
name: { type: string(255), notnull: true }
VodCasting:
columns:
program_id: { type: integer, primary: true }
person_id: { type: integer, primary: true }
role: { type: string(255) }
rank: { type: smallint }
relations:
VodProgram: { onDelete: CASCADE, local: program_id, foreign: id }
VodPerson: { onDelete: CASCADE, local: person_id, foreign: id }
My problem is creating fixtures file with the "role" and "rank" fields present in the VodCasting table.
Here is my actual fixtures:
VodPerson:
kosinski:
name: Joseph Kosinski
VodProgram:
tron:
VodPersons: [kosinski] # where to put the role and rank infos ?
title: Tron
year: 2010
I tried something like :
VodProgram:
tron:
VodPersons:
kosinski:
rank: 1
title: Tron
...
with no luck.
Any suggestions?
Thanks.
Have you tried something like that :
VodPerson:
kosinski:
name: Joseph Kosinski
VodProgram:
tron:
title: Tron
year: 2010
VodCasting:
tron_kosinski:
role: 'Director'
rank: 1
VodPerson: kosinski
VodProgram: tron
does embedRelation() (sfPropel15Plugin) works for many-to-many
relationships? If not any experience or tutorial to get that (embed
forms for m:m relations)?
Regards
Javi
schema.yml
product:
id: ~
name: {type: varchar(255), required: true}
price: {type: integer, required: true}
order_list:
id: ~
order_id: {type: integer, required: true, foreignTable: order, foreignReference: id, onDelete: cascade, onUpdate: cascade}
product_id: {type: integer, required: true, foreignTable: product, foreignReference: id, onDelete: cascade, onUpdate: cascade}
order:
id: ~
name: {type: varchar(255), required: true}
Class form:
class OrderForm extends BaseOrderForm
{
public function configure()
{
$this->embedRelation('OrderList');
}
}
Add it look like:
I'm getting a weird error in symfony 1.4 with doctrine 1.2. My schemas seem to be normal. But whenever I execute the doctrine:build --all --no-confirmation --and-load task, it would output the error SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'default_edition_id' cannot be null. If I set notnull to false for the default_edition_id field, it would actually just be null. Can anyone help me out on what I may be missing?
Here is my schema file (chapter.yml):
Chapter:
actAs:
Timestampable: ~
Versionable:
versionColumn: version
className: %CLASS%Version
SoftDelete: ~
columns:
name: string
chapter_number: { type: integer, notnull: true }
series_id: { type: integer, notnull: true }
default_edition_id: { type: integer, notnull: true }
disabled:
type: enum
values: [1, 0]
default: 0
notnull: true
relations:
DefaultEdition:
local: default_edition_id
class: Edition
foreign: id
foreignAlias: DefaultChapter
foreignType: one
type: one
# onDelete: CASCADE
Series:
local: series_id
foreign: id
onDelete: CASCADE
Editions:
type: many
class: Edition
local: id
foreign: chapter_id
and my edition schema (edition.yml):
Edition:
actAs:
Timestampable: ~
Sluggable:
fields: [name]
Versionable:
versionColumn: version
className: %CLASS%Version
SoftDelete: ~
columns:
name: string
completed_reads: { type: integer, notnull: true, default: 0}
views: { type: integer, notnull: true, default: 0 }
language_id: { type: integer, notnull: true }
chapter_id: { type: integer, notnull: true }
disabled:
type: enum
values: [1, 0]
default: 0
notnull: true
relations:
Pages:
type: many
class: Page
local: id
foreign: edition_id
Language:
local: language_id
foreign: id
type: one
onDelete: CASCADE
Chapter:
local: chapter_id
foreign: id
onDelete: CASCADE
Fixtures:
Chapter:
bakuman_chapter:
Series: bakuman
chapter_number: 86
DefaultEdition: edition_1
bakuman_chapter2:
Series: bakuman
DefaultEdition: edition_2
chapter_number: 90
Edition:
edition_1:
name: edition 1
Chapter: bakuman_chapter
ScanlationGroup: [group_1, group_2, group_3]
Language: english
edition_2:
name: edition 2
Chapter: bakuman_chapter2
ScanlationGroup: [group_4]
Language: japanese
edition_2_2:
name: edition 2_2
Chapter: bakuman_chapter2
ScanlationGroup: [group_4, group_2]
Language: english
"If I set notnull to false for the default_edition_id field, it would actually just be null". In this sentence, was does "it" refer to? Notnull means that the value 'null' is acceptable for this field, not that its value will always be null, if this was what you meant.
I am using Symfony 1.3.2 with Propel ORM on Ubuntu 9.10.
I have a user profile table, which has many other tables linked to it (i.e. user_profile.id is a FK in many other tables.
My db schema looks something like this:
user_profile:
_attributes: { phpName: UserProfile }
id: ~
guard_id: { type: integer, foreignTable: sf_guard_user, foreignReference: id, required: true }
address: { type: longvarchar, required: true }
vehicle_type:
_attributes: { phpName: VehicleType }
id: ~
name: { type: varchar(32), required: true }
user_vehicle:
_attributes: { phpName: UserVehicle }
id: ~
user_id: { type: integer, foreignTable: user_profile, foreignReference: id, required: true }
vehicle_type: { type: integer, foreignTable: vehicle_type, foreignReference: id, required: true }
license_plate: { type: varchar(16), required: true }
user_child:
_attributes: { phpName: UserChild }
id: ~
user_id: { type: integer, foreignTable: user_profile, foreignReference: id, required: true }
gender: { type: boolean, required: true }
name: { type: varchar(32), required: true }
I would like to embed the other objects that link to the user profile object, in the user profile form, so that when I am performing CRUD on a user profile form, the related objects (e.g. UserVehicle, UserJob are also CRUD at the same time as the user profile object).
I need a simple snippet that will show how to:
Embed the various related objects (i.e. UserVehicle, UserChild) into the UserProfile form
Create/Update/Delete the various related objects as the operation is being carried (please note, a user can have more than 0-N vehicles or children assigned to them
Have you read the documentation?:
// lib/form/doctrine/ProductForm.class.php
public function configure()
{
$subForm = new sfForm();
for ($i = 0; $i < 2; $i++)
{
$productPhoto = new ProductPhoto();
$productPhoto->Product = $this->getObject();
$form = new ProductPhotoForm($productPhoto);
$subForm->embedForm($i, $form);
}
$this->embedForm('newPhotos', $subForm);
}
For the create/delete/update part, this article might give some help.
I never found the official approach right for my needs. I developed a completely different approach. In the company where I used to work we used in production this new approach, finding it a bit more elastic and simple. The key concept is "don't use Symfony's Form class and you will discover that embedding forms can be a very simple task"
I hope this can help you embedding forms.