Cake PHP Model Associations - What am I doing wrong? - cakephp

No matter how many times I read through the documentation, look at examples I cannot get my model to "associate" with another.
Here is my example:
I have a table called kits and a table called grades (read books and authors).
kits looks like this (simplified):
id (PK)
grade_id (FK)
name
grades looks likes this:
id (PK)
code
Each kit will have only 1 grade. I don't see any issue with naming conventions, it follows as prescribed in the API.
--
I have a controller called KitsController.php that looks like this:
class KitsController extends AppController {
public function index() {
//simple find that limits to one (for readability)
$pigs = $this->Kit->find("all", array(
"limit" => 1
));
$this->set("pigs", $pigs);
}
}
I have a corresponding index.ctp file that outputs the variable $pigs (not a production level variable name I know).
--
I have my model called KitModel.php
class Kit extends AppModel {
public $belongsTo = "Grade";//here is where I am confused
}
...and an empty Grade model for a placeholder
class Grade extends AppModel {
}
--
The Problem:
When the array prints out on the page it looks like this.
Array ( [0] => Array (
[Kit] => Array (
[id] => 1
[grade_id] => 1
[name] => Ferrari
) ) )
From my understanding when I print out the results it should include the Grade information along with the kit information. It certainly does for every example I have seen online. I have also tried different relationships (hasOne, etc) but to no avail. Also I have tried the long form by passing in an array with the classname and foreign key but if my schema matches cakePHP convention I shouldn't have to do that.
What am I missing?

I have my model called KitModel.php
Your model filename is incorrect. It should be Kit.php. If CakePHP doesn't find a model file named as per convention it uses an AppModel instance for the model.

Related

Cakephp table name error [duplicate]

This question already has answers here:
CakePHP specify table-name
(2 answers)
Closed 7 years ago.
I created a table named as quantities_master but when i using modal name as QuantitiesMaster it is showing some errors. what would be modal name of quantities_master table name?
Table names should be plural and model names singular in CakePHP. So you should have a table named quantities_masters and a QuantitiesMaster model.
However, if you need to have a table with a singular name you can define this in the model.
In CakePHP 2:-
class QuantitiesMaster extends AppModel {
public $useTable = 'quantities_master';
}
In CakePHP 3:-
class QuantitiesMasterTable extends Table
{
public function initialize(array $config)
{
$this->table('quantities_master');
}
}
Only ever break from CakePHP's naming conventions when you have no other choice as it makes working with CakePHP significantly harder!
If you find determining the plural and singular of words for CakePHP (i.e if English is not your first language) then the CakePHP Inflector website is really handy.
The model is looking for quantities_masters table. Add this line at the beginning of the class and it will work fine:
class QuantitiesMaster extends AppModel {
public $useTable = 'quantities_master';
}

Eloquent relation with where condition on model attribute

I have two models Student and StudentRevision with Student model having hasMany relation with StudentRevision model. I have defined a hasMany relation in Student as
public function revisions()
{
return $this->hasMany(
'StudentRevision',
'sid'
);
}
I have a field in students table (Student model) which references current revision of student from student_revisions table.
The table structure is something like this.
students sid srid name ....
student_revisions srid sid batch ....
Now i want to define hasOne relation with StudentRevision model which references current revision linked with Student. Currently I have defined this relation as:
public function current()
{
return $this->hasOne(
'StudentRevision',
'sid'
)
->where('srid', $this->srid);
}
But the problem with this relation is, that $this->srid is not available during query building process and can be only there after the actual model is available.
Please help how to overcome this.
I don't think you can define it as relation. But what you can do is this:
public function current(){
return $this->revisions()->where('srid', $this->srid)->get();
}
This way you can access it by $student->current(). You can even go a bit further and make it more relationship like:
public function current(){
return $this->revisions()->where('srid', $this->srid);
}
public function getCurrent(){
return $this->current()->get();
}
protected $appends = array('current');
Here we define an accessor for our attribute. Laravel Docs (scroll down to the bottom)
We can then use it like this:
$student->current; // retrieves the model
$student->current(); // retrieves an instance of the query builder

cakePHP - model relations

I'm developing a system for a University here in Brazil. In this sytem I've got the following models:
- Country;
- State;
- City;
- University;
- Unit;
- Class;
Ok. and the relations are:
- State belongs to Country;
- City belongs to State;
- University belongs to Country (because, in my database, not every country has states registered to it and not every state has citys registered to it, so I could not demand from the user to register a University to a City);
- Unit belongsTo university;
- Class belongs to University (because not every University has Units registered to it);
Ok. I guess now I've set a good background for you guys to understand my situation. Now onto the question itself:
In the Views of my Model Class I wanna display the Country and (IF there are State City). And I may have the need to display such content in other Model views such as Unit and University.
But when I try to do that in my Class model I can only display the country_id. The foreign key in my university database table. And why is that, that is because my Class model belongs to University, so it's pretty easy to access my University's properties. However I do not wish to access the id of the Country, I want it's Name. And maybe in the future I might want other properties, who knows?
HOW DO I DO THAT? How do I access the properties of the Model Country when my Model Class has NO direct relation to it?
many thx hugs and kisses. Hope someone can help me with this one.
p.S:
I've managed a kinda loser solution: In my Class Controller I've done the following (so I can access variables of the Models Country, State and City):
In the View function I've loaded the Models for State and City (the country Model I can access by the relation Class->University->Country);
Then I used a find method to find the respective country, state and city for the Class in question I wanna display in view.ctp. The code follows:
public function view($id = null) {
$this->Class->id = $id;
$this->set('class', $this->Class->read());
$this->loadModel('State');
$this->loadModel('City');
$country = $this->Class->Universsity->Country->find('first', array('conditions' => array('Country.id' => $this->Class->data['University']['country_id']),));
$state = $this->State->find('first', array('conditions' => array('State.id' => $this->Class->data['University']['state_id']),));
$city = $this->City->find('first', array('conditions' => array('City.id' => $this->Class->data['University']['city_id']),));
$this->set('country',$country['Country']);$this->set('city',$city);
$this->set('state',$state);
}
And it kinda works...In my Wiew.ctp I get an array for Country data, and array for State data and an array for City data. And in the view I check to see if the state and city arrays are not length = 0 to display them and all...but I think there HAS to be a better way to do This.
P.P.S:
The other question is...what about the Index.ctp? How will I do that if I do not know which Class I'm working with? Will I have to have logic and find methods in the View? Isin't that just messing up the code?
Without posting your code, it's difficult to point you in the right direction. However, working on the assumption that you have your models configured correctly you should be able to do the following:
ClassController.php
public class ClassController extends AppController{
public $uses = array('Class');
public function view($id){
$class = $this->Class->find('first', array('conditions' => array('Class.id' => $id));
$this->set('class', $class);
}
}
view.ctp
<?php echo $class['Country']['name']?>
You may find however you will have to configure the recursive parameter of your class model so that CakePHP retrieves all the associated data. This can be done one of two ways:
Configure the recursive parameter within your Class model (see the documentation on how to do this). This sets the default value for recursive whenever you retrieve records from the database and you don't specify the attribute in your options.
Set the recurisve parameter within your find(...) method calls. I favor this one because it helps avoid placing a heavy load on the database when you don't need the data it retrieves.
For example, in your controller you could do the following:
public function view($id){
$class = $this->Class->find('first', array('conditions' => array('Class.id' => $id), 'recursive' => 3));
$this->set('class', $class);
}
Just a warning, don't set recursive to a value higher than you need, otherwise you may retrieve stuff that you don't particularly require. Use the debug() function to inspect what you're model is currently retrieving so you can make more of an informed decision:
debug($class);
I hope this is of some help!

define model association without the second model

Is there a way in CakePHP 1.3 to define a model association without having a model for the associated table? For example:
<?php
class SomeModel extends AppModel
{
var $useTable = 'some_table';
var $belongsTo = array(
'AnotherModel' => array(
// association data here
)
);
}
?>
Where AnotherModel doesn't actually have a model file. I just want to define the table that model would use and the association details. Is this possible?
Quick answer is: It should be fine. Have you tried it? Worse case scenario is it won't work without the file, so just add the model file. It takes all of two seconds:
<?php
class AnotherModel extends AppModel {
var $name = 'AnotherModel';
}
?>
Done!
UPDATE
If you follow cake convention on the naming of tables, you should be able to reference the table using the appropriate name without the model file. For example:
my_models = MyModel
your_models = YourModel
model_tables = TableModel
However, if you have a table that does not follow convention, you must create a model file that defines $useTable to indicate which table it relates to:
some_table = model file: SomeTable where $useTable = 'some_table';
another_model = model file: CustomModel where $userTable = 'anotherModel';
There is no other way around it. CakePHP is not magic. It needs to know what table is being referenced. Unless you are doing joins. Then in the join you can reference the table.

CakePHP: To Create A New Controller

I'm using CakePHP 2.0.5 (but this isn't necessarily a cakephp specific question). I have a Coupon and a User model. Each time a user prints a coupon (proccessed by: Coupon Controller):
class CouponsController extends AppController {
public function printcoupon($id = null) {
// code
}
}
I want to save the information to a "coupons_printed" table (id/coupon_id/user_id/created). Should I create a new model for this, or should I just create a function inside of the Coupon model similar to (and call it in the controller each time that page is viewed)?:
class Coupon extends AppModel {
function insertIntoPrinted($id) {
$this->query("UPDATE coupons_printed SET .....");
}
}
Whatever you do, a raw SQL query is not the best way to go. Always use CakePHP methods if at all possible (and almost always it is possible).
You should put the insertIntoPrinted() function in the CouponsPrinted model (although, as a side note, PrintedCoupon would be a more natural way to name the model...) You can then add a HasMany relationship to the Coupon model ($hasMany = array( 'CouponsPrinted' )) and call the function in the CouponsController:
public function printcoupon($id = null) {
$this->Coupon->CouponsPrinted->insertIntoPrinted( $id );
}
CakePHP's model has a thing call association.
In your case, Coupon has a hasMany association with coupons_printed.
You can create a new model, or query using the association in the Coupon model, the generated queries will be the same, I believe.
Your CouponsController already depend on Coupon Model, so not creating another model is a better solution.

Resources