foreign key never save with embed relation - symfony1

I take many hours to find a solution to save the foreign key in the mother table.
I'm trying to use embed relation with symfony 1.4 (i have ahDoctrineEasyEmbeddedRelationsPlugin too).
When i read the symfony documentation here
http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms
the schema is :
Product:
columns:
name: { type: string(255), notnull: true }
price: { type: decimal, notnull: true }
ProductPhoto:
columns:
product_id: { type: integer }
filename: { type: string(255) }
caption: { type: string(255), notnull: true }
relations:
Product:
alias: Product
foreignType: many
foreignAlias: Photos
onDelete: cascade
the embedRelation looks like:
// lib/form/doctrine/ProductForm.class.php
public function configure()
{
// ...
$this->embedRelation('Photos');
}
In my case i can't do otherway, it's the contrary, the product have the relation keys, i have something like that:
Product:
columns:
name: { type: string(255), notnull: true }
price: { type: decimal, notnull: true }
photoid: { type: integer }
ownerid: { type: integer }
relations:
Photo:
local: photoid
foreign: id
type: one
Owner:
local: ownerid
foreign: id
type: one
Photo:
columns:
id : { type: integer }
filename: { type: string(255) }
caption: { type: string(255), notnull: true }
owner:
columns:
id : { type: integer }
firstname: { type: string(255) }
lastname: { type: string(255), notnull: true }
and the embedRelation:
// lib/form/doctrine/ProductForm.class.php
public function configure()
{
// ...
$this->embedRelation('Photo');
$this->embedRelation('Owner');
}
And there are not widget related to the product like name or price to update in the form but only informations coming from photo and owner table.
When i save the new form, photo and owner object are save in the table, and ids are created with sequences. The problem is that Product is never update. photoid and ownerid still stay to null.
It's like embedded form Photo and Owner are save after the root form.
Is it possible to use embedrelation in that case?
If then what is the correct way to save the foreign keys in Product table when the root form is save in the processForm?
What's the trick, thx for help.

In PhotoForm.class.php use:
$this->useFields(array('filename', 'caption'));
And read the documentation

Related

How to query and return the stored id and not the joined description

Perhaps an example would best describe my problem:
Schema:
Referral:
actAs: { timestampable: ~ }
columns:
id: { type: integer, primary: true, notnull: true, autoincrement: true, unique: true }
other_stuff: { type: string }
reasonCode: { type: integer }
relations:
ReasonCode: { local: reasonCode, foreign: id, foreignAlias: ReasonCodes }
ReasonCode:
columns:
id: { type: integer, primary: true, notnull: true, autoincrement: true, unique: true }
description: { type: string }
Query (referralTable.class.php):
public function getObjectByReferralId($id){
$q = Doctrine_Query::create()
->select('*')
->from('referral_submissions')
->where('referral_id=?', $id)
->fetchOne();
return $q;
}
Call in template:
<?php
$id = <source of id>;
echo Doctrine_Core::getTable('referral')->getObjectByReferralId($id)->getReasonCode();
?>
The above call in the template to get the reasoncode returns the "description" stored in the ReasonCode table, not the stored id in the Referral table. I need the actual id, not the joined description. What am I missing?
It's confusing because you named your foreign key with the name of your relation. So when you think you are getting the key, you fetch the relation. And I guess Doctrine do not retrieve the primary key since there is only one field in your ReasonCode table, so it returns the description field.
Try with :
Doctrine_Core::getTable('referral')
->getObjectByReferralId($id)
->get('reasonCode');
By the way, you also can retrieve the id using the relation:
Doctrine_Core::getTable('referral')
->getObjectByReferralId($id)
->getReasonCode()
->getId();
I think you should define your foreign key like : reason_code_id instead of reason_code. Then your schema will become:
Referral:
actAs: { timestampable: ~ }
columns:
id: { type: integer, primary: true, notnull: true, autoincrement: true, unique: true }
other_stuff: { type: string }
reasonCode_id: { type: integer }
relations:
ReasonCode: { local: reasonCode_id, foreign: id, foreignAlias: ReasonCodes }
And you will be able to retrieve the id using:
Doctrine_Core::getTable('referral')
->getObjectByReferralId($id)
->getReasonCodeId();

How to update sfUserProfile after the completion of a separate module? postSave() not working

I have a registration form that includes sfRegistration and sfProfile, which after completion, get's redirected to another form - to determine the user's corporation and is a seperate module. The sfProfile includes a field from the corporation module... the corporate_id. But since the corporate_id is not part of the profile, it does not get included at registration time. Here's the question, after completion of the corporation module, what is the best way to update the user's profile with the corporate_id of the newly completed corporation module? I tried this:
public function postSave()
{
$corpId = $this->form->getId();
$logged_user_id = sfContext::getInstance()->getUser()->getId();
Doctrine_Query::create()
->update('sf_guard_user_profile p')
->set('p.corporate_id', $corpId)
->where('p.user_id' == $logged_user_id )
->execute();
}
placed into the action of the company module, but it is not updating the profile with the company_id.
Suggestions?
UPDATE - per request, here is the information requested: (my >>lib>form>>doctrine>>CorporationForm.class.php is empty... I was trying my functions in the actions class... which may be the issue). Just to clarify, I just need to update the user's profile with the newly created corporate_id after the user completes the corporation module.
And my schema:
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_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
sfGuardUserProfile:
actAs: { Timestampable: ~ }
columns:
id: { type: integer, primary: true, notnull: true, autoincrement: true, unique: true }
user_id: { type: integer }
corporate_id: { type: integer }
type_id: { type: integer, notnull: true }
prefix_id: { type: integer }
middle_name: { type: string(55) }
suffix_id: { type: integer }
phone: { type: string(55), notnull: true }
home_address_line_one: { type: string }
home_address_line_two: { type: string }
home_city: { type: string }
state_id: { type: integer }
home_zip: { type: integer }
relations:
User: { class: sfGuardUser, local: user_id, foreign: id, type: one, foreignType: one, foreignAlias: Profile }
Type: { local: type_id, foreign: id, type: one, foreignAlias: Types }
Prefix: { local: prefix_id, foreign: id, type: one, foreignAlias: Prefixs }
Suffix: { local: suffix_id, foreign: id, type: one, foreignAlias: Suffixs }
State: { local: state_id, foreign: id, foreignAlias: States }
Corporation: { local: corporate_id, foreign: id, foreignAlias: Corporations }
Corporation:
columns:
id: { type: integer, primary: true, notnull: true, autoincrement: true, unique: true }
user_id: { type: integer }
name: { type: string(55), notnull: true }
address_line1: { type: string(255), notnull: true }
address_line2: { type: string(255), notnull: true }
city: { type: string(25), notnull: true }
state_id: { type: integer, notnull: true }
zip: { type: string(25), notnull: true }
phone: { type: string(25), notnull: true }
email: { type: string(100), notnull: true }
website: { type: string(100) }
logo: { type: string(255) }
relations:
User: { class: sfGuardUser, local: user_id, foreign: id, foreignAlias: Users }
In your form:
public function doUpdateObject($values)
{
parent::doUpdateObject($values);
$this->getObject()->setCorporateId(your value);
}
For example
//apps/frontend/yourmodule/action.class.php
protected function processForm(sfWebRequest $request, sfForm $form)
{
$form->bind($request->getParameter($form->getName()), $request->getFiles($form->getName()));
if ($form->isValid())
{
$corporation = $form->save();
$user_id=$this->getUser()->getGuardUser()->getId();
$profile = Doctrine_Core::getTable('sfGuardUserProfile')->findOneByUserId($user_id);
$profile->setCorporateId('your value');
Don't forget the ->save();
public function setId()
{
$user_id = $this->getUser()->getGuardUser()->getId();
$corp_id = 1;
$user_profile = Doctrine_Core::getTable('sfGuardUserProfile')->findOneByUserId($user_id);
$user_profile->setCorporateId($corp_id)->save();
}
protected function processForm(sfWebRequest $request, sfForm $form)
{
$form->bind($request->getParameter($form->getName()), $request->getFiles($form->getName()));
if ($form->isValid())
{
self::setId();
$corporation = $form->save();
$this->redirect('dashboard/index');
}
}

Backend sfGuardUser module

I use symfony 1.4.11 with Doctrine
I have sfGuardUser module in backend. I have sfGuardUserProfile table.
sfGuardUserProfile:
connection: doctrine
tableName: sf_guard_user_profile
columns:
id: { type: integer(4), primary: true, autoincrement: true }
user_id: { type: integer(4), notnull: true }
salutation: { type: string(10), notnull: true }
first_name: { type: string(30), notnull: true }
last_name: { type: string(30), notnull: true }
country: { type: string(255), notnull: true }
postcode: { type: string(10) , notnull: true }
city: { type: string(255), notnull: true }
address: { type: string() , notnull: true }
phone: { type: string(50) }
email: { type: string(255), notnull: true }
validate: { type: string(17) }
banned: { type: boolean, default: 0 }
payed_until: { type: datetime, notnull: true}
relations:
User:
class: sfGuardUser
foreign: id
local: user_id
type: one
onDelete: cascade
onUpdate: cascade
foreignType: one
foreignAlias: Profile
indexes:
user_id_unique:
fields: [user_id]
type: unique
SfGuardUser table:
GuardUser:
actAs: [Timestampable]
columns:
id:
type: integer(4)
primary: true
autoincrement: true
username:
type: string(128)
notnull: true
unique: true
algorithm:
type: string(128)
default: sha1
notnull: true
salt: string(128)
password: string(128)
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
I have next sfGuardUserForm:
public function configure()
{
parent::configure();
$profileForm = new sfGuardUserProfileForm($this->object->Profile);
unset($profileForm['user_id'],$profileForm['banned'],$profileForm['validate'],$profileForm['payed_until']);
$profileForm->widgetSchema['salutation'] = new weWidgetSalutationI18n();
$profileForm->widgetSchema['country'] = new sfWidgetFormI18nChoiceCountry();
$profileForm->setDefault('country', 'DE');
$this->embedForm('Profile', $profileForm);
}
So, when I add new user from backend, in my sfGuardUserProfile table user_id = 0 ...
Try if this works for you:
public function configure()
{
parent::configure();
$profile = new sfGuardUserProfile();
$profile->setUserId($this->getObject()->id);
$profileForm = new sfGuardUserProfileForm($profile);
$this->embedForm('Profile', $profileForm);
}
I'm not really sure, but form the top of my head it's because you unset the user_id value.
Somethings that first came to mind are:
Read this (to define a primary key, the keyword is primaryKey: true not primary: true and they dont need to be defined as autoincremental, ORM can guess it for himself)
Dont unset the user_id or any ids of forms , they are hidden by default so that should not be a problem.
Check those poitns and see if he problem persist, if so i cuold be something not properly updated when changing the schema (remember always clearing cache and building all classes every time you modify your schema)
Hope this helps!

properties of a n:m relation in doctrine

Hy guys
I've got the following schema for my objects:
Product:
columns:
name: { type: string(255) }
Basket:
columns:
current_status: { type: integer }
relations:
Products: { class: Product, refClass: BasketProducts, onDelete: CASCADE }
BasketProducts:
columns:
product_id: { type: integer, primary: true }
basket_id: { type: integer, primary: true }
quantity: { type: integer(4) }
relations:
Product: { local: product_id, onDelete: CASCADE }
Basket: { local: basket_id, onDelete: CASCADE }
Now in the frontend I try to show the users basket, getting the products by
foreach($basket->getProducts() as $product) {
echo $product->getId();
echo $product->getName();
}
The question now, how can i access the quantity field from the BasketProducts?
You will need to query the middle table directly in order to do this.
A good way to do this, is to add a function in your Basket.class.php that will retrieve the data you need based on a BasketID.
You could also create the function in your BasketTable.class.php if you'd like to include the data when fetching a particular basket (ie. getBasketWithProductQuantities())
I don't have any Doctrine code handy at this time.

Symfony Doctrine Schema Segmentation Fault

I'm setting up my first symfony project, and am having trouble with the schema. I'm not sure if I'm going about it the right way.
I'm having a problem with two of my classes. I have Clients, which can have many Contacts, one of the contacts needs to be selected as the invoice contact. This is my schema:
NativeClient:
actAs: { Timestampable: ~ }
columns:
name: { type: string(255), notnull: true }
address: { type: string(255) }
postcode: { type: string(9) }
tel: { type: string(50) }
fax: { type: string(50) }
website: { type: string(255) }
client_status_id: { type: integer, notnull: true, default: 0 }
priority: { type: boolean, notnull: true, default: 0 }
invoice_contact_id: { type: integer }
invoice_method_id: { type: integer }
relations:
NativeContact: { local: invoice_contact_id, foreign: id, foreignAlias: NativeInvoiceContacts }
NativeClientStatus: { local: client_status_id, foreign: id, foreignAlias: NativeContacts }
NativeInvoiceMethod: { local: invoice_method_id, foreign: id, foreignAlias: NativeClientStatuses }
NativeContact:
actAs: { Timestampable: ~ }
columns:
client_id: { type: integer, notnull: true }
name: { type: string(255), notnull: true }
position: { type: string(255) }
tel: { type: string(50), notnull: true }
mobile: { type: string(50) }
email: { type: string(255) }
relations:
NativeClient: { onDelete: CASCADE, local: client_id, foreign: id, foreignAlias: NativeClients }
NativeClientStatus:
actAs: { Timestampable: ~ }
columns:
name: { type: string(255), notnull: true }
NativeInvoiceMethod:
actAs: { Timestampable: ~ }
columns:
name: { type: string(255), notnull: true }
If i remove the following line (and associated fixtures) it works, otherwise I get a segmentation fault.
NativeContact: { local: invoice_contact_id, foreign: id, foreignAlias: NativeInvoiceContacts }
Could it be getting in a loop? Trying to reference the Client and the Contact over and over? Any help would be greatly appreciated! Thanks!
Darren
Old question I know, but heres a follow up solution. Sometimes Doctrine will throw this error for seemingly no reason whatsoever. Im sure there is an underlying reason, but we dont all have time to debug the entire Doctrine source.
Try specifying --env=[your env], and it may just work - has for me.
Darren, it seems like you're defining the relationship at both ends while using conflicting criteria...
NativeContact: { local: invoice_contact_id, foreign: id, foreignAlias: NativeInvoiceContacts }
...relationship is between "invoice_contact_id" and undeclared "id" PK in NativeContact.
NativeClient: { onDelete: CASCADE, local: client_id, foreign: id, foreignAlias: NativeClients }
... same relationship is between "client_id" and undeclared "id" PK in NativeClient.
I personally only define these in one end and let Doctrine handle the rest, but it depends on what you're trying to achieve here. If ONE client HAS MANY contacts, you could drop the second declaration and define the relationship in the clients table only and add "type: many, foreignType: one" to state that it's a one-to-many relationship.

Resources