Cakephp - Multiple Models for one Table - php

I have a User model that is used to store data on users of a dental examination system.
Typically, three types of users will exist: Admininistrator, Location Manager and Examiner.
It seems to have become necessary to treat these three roles as seperate models in my application (imagine how I'd have a different view for each role with different options etc... It's a nightmare).
How would I go about setting up the relationships in each Model.
My first thought is:
//Administrator Model
class Administrator extends User {
$name = 'Administrator';
$table = 'User';
$belongsTo = array(
'User' => array(
'className' => 'User',
'conditions' => array('User.role' => 'administrator'),
)
);
}
And then the User model will reference this one using a hasMany? In terms of CakePHP convention, how would one actually model this accurately?
Also, would this model extend the User model or the AppModel?

Of course you can create different models using the same table name. To do so, link each model with specific table with $useTable property (not $table):
class Administrator extends AppModel {
public $useTable = 'User';
}
But I don't know any CakePHP model property which will allow you to filter data returned when fetching results... You can only write your own conditions when linking model with another one, for example:
class SomeOtherModel extends AppModel {
public $hasMany = array(
'Administrator' => array(
'className' => 'Administrator',
'conditions' => array('Administrator.role' => 'administrator')
)
);
}
Which is not a good solution, because it will work only when executing queries for SomeOtherModel model.
You can also try applying an afterFind() callback to your Administrator / Examiner / ... models which will delete users of another role than needed, but of course it is not an efficient solution.
Another solution is just creating different database views which will contain only users of selected role (more on views - here). Then you can point each view to your CakePHP model, just as it was a normal database table.
But this solution is also not perfect. If you will have to add a new user role or change your table schema in the future, you will also have to modify your database views.

Related

Relate to another table without using prefixes

So i have a task of creating a mobile version of an existing website but its built with a different framework which i didnt started.
The client wants to use CakePhp on it. so im using CakePhp 2.5.7. My question is. Is there a way to relate another table from an existing table without using prefixes?
To make it more clear i have this on my controller
public function index(){
$this->loadModel('Bulletin');
$bulletins = $this->Bulletin->find('all');
}
in my model
class Bulletin extends AppModel{
var $useTable = 'bulletin';
var $hasMany = array(
'BulletinComment' => array(
'className' => 'BulletinComment',
'foreignKey' => 'bulletinid',
),
);
}
but the bulletincomment table on the database has no prefix. and showing error on page
Error: Table bulletincomments for model bulletincomment was not found in datasource default.
I tried creating BulletinComment model like this
class BulletinComment extends AppModel{
var $useTable = 'bulletincomment';
}
but to no avail. Im still getting error. Is it possible to use any relation without adding prefixes?
Assuming prefixes are setup in the database connection (/app/Config/database.php) you can override it for one table if you add this to the model:
public $tablePrefix = '';
Or you could remove the prefix in the connection and add it back for the models that need it, depending on which is faster.

CakePHP associations with 3 tables

I have 3 tables: Users, Profiles and Posts.
A User may have one Profile, and a Profile must have a User, a Post must have a User, and User may have many Posts. I have set this up in my Models and it all seems to work fine.
However when viewing a list of posts I am trying to show the Author firstname which is stored in the Profile table. But it's the User and Post table that are linked, and then the User table is linked to the Profile table. So their is no direct relation between the Post and the Profile.
How do I get this information?
Currently I'm trying to show this in the view with: <?php echo $post['Profile']['firstname']; ?> but because their is no direct association between the post and profile it does not work and I get the error: Undefined index: Profile
I have tried to do:
public function index()
{
$this->Post->recursive = 2;
$this->set('posts', $this->paginate('Post'));
}
but still no luck on getting the rest of the associations to come through!
Can anyone help? Thanks
There are two ways to do this. One way to accomplish this is to join tables on the fly. The other way to do this is with the containable behaviour.
To use the containable behaviour you must add var $actsAs = array('Containable'); to all the models involved (or AppModel if you use it a lot). Then you can something like this in the controller:
$post = $this->Post->find('first', array(
'conditions' => array('id' => $id),
'contain' => array('User' => 'Profile')
));
From the view you could use <?php echo $post['User']['Profile']['firstname']; ?>

CakePHP: controller uses another model instead of its own

The situations looks like this: I have two models with controllers and everything, WrittenTest and WrittenTestAnswer. The problem is that whenever I try to access model WrittenTestAnswer, both from WrittenTestsController (using $this->loadModel() before) and from its own WrittenTestAnswersController, it somehow accesses WrittenTest instead. I noticed it when data wasn't saved to WrittenTestAnswer, $this->WrittenTestAnswer->find() also returned data from written_tests table. I have no idea what's going on. I checked names and stuff so many times already. I am using CakePHP 1.3. Thanks for any help.
EDIT:
code from WrittenTestAnswer model:
class WrittenTestAnswer extends AppModel {
public $name = 'WrittenTestAnswer';
public $displayField = 'written_test_answer';
public $belongsTo = array(
'WrittenTest' => array(
'className' => 'WrittenTest',
'foreignKey' => 'written_test_id',
),
);
}
EDIT so for example this (in WrittenTestAnswersController)
debug($this->WrittenTestAnswer->name);
outputs WrittenTest. And
$this->WrittenTestAnswer->find('first');
returns first row from written_tests. Any idea what's going on?
How are you accessing the model? If the relationships are setup correctly, you shouldn't need to use $this->loadModel() at all. You can just access the related model through its parent like so:
$this->WrittenTest->WrittenTestAnswer->find('all');
This might not be the cause of your problems but we cannot tell until you actually post the code that's not working.

CakePHP: How to specify models while retrieving data?

I want to retrive data with recursive level 3. The problem is that It adds all 8 linked models but I need data from only three data models. Is there any way to ignore some models or specifically asked some models but not all. something like useModel('Model1', 'Model2')?
It's better to use the Containable behavior, which will allow you to specify find conditions like this:
$this->Post->find('all', array(
'contain' => array(
'Tag',
'Comment' => array(
'User')
)
)
);
Also, in conjunction with this, it's good to set $recursive to -1 in your AppModel.
class AppModel extends Model {
var $recursive = -1;
var $actsAs = array('Containable');
}
This will give you the finer control you need and ensure that your queries don't bloat as more relationships get added to your models over time.

adding hasMany association causes find() to not work well

OK, I am a little bit lost...
I am pretty new to PHP, and I am trying to use CakePHP for my web-site.
My DB is composed of two tables:
users with user_id, name columns
copies with copy_id, copy_name, user_id (as foreign key to users) columns.
and I have the matching CakePHP elements:
User and Copy as a model
UserController as controller
I don't use a view since I just send the json from the controller.
I have added hasMany relation between the user model and the copy model see below.
var $hasMany = array(
'Copy' => array(
'className' => 'Friendship',
'foreignKey' => 'user_id'
)
);
Without the association every find() query on the users table works well, but after adding the hasMany to the model, the same find() queries on the users stop working (print_r doesn't show anything), and every find() query I am applying on the Copy model
$copy = $this->User->Copy->find('all', array(
'condition' => array('Copy.user_id' => '2')
));
ignores the condition part and just return the whole data base.
How can I debug the code execution? When I add debug($var) nothing happens.
I'm not an expert, but you can start with the following tips:
Try to follow the CakePHP database naming conventions. You don't have to, but it's so much easier to let the automagic happen... Change the primary keys in your tabel to 'id', e.g. users.user_is --> users.id, copies.copy_id -->copies.id.
Define a view, just for the sake of debugging. Pass whatever info from model to view with $this->set('users', $users); and display that in a <pre></pre> block
If this is your first php and/or CakePHP attempt, make sure you do at least the blog tutorial
Make CakePHP generate (bake) a working set of model/view/controllers for users and copies and examine the resulting code
There's good documentation about find: the multifunctional workhorseof all model data-retrieval functions
I think the main problem is this:
'condition' => array('Copy.user_id' => '2')
It should be "conditions".
Also, stick to the naming conventions. Thankfully Cake lets you override pretty much all its assumed names, but it's easier to just do what they expect by default.
The primary keys should be all named id
The controller should be pluralised: UsersController
First off, try as much as possible to follow CakePHP convention.
var $hasMany = array(
'Copy' => array(
'className' => 'Friendship',
'foreignKey' => 'user_id'
)
);
Your association name is 'Copy' which is a different table and model then on your classname, you have 'Friendship'.
Why not
var $hasMany = array(
'Copy' => array('className'=>'Copy')
);
or
var $hasMany = array(
'Friendship' => array('className'=>'Friendship')
);
or
var $hasMany = array(
'Copy' => array('className'=>'Copy'),
'Friendship' => array('className'=>'Friendship')
);
Also, check typo errors like conditions instead of condition
Your table name might be the problem too. I had a table named "Class" and that gave cake fits. I changed it to something like Myclass and it worked. Class was a reserved word and Copy might be one too.

Categories