I'm using Symfony 1.4 with Doctrine.
Here's my initial schema:
Page:
tableName: page
columns:
ref:
type: string(50)
notnull: true
unique: true
I'd like to remove the index on the ref column using migrations.
So the schema becomes:
Page:
tableName: page
columns:
ref:
type: string(50)
notnull: true
And my migration file is something like:
class Changepageref extends Doctrine_Migration_Base
{
public function up()
{
$this->removeIndex('page','ref');
}
public function down()
{
$this->addIndex('page','ref', array('fields'=>array('ref'=>array()),'unique'=>true));
}
}
But this won't work when I run it because it's looking for an index named "ref_idx". But if I look at my database, doctrine created an index named "ref", not "ref_idx".
What am I doing wrong?
You can define the default naming of the indexes: the default is "_idx". You can change in on the connection manager.
http://www.doctrine-project.org/projects/orm/1.2/docs/manual/configuration/en#naming-convention-attributes shows it like
$manager->setAttribute(Doctrine_Core::ATTR_IDXNAME_FORMAT,
'%s_index');
Try to set it there and it should be persistent throughout your application with the index names.
Related
I need some help here understanding how this works. See I'm using sfDoctrineGuardPlugin and add a Profile table as follow:
SfGuardUserProfile:
connection: doctrine
tableName: sf_guard_user_profile
columns:
id: { type: integer(8), primary: true }
user_id: { type: integer(8), primary: false }
idempresa: { type: integer(4), primary: false }
relations:
User:
local: user_id
class: sfGuardUser
type: one
foreignType: one
foreignAlias: SfGuardUserProfile
onDelete: CASCADE
onUpdate: CASCADE
Now I need to setup a field value based on logged in user in SdrivingEmisorForm, for that I need to access to idempresa on sf_guard_user_profile but I don`t know how :-( I tried all this:
$user = sfContext::getInstance()->getUser();
echo $user->getGuardUser()->getProfile()->getIdempresa();
echo $this->getUser()->getGuardUser()->getProfile()->getIdempresa();
echo $user->getProfile()->getIdempresa();
and none works, which is the right way to access to profile fields based on my schema definition? Can any take a brief and explain a bit how I must understand this in order to no get the same doubt if things changes some day?
EDIT
I've found the solution but using sfContext::getInstance() which many says is wrong, so in this case what is the right way to do this. Below th code works for me:
$user = sfContext::getInstance()->getUser()->getGuardUser()->getSfGuardUserProfile()->getIdempresa();
PS: I'm access from SdrivingEmisorForm class
You are defining the foreignAlias as SfGuardUserProfile, so you should use this name for the getter.
In some action:
$profile = $this->getUser()->getGuardUser()->getSfGuardUserProfile();
In some template:
$profile = $sf_user->getGuardUser()->getSfGuardUserProfile();
Then:
echo $profile->getIdempresa();
I have simple schema with one-to-one relation:
Site:
columns:
name: { type: string(255) }
User:
columns:
name: { type: string(255) }
site_id: { type: integer }
relations:
Site: { foreignType: one }
I am overriding Site::save() method (which is called when I edit Site from admin generator), where I need to do smth with User, and User references Site again:
echo $this->getUser()->getSite()->getName();
When getSite() is called, $this is overwritten by values from database, because Doctrine loads "Site" relation from db and replaces $this according to identity map. Obviously, all changes to object are lost. After some code reading i got that User object does not have _references['Site'] set after getUser(), that's why Doctrine tries to load Site from db. If i prepend
$this->getUser()->setSite($this);
, then everything works as expected and no additional queries are made. Another workaround is to join relations in query:
$this->site = Doctrine::getTable('Site')
->createQuery('s')
->leftJoin('s.User u')
->leftJoin('u.Site us')
->fetchOne();
But is that an intended behaviour? How can I make Doctrine know that $this === $this->getUser()->getSite()? I use symfony 1.4.18 with Doctrine 1.2.4. Thank you.
I have changed the schema of a Symfony application by transforming a one-to-many relationship to a many-to-many relationship between a Sample model and a Collector model. The Sample model had a collector_id foreign key and now there is an intermediate model (SampleCollectors) with two foreign keys: sample_id and collector_id.
Sample:
columns:
id: { type: integer, primary: true, autoincrement: true }
...
collector_id: ... # This column is removed
...
relations:
...
Collectors: { foreignAlias: Collectors, class: Collector, local: sample_id, foreign: collector_id, refClass: SampleCollectors }
Collector:
columns:
id: { type: integer, primary: true, autoincrement: true }
...
relations:
Samples: { foreignAlias: Samples, class: Sample, local: collector_id, foreign: sample_id, refClass: SampleCollectors }
SampleCollectors:
columns:
sample_id: { type: integer, primary: true }
collector_id: { type: integer, primary: true }
relations:
Sample: { onDelete: cascade }
I have edited the schema.yml file like above and executed the following tasks:
php symfony doc:generate-migrations-diff
php symfony doc:build --all-classes
which has rebuilt every involved model/form/filter and created two migration classes.
Since the database is already in production-mode, I have tuned the migration classes to move the foreign key of the one-to-many relationship (Sample.collector_id) to the many-to-many intermediate table (SampleCollectors.collector_id):
public function preUp() {
$sampleTable = Doctrine_Core::getTable('Sample');
// I do this because collector_id has disappeared after model regeneration.
$sampleTable->setColumn('collector_id', 'integer', null, array('type' => 'integer'));
$this->samples = $sampleTable->findAll()->toArray();
}
public function up() {
// ...
$this->removeColumn('sample', 'collector_id');
// ...
$this->createTable('sample_collectors', array(...), array(
'type' => 'INNODB',
'primary' => array(0 => 'sample_id', 1 => 'collector_id'),
...));
}
public function postUp() {
foreach ( $this->samples as $sample ) {
$sampleCollector = new SampleCollectors();
$sampleCollector->setSampleId($sample['id']);
$sampleCollector->setCollectorId($sample['collector_id']);
$sampleCollector->trySave();
}
}
I have migrated the database and everything went apparently well.
But now that I'm updating the controllers, views, etc., Doctrine still tries to retrieve the collector_id column from Sample, instead of navigating through the many-to-many relationship.
Since the Sample model does not store a reference to it anymore, why does Doctrine insist on that? I checked the BaseSample class and it does not have a hasColumn() method setting a column collector_id. BTW, I clear the cache as well.
Thanks!
I finally found the problem. I had configured Doctrine to use the APC cache system in ProjectConfiguration class:
public function configureDoctrine(Doctrine_Manager $manager) {
$manager->setAttribute(Doctrine::ATTR_QUERY_CACHE, new Doctrine_Cache_Apc());
}
This cache is not cleared when you execute php symfony cache:clear, since is not a Symfony thing but a PHP and web server thing.
You can either restart the web server or use apc_clear_cache(), as noted in this question regarding APC cache.
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
I'm doing a blog engine in Symfony. Here's part of my schema :
Content:
connection: doctrine
tableName: ec_content
columns:
id:
type: integer(4)
fixed: false
unsigned: true
primary: true
autoincrement: true
(...)
relations:
Author:
local: author_id
foreign: id
type: one
State:
local: state_id
foreign: id
type: one
Type:
local: type_id
foreign: id
type: one
(...)
In the administration pages, I want to display the type of the articles, but symfony only shows the type_id, why is that ?
EDIT: here's my generator.yml : I haven't modified it much yet.
generator:
class: sfDoctrineGenerator
param:
model_class: Content
theme: admin
non_verbose_templates: true
with_show: false
singular: ~
plural: ~
route_prefix: content_Brouillons
with_doctrine_route: true
actions_base_class: sfActions
config:
actions: ~
fields: ~
list:
title: Brouillons
display: [Type, State, title, link]
filter: ~
form: ~
edit: ~
new: ~
OK.
In your generator.yml, on the display line, Symfony (via Doctrine) will look for a field name in your model class that corresponds to each field you want to display. If the field name doesn't exist, it will then look for a corresponding getFieldName() method and call that.
In your example, you have Type as a field name, which will be calling getType() - this will fetch the relation in. By default, Doctrine assumes that when you want to convert a model to a string (eg for display in your list), you want to use the primary key - in your case, the ID value.
To overcome this, add a __toString() method as follows, to your Doctrine lib/model/doctrine/EcType.class.php file:
class EcType extends BaseEcType
{
public function __toString()
{
return $this->type;
}
}
and you should see the 'type' field being displayed in your admin generated list.