I've been banging my head against the wall with a really annoying issue. I have two model classes:
class User extends AppModel {
var $name = 'User';
var $hasMany = array(
'Application' => array(
'className' => 'Application',
'foreignKey' => 'user_id',
'dependent' => false,
)
);
}
class Application extends AppModel {
var $name = 'Application';
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
)
);
}
I want to pull Applications and the fields of User associated with it.
$this->Applications->find();
No matter what I set $recursive to, it's still giving me only one output:
Array
(
[Applications] => Array
(
[id] => 1
[user_id] => 3
[datecreated] =>
[status] =>
[source] => 1
)
)
On the other hand, when I pull the data from Users table with recursive set to 2, I get all the users, with their applications, WITH the user data associated with the application WITH the applications associated with the user. To put it plain and simple, here's what I get:
Array
(
[0] => Array
(
[User] => Array
(
[id] => 3
[email] => email#email.email
[password] => hashstring
[socialsecurityno] => 21232134123
[role_id] => 3
[firstname] => Firstname
[lastname] => Lastname
[status] => 1
)
[Application] => Array
(
[0] => Array
(
[id] => 1
[user_id] => 3
[datecreated] =>
[status] =>
[source] => 1
[User] => Array
(
[id] => 3
[email] => email#email.email
[password] => hashstring
[socialsecurityno] => 21232134123
[role_id] => 3
[firstname] => Firstname
[lastname] => Lastname
[status] => 1
[Application] => Array
(
[0] => Array
(
[id] => 1
[user_id] => 3
[datecreated] =>
[status] =>
[source] => 1
)
)
)
)
)
)
)
What I want, is to get from the Applications, its associated user info, and that's it. I'm pretty much out of ideas short of creating a habtm relationship between applications and users, which would be technically incorrect, as one user can have many applications but one application only has one user.
Right now, Applications is connected with Users via user_id in Applications table, which... should be kind of obvious, but probably should be noted anyway.
Any kind of help with this could be appreciated, I'm literally out of ideas.
If Model::find is called with no parameters, Cake treats it as though you made this request:
Model::find('first',array('limit'=>1));
This explains why it's only retrieving the first Application. To retrieve all Applications, modify your call to:
$this->Application->find('all');
This doesn't explain why Model::find is ignoring the model's recursive setting, and, indeed, I can't find a way to reproduce that issue, unless it's something silly like you have typoed the model name when setting the recursion level (e.g. $this->Applications->recursive = 1;; note the pluralization of "Application").
Hope this helps.
Related
I have a attributes_products and a products table, i don't know why but my data are saved twice (for the attributes_products_table). so if i go to the product page i will insert one row, i will get one data but if there is one data for example, cake will save this data twice plus the new one. Thanks
if($this->request->is('post') || $this->request->is('put') ){
$d = $this->request->data;
if($this->Product->saveall($d, array('deep' => 'true'))){
$this->Session->setFlash("Le produit a bien été enregistré","notif");
}
}
Product Model ;
public $hasMany = array(
'AttributsProduct' => array(
'className' => 'AttributsProduct',
'foreignKey' => 'product_id',
'dependent' => false
),
'ImagesProduct' => array(
'className' => 'ImagesProduct',
'foreignKey' => 'product_id',
'dependent' => false
)
);
Array
(
[Product] => Array
(
[company_id] => 18
[name] => iWatch
[category_id] => 1
[description] => iWatch
[id] => 4
[main_image_file] => Array
(
[name] =>
[type] =>
[tmp_name] =>
[error] => 4
[size] => 0
)
)
[AttributsProduct] => Array
(
[1] => Array
(
[attribut_id] => 2
[description] => sceen
)
[2] => Array
(
[attribut_id] => 1
[description] => monitor
)
)
)
The new generated array for the HABTM record needs to know the existent id if it already exists, or a null if it's supposed to create a new record. In any case, it should have the belongsTo id as well for both tables in the relationship.
In CakePHP if I run the following find command
$this->Instructor->find('all');
the following is returned:
Array
(
[0] => Array
(
[Instructor] => Array
(
[id] => 1
[user_id] => 3
[bio] => A billionaire playboy, industrialist and ingenious engineer, Tony Stark suffers a severe chest injury during a kidnapping in which his captors attempt to force him to build a weapon of mass destruction. He instead creates a powered suit of armor to save his life and escape captivity. He later uses the suit to protect the world as Iron Man.
)
[User] => Array
(
[id] => 3
[first_name] => Tony
[last_name] => Stark
[asurite_user] => tstark
[asurite_id] =>
[password] =>
[email] => tstark#example.com
[created] => 2012-10-30 09:57:36
[modified] => 2012-10-30 09:57:36
)
[Course] => Array
(
[0] => Array
(
[id] => 1
[slug] => beatles
[sln] => AAA001
[course_number] =>
[title] => The Beatles
[description] => This is a class about the Beatles. If this were a real description, more information would be listed here.
[state] =>
)
[1] => Array
(
[id] => 2
[slug] => elvis
[sln] => AAA002
[course_number] =>
[title] => Elvis: The King of Rock
[description] => All about the king of rock and roll, Elvis Presley.
[state] =>
)
)
)
[1] => Array
(
...
There is a many-to-many relationship between "Instructor" and "Course". How can I filter the results based on the "Course"s each "Instructor" belongs to? I tried the following without success:
$instructors = $this->Instructor->find('all', array(
'conditions' => array('Course.id' = 2)
));
If you're trying to restrict your parent item based on conditions against your child item, you can either do your main query through the child model instead of the main model, and contain() the rest, or use MySQL Joins - available in CakePHP via joins().
You need to (re)bind the associations for your Instructor model with hasOne and use these settings:
'CoursesInstructor' => array(
'className' => 'CoursesInstructor',
'foreignKey' => false,
'conditions' => 'Instructor.id = CoursesInstructor.id'),
'Course' => array(
'className' => 'Course',
'foreignKey' => false,
'conditions' => 'CoursesInstructor.course_id = Course.id');
This will generate the correct SQL with the required joins and your conditions will work.
I am working on building a json Rest api with CakePHP. It works great, except I can't seem to get the proper structure to the response.
I two tables: Users and Profiles. Users hasOne Profiles. Profiles has a foreign key.
Models: Users.php (with public $hasOne = 'Profile'), Profiles.php
Controller: UsersController.php
The response is:
[2] => Array
(
[User] => Array
(
[id] => 3
[firstname] => test
[lastname] =>
[email] =>
[password] =>
[created] => 2012-09-04 16:44:04
[modified] => 2012-09-04 16:44:04
)
[Profile] => Array
(
[id] =>
[skill] =>
[user_id] =>
)
)
I really want the response to be like this:
[2] => Array
(
[User] => Array
(
[id] => 3
[firstname] => test
[lastname] =>
[email] =>
[Profile] => Array
(
[id] =>
[skill] =>
[user_id] =>
)
)
)
I have looked in the join(), bind(), containable...I can't seem to find the solution for nested table. Any ides to get Profile to be nested within the Users?
Cakephp won't do it, since it isn't the structure it uses to manage data. You will have to do it manually. If you are working with a single result (as the given by find('first')) Try something like this (I haven't tested it):
$result = $this->User->find('first', array('conditions' => array('User.id' => 1)));
Set::insert($result, 'User.Profile', $result['Profile']);
uset($result['Profile']);
Ive a HABTM relationship where the output is like below, what i would like to do is have cakephp return a "list" with just the "friend.id" and "friend.company_name" and exclude the "User".
Ive spent quite a while researching how to do this and cant get it to work.
My "search method" in users controller; i think i need to use the containable behaviour but im not sure what to do. ive managed to get the "friend" results only show 2 fields but i need to get rid of the "User" results. How do i do this?
The relationship is defined as in the user model file;
var $hasAndBelongsToMany = array(
'Friend' => array(
'joinTable' => 'retailerrelationships',
'className' => 'User',
'foreignKey' => 'retailer_id',
'associationForeignKey' => 'supplier_id'
)
);
user action in user controller:
$this->User->Behaviors->attach('Containable');
$users=$this->User->find('all',array('conditions'=>array('User.id'=>$this->Auth->user('id')),'contain'=>array('Friend.id','Friend.company_name')));
$this->set('users' ,$users);
debug Output
Array
(
[0] => Array
(
[User] => Array
(
[id] => 104
[username] => admin
)
[Friend] => Array
(
[0] => Array
(
[id] => 107
[company_name] => carskitchens
[Retailerrelationship] => Array
(
[id] => 12
[retailer_id] => 104
[supplier_id] => 107
[created] => 2012-03-28 10:14:23
[modified] => 2012-03-28 10:14:23
)
)
[1] => Array
(
[id] => 112
[company_name] => mr manufacturer
[Retailerrelationship] => Array
(
[id] => 13
[retailer_id] => 104
[supplier_id] => 112
[created] => 2012-03-28 11:26:52
[modified] => 2012-03-28 11:26:52
)
)
)
)
)
You should look at the Set class.
Try this
Set::combine($results, '{n}.Friend.id', '{n}.Friend.company_name');
I would like to be able to list the 10 most popular tags (subjects) of my site on the right menu as an element.
I however have been thinking 30 minutes about this now and unlike ending up with 1 statement to do this, I seem to be ending up with 3 statements that would drastically decrease the performance of the site.
I have a site with short stories and tags. This is a HABTM (Has-and-belongs-to-many) relationship between them using a table 'stories_tags'. A story can have multiple tags and a tag can be used by multiple stories.
The goal is listing $tagname ($storycountwiththattag), from highest number of stories per tag, to 10th highest. I have this so far, but it doesn't seem too close.
$tags = $this->Tag->find('all',array('fields'=>array('Tag.name')));
$tags_count = $this->Tag->Story->find('count',array('conditions'=>array('Story.tag'=>$tags)));
debug($tags_count);
I have tried a lot of possible queries. I could do it with restricted find('all')'s, or with:
Getting all ID's of all tags
Running 1 count-query per tag...
Use those results.
But I have picked Cakephp to make better applications so I wondered how you guys would do this! The site gets only a few hundred visitors daily, so performance is not extremely vital, but avoiding extremely dumb queries seems something I should try to do even if some performance penalty wouldn't matter.
use counterCache on your tag (although you can't use with HABTM though, you'll have to define another "Tag hasMany StoriesTag" relationship. You can also Cache the query result.
I make some test in the same scenario but differents ModelNames. I hope you can use it.
function top(){
$options = array(
'fields' => array('*','COUNT(CategoriesEnterprise.enterprise_id) AS num')
, 'group' => array( 'CategoriesEnterprise.category_id' )
, 'order' => 'num DESC'
, 'limit' => '3'
, 'joins' => array(array(
'table' => 'categories',
'alias' => 'Category',
'type' => 'LEFT',
'conditions' => array('CategoriesEnterprise.category_id = Category.id')
))
);
$categories = $this->Category->CategoriesEnterprise->find('all', $options);
debug($categories);
$this->autoRender = false;
}
The result
Array
(
[0] => Array
(
[CategoriesEnterprise] => Array
(
[category_id] => 3
[enterprise_id] => 7
)
[Category] => Array
(
[id] => 3
[name] => Turismo y Viajes
[modified] => 2011-05-16
[created] => 2011-04-14
)
[0] => Array
(
[num] => 4
)
)
[1] => Array
(
[CategoriesEnterprise] => Array
(
[category_id] => 24
[enterprise_id] => 5
)
[Category] => Array
(
[id] => 24
[name] => Compras
[modified] => 2011-05-05
[created] => 2011-05-05
)
[0] => Array
(
[num] => 3
)
)
[2] => Array
(
[CategoriesEnterprise] => Array
(
[category_id] => 32
[enterprise_id] => 8
)
[Category] => Array
(
[id] => 32
[name] => Salud y Belleza
[modified] => 2011-05-16
[created] => 2011-05-16
)
[0] => Array
(
[num] => 3
)
)
)