One Way One-To-One Association in CakePHP - database

I have an idea of how to do this but it doesn't seem like proper convention. I have a Submission model and a Revision model each with their similarly named tables. Each Submission can have one or more Revisions associated to it in a $hasMany relationship. The Revision model hence has a $belongsTo relationship linking back to the Submission.
In addition to having this relationship, the Submission model needs to have another association (called activeRevision) to a particular Revision in a $hasOne style of relationship. However, the $hasOne type requires the foreign key to be in the Revision table. I want it to be in the Submission table, so I don't need to query all of the Submission's Revisions to find the active one. I realized just specifying a $belongsTo relationship in the Submission would do what I want, but this feels wrong to me as now the two models "belong to eachother".
Is there a better way to go about this?

I wouldn't worry too much because of the 'naming' of the relation. By having the foreign key of the Revision inside the Submission table, CakePHP is, in fact, right that you've created a 'belongsTo' relation.
Although not strictly the 'right' (?) relation, in this situation, this looks like it's an easy way to achieve what you want. Just be sure to add an additional condition to your relation to prevent that a revision of another submission can be set as the current revision, i.e.;
public $belongsTo = array(
'Revision' => array(
'conditions' => array(
'Revision.submission_id = Submission.id',
)
)
);
However, make sure to add a proper comment in your code to prevent confusion if you're (or somebody else is) looking at your code in a later stage. (e.g. "note: using belongsTo relation, because its easier to maintain)
If you really want to convert it to a hasOne relation, you'll have to add an additional column to the 'Revisions' table, for example 'is_curreny_revision'. However, you will also need to be sure that only one revision of a submission can be set to be the current revision.
If you're using PostgreSQL, this can be achieved using a 'partial unique' index (see this question on StackOverflow; PostgreSQL: Conditional unique constraint). MySQL does not support partial indexes, so you're out of luck there

Related

How can i get cakephp current model's foreign key column name?

Is there way to get current model's foreign key name in other model something like this
echo $this->Category->whatIsMyForeignKeyName();
// expected output 'category_id'
Edit: Version
strtolower($this->Category->alias).'_id'
somehow seems not in spirit of cake.
If you know what kind of relation it is (belongsTo for example), you can easily look it up in the defined relations:
$foreignKey = $this->belongsTo['Category']['foreignKey'];
What you did with strtolower will work in almost all (or maybe all?) cases, though a slightly more thorough way would be something like:
$fkey = Inflector::singularize(Inflector::tableize($this->Category->alias)).'_id';
But the question I'd be asking is why do you want to do that? Why not just hard-code it as 'category_id'?
I had the same issue and I solved it in another way.
joshua.paling's solution finds you the default foreign key. Anyway, I think you can find it a step easier:
Inflector::underscore($baseModelName).'_id';
But as a matter of fact a model may have different foreign keys for each associations. Let's assume there is a "Base" and it has many "Associated" (these are dummy names for models). The relations is "hasMany" relation.
So your definition of "Base" model is the following:
class Base extends AppModel {
public $hasMany = array(
'Associated'
);
}
In the "BaseController" you can retrieve the foreign key that links these models together in the following way:
$this->Base->hasMany['Associated']['foreignKey']
This is the foreign key used for linking "Associated" rows to the relating "Base" row in the database.
I know this question is already answered more then a year ago but I hope my answer could help some other people :)

CakePHP baking fixtures doesn't care about unique fields

An example:
I have a User model with a field 'username'
In the $validate array, I have set 'isunique' rule for 'username'. It works, no problem.
But every time I generate fixture, the auto generated value for this field is not unique.
Same problem for other models.
Any idea how to get bake to produce unique values for fileds with 'isunique' rule?
Thank you.
Why do you even think cake/fixtures would so such a thing?
It doesnt!
Your validation rules have absolutely nothing to do with your indexes.
Validation get triggered when using validates() or save().
But your database does not have to have those "unique" indexes for it to work.
If you really want them in your fixtures, too, you need to define them there manually (see the primary key index on how to do that).

Implementing tag clouds with CakePHP

I did a little research on tag clouds, and I ended up choosing a schema similar to the Wordpress one seen in this page: http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html
Currently, the tables that I have created is: Posts, PostsTagMaps, PostsTags
1) Would I need to create a table for PostsTagMaps even if I don't plan on using a controller?
2) A Post hasMany PostTagMaps. I'm not sure where should I be defining this relationship. I think it should be the Post model, but then I would have to join the PostsTags table to PostTagsMaps then join it to Posts, so I wanted to ask for some advice.
The easy solution is to follow Cake conventions (which will look very similar to the solution you linked to). You'll have three tables:
posts, tags, posts_tags
Then your Post model HABTM Tag model. The join table will automatically be used by Cake to save and retrieve the information. Check the book for more information on setting up your schema.
Cake is flexible enough where you can do it however you want, but if it's a basic sort of posts-tags relationship, the convention method is the way to go.
If you want to use a custom model/table like PostsTagMaps, then do this by using the 'with' key in your HABTM relationship definition. The 'with' key tells Cake to use a specific model (and therefore a specific table) instead of an automatically generated version. In this case, your tag model sounds like it's PostsTags and your HABTM table is PostsTagMaps, so the 'with' key on Post HABTM PostsTag would be PostsTagMap.

CakePHP Associations, Containable, and Threaded

Hi I've got a couple of questions regarding associations and how they play in cases
of complex find() calls.
If I've got a model Post and a model Comment with the latter having a parent_id field
and I want to fetch a post with its associated comments threaded, do I simply perform a
find('threaded', ...) on Post itself or will this result in an error because Post doesn't
have a parent_id? I am particularly concerned about a Containable + Threaded find. (the
example I give here is a simplified version of what I actually need to implement)
What is the significance of Association Names? Does Containable work on association names
or model names? (the reason I want to know this is because I'm trying to implement polymorphic models by having condition-specific model associations, often having multiple associations to the same model)
I think that containable would not support threaded finds on the contained models. EG you might have a post_id column in your comments table, and do something like:
$this->Comment->find('threaded', array(
'conditions' => array(
'post_id' => 5)));
Although the book may say that Containable uses the model name, I have regularly used the association name in Containable when I have multiple joins between the same models. For simple projects, the model name is usually the same as the association name, so that may be why the book says that.

CakePHP hasAndBelongsToMany (HABTM) Delete Joining Record

I have a HABTM relationship between Users and Locations. Both Models have the appropriate $hasAndBelongsToMany variable set.
When I managing User Locations, I want to delete the association between the User and Location, but not the Location. Clearly this Location could belong to other users. I would expect the following code to delete just the join table record provided the HABTM associations, but it deleted both records.
$this->Weather->deleteAll(array('Weather.id' => $this->data['weather_ids'], false);
However, I am new to CakePHP, so I am sure I am missing something. I have tried setting cascade to false and changing the Model order with User, User->Weather, Weather->User. No luck.
Thanks in advance for any help.
Not quite sure how Weather is related to your models, so I'll just go with the traditional names, LocationsUser is the joining table. This should delete all associations between the user with id $id and any locations:
$this->User->LocationsUser->deleteAll(array('LocationsUser.user_id' => $id), false);
Notice also that you're missing a closing bracket in your code snippet.

Resources