CakePHP Access Multiple Database Table from a Model - cakephp

I am using CakePHP 2.x
There are several database tables setup :
1) Fruit
2) Vege
3) Drink
I am able to access these database tables in a CONTROLLER using this line below. With this line, I am able to access these other tables.
public $uses = array('Get', 'Fruit', 'Vege', 'Drink');
My problem is when trying to access them in a MODEL. When I try this code below, an error occurs.
App::uses('AppModel', 'Model');
class Get extends AppModel {
public function getHistory( $limit ) {
$searchLimit = $limit;
$raw = $this->Fruit->find('all')
An error occurs at the line '$this->Fruit'.
Call to a member function find() on a non-object...
Any ideas how to call multiple database tables in a single MODEL ?

As accessing all the database tables work perfectly in the CONTROLLER, I did this in the CONTROLLER instead of the MODEL. It seems much easier and straight forward to do this in CONTROLLER.
A private function is created in the CONTROLLER, and accessed by other functions using '$this->myPrivateFunctionName()'

First you should read on model associations Model associations
Second, if that doesn't fit your needs (meaning there is no clear association between models, honestly I don't see connection between Get and Fruit) you can use ClassRegistry:
$Fruit = ClassRegistry::init('Fruit');
Before you can use ClassRegistry you must add this before class definition:
App::uses('ClassRegistry', 'Utility');

Associate model by $belongsTo, $hasMany or what ever relation you want.
than access by $this->Fruit->find()

Related

Getting CakePHP to work with existing "non-Cake" database

I am building a new app based on multiple databases with many tables which don't follow any Cake conventions. I want to use CakePHP but I'm not sure if it's possible without the database in a Cake format.
Problems include:
Tables not named as Cake expects
Primary keys are not necessarily named id (e.g. it might be order_id)
Foreign keys are not necessarily named like other_table_id
Changing the database tables is not an option.
Is it possible to manually configure the schema in each model so that Cake will then know how the model relationships need to work? Or should I just give up on using Cake?
yes. you can still use CakePHP in your case.
Check out various Model attributes to fit your needs
http://book.cakephp.org/2.0/en/models/model-attributes.html.
e.g.
public $useTable = 'exmp' can be used to configure what table to use.
public $primaryKey = 'example_id'; can be used to configure the primary key's name
**Try this code sample............**
More detail here http://book.cakephp.org/2.0/en/models/model-attributes.html
<?php
class Example extends AppModel {
// Name of the model. If you do not specify it in your model file it will be set to the class name by constructor.
public $name = 'Example';
// table name example
public $useTable = example;
// example_id is the field name in the database
public $primaryKey = 'example_id';
}
?>

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!

CakePHP 2.3 adding new folder to load models not working

I'm using the following code in my bootstrap.php (as explained here) to load models also from another folder:
App::build(array('Model' => array('/my/path/to/models')));
This seems to work. I have a model MyModel inside that folder, which I include in the controller I want to use it like usually:
var $uses = array('MyModel');
If I print App::objects('Model'), the model MyModel is shown in the list, so I assume it's loaded correctly. However, when I try to use the model (i.e. $this->MyModel->find() it never finds anything, it always returns an empty array.
Note that if I put the same exact model (MyModel) in the typical models folder (app/Model/) then it all works fine.
What am I missing to make this work?
EDIT
Ok, so it seems that the problem is in the connection to the database when the model is placed in that folder outside app. With the code shown above, Cake finds the model. However, when I do a find(), I get a missing table error for the datasource (default in this case).
Is it possible that the model isn't loading the correct database configuration because that configuration is inside the app/Config folder? How can I make that model load that configuration? If I have to put that configuration somewehre else (maybe in the same outside folder?) I can do that, but how do I tell the model to find it?
EDIT 2
I can see better what the problem is now. If I put a model in a different folder (other than app/Model) and use App::build() to set the path of that new folder, Cake finds it, there's no doubt (I use App::objects('Model') and the model is listed with all the other models from app/Model).
However, it's like Cake is not actually reading what's inside that model class, or at least not everything. It seems to read the $useDbConfig variable, but it ignores $useTable and any function I have defined in that model. Example of my model:
class Usuario extends AppModel {
var $name = 'Usuario';
var $primaryKey = 'id_usuario';
var $useDbConfig = 'BD_ControlAcceso';
function createTempPassword($len) {
//some code
}
}
If I do a $this->Usuario->find('all'), it returns all the records correctly. However, if I call $this->Usuario->createTempPassword(7) I get a Database Error.
I have another model (MyModel) in that same folder with a $useTable = 'mytable'. If I don a find() on it, I get an error saying that mytable table could not be found. However, if I do $this->MyModel->useTable = 'mytable' then it works fine.
How is this possible? What's going on here?
EDIT 3
I just want to add that I've done extensive testing and the issue is clear: Cake "knows" that the model is in the external folder (confirmed by printing App::objects('Model'), the model is listed there, and if I remove it from that folder then it's not listed). But even though it knows it's there, it ignores whatever is inside the model file. I've tried all the methods below to load the model but none of them worked. Is this a bug in CakePHP? If not, what am I doing wrong?
You should use App::uses('MyModel', 'Model') and is should go before the class declaration like so:
<?php
App::uses('MyModel', 'Model');
App::uses('AppController','Controller');
class UsersController extends AppController {
// controller class
}
Another thing to try is loading the model where you need it:
$this->loadModel('MyModel');
The other thing you can try is the Model instantiation in the top of your model class. Try updating your model to:
App::uses('AppModel','Model');
class Usuario extends AppModel {
var $name = 'Usuario';
var $primaryKey = 'id_usuario';
var $useDbConfig = 'BD_ControlAcceso';
function createTempPassword($len) {
//some code
}
}

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.

Problem with altering model attributes in controller

Today I've got a problem when I tried using following code to alter the model attribute in the controller
function userlist($trigger = 1)
{
if($trigger == 1)
{
$this->User->useTable = 'betausers'; //'betausers' is completely the same structure as table 'users'
}
$users = $this->User->find('all');
debug($users);
}
And the model file is
class User extends AppModel
{
var $name = "User";
//var $useTable = 'betausers';
function beforeFind() //only for debug
{
debug($this->useTable);
}
}
The debug message in the model showed the userTable attribute had been changed to betausers.And It was supposed to show all records in table betausers.However,I still got the data in the users,which quite confused me.And I hope someone can show me some directions to solve this problem.
Regards
Model::useTable is only consulted during model instantiation (see the API documentation for Model::__construct). If you want to change the model's table on the fly, you should use Model::setSource:
if ( $trigger == 1 ) {
$this->User->setSource('betausers');
}
The table to use is "fixed" when the model is loaded/instantiated. At that time a DB connection object is created, the table schema is being checked and a lot of other things happen. You can change that variable later all you want, Cake is not looking at it anymore after that point.
One model should be associated with one table, and that association shouldn't change during runtime. You'll need to make another model BetaUser and dynamically change the model you're using. Or rethink your database schema, a simple flag to distinguish beta users from regular users within the users table may be better than a whole new table.

Resources