Doctrine: Define many-to-many relation inline in fixture - symfony1

I want to know the correct way of defining many-to-many relations inline in a Doctrine Fixture. Consider sfDoctrineGuardPlugin for example. The schema can be found here
I'm defining a fixture like:
I already have 2 groups in the sfGuardGroup table, so I wish to refer the group_id
sfGuardUser:
soc-sfUser-1:
first_name: Mrs
last_name: Balasubramanium
email_address: balasubramanium#gmail.com
username: balasubramanium#gmail.com
password: admin
Groups: [{group_id: 2}]
is_active: 1
Is this correct?

If you are also defining the groups in that fixture, you can reference them by name:
sfGuardGroup:
GroupAdmin: ...
GroupEditor: ...
sfGuardUser:
...
Groups: [GroupEditor]
If you want to specify an actual ID you should write it this way:
sfGuardUser:
foo:
first_name: Foo
last_name: Bar
...
sfGuardUserGroup: [{group_id: 2}]
Why? If you take a look at the schema.yml file of sfDoctrineGuardPlugin you can see a refClass property on sfGuardUser relations:
relations:
Groups:
...
refClass: sfGuardUserGroup
It's a little tricky and not so well documented in Doctrine, but it seems to work.

Related

Populate symfony admin generator's select field based on schema

I've inherited the development of a symfony 1.4 app (though It's my first symfony project).
After digging a bit on that app I've discovered a bug that is driving me nuts.
On the admin generator list page of a module there are two select fields in the filter form that should list each one a type of users (partners and clients), however both listings show all the users.
The generator.yml shows that both select fields should be populated by parter_id and client_id
[...]
filter:
display: [date, client_id, partner_id, ...]
form: ~
edit: ~
new: ~
[...]
Looking at the schema of the module it's obvious why symfony is populating the select fields with the same content because the relations of both client_id and partner_id are equivalent:
SomeModule:
tableName: client_requests
columns:
id: {type: integer, primary: true, autoincrement: true}
partner_id: {type: integer, notnull: true}
client_id: {type: integer, notnull: true}
date: {type: timestamp}
...
relations:
partner:
class: sfGuardUser
local: partner_id
foreign: id
type: one
client:
class: sfGuardUser
local: client_id
foreign: id
type: one
As per the above schema symfony has no other choice but to generate the select fields as:
select * from sf_guard_user;
The difference between partner and client is made by sfGuardGroup and sfGuardUserGroup, the related parts of the schema from ./plugins/sfDoctrineGuardPlugin/config/doctrine/schema.yml are:
sfGuardGroup:
actAs: [Timestampable]
columns:
name:
type: string(255)
unique: true
description: string(1000)
relations:
Users:
class: sfGuardUser
refClass: sfGuardUserGroup
local: group_id
foreign: user_id
foreignAlias: Groups
...
sfGuardUser:
actAs: [Timestampable]
columns:
first_name: string(255)
last_name: string(255
...
relations:
Groups:
class: sfGuardGroup
local: user_id
foreign: group_id
refClass: sfGuardUserGroup
foreignAlias: Users
Permissions:
class: sfGuardPermission
local: user_id
foreign: permission_id
refClass: sfGuardUserPermission
foreignAlias: Users
...
What I would like to is to generate those fields with a query like:
select u.*
from sf_guard_user as u
JOIN (sf_guard_user_group as ug JOIN sf_guard_group as g
ON (ug.group_id = g.id)) ON (u.id = ug.user_id)
where g.name = 'partner';
I've researched for a way to edit the module's schema to reflect the relation between client_id and partner_id with their group name to get the filter form select fields right, but I've ended believing that that is a wrong approach
¿is it possible to modify the module's schema to allow symfony to populate correctly the select fields?
¿or that approach is completely wrong and instead I should hack the methods that render those fields to populate them with the right queries? If so hints in that direction would be appreciated.
Thanks
Just edit your form (probably sfGuardUserForm) and add the query to the partner_id widget. Something like:
$query = Doctrine::getTable('sfGuardUser')->createQuery('u')->etc etc...
$this->widgetSchema['partner_id']->setOption('query', $query)
You'll probably need to do the same to the validator for that field:
$this->validatorSchema['partner_id']->setOption('query', $query)
If you cannot edit that specific form (maybe it is used in another part of the app), just make a new one that extends it. And then, you just need to specify the form class in the generator.yml file.

Does sfGuardUser table have a primary key?

I'm new to Symfony and Doctrine and am writing a web app. I added the sfDoctrineGuardPlugin to my project. When I open the schema.yml file for the plugin I see this:
sfGuardUser:
actAs: [Timestampable]
columns:
first_name: string(255)
last_name: string(255)
email_address:
type: string(255)
notnull: true
unique: true
username:
type: string(128)
notnull: true
unique: true
algorithm:
type: string(128)
default: sha1
notnull: true
salt: string(128)
password: string(128)
is_guest:
type: boolean
default: 0
is_active:
type: boolean
default: 1
is_super_admin:
type: boolean
default: false
last_login:
type: timestamp
indexes:
is_active_idx:
fields: [is_active]
relations:
Groups:
class: sfGuardGroup
local: user_id
foreign: group_id
refClass: sfGuardUserGroup
foreignAlias: Users
Permissions:
class: sfGuardPermission
local: user_id
foreign: permission_id
refClass: sfGuardUserPermission
foreignAlias: Users
Does this schema generate a table with a primary key (and if so, how do I access it)? I've looked online and most of the pages that cover the schema for sfGuardUser display an id column that is the primary key. What am I missing? Thanks.
Yes, it's id, accessed as sfGuardUser u --> u.id, as in...
$user = Doctrine::getTable('sfGuardUser')->findOneById(55);
or...
$q = Doctrine_Query::create()
->select('u.*')
->from('sfGuardUser u')
->where('u.id = ?', 55);
$q->execute();
I think somewhere in the Doctrine documentation it says that Doctrine auto-generates an "id" primary key if one isn't declared in the YAML file. It used to be declared explicity in the sfGuardPlugin schema but as of Symfony 1.4.8 (I think), it's just not written.
One thing to watch out for is that elsewhere in your schema, you need to make sure that you declare the same numeric type for the other end of the foreign key relationship or otherwise it'll throw an error. I think it's just type: integer that you need.
If no primary key is given, doctrine will create an id fieldwith type bigint and with a primary key.

one-to-many and saving records

I am creating a simple CMS and I have a set of templates, each template can have multiple blocks within them.
So I have a one-to-many relationship between the templates and blocks (1 template can have many blocks)
So, when I create a block, it has a drop down of the templates that I can associate the block to using sfDoctrineChoice widget.
In my BlockForm.class.php
new sfWidgetFormDoctrineChoice(array('model' => 'Template', 'multiple'=>true, 'expanded'=>false))
My schema is:
Template:
actAs:
Timestampable: ~
columns:
name:
type: varchar(255)
layout:
type: text
relations:
Block:
class: Block
local: id
foreign: template_id
type: many
foreignType: one
alias: Block
foreignAlias: Template
Block:
columns:
template_id: { type: integer(8), notnull: true }
content: { type: clob, notnull: true }
The problem comes when I try to save the choices. It gives me a:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens when I select 2 or more templates or when I select 1 option:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (db.block, CONSTRAINTblock_template_id_template_idFOREIGN KEY (template_id) REFERENCEStemplate(id))
Is my schema correct to do what I'm looking to do?
Thanks
Build the database tables the way you want them first.
Rename your old schema.yml to schema-20110610.yml
Run task symfony doctrine:build-schema
Take a look at the new schema.yml file you created. It may give you an idea of what you are doing wrong...
You must add foreign key constraint. onDelete and onUpdate.
Template:
actAs:
Timestampable: ~
columns:
name:
type: varchar(255)
layout:
type: text
Block:
columns:
template_id: { type: integer(8), notnull: true }
content: { type: clob, notnull: true }
relations:
Template:
local: template_id
foreign: id
foreignAlias: Blocks

symfony - sfDoctrineGuard - loading fixture data

I'm currently using the sfDoctrineGuardPlugin and sfForkedDoctrineApplyPlugin and when I reload data using doctrine:data-load
I get the following:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (my_db.sf_guard_user_profile, CONSTRAINTsf_guard_user_profile_user_id_sf_guard_user_id_1FOREIGN KEY (user_id) REFERENCESsf_guard_user(id) ON DELETE CASCADE)
This is really annoying as I can't seem to load any of the records that are in my fixtures.
I've copied the schema from the sfForkedDoctrineApplyPlugin and extended it a little bit:
sfGuardUserProfile:
actAs:
Timestampable: ~
columns:
user_id:
type: bigint(20)
notnull: true
default:
unsigned: false
primary: false
unique: false
autoincrement: false
email_new:
type: string(255)
unique: true
firstname:
type: string(255)
lastname:
type: string(255)
city:
type: varchar(255)
validate_at:
type: timestamp
validate:
type: string(33)
relations:
User:
class: sfGuardUser
foreign: id
local: user_id
type: one
onDelete: cascade
foreignType: one
foreignAlias: Profile
indexes:
validate:
fields: [validate]
Does anyone know how to fix this?
Thanks
user_id:
type: bigint(20)
ist not compatible to sfGuardUser
sfGuardUser:
type: integer()
In your fixtures for sfGuardUserProfile you need to specify the sfGuardUser link as you have a foreign link to it that cannot be null
sfGuardUserProfile:
bob_profile:
sfGuardUser: bob # Set the link
firstname: bob
# bobs_profile fixtures
sfGuardUser:
bob:
# bobs fixtures
Check User's id type.
It has to be the same as sfGuardUserProfile user_id is: bigint(20)
Ok, so I had to add interger(11) to all of the tables in sfDoctrineGuardPlugin. A bit hacky, but works now

In doctrine what implications do 'relations:' have if the 2 relations are defined for two seperate column with a same table?

Suppose I have defined VendorClientLicense model like this:
VendorClientLicense:
tableName: vendor_client_licenses
columns:
id:
type: integer(4)
primary: true
notnull: true
autoincrement: true
status:
type: string(255)
default: 'pending'
client_id:
type: integer(8)
notnull: true
vendor_id:
type: integer(8)
notnull: true
relations:
sfGuardUser:
class: sfGuardUser
local: client_id
foreign: id
foreignAlias: VendorClientLicenses
foreignType: many
owningSide: true
sfGuardUser:
class: sfGuardUser
local: vendor_id
foreign: id
foreignAlias: VendorClientLicenses
foreignType: many
owningSide: true
indexes:
fk_vendor_client_licenses_sf_guard_user1:
fields: [client_id]
fk_vendor_client_licenses_sf_guard_user2:
fields: [vendor_id]
options:
charset: utf8
collate: utf8_unicode_ci
If you see the two relations are defined with same name 'sfGuarduser'; What I have found for this in mysql is that in generated database client_id does not show any association with sfGuardUser, whereas vendor_id does! If I change it to 'sfGuardUser1' and 'sfGuardUser2' then shows both relationship! So I assume eventually this has important significance and should not be identical for a same model. Is there any other implications for it?
Plus can you name me a good schema generator like 'mysqlworkbenchdoctrineplugin' which handles situation like this automatically?
Yes, you need to name them differently.
I asked & received for the same problem here:
MySQL: Two foreign keys in one table referring to another table
I haven't had any problems with it.
Regarding the plugin, sorry can't help you.

Resources