CakePHP - listing entries grouped by program_id - php

I have the following relations between my models
Program hasMany Classroom
Classroom belongsTo Program
What I am trying to achieve is to display all the classrooms, grouped by program, for example:
Program 1
-Classroom 1
-Classroom 2
-Classroom 3
Program 2
-Classroom 1
-Classroom 2... etc
My index action in ClassroomsController:
function index() {
$this->Access->grantAdmin();
$this->Classroom->recursive = 1;
$this->set('classrooms', $this->paginate());
}
I tried to use this:
var $paginate = array(
'group' => 'program_id'
);
But it didn't work as I expected. Any ideas? Thanks

Try adding:
var $actsAs = array('Containable');
to the Program model. Then in the controller:
$programs = $this->Classroom->Program->find('all', array(
'contain' => array(
'Classroom',
),
));
$this->set(compact('programs'));
This should return your data in the hierarchy you're looking for. See the Containable behaviour documentation for more details. Note that you don't need the $this->Classroom->recursive statement if you use Containable.
Your own code example shows that you're using pagination. It should be fairly easy to put containable and pagination together by looking around the docs.

Related

Creating new record and relationships in one go

I have the following basic schema:
players
id
name
profiles
id
player_id
email
subsets
id
profile_id
alias
I was under the impression the following operation was possible when creating a new record:
Player::create([
'name' => 'Player 1',
'profile.email' => 'player1#email.com',
'profile.subset.alias' => 'Player 1 alias'
]);
Since this code doesn't seem to work, is there anyway to save relationships records together with the create method?
Basically, you can't do this as easy as it looks.
In the docs, all related models are created after the base model is created
$profile = new Profile(array('email' => 'player1#email.com','alias'=>'Player 1 alias'));
$player = new Player(array('name'=>'Player 1'));
$player = $post->profile()->save($profile);
However , if you really want to do it in one go, you can overwrite the save() method in the Player model :
public function save(){
Database::transaction(function() {
$profileModel = new Profile($this->profile);
parent::save();
$this->profile()->insert($profileModel);
});
}
You will then pass the array to the Player method like :
array(
name='Player name',
profile=>array(
email=>'player1#email.com',
subset=>array(
alias=>'Player 1 alias'
)
);
Although this is not a recommended action.
Please read more about how to save the Eloquent models and relationships :
Tutorial 1
Tutorial 2
Everywhere is suggested to create the base model first, then the related models.

List posts by category in CakePHP

I'm new to CakePHP. Please help me to write a function to retrieve posts under a particular category for my blog app built using CakePHP.
My table structure:
posts: id, post, body, created, category_id
category: id, group
Also I had defined:
Inside post model - var $belongsTo = 'Category';
Inside category model - var $hasMany = 'Post';
find() is the generic query method for Models in CakePHP.
An example would be:
$results = $this->Post->find('recursive' => -1, 'conditions' => array('Post.category_id' => 1));
debug($results);
There are many ways to achieve what you want. I encourage you to read the docs or working through the CakePHP Blog Tutorial.
$this->Post->find('all', array('conditions' => array('Post.category_id' => $category_id)));
where $category_id is the id of category that you want to retrieve results from database
hope this helps

Retrieving models without getting associated models - CakePHP

I use the find('all') function to retrieve the post records from my database, but this will also return all the User information that is associated with the Post model with a belongsTo - hasMany relationship.
The downside of this is that the user model contains password and other important information. Is this considered a security issue? I am nowhere echo-ing the information on the view.
Thanks
EDIT:
I modified my code but I am still getting the associated models.
$this->set('posts_list',$this->Post->find('all',array('contain' => false, 'order' => array('Post.price ASC'))));
Any ideas?
You have several options. You can set the recursive property on a model:
$this->Post->recursive = -1;
$posts = $this->Post->find('all');
Alterantively, you can specify recursive as an option to your search:
$posts = $this->Post->find('all', array(
'recursive' => -1,
'conditions' => ...
);
You can also use the Containable behaviour in your Post model. In that case you can specify an empty set:
class Post extends AppModel {
var $actsAs = array('Containable');
}
$this->Post->contain();
$posts = $this->Post->find('all');
Or, specified in the query:
$posts = $this->Post->find('all', array(
'contain' => false,
);
The upside for the Containable behaviour is when you later on associate other models with your post. Suppose that you implement a Tag model. Now you want to find a post with it's tags, but not the use model:
$posts = $this->Post->find('all', array(
'contain' => array('Tag'),
);
Not necessarily.
But you are retrieving information when you don't need it. It's not a problem now, but keep in mind this becomes a huge problem when you have a lot of associated data
Consider setting your recursive attribute to -1 (or 0 if needed)
$this->Model->recursive = -1;
This will pull data only from the selected model
Or for more fine tuned selection, you can use the Containable behavior : http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
This allows you to select which associations to keep when retrieving data.
just so you know
$this->Model->recursive = -1 will remove all associations
$this->Model->recursive = 0 will remove only hasMany assosiation (so it keeps belongsTo)
Do u use this:
$this->Post->find('all')// If u access it from Post controller
OR,
$this->User->Post->find('all')//If u access it from User controller

CakePHP paginate results with a condition on another table linked with HABTM

I've done some searching but I can't find anything relevant enough/working for my scenario. I've got:
Jobs <--> HABTM (Users_jobs table) <--> Users
I would like to do a paginate() from my Job controller with a condition on the User.id, as I do need to fetch -and paginate- all the jobs from the current user.
If you do provide a link to another topic/site, please provide an explanation with it and how you would apply it to my case.
Cheers,
Nicolas.
Make sure your HABTM associations are setup correctly (cake bake would expect a join table of jobs_users rather than users_jobs (see: Cakephp-HABTM) If they are, change the references to JobsUser in the example below to UsersJob to match the layout you described.
//In an action in jobs_controller.php
//Fake a HasOne association to the JobsUser model, setting $reset to false
$this->Job->bindModel(array(
'hasOne' => array(
'JobsUser'
)
), false);
//Setup the paginate conditions, grouping on job.id
//Set $user_id to the user to filter results by (can also be an array of users)
$options = array(
'group' => 'Job.id',
'conditions' => array(
'JobsUser.user.id' => $user_id
)
);
$this->paginate = $options;
$users = $this->paginate();

CakePHP HATBM not working

I'm starting a cakephp app, I've never used it in real world so I'm a bit confused how HABTM works, even though I read the documentation I couldn't get even the $this->User->Subscription and didn't see any extra object dumped
What I want is to create a HATBM between users and subscriptions
so I created three tables (users,subscriptions,users_subscribers)
Then in my User.php model I did this
var $hasAndBelongsToMany =
array(
'Subscription' =>
array('className'=>'Subscription',
'joinTable' => 'users_subscribers',
'foreignKey' => 'user_id',
'associationForeignKey' => 'subscription_id',
'unique' => true,
)
);
SUbscription.php
var $hasAndBelongsToMany = array(
'User'=>array('className'=>'User',
'joinTable' => 'users_subscribers',
'foreignKey' => 'subscription_id',
'associationForeignKey' => 'user_id',
'unique' => true));
Even with the tags example and following it, I cannot get the relation set, I also added the line <?php echo $this->element('sql_dump'); ?> to see if its running which it isn't...
Could anyone guide me how exactly you get HATBM to work, what else do I need to verify?
Full code:
pages_controller.php
http://sao.pastebin.com/PWQMhE2z
User model:
http://sao.pastebin.com/PWqwAj1v
Subscription model:
http://sao.pastebin.com/MfVFR4Kw
subscriptions SCHEMA:
http://sao.pastebin.com/mLRcEp1c
User SCHEMA:
http://sao.pastebin.com/UeTRHh3u
users_subscriptions SCHEMA:
http://sao.pastebin.com/4UeSDZte
The simplest and fastest way to get this working is by following CakePHP's rule of configuration over customization.
This means following the CakePHP conventions unless you have a very good reason not to.
I'd strongly recommend starting with a basic setup that you know works, and then modifying that if you need to. Here's a quick and easy way to get up and running.
The Database Tables
Start with three database tables: users, subscriptions and subscriptions_users. The schemas you already have are ok, but I'd make a couple modifications to make sure things go smoothly:
Add a name or title column to the users table. Either that, or you'll have to add the $displayField property to your User model. If you don't do this you'll miss out on some of the "automagic" that CakePHP provides. More info on $displayField
Change the join table's name to subscriptions_users. This is the CakePHP convention and there's no reason not to save yourself the time and worry of following it. :-)
Use the following schema for the join table:
CREATE TABLE subscriptions_users (
subscription_id int(11) NOT NULL,
user_id int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Note that there aren't any keys defined. From the CakePHP manual: "To avoid any issues - don't define a combined primary key for these two fields, if your application requires it you can define a unique index."
The Models
Try to keep your code clean. There are a lot of sensible defaults implemented in CakePHP and there's no point in defining them when they're already defined.
The following models should work for you:
user.php
<?php
class User extends AppModel {
var $hasAndBelongsToMany = array('Subscription');
}
?>
subscription.php
<?php
class User extends AppModel {
var $hasAndBelongsToMany = array('User');
}
?>
Pretty simple. Just be sure your model files are named correctly: user.php and subscription.php, all lowercase.
Also, note that you don't have to set any of the relationship options (className, joinTable, etc.) unless they need to be something besides the default. Ninety percent of the time the defaults should serve you just fine.
You should be up and running now. You can make sure the model objects are being loaded and are accessible in your controllers like this:
users_controller.php
<?php
class UsersController extends AppController {
var $name = 'Users';
function index() {
$this->autoRender = false;
var_dump(is_object($this->User));
var_dump(is_object($this->User->Subscription));
}
}
?>
subscriptions_controller.php
<?php
class SubscriptionsController extends AppController {
var $name = 'Subscriptions';
function index() {
$this->autoRender = false;
var_dump(is_object($this->Subscription));
var_dump(is_object($this->Subscription->User));
}
}
?>
The output of /users and /subscriptions should both be bool(true) bool(true).
You can see the full models by doing pr($this->User);.
Deleting records
If you delete a single record using, for example, $this->User->delete($user_id), all the records in the join table with that user ID will automatically be deleted as well.
If you want to delete a single record from a HABTM join table, without deleting the records that it links to, in effect, "unjoining" the two records, you can do it through the SubscriptionsUser model. This is a model that is created on the fly whenever there's a HABTM relationship.
See here for an example: CakePHP hasAndBelongsToMany (HABTM) Delete Joining Record
I did a test app with a basic schema and I get all the relations right. I suspect your woes have to do with the fact that you did $uses = array('User', 'Subscription');Why don't you try with $uses = $uses = array('User'); and then try
$this->User->find('all');
$this->User->Subscription->find('all');
You also need to define the same HABTM relation in your Subscription.php model. If I recall correctly, CakePHP internally fetches some of the required information from the other side's HABTM configuration.
I always use two "hasMany" relations and one "belongsTo" relation to get the HABTM effect in CakePHP with more control.
Try this:
User model (user.php)
class User extends AppModel {
public $name = 'User';
public $actsAs = array('Containable');
public $hasMany = array('UserSubscription');
}
Subscription model (subscription.php)
class Subscription extends AppModel {
public $name = 'Subscription';
public $actsAs = array('Containable');
public $hasMany = array('UserSubscription');
}
UserSubscription model (user_subscription.php)
class UserSubscription extends AppModel {
public $name = 'UserSubscription';
public $belongsTo = array('User','Subscription');
}
pages/home action (pages_controller.php)
public function home() {
$data = array(
'User' => array(
'id' => 1, 'user_email' => 'allenskd#gmail.com', 'user_password' => 'fdfdkert', 'user_salt' => 'haha', 'user_displayname' => 'David'
),
'UserSubscription' => array(
'user_id' => '1', 'subscription_id' => '1'
),
'Subscription' => array(
'id' => 1, 'title' => 'My first plan', 'price' => '30.00', 'subscriber_count' => '1'
),
);
$this->Subscription->save($data);
$this->User->saveAll($data);
$test = $this->User->find('all', array('contain' => array('UserSubscription' => array('Subscription'))));
pr($test);
}

Categories