Cakephp belongsto with order - cakephp

So I have a self-referencing model like so.
class Category extends AppModel {
public $order = "Category.name";
public $belongsTo = array(
'ParentCategory' => array(
'className' => 'Category',
'foreignKey' => 'parent_id',
'order' => 'ParentCategory.name'
)
);
}
The sql query it produces is this:
SQL Query: SELECT `ParentCategory`.`id`, `ParentCategory`.`name` FROM `cakephp`.`categories` AS `ParentCategory` WHERE 1 = 1 ORDER BY `Category`.`name` ASC
Which will not work because "Category" is not a table name here.
What am I doing wrong here. Why is it not respecting my "order" rule?

I found the solution to a simliar issue in the CakePHP docs:
http://book.cakephp.org/2.0/en/models/virtual-fields.html#virtual-fields-and-model-aliases
So basically, anytime you want to use Model Aliasing, it is best to define the values in the constructor like this:
public function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
$this->order = $this->alias.".whatever";
}

Related

How to Inherit $belongsTo of AppModel in Extended Model in Cakephp

In Cakephp,
I have used belongsTo in AppModel
class AppModel extends Model {
public $actsAs = array('Containable');
public $belongsTo = array(
'ModifiedBy' => array(
'className' => 'User',
'foreignKey' => 'common_modified_by_user_id'
)
);
}
Now I also want to apply belongs to in UserModel
class User extends AppModel {
public $belongsTo = array(
'School' => array(
'className' => 'User',
'foreignKey' => 'school_id'
)
);
}
But when i do so...it over rides the belongsTo of App model and on School data comes in the fetched array....
Please Help...
No automatic merging of associations
Other than the $actsAs and $findMethods variables, association configurations are not being merged automatically, you'll have to do that on your own.
It should be rather simple to solve, using Object::_mergeVars() in your User models constructor should do the trick:
public function __construct($id = false, $table = null, $ds = null) {
$parent = get_parent_class($this);
$this->_mergeVars(array('belongsTo'), $parent);
parent::__construct($id, $table, $ds);
}
ps. you might want to have a look at behaviors, they might be the better option for your needs.

Dynamic model relations in CakePHP

I'm trying to define the relations for a specific Model depending on environment variables.
Like this:
class Book extends AppModel {
public function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
if (Configure::read('prefix') == 'admin') {
$this->hasMany['Page'] = array(
// ...
'conditions' => array( /* all pages */ )
);
} else {
$this->hasMany['Page'] = array(
// ...
'conditions' => array( /* only public pages */ )
);
}
}
}
You could argue that I should apply these conditions in the query. But because I'm working with deeply nested relations I wanted to keep conditions centralised.
Now the problem that occurs is: if the Page model has relations to e.g. the Paragraph model and from the BookController I'm trying:
$this->Book->find('first', array(
'conditions' => array('Book.id'=>1),
'contain' => array('Page' => array('Paragraph'))
));
... CakePHP will tell me that Paragraph is not related to the Page model.
If I create the relation by defining a model attribute all goes well:
class Book extends AppModel {
public $hasMany = array(
'Page' => array(
// ...
)
);
}
Why is this? Do I need to manually establish those relations? Is my timing (__construct()) incorrect and should this be done elsewhere?
Kind regards,
Bart
Yes, your timing is incorrect. You should either apply these configuration options before invoking the parent constructor:
if (Configure::read('prefix') == 'admin') {
// ...
}
parent::__construct($id, $table, $ds);
or use Model::bindModel() instead which will create the necessary links:
$this->bindModel(
array('hasMany' => array(
'Page' => array(
// ...
'conditions' => array( /* ... */ )
)
)),
false
);
See also http://book.cakephp.org/...html#creating-and-destroying-associations-on-the-fly

CakePHP Model to contain iteself

I need to join a model to itself... but I get the error "Not unique table/alias: 'Image'"
Image Schema:
id: int
thumbnail_image_id: int null
key: varchar... filename
location: varchar... s3 or local
created: datetime
modified: datetime
Image Model:
<?php
App::uses('AppModel', 'Model');
class Image extends AppModel {
public $belongsTo = array(
'Thumbnail' => array(
'className' => 'Image',
'foreignKey' => 'thumbnail_image_id'
)
);
public $hasOne = array(
'Thumbnail' => array(
'className' => 'Image',
'foreignKey' => 'thumbnail_image_id'
)
);
public function exampleFunction() {
return $this->find('all', array(
'contain' => array('Thumbnail')
));
}
Running exampleFunction it gives me the error "Not unique table/alias: 'Image'". CakePHP builds the SQL like this:
SELECT `Image`.`id`, `Thumbnail`.`id` FROM `images` AS `Image` LEFT JOIN `images` AS `Image`.`thumbnail_image_id` = `Thumbnail`.`id`;
but it should be something like this... right? (notice the inverted ON):
SELECT `Image`.`id`, `Thumbnail`.`id` FROM `images` AS `Image` LEFT JOIN `images` AS `Thumbnail`.`id` = `Image`.`thumbnail_image_id`;
If I run both SQL queries above in mysql console the second works.
Suggestions?
The problem is that you have used Thumbnail in both $belongsTo and $hasOne.
The Model will have no idea which association to use for the 'contain'.
Rename or remove one of your associations so they are unique.

cakephp model with hasmany

I have question in cakephp model,
I want to add dynamic condition in var $hasMany keyword
I want to add condition like current user_id, i got user Id after my login.
var $hasMany = array(
"AskComment"=>array('limit'=>3),
'AskStatistic',
'AskContactsLink',
'AskStatistic',
'AskObject',
'AskLikes'
);
If you want to add dynamic condition in your model, then you might have to bind the model association-ship dynamically into your controller's code. Write the following code into your controller's method for which you want to impose some new condition on the existing/new associated models.
$this->PrimaryModel->bindModel(array('hasMany' => array(
'AskComment' => array(
'className' => 'AskComment',
'foreignKey' => 'primary_id',
'conditions' => array('AskComment.user_id' => $user_id)
)
)
));
Take a look at this link: Creating and destroying associations on the fly. This will surely help you to achieve the same.
I think its better to put your association in the construct function of your Model.
like this:
/**
* #see Model::__construct
*/
public function __construct($id = false, $table = null, $ds = null) {
public $hasMany = array(
'AskComment' => array(
'className' => 'AskComment',
'foreignKey' => 'primary_id',
'conditions' => array(
'AskComment.user_id' => $user_id,
),
),
);
}

CakePHP containable order condition not working

I'm having problems with a very simple ordering query. I have a Post model and a Tag model with a HABTM relationship and am trying to return a list of all posts with a particular tag assigned to them, ordered by the date the post is created.
$this->set('data', $this->Post->Tag->find('all', array(
'conditions' => array('Tag.id' => 1),
'contain' => array('Post' => array(
'order' => 'Post.created_date desc'
))
)));
While this returns the list of posts, it is not sorted by date.
With debugging on, it looks like the following query is being used:
SELECT `Post`.`id`, `Post`.`title`, `Post`.`created_date`, `PostsTag`.`post_id`, `PostsTag`.`tag_id`
FROM `database`.`posts` AS `Post`
JOIN `database`.`posts_tags` AS `PostsTag` ON (`PotsTag`.`tag_id` = 1 AND `PostsTag`.`post_id` = `Post`.`id`)
Code for posts model:
class Post extends AppModel {
public $name = 'Post';
public $hasAndBelongsToMany = array('Tag');
}
Code for tags model:
class Tag extends AppModel {
public $name = 'Tag';
public $hasAndBelongsToMany = array('Post');
}
Any help on the issue would be much appreciated - I'm using CakePHP 2.1. if it makes any difference.
What about defining the order attribute in your Tag Model?
Like e.g.
var $hasAndBelongsToMany = array(
'Post' => array(
'order' => 'Post.created_date'
)
);
I don't think that the "order" should be inside of "contain".
Try with:
$this->set('data', $this->Post->Tag->find('all', array(
'conditions' => array('Tag.id' => 1),
'contain' => array('Post'),
'order' => 'Post.created_date desc'
)));
or just:
$this->set('data', $this->Post->Tag->find('all', array(
'conditions' => array('Tag.id' => 1),
'order' => 'Post.created_date desc'
)));
Read this:-
http://www.jamesfairhurst.co.uk/posts/view/adding_tags_to_a_cakephp_app_hasAndBelongsToMany/
http://edivad.wordpress.com/2007/04/19/cakephp-hasandbelongstomany-habtm/
//try this
CREATE TABLE `tags` (
`id` int(11) NOT NULL auto_increment,
`tag` varchar(100) NOT NULL,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `posts_tags` (
`post_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL
);
//Creating the Models and Relationships
class Tag extends AppModel {
var $name = 'Tag';
var $hasAndBelongsToMany = array('Post'=>array('className'=>'Post'));
}
class Post extends AppModel {
var $name = 'Post';
var $hasMany = array('Comment'=>array('className'=>'Comment'));
var $hasAndBelongsToMany = array('Tag'=>array('className'=>'Tag'));
}

Resources