CakePHP 2.1 pagination for habtm - cakephp

I am using cakephp 2.1 and developing an application, which contain the following table structures.
1. people(id, name)
2. movies(id, name)
and 'people' habtm movies by tables as follows.
1. castsmovie(id, person_id, movie_id)
2. directorsmovie(id, person_id, movie_id)
3. moviesmusicdirector(id, person_id, movie_id)
4. moviesproducers(id, person_id, movie_id)
5. movieswriter(id, person_id, movie_id)
6. cinematographersmovie(id, person_id, movie_id)
I wanna fetch the movies for perticular person and paginate the movies for him.
So the code I have written is in controller
$this->paginate = array('Person' => array(
'contain' => array(
'CastsMovie' => array('Movie'),
'DirectorsMovie' => array('Movie'),
'MoviesProducer' => array('Movie'),
'MoviesMusicDirector' => array('Movie')),
'MoviesWriter' => array('Movie'),
'CinematographersMovie' => array('Movie')
),
'conditions' => array('Person.id' => $id)));
and the result is as follows
array(
(int) 0 => array(
'Person' => array(
'id' => '101',
'name' => 'Darshan Thoogudeep',
),
'CastsMovie' => array(
(int) 0 => array(
'id' => '53',
'movie_id' => '14',
'person_id' => '101',
'order' => '1',
'Movie' => array(
'id' => '14',
'name' => 'Krantiveera Sangolli Rayanna',
)
),
(int) 1 => array(
'id' => '78',
'movie_id' => '19',
'person_id' => '101',
'order' => '0',
'Movie' => array(
'id' => '19',
'name' => 'Saarathi',
)
),
(int) 2 => array(
'id' => '137',
'movie_id' => '35',
'person_id' => '101',
'order' => '1',
'Movie' => array(
'id' => '35',
'name' => 'BulBul',
)
),
(int) 3 => array(
'id' => '153',
'movie_id' => '42',
'person_id' => '101',
'order' => '0',
'Movie' => array(
'id' => '42',
'name' => 'Viraat',
)
)
),
'CinematographersMovie' => array(),
'DirectorsMovie' => array(),
'MoviesMusicDirector' => array(),
'MoviesWriter' => array(),
'MoviesProducer' => array()
)
)
But I want to fetch all movies of perticular person with limit as 20.. So that I can easily paginate the limit of movies in each page.. Please help me to get the soluting.. The work is more appreciated.

I would suggest changing your data model so you have just one HABTM table:
people_movies(id, person_id, movie_id,role_id)
You would also need a role table:
role(id, role_name)
Then you can store them all in the same table and add additional roles in future if required.
Using this approach the query to get all movies for one person will be much simpler.

Related

cant get required records from habtm in cakephp

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.

Order related element in the view Cakephp

I have an Album and Picture Models. Album HasMany Pictures. Picture BelongsTo Album.
I click VIEW on an album, and it shows The Album name, genere, year etc.
And below it shows Related Pictures. So what i want to do is to find a way to sort related picture according a specific column (sort).
albums id | name | genere | year
pictures id| albim_id | picture | sort .
This is the find() statement:
public function view($id = null) {
if (!$this->Album->exists($id)) {
throw new NotFoundException(__('Album not Valid!'));
}
$options = array(
'conditions' =>array(
'Album.'. $this->Album->primaryKey => $id
),
'contain' => array(
'Picture' => array(
'order' => array(
'Picture.sort' => 'ASC'
)
)
)
);
$this->set('album', $this->Album->find('first', $options));
}
but still it doesen't order the picture on ascending order on album view.
when i do a debug($albums); i get this:
'AlbumPictures' => array(
(int) 0 => array(
'id' => '162',
'album_id' => '80',
'pic_path' => '14022988892.jpg',
'sort' => '7',
),
(int) 1 => array(
'id' => '163',
'album_id' => '80',
'pic_path' => '140229888922sYSpcukDw.jpg',
'sort' => '1',
),
(int) 2 => array(
'id' => '164',
'album_id' => '80',
'pic_path' => '1402298889facebook-default-no-profile-pic.jpg',
'sort' => '4',
),
(int) 3 => array(
'id' => '165',
'album_id' => '80',
'pic_path' => '1402298889holder.png',
'sort' => '5',
),
(int) 4 => array(
'id' => '167',
'album_id' => '80',
'pic_path' => '1402298890profile.jpg',
'sort' => '6',
),
(int) 5 => array(
'id' => '170',
'album_id' => '80',
'pic_path' => '1402298890Untitled-15.png',
'sort' => '2',
),
(int) 6 => array(
'id' => '171',
'album_id' => '80',
'pic_path' => '1402298890Untitled-17.png',
'sort' => '3',
)
)
As you see sort column is not in order.
Well In Your Album Model, where your associations are, you can specify the order of related pictures like this.
app/Model/Album.php
public $hasMany = array(
'Pictures' => array(
'className' => 'Pictures',
'foreignKey' => 'album_id',
'order' => array('sort' => 'asc' ),
)
);
hope this helps ;-)
My way is more easy custumize for other case:
$this->Album->recursive=-1;
$album= $this->Album->find('first',
array('joins'=>array(array('type'=>'INNER','table'=>'pictures','alias'=>'Picture',
'conditions'=>array('Album.id=Picture.album_id','Album.id='.$id))),
'order'=>'Picture.sort ASC'));

Containable to do show deeper data or join table

I have 3 tables: projects, project_reminder_users, project_types.
The relations is as follow:
Project => belong to => ProjectType
hasMany => ProjectReminderUser
ProjectReminderUser => belong to => Project
ProjectType => hasMany => Project
I get all data based on who assigned(ProjectReminderUser) by this
$this->Project->ProjectReminderUser->Behaviors->load('Containable');
$this->paginate = array(
'ProjectReminderUser' => array(
'limit' => $limit,
'contain' => array(
'Project' => array(
'ProjectComment',
'ProjectFile',
),
'User'
),
'conditions' => array(
'User.group_id' => $this->Session->read('Auth.User.group_id'),
'ProjectReminderUser.user_id' => $this->Session->read('Auth.User.id'),
'Project.project_status_id' => PROJECT_STATUS_OPEN,
),
'order' => 'Project.due_date',
)
);
$this->set('myTasks', $this->paginate('ProjectReminderUser'));
and the result look like this
array(
'ProjectReminderUser' => array(
'id' => '96',
'user_id' => '1',
'project_id' => '46'
),
'Project' => array(
'id' => '46',
'project_type_id' => '9',
'contact_id' => null,
'company_id' => null,
'subject' => 'Test Modified Field',
'description' => 'Test Modified Field',
'ProjectFile' => array(
(int) 0 => array(
'id' => '19',
'project_id' => '46',
'user_id' => '6',
'file_path' => '46_bhbinary_xmm_1728.jpg',
'notes' => null,
'created' => '2013-11-26 18:37:49'
),
),
'ProjectComment' => array(
)
),
'User' => array(
'password' => '*****',
'id' => '1',
'group_id' => '1',
'email' => 'xxx#xxxxx.com',
'first_name' => 'xxxx',
'deleted' => false,
'displayName' => 'xxxxx'
)
)
In the result There is data for Project.project_type_id, but I would like to have more detail of that. So I can show it as name instead of number. maybe like ProjectType.name instead.
How can I achieve this, so I can sort it in the view? something like this
$this->Paginator->sort('ProjectType.name', 'Type');
The problem is that Paginator doesn't play nice with deep model associations. I think though if rather than using Cake's methods for doing model associations, you instead do your joins manually, you may be able to work out the sorting as you want. See the below discussion.
http://sinkpoint.railsplayground.net/cakephp-pagination-deep-sort-and-habtm/
Worst comes to worse, you may have to also rewrite the model's paginate function to deal with sorting how you need it to.
How about
'contain' => array(
'Project' => array(
'ProjectComment',
'ProjectFile',
'ProjectType',
),
'User'
),
Looks like you did not contain "ProjectType"

saveAll: save new data for related model or use existing record

I'm trying to update data about many shipments with one form.
Shipment model belongsTo Shippingaddress model and Shippingaddress hasMany Shipment.
In interface user can use his previously saved Shippingaddress from select field or fill small form and add new one.
Currently example structure of data which are posted to controller looks like this:
array(
(int) 0 => array(
'Shipment' => array(
'id' => '223',
'shippingaddress_id' => '8',
)
),
(int) 1 => array(
'Shipment' => array(
'id' => '224',
'shippingaddress_id' => '',
),
'Shippingaddress' => array(
'recipient' => 'some name',
'address' => 'some addres data',
'zip' => '00-555',
'city' => 'some city',
)
),
(int) 2 => array(
'Shipment' => array(
'id' => '225',
'shippingaddress_id' => '12',
)
)
)
It would be nice to save Shiippingaddress data and update all Shipments in one transaction with
$this->Shipment->saveAll($data).
Is it possible?
I was trying many combination of posted array structure but without success.
Your $data structure should looks like this:
$data = array(
'Shippingadress' => array(
'0' => array(
'id' => '8',
'Shipment' => array(
'id' => '223'
)
),
'1' => array(
'recipient' => 'some name',
'address' => 'some addres data',
'zip' => '00-555',
'city' => 'some city'
'Shipment' => array(
'id' => '224'
)
),
'2' => array(
'id' => '12',
'Shipment' => array(
'id' => '255'
)
),
)
);
For save use saveMany:
$this->Shippingadress->saveMany($data, array('deep' => true) );
You don't need to specify shippingadress_id to empty string because Cake already takes care of it and put all relevant foreign keys based on the relationship of your models.

CakePHP find() and related models and conditions

I am calling find() on my Game model in order to get the reviews of that game for a particular platform. The problem is that the find() call doesn't seem to be paying attention to my conditions array. The call returns all the reviews for a game regardless of the platform_id.
I have these model associations:
User hasMany Review
Game hasMany Review
Review belongsTo Game
Review belongsTo User
Game HABTM Platform
This is the find call that I created:
$options = array(
'group' => array(
'Game.id'
),
'joins' => array(
array(
'table' => 'reviews',
'type' => 'LEFT',
'conditions' => array(
'Game.id=reviews.game_id'
)
),
array(
'table' => 'platforms',
'type' => 'LEFT',
'conditions' => array(
'reviews.platform_id=platforms.id'
)
),
array(
'table' => 'users',
'type' => 'LEFT',
'conditions' => array(
'reviews.user_id=users.id'
)
)
),
'fields' => array(
'Game.id', 'Game.name',
'platforms.id', 'platforms.name',
'users.id', 'users.username'
),
'conditions' => array(
'AND' => array(
'NOT' => array('reviews.review_text' => NULL),
'platforms.id' => $pid,
)
),
'limit' => 5
);
$this->Game->find('all', $options);
Here is a sample return for a find() call for platform_id=2:
array(
(int) 0 => array(
'Game' => array(
'id' => '58',
'name' => 'Bioshock 2'
),
'platforms' => array(
'id' => '2',
'name' => 'PlayStation 3'
),
'users' => array(
'id' => '20',
'username' => 'pspmaniac'
),
'Review' => array(
(int) 0 => array(
'id' => '32',
'review_text' => 'This is the PC review.',
'score' => '4',
'user_id' => '20',
'game_id' => '58',
'created' => '2013-04-30 19:59:40',
'platform_id' => '10'
),
(int) 1 => array(
'id' => '33',
'review_text' => 'This is the PS3 review.',
'score' => '7',
'user_id' => '20',
'game_id' => '58',
'created' => '2013-04-30 20:00:04',
'platform_id' => '2'
),
(int) 2 => array(
'id' => '34',
'review_text' => 'This is the XBOX 360 review.',
'score' => '6',
'user_id' => '20',
'game_id' => '58',
'created' => '2013-04-30 20:00:22',
'platform_id' => '1'
)
)
)
);
In the 'Review' index, it returns three reviews for the game (platform ids 10, 2, and 1) when it should only return the review with platform_id=2.
This is my reviews table:
CREATE TABLE reviews
(
id mediumint unsigned not null auto_increment,
review_text mediumint,
score int not null,
user_id mediumint unsigned not null,
game_id mediumint unsigned not null,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id),
FOREIGN KEY (game_id) REFERENCES games (id)
);
So, in the end, the only thing wrong with the returned array is that it contains reviews not only for the condition 'platforms.id=2' but for all platform ids.
Solution
Using Dave's comment, I came up with this solution to my problem using containable:
$this->loadModel('Review');
$this->Review->find('all', array( 'contain' => array('Platform'), 'conditions' => array( 'Review.platform_id' => 2 )
));

Resources