Yii Relations with non-Primary keys - php

I have a mysql table and a mysql view I'm trying to build relations for.
The table(commissions) is as follows:
--commissions--
id(primary Key)
date_added
order_id
salesrep_id
customer_id
commission_total
status
The view(rep_view_customer) is as follows:
--rep_view_customer--
entity_id
email
first_name
last_name
company
I'm trying to relate rep_view_customer to commissions on commissions.customer_id = rep_view_customer.entity_id.
I've tried using the on option:
'rep_view_customer' => array(self::HAS_ONE, 'RepViewCustomer', '', 'on'=>'rep_view_customer.entity_id = t.customer_id')
I also tried setting the primary key for the rep_view_customer model using:
public function primaryKey(){
return 'entity_id';
}
But I always seem to end up with an error similar to:
CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]:
Column not found: 1054 Unknown column 't.customer_id' in 'where
clause'. The SQL statement executed was: SELECT
rep_view_customer.entity_id AS t1_c0,
rep_view_customer.email AS t1_c1,
rep_view_customer.first_name AS t1_c2,
rep_view_customer.last_name AS t1_c3,
rep_view_customer.company AS t1_c4 FROM rep_view_customer
rep_view_customer WHERE (rep_view_customer.entity_id =
t.customer_id)
I'm at my wit's end what to try next

You will have to create a foreign key inside repview_customer to relate to commissions. You won't be able to do it with just a primary key.

I did it this way and it works:
so in the commissions model you put: (it does the relation through itself within the model, then the join output will be the same as the normal relation but with other unique key in commission model)
public function relations()
{
return array(
'commission' => array(self::HAS_ONE, 'Commission', 'entity_id', 'on' => 'commission.customer_id=rep_view_customer.entity_id'),
'rep_view_customer' => array(self::HAS_MANY, 'RepViewCustomer', '', 'through' => 'commission', 'condition' => '...'),
),
}

Related

How to change default alias name in Yii 1.1?

I have joined with two table by using model association. This two tables are films and movie_streams But there is some error
My Query:
$film = Film::model()->with('movie_streams')->find(array('select' => '*', 'condition' => 'user_id=:user_id, 'params' => array(':user_id' => $user_id)));
Film.php model:
public function relations() {
return array(
'movie_streams' => array(self::HAS_MANY, 'MovieStream','movie_id'),
);
}
Error Message:
CDbCommand failed to execute the SQL statement: SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'user_id' in where clause is ambiguous
I saw by default taking alias name. For films table t and for movie_streams table t0
How to set manual alias what I want for my above two tables?
You can avoid the collision of tables aliases by specifying the alias property of the relation.
$comments = Comment::model()->with(array(
'author',
'post',
'post.author' => array('alias' => 'p_author'))
)->findAll();
use
model_name.feild_name
$film = Film::model()->with('movie_streams')->find(array('select' => '*', 'condition' => 'film.user_id=:user_id, 'params' => array(':user_id' => $user_id)));
or
avoid collision of table by using allias
$comments=Comment::model()->with(array(
'author',
'post',
'post.author'=>array('alias'=>'p_author')))->findAll(array(
'order'=>'author.name, p_author.name, post.title'
));
, more details here

Column not found: 1054 Unknown column 'TaskTags.id' in CakePHP

I have Three tables Projects, Tasks and Tags. Projects.id is the primary key of the first table, Tasks.id is the PK of the second table and Tags.id is the PK of Third table.
$test = $this->Projects->find('all',
array(
'recursive' => 2
)
);
Returns right data.
But
$test = $this->Projects->find('all',
array(
'recursive' => 2,
'conditions' => array('Tags.id = ' => '10')
)
);
Gives below error.
Column not found: 1054 Unknown column 'Tags.id' in 'where clause'.
I do have id field for Tags table, Why getting this error?
Projects Model Code snippet
public $primaryKey = 'id';
public $hasMany = array(
'Tasks' => array('className' => 'Tasks','foreignKey' => 'project_id')
);
Tasks Model Code snippet
public $primaryKey = 'id';
public $hasMany = array(
'Tags' => array('className' => 'Tags','foreignKey' => 'task_id')
);
This is because you can not pass condition on hasMany associated Model fields.
To make this work, pass "joins" in the Find condition, this will work fine.
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html

Using self::STAT in relations to find the single latest related record

I am now having two tables tbl_user and tbl_log, and User and Log ActiveRecord classes respectively.
tbl_log
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`log_date` datetime NOT NULL,
`remarks` varchar(255) NOT NULL,
User class relations
public function relations() {
return array(
'rLog' => array(self::HAS_MANY, 'Log', 'user_id'),
);
}
What I am trying to achieve is to retrieve the latest record on tbl_log, that belongs to a certain user.
I have tried to add the following relation to the User class:
'lastLogDate' => array(self::STAT, 'Log', 'user_id', 'select'=>'log_date', 'order'=>'log_date DESC', 'group'=>'user_id', 'defaultValue'=>'N/A'),
so that I could retrieve the log_date from the latest record by calling something like:
$model = User::model()->findByPk($id);
echo $model->lastLogDate;
But then I realized it was actually not working properly. The log_date returned was always from the record with the smallest id on the tbl_log table, probably due to the behavior of GROUP BY and ORDER BY on a SQL query.
So now, I would like to know how (if possible) to achieve this by using a similar approach (i.e. using relations in the ActiveRecord class)? Thanks in advance.
The idea to go is using 'order' and 'limit', example:
'order'=>'log_date DESC',
'limit'=>1,
But you were wrong when use this type of relationship SELF::STAT, it is used to count the returned of records, not latest record
I don't usually use it that way, instead here is how I will:
In Log model, you should have:
public function relations()
{
return array(
'belongUser' => array(self::BELONGS_TO, 'User', 'user_id'),
}
And it would be simple like below
//get first found Log record of the user by given user_id and sort by log_date DESCENDANT
$lastLogDateRecord = Log::model()->with(array(
'belongUser' => array(
'condition' => 'user_id = :user_id',
'params' => array('user_id'=>$id) //$id is user_id param what user want
)
))->findByAttributes(array(), array('order' => 'log_date DESC'));

Ordering posts by their tag in a HABTM relationship

I have correctly set up a HABTM relationship between Post and Tag. When the user navigates to a URL like http://site.com/tag/test I want to show all the posts tagged with test.
Using the following code gets the tag information and all the posts which have that tag:
public function view($name) {
$this->set('tag', $this->Tag->findByName($name));
}
However, the posts it returns are not sorted by their created column, they seem to be retrieved on a "first come first serve" basis. I tried doing this:
public function view($name) {
$this->set('tag', $this->Tag->findByName($name, array(
'order' => array('Post.created DESC')
)));
}
However that gave me an SQL error:
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Tag.'
in 'field list'
SQL Query: SELECT DISTINCT Tag.` FROMportfolio.tagsASTag
WHERETag.name` = 'test' LIMIT 1
Is there any way for me to order posts from newest to oldest in the query or do I have to reformat the result array in my controller?
You need to do a find on the Post model and then force an ad-hoc join from the join table to the tag table, set a condition where Tag.name = $name and sort Post.created DESC
Or by rebinding some models. Example from cookbook:
$this->Recipe->bindModel(array(
'hasOne' => array(
'RecipesTag',
'FilterTag' => array(
'className' => 'Tag',
'foreignKey' => false,
'conditions' => array('FilterTag.id = RecipesTag.tag_id')
))));
$this->Recipe->find('all', array(
'fields' => array('Recipe.*'),
'conditions'=>array('FilterTag.name'=>'Dessert')
));
Apply it to your case (Recipe - > Post and RecipesTag -> PostsTag) and just add your sort

Relational Yii ActiveRecord for table with composite key having NULL values

For storing user-defined bookmarks on some site, I have a table with the composite key:
CREATE TABLE bookmarks (
user_id int not null,
book_id int not null,
page_id int,
...
);
CREATE UNIQUE INDEX ON bookmarks(user_id, book_id, page_id);
Note, that page_id can be NULL, and user_id and book_id can not. When page_id is null, the bookmark is set for the whole book, otherwise - for certain page.
Corresponding ActiveRecord class defines some relations:
public function relations() {
return array(
"user" => array(self::BELONGS_TO, "User", "user_id"),
"book" => array(self::BELONGS_TO, "Book", "book_id"),
"page" => array(self::BELONGS_TO, "Page", "page_id"),
);
}
and a primaryKey() method::
public function primaryKey() {
return array("user_id", "book_id", "orig_id");
}
Now I want to get all bookmarks for the whole book for some user. So, I do:
$bookmarks = Bookmark::model()->findAll(array(
"condition" => "t.user_id = :user_id AND t.page_id IS NULL",
"params" => array(":user_id" => 1),
));
It works great, returning 4 records, but obviously, I want to use some related data from books table:
$bookmarks = Bookmark::model()->findAll(array(
"with" => "book",
"condition" => "t.user_id = :user_id AND t.page_id IS NULL",
"params" => array(":user_id" => 1),
));
and now I get 0 records (count($bookmarks) == 0), although the generated SQL statement selects all needed data, it is just not recognised by CActiveRecord class. Another weird thing is, that when I try to fetch all page bookmarks, everything is okay:
$bookmarks = Bookmark::model()->findAll(array(
"with" => "book",
"condition" => "t.user_id = :user_id AND t.page_id IS NOT NULL",
"params" => array(":user_id" => 1),
));
What am I doing wrong? How to make expression in the second example return some data? PHP 5.4.0, Yii 1.1.8, PostgreSQL 9.1.4, +32°C outside.
Your issue may be solved in this way:
Add a surrogate PK to the Bookmark table (e.g. auto-incremental sequence).
Remove primaryKey() function.
You may also use more convenient code:
public function relations()
{
return array(
//...
'wholeBook' => array(self::BELONGS_TO, 'Book', 'book_id', 'on'=>"page_id IS NULL", 'joinType'=>'INNER JOIN'),
//...
);
}
Then in the controller just:
$bookmarks = Bookmark::model()->with('wholeBook')->findAllByAttributes(array('user_id'=>1));
As a matter of fact, with UNIQUE key instead of PRIMARY and primaryKey() you use hack to evade impossibility of using NULL column in composite PKs.
ActiveRecord is a sort of ORM, so any logic in SQL must be translated into AR (Yii automatically loads DB schemas), and it must be correct logic.
If I were you I'd normalize SQL to something like this:
Because of those are two different types of bookmarks with different relations. You should join them only in view logic, not in relation structure. IMHO

Categories