I have a few nested models which I'm trying to load using Containable behaviour in CakePHP.
Most of it works fine.
However, 1 model that has a hasMany relation only returns 1 object:
$article = $this->News->find('first',array(
'conditions'=>array('News.id'=>$id),
'contain' => array(
'Newslayout',
'Newspicture'=> array(
'NewspicturesProduct' => array(
'Product' => array(
'Brand',
'Category'
)
)))
));
The object only being loaded once is the relation Newspicture hasMany NewspicturesProduct
When I log the queries, I get the following:
SELECT `NewspicturesProduct`.`id`, `NewspicturesProduct`.`x`, `NewspicturesProduct`.`y`, `NewspicturesProduct`.`product_id`, `NewspicturesProduct`.`newspicture_id`, `NewspicturesProduct`.`w`, `NewspicturesProduct`.`h` FROM `edclondon`.`newspictures_products` AS `NewspicturesProduct` WHERE `NewspicturesProduct`.`newspicture_id` = 3
Which gives me 3 results in phpMyAdmin. But only 1 in CakePHP's debug:
'Newspicture' => array(
(int) 0 => array(
'id' => '3',
'news_id' => '2',
'newspicture_file_path' => '5022443f-ddf8-4115-ae57-618e9d60b047.jpg',
'newspicture_file_size' => '1232546',
'order' => null,
'NewspicturesProduct' => array(
'id' => '1',
'x' => '0.180664',
'y' => '0.295312',
'product_id' => '3',
'newspicture_id' => '3',
'w' => '0.286133',
'h' => '0.478125',
'Product' => array(
'id' => '3',
//....
'Brand' => array(
'id' => '6',
//...
),
'Category' => array(
'id' => '6',
//....
)
)
)
)
When retrieving the Newspictures object rather then retrieving the News object, I do get all 3 NewspicturesProduct objects.
It seems to me that the code corresponding the query you showed should be:
$article = $this->News->find('first',array(
'contain' => array(
'Newslayout',
'Newspicture'=> array(
'NewspicturesProduct' => array(
'conditions'=>array('NewspicturesProduct.newspicture_id'=>'3')
'Product' => array(
'Brand',
'Category'
)
)))
));
and not the one you gave...
It seems you need 3 records from NewspicturesProduct. If that then you can try:
$article = $this->News->find('first',array(
'contain' => array(
'Newslayout',
'Newspicture'=> array(
'NewspicturesProduct' => array(
'conditions'=>array(
'limit'=> 3
),
'Product' => array(
'Brand',
'Category'
)
)))
));
Related
I have cakephp 2.8 project, I have an array returned by Model->find('all',array('joins')) which is something like this
array(
(int) 0 => array(
'Result' => array(
'id' => '1',
'student_id' => '1',
),
'User' => array(
'fullname' => 'Alam'
)
),
(int) 1 => array(
'Result' => array(
'id' => '2',
'student_id' => '11',
),
'User' => array(
'fullname' => 'Student 1'
)
)
);
I want this array as below
array(
(int) 0 => array(
'id' => '1',
'student_id' => '1',
'fullname' => 'Alam'
),
(int) 1 => array(
'id' => '2',
'student_id' => '11',
'fullname' => 'Student 1'
)
);
I tried Set::extract('/Result/.'); , Set::extract('/Result/User/.'); and other variations but I am not getting desired result.
I know I can do it by foreach loop but I want if it can be done by some builtin php or cakephp function.
I haven't managed to use only one function, but, maybe this will do the trick for you:
$t = Hash::mergeDiff(
Hash::extract($inputArray, '{n}.Result'),
Hash::extract($inputArray, '{n}.User')
);
debug($t);
I have 3 model:
Association HasMany Service
Service HasBelongs Association and HasMany Member
Member HasBelongs Service
I want find member by association but I find Service by association.
$associations = $this->Member->Service->Association->find('all',
array(
'fields'=>array('id','libelle')
));
the result debug is:
array(
(int) 0 => array(
'Association' => array(
'id' => '1',
'libelle' => 'الادارة العامة للصحة العسكرية'
),
'Service' => array(
(int) 0 => array(
'id' => '1',
'libelle' => 'Divers',
'association_id' => '1'
),
(int) 1 => array(
'id' => '2',
'association_id' => '1'
),
(int) 2 => array(
'id' => '3',
'libelle' => 'مكتب الضبط BO',
'association_id' => '1'
)
)
),
(int) 1 => array(
'Association' => array(
'id' => '2',
'libelle' => 'أعضاء الديوان والمديرين'
),
'Service' => array()
),
(int) 2 => array(
'Association' => array(
'id' => '3',
'libelle' => 'المستشفات والمراكز والمصحات '
),
'Service' => array()
),
(int) 3 => array(
'Association' => array(
'id' => '4',
'libelle' => 'المستشفى العسكري الاصلي للتعليم '
),
'Service' => array()
)
I want find the member by association example: all member that belong to the Association الادارة العامة للصحة العسكرية ie all members of the services 1, 2, 3
You can use 'contain' to do that.
There are some examples in the book: http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
In Cakephp I need to get the tutors who teach a subject 'primary English'. Instead I get all the tutors with any subject so the condition gets ignored with no error. There is a habtm relationship between tutors and subjects they teach.
$this->Tutor->Behaviors->load('Containable');
$tutors=$this->Tutor->find('all',array(
'contain' => array('Subject',array( 'conditions'=> array('Subject.name' => 'Primary English'))),
'contain' => array('Subject'),
'recursive' =>-1,
// 'order'=> $orderoptions,
'fields'=>array('Tutor.last_name', 'Tutor.first_name','Tutor.id' ),
));
debug( $tutors);
array(
(int) 0 => array(
'Tutor' => array(
'last_name' => 'Wyers',
'first_name' => 'Adele',
'id' => '13'
),
'Subject' => array()
),
(int) 1 => array(
'Tutor' => array(
'last_name' => 'Payet',
'first_name' => 'Allison',
'id' => '7'
),
'Subject' => array(
(int) 0 => array(
'id' => '4',
'name' => 'English - Year 11',
'TutorsSubject' => array(
'id' => '30',
'tutor_id' => '7',
'subject_id' => '4'
)
),
Remove 'recursive' => -1. This prevents it from selecting relationships recursively. If this still doesn't work then put 'recursive' => 2 in.
I have a site with the usual sort of sellers, items and images. The models look like this:
class Seller extends AppModel {
$hasMany = array('Item');
...
}
class Item extends AppModel {
$belongsTo = array('Seller')
$hasMany = array('Image');
...
}
class Image extends AppModel {
$belongsTo = array('Item');
...
}
My problem is that when I retrieve a list of Items, the data comes out in a different format depending on whether I am getting a list of all Items (to display to the public) in the ItemsController, or the details of a Seller and their Items in the SellersController.
Briefly Item->find('all') retrieves an array of
array( 'Item' => array( <item stuff> ),
'Images' => array of array( <image stuff> ) );
whereas the Seller->find('first', ...) retrieves the Items as
array( 'Seller' => array( <seller stuff> ),
'Item' => array of array ( <item stuff>
'Images' => array of array( <image stuff> ) );
In the 2nd case the Images element is nested within the Item part. Having the data formatted so differently makes it harder to re-use View code. Also my Item afterFind() won't work properly has problems when the Images bit isn't where it expects it to be.
QUESTION
Is there a simple way to prevent the 'Images' part being nested within the 'Item' part in the 2nd situation?
I am using Cake 2.4
Formats in More Detail
All items:
// in ItemsController.php
debug($this->Item->find('all'));
produces this:
array(
(int) 0 => array(
'Item' => array(
'id' => '1',
'title' => 'tom item 1',
'seller_id' => '1'
),
'Seller' => array(
'id' => '1',
'name' => 'tom'
),
'Images' => array(
(int) 0 => array(
'id' => '1',
'item_id' => '1',
'path' => 'tom_1_1'
),
(int) 1 => array(
'id' => '2',
'item_id' => '1',
'path' => 'tom_1_2'
)
)
),
(int) 1 => array(
'Item' => array(
'id' => '2',
'title' => 'tom item 2',
'seller_id' => '1'
),
'Seller' => array(
'id' => '1',
'name' => 'tom'
),
'Images' => array(
(int) 0 => array(
'id' => '3',
'item_id' => '2',
'path' => 'tom_2_1'
),
(int) 1 => array(
'id' => '4',
'item_id' => '2',
'path' => 'tom_2_2'
)
)
),
...
A single Seller + associated Items:
// In SellersController.php
debug($this->Seller->find('first',
array('conditions' => array('id' => $id), 'recursive' => 2)));
produces:
array(
'Seller' => array(
'id' => '1',
'name' => 'tom'
),
'Item' => array(
(int) 0 => array(
'id' => '1',
'title' => 'tom item 1',
'seller_id' => '1',
'Seller' => array(
'id' => '1',
'name' => 'tom'
),
// Look! 'Images' is WITHIN 'Item !!!
'Images' => array(
(int) 0 => array(
'id' => '1',
'item_id' => '1',
'path' => 'tom_1_1'
),
(int) 1 => array(
'id' => '2',
'item_id' => '1',
'path' => 'tom_1_2'
)
)
),
(int) 1 => array(
'id' => '2',
'title' => 'tom item 2',
'seller_id' => '1',
'Seller' => array(
'id' => '1',
'name' => 'tom'
),
'Images' => array(
(int) 0 => array(
'id' => '3',
'item_id' => '2',
'path' => 'tom_2_1'
),
(int) 1 => array(
'id' => '4',
'item_id' => '2',
'path' => 'tom_2_2'
)
)
),
....
This is the expected and correct behavior as Image is not directly associated with Seller, but with Item.
Imagine, how would you determine the proper association when Image would be defined on the same level as Item? That would indicate an association with Seller which doesn't exist.
If you want a different structure, format it in your afterFind callback or wherever it's appropriate. However, I wouldn't recommend trying to work against the CakePHP standards. In case applicable, adapt your view code.
Your question is not clear to me. If just wants to prevent Image to coming in 2nd case, try this
$this->Seller->Item->unbindModel(array(
'hasMany' => array('Image')
));
$result = $this->Seller->find('first',
array('conditions' => array('id' => $id), 'recursive' => 2)));
debug($result);
I have 2 tables, Militia and Injunctions. Militia can have many injunctions and injunctions only belong to one militia. I set those up in the models but when i call a find all for militia the injunctions aren't pulled out.
Militia model
class Militia extends AppModel {
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
public $hasMany = array(
'Injunction' => array(
'className' => 'Injunction',
'foreignKey' => 'militia_id'
//'conditions' => array("not" => array('Injunction.removed' => null))
)
);
}
Injunctions model
class Injunction extends AppModel {
public $belongsTo = array(
'Militia' => array(
'className' => 'Militia',
'foreignKey' => 'militia_id'
)
);
}
and the query getting the militia members
$user = $this->Session->read("User");
$militias = $this->Militia->find('all',
array(
'conditions'=>array(
"Militia.user_id" => $user['User']['id'],
"Militia.deleted" => 0
)
)
);
output
/app/Controller/UsersController.php (line 41)
array(
(int) 0 => array(
'Militia' => array(
'id' => '26',
'first_name' => 'Chris',
'last_name' => 'Morris',
'created' => '2013-02-11 13:45:24',
'user_id' => '2',
'status' => '1',
'deleted' => '0'
)
),
(int) 1 => array(
'Militia' => array(
'id' => '31',
'first_name' => 'John',
'last_name' => 'Smith',
'created' => '2013-02-11 14:03:50',
'user_id' => '2',
'status' => '0',
'deleted' => '0'
)
),
(int) 2 => array(
'Militia' => array(
'id' => '32',
'first_name' => 'test',
'last_name' => 'user',
'created' => '2013-02-11 14:21:38',
'user_id' => '2',
'status' => '0',
'deleted' => '0'
)
),
(int) 3 => array(
'Militia' => array(
'id' => '33',
'first_name' => 'test',
'last_name' => 'user',
'created' => '2013-02-11 14:24:02',
'user_id' => '2',
'status' => '1',
'deleted' => '0'
)
)
)
I've done the same thing before on other projects but for some reason this one time it's not pulling out the associated data. It's probably something stupid like a typo but I've been looking and testing and can't find anything wrong.
Check ORM (hasOne, hasMany, belongsTo, hasAndBelongsToMany) definition,
Check if foreign key ids are set right
Check if there are data's in the table and its related table.
Check the results of find without condition
Check to see if recursive level is greater than 0
To rule out your old cached query issue, set debug level higher to 0
Look out in the bottom section of sql dump to see what query is being fired, if it feels ok try same query with SQL away from Cake/Php.