I have three Models in cakephp
//Union
public $hasMany = 'Member';
and
//Member
public $hasOne = 'Post';
where as post contains post names
Now the problem is when I use:
$this->Union->findById(1);
in Union controller it shows linked Members but not name of posts
[Union] => Array
(
[id] => 1
[Name] => Dawa vyapar mandal
[created] => 2014-03-31 14:08:12
)
[Member] => Array
(
[0] => Array
(
[id] => 1
[Name] => Ashish
[post_id] => 1
[union_id] => 1
[created] => 2014-03-31 14:11:02
)
[1] => Array
(
[id] => 2
[Name] => Ashu
[post_id] => 1
[union_id] => 1
[created] => 2014-07-01 15:01:15
)
)
)
so how to achieve Post Model inside Member Model?
You have to make the model to be recursive to the level upto which you need data.
In your case, you need the data upto 2nd level, so make recursive as -
$this->Union->recursive = 2;
And after that find your data -
$this->Union->findById(1)
Related
I have 2 table booking and message , now I want to show booking request and message in inbox at a time.
$this->paginate = array(
'conditions' => $conditions,'limit' =>10,
'order'=>array('Booking.created'=>'DESC'));
$bookings = $this->paginate('Booking');
$this->paginate = array(
'conditions' => $conditions,'limit' =>10,
'order'=>array('MessageDetail.created'=>'DESC'));
$messages = $this->paginate('MessageDetail');
i have merge both table data ( array_merge($bookings, $messages); )
now i want to it sort date wise (or any conditions)
Array
(
[0] => Array
(
[Booking] => Array
(
[id] => 4
[host_id] => 21
[place_id] => 10
[room_id] => 13
[user_id] => 12
[message_detail_id] => 16
[created] => 2013-04-23 14:44:03
[accept_date] =>
[cancel_date] =>
)
)
[1] => Array
(
[Booking] => Array
(
[id] => 3
[host_id] => 21
[place_id] => 10
[room_id] => 13
[user_id] => 12
[message_detail_id] => 13
[created] => 2013-04-15 14:10:59
[accept_date] => 2013-04-15 14:40:47
[cancel_date] =>
)
)
[2] => Array
(
[MessageDetail] => Array
(
[id] => 17
[message_id] => 2
[user_id] => 12
[sender_id] => 21
[unread] => 0
[created] => 2013-04-24 12:11:47
)
)
[3] => Array
(
[MessageDetail] => Array
(
[id] => 15
[message_id] => 2
[user_id] => 12
[sender_id] => 21
[booking_id] => 3
[unread] => 0
[created] => 2013-04-15 15:01:12
)
)
)
Thanks in advance.
Option #1:
Create a third Model named "BookingAndMessage". You could use the Model's afterSave method (on both Booking and Message) to create a duplicate record in your new model. You could then query the BookingAndMessage in the proper sort order.
Option #2: To solve the problem, as it stands, you will want to use PHP's usort function (also explained here PHP Sort a multidimensional array by element containing date).
<?php
$BookingsAndMessages = array_merge($bookings, $messages);
function date_compare($a, $b)
{
$modelKeyA = array_key_exists('Booking',$a) ? 'Booking' : 'MessageDetail';
$modelKeyB = array_key_exists('Booking',$b) ? 'Booking' : 'MessageDetail';
$t1 = strtotime($a[$modelKeyA]['created']);
$t2 = strtotime($b[$modelKeyB]['created']);
return $t1 - $t2;
}
usort($BookingsAndMessages, 'date_compare');
// Would sort the merged records by `created` date
?>
The downside to option 2 is, you are going to have to create rules for each field (and sort direction).
Perhaps you should Union your queries first, the Order.
$bookings = $this->Bookings->find('all', [
'conditions' => $conditions,'limit' =>10,
]);
$messages = $this->find('all', [
'conditions' => $conditions,'limit' =>10
]);
$data = $bookings->union($messages);
// This works if your first selected field is the one you want to sort.
$data->epilog('ORDER BY 1 ASC');
reference:
How do you modify a UNION query in CakePHP 3?
I have simple model relationship in CakePHP 1.3 with Categories -> Products
Category hasMany Products
There is slight difference between the data arrays which I get in the different controllers. The Product data is in the main product array when getting as associated model in the Categories controller and is separated when getting it in Products.
For Example to get 'Product1'
in Categories - $category['Product'][0]['title']
and in Products - $product[0]['Product']['title']
I would like to use same element for displaying the products. It does not matter which array scheme will be used just to be the same. And where is the right place to make the modification? I can modify those arrays after getting them, but don't think that it is the best option.
When I am in the Categories controller and get a category I get this:
// $this->Category->findById('12');
Array
(
[ProductCategory] => Array
(
[id] => 12
[title] => Category 1
[updated] => 2013-02-24 10:06:15
[created] => 2013-02-24 10:06:15
)
[Product] => Array
(
[0] => Array
(
[id] => 4
[parent_id] => 12
[title] => Product1
[updated] => 2013-02-24 10:17:01
[created] => 2013-02-24 09:12:59
)
[1] => Array
(
[id] => 6
[parent_id] => 12
[title] => Product2
[updated] => 2013-02-24 10:16:54
[created] => 2013-02-24 09:13:53
)
)
And when getting all the products inside the Products controller:
// $this->Product->find('all');
Array
(
[0] => Array
(
[Product] => Array
(
[id] => 10
[parent_id] => 12
[title] => Product1
[updated] => 2013-02-24 10:16:42
[created] => 2013-02-24 09:16:35
)
)
[1] => Array
(
[Product] => Array
(
[id] => 8
[parent_id] => 12
[title] => Product2
[updated] => 2013-02-24 10:16:47
[created] => 2013-02-24 09:15:39
)
)
)
)
One of your finds is a find('all') and the other is a findById() (which uses find('first')).
Both of these return data in a different format, since find('first') knows you only want one item, and find('all') is an unknown set of item(s).
Just use find('all') for both, but set your limit based on whether you need only one or more than one. Then, your data will be returned exactly the same.
Which Controller you retrieve your data from has no effect on the data returned. Which MODEL however, does - so just make sure you're doing your find from the same model.
Eg.
//in your ProductsController
$this->Product->find('all');
//in your CategoriesController
$this->Category->Product->find('all');
// in some other controller
$this->loadModel('Product);
$this->Product->find('all');
PS - BUT it's better if you don't do your "finds" in your Controller - make a method in your Model, and call it from your Controller(s) so instead of $this->Product->find(), it would be $this->Product->getProducts() (or whatever you want to call it). (read more about "fat models, skinny controllers" for reasons/examples...etc).
Dave is right, the difference is the method you're using... Even though you claim that associated data is always merged, your find on the 'Product' model is NOT associated data, so the format WILL always be different.
I've been here for a short while and I've already noticed that Dave knows his stuff. :)
I agree with the fat models/skinny controllers paradigm for clean, efficient code.
If you changed:
<?php
$this->Category->contain(array(
'Product'
));
$this->Category->find('all',
array(
'conditions' => array(
'Category.id' => $id // 12 for your OP.
),
'limit' => 1
)
);
?>
Should give you:
<?php
array
(
[0] => array
(
'Category' => array
(
[id] => 12
[title] => Category 1
[updated] => 2013-02-24 10:06:15
[created] => 2013-02-24 10:06:15
),
'Product' => array
(
[0] => array
(
...
),
[1] => array
(
...
)
)
)
)
?>
Please correct me if I am mistaken, thanks!
Or if you want "Products" to look like:
<?php
'Product' => array
(
[0] => array
(
'Product' => array
(
...
)
)
)
?>
when fetching data from the category model, you would need to fetch the associated data manually, e.g.:
<?php
$this->Category->contain();
$cats = $this->Category->find('all');
foreach ($cats as &$cat) {
$this->Category->Product->contain(); // You have to contain for each find.
$cat['Product'] = $this->Category->Product->find('all',
array(
'conditions' => array(
'Product.category_id' => $cat['Category']['id']
)
)
);
}
?>
I have 3 users tables on my DB:
Users
users_twitter
users_web
Users is the parent of both users_twitter and users_web.
And then another table for comments. Both kind of users can comment.
So, when I want to show the comments I need to get information of the author of each comment.
In order to do this I am using the variable $belongsTo on the /Model/Comment.php like this:
public $belongsTo = array(
'users' => array(
'foreignKey' => 'idUser'
)
);
In Controller/CommentController, when i do this:
public function index($idPost) {
$this->Comment->recursive = 0;
return $this->Comment->find('all');
}
I get this kind of array:
[0] => Array
(
[Comment] => Array
(
[id] => 1
[idPost] => 441
[idUser] => 387371023
[comment] => hello word
[created] => 2012-03-01 00:00:00
)
[User] => Array
(
[id] => 1
[username] => myname
)
)
And what I want is to get more info yet, the one of the subtype of Users, depending on the existence of the ID on the subtype tables.
In case it was an id of a user_web table, I would like to get this:
[0] => Array
(
[Comment] => Array
(
[id] => 1
[idPost] => 441
[idUser] => 387371023
[comment] => hello word
[created] => 2012-03-01 00:00:00
)
[User] => Array
(
[id] => 1
[username] => myname
[users_web] => Array
(
[id] => 1
[username] => myName
[password] => XXXXX
[verified] => 1
[created] => 1
)
)
Do you know if that's possible with CakePHP?
As far as I know, with $hasOne I only get one level more, I need two.
In your AppModel add
public $actsAs = array('Containable');
In your index:
public function index($idPost) {
return $this->Comment->find('all', array(
'contain' => array('User.UsersWeb')));
}
Your User model has to be associated with a UsersWeb model to make this work.
See http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html#containing-deeper-associations for a complete description.
Also why do you return the data in the controller index? Are you using requestAction for this? And why don't you use pagination? Do you really want to display hundreds of comments on one page?
See http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html
I have a bit more complex system...
I have
users model - hasMany Ads
ads model - hasMany "placads"
placads model - belongsTo Ads and Places
places model - hasMany placads
Now I run query like this:
$this->set(
'ad',
$this->User->Ad->find(
'all',
array(
'conditions' => array('Ad.user_id' => $this->Auth->user('id'))
)
)
);
and I am getting this without "Place" in * mark
[0] => Array
(
[Ad] => Array
(
[id] => 1
[user_id] => 1
[name] => bota
)
[Placad] => Array
(
[0] => Array
(
[id] => 1
[ad_id] => 1
[place_id] => 1
[count] => 10
*[Place] => Array
(
info about place
)*
)
[1] => Array
(
[id] => 2
[ad_id] => 1
[place_id] => 2
[count] => 20
*[Place] => Array
(
info about place
)*
)
)
)
What should I do to get something like I wrote into the * mark?
Thanks in advance!
use recursive:
http://book.cakephp.org/view/1063/recursive
$this->User->Ad->recursive = 2; // before find
alternatively:
$this->User->Ad->find( 'all',
array(
'recursive' => 2,
'conditions' => array('Ad.user_id' => $this->Auth->user('id'))
)
)
number 2 is an example, but should do in your case
2nd alternative:
use Containable
http://book.cakephp.org/view/1323/Containable
Basically I have following models in CakePHP:
User(id, username)
Photo(id, user_id, path)
I have set up following relation: User hasMany Photo.
On one screen, I would like to list users, and show random photo next to each user. I tried setting up following relation:
User hasOne SamplePhoto (where SamplePhoto is just Photo model)
but when user has two photos for instance, he is listed twice on the list.
basically my question is: can you reduce hasMany relation to hasOne, without adding any fields to table schema presented above? I would like to tell cake - find the first record in the Photo table which matches a certain user_id.
You could also use the Containable behaviour and then set up something like:
$this->User->find(
'all',
array(
'contains' => array(
'Photo' => array(
'order' => 'rand()',
'limit' => 1
)
)
)
);
You should then get something like
Array
(
[User] => Array
(
[id] => 121
[username] => tom
)
[Photo] => Array
(
[0] => Array
(
[id] => 123
[user_id] => 121
[path] => Somewhere
)
)
)
if you do a find like $this->User->read(null,$id), the return will be an array that looks something like:
Array
(
[User] => Array
(
[id] => 121
[username] => tom
)
[Photo] => Array
(
[0] => Array
(
[id] => 123
[user_id] => 121
[path] => Somewhere
)
[1] => Array
(
[id] => 124
[user_id] => 121
[path] => SomeOtherPlace
)
)
)
From this array you can pick the photo however you like, be it the first:
$this->data['Photo'][0]
the last:
$this->data['Photo'][count($this->data['Photo'])]
an explicit record:
$this->data['Photo'][3]
or by some random means:
$this->data['Photo'][$rnd]
Don't make this more complicated than it needs to be. :)
$data = $this->User->Photo->find('first',
array('conditions' => array('Photo.user_id' => $id)));
Gives you a photo in $data['Photo'] with the user attached in $data['User'].
You'd do something like:
$user = $this->User->find('first', array('conditions' =>
array('username'=>$this->data['User']['username'],
'active'=>true) ));