I have taken over a project for cakePHP, I am new and I find it not easy, Magento should be difficult but I find cakePHP more difficult, but maybe I have not reach the moment I know it ...
I have the next model (for table postcodes):
public $belongsTo = array(
'Postcode' => array(
'className' => 'Postcode',
'foreignKey' => 'postcode_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
Everything works, but with the tool AgentRansack I can't find the model Postcode. And besides the name of the table is postcodes, I can't even find a relation for Postcode and postcodes.
How can such a model setup in a different way than with a class Postcode.php ?
When requesting models for which no concrete model class exists (or cannot be found for whatever reason), dynamic model objects will be generated from the AppModel class.
From the CakePHP Cookbook:
CakePHP will dynamically create a model object for you if it cannot find a corresponding file in /app/Model. This also means that if your model file isn’t named correctly (for instance, if it is named ingredient.php or Ingredients.php rather than Ingredient.php), CakePHP will use an instance of AppModel rather than your model file (which CakePHP assumes is missing). If you’re trying to use a method you’ve defined in your model, or a behavior attached to your model, and you’re getting SQL errors that are the name of the method you’re calling, it’s a sure sign that CakePHP can’t find your model and you need to check the file names, your application cache, or both.
http://book.cakephp.org/2.0/en/models.html#understanding-models
By the sounds of it you need to create a class for your 'postcodes',
Read the following: http://book.cakephp.org/2.0/en/models.html
But it should look something like this:
// app/Model/Postcode.php
App::uses('AppModel', 'Model');
class PostCode extends AppModel {
public $validate = array(
// Validation
);
// Replace 'ModelName' with the name of the class where the code sites you mentioned above
public $hasMany = array(
'ModelName' => array(
'className' => 'ModelName',
'foreignKey' => 'postcode_id'
)
);
}
Related
I have the following models:
class Useragent extends AppModel {
public $validate = array(
'useragent' => array(
'unique' => array(
'rule' => 'isUnique',
),
)
);
public $hasMany = array(
'LoggedActions'
);
}
and
class LoggedAction extends AppModel {
public $belongsTo = array(
'Useragent' => array(
'className' => 'Useragent',
)
}
}
The purpose of these two models is to keep track of the IP address and user agent of the site visitors. I want the tables to be normalized, as I don't want every row to repeat the long user agent string.
To track a visitor, the code would look like:
$data=array(
'LoggedAction'=>array(
'ip_address' => 3232235521, //INET_ATON format
),
'Useragent'=>array(
'useragent'=>'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36'
)
);
$this->LoggedAction->saveAssociated($data);
I want the Useragent model to ignore the save if the user agent is already present in the useragents table (based solely on the field Useragent.useragent, not on Useragent.id which is unknown when performing the save).
I know I can implement this on the controller, by dealing with Useragent first and then with LoggedAction. However, I would like the model to take care this transparently.
Returning false in Useragent::beforeSave() if the record exists does not work, as nothing is saved.
Replacing Useragent['id'] in Useragent::beforeSave() with the id from the existing record fetched from the db, will not validate. Removing the validation rule will throw Integrity constraint violation: 1062 Duplicate entry '1' for key 'PRIMARY'.
An option is to override the Useragent::save() method, so that it ignores the save operation, but sets the Useragent->id to the id of the record fetched from the db and returns the array (like a normal save would do), but not sure if this will break other functionality.
Another option is to write a method called something like LoggedAction::saveWithUseragent(), which will implement the described functionality. But as I said, I would like the model Useragent to take care of this as transparently as possible.
Is there a better way of implementing this that I am missing?
I finally chose to override Useragent::save().
This is how my Useragent class now looks:
class Useragent extends AppModel
{
public $displayField = 'useragent';
public $hasMany = array(
'LoggedActions'
);
public function save($data = null, $validate = true, $fieldList = array()){
if ($useragent=$this->findByUseragent($data['useragent'])){
$this->id=$useragent[$this->alias]['id'];
return($useragent);
}
return parent::save($data,$validate,$fieldList);
}
}
No problems so far.
The same approach could be used for tags associated with other models.
As an example lets imagine we have a simple tv show database. Show and Episode as Model.
An Episode belongsTo one Show and one Show hasMany Episodes.
In the episodes/index view we are just echoing all episodes, the same goes for the shows/index view. But I also want to echo lets say the first 5 episodes of each show (just the title). I could simply limit the episodes by setting the limit attribute for the hasMany association.
In shows/episode/x(id) view I want to echo all episodes. And therefore I can't simply use the limit attribute for the hasMany association since it is view dependent.
What solution should I choose to implement that? I could only archive that by using some "dirty workarounds/hacks" but I feel like this is an usual problem and there might be some actual solution.
I believe what you are looking for is the containable behaviour.
Read the doc:
http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
Then remove any limit to your associations. Below there is a way of how you can use containable behavior in your example.
class Shows extends AppModel {
public $actsAs = array('Containable');
}
class ShowsController extends AppController {
//Bring all the shows and 5 episodes
public function index(){
$this->Show->find('all', array('contain' => array(
'Episode' => array('limit' => 5)
)));
}
public function view($id){
//Bring the show
$this->Show->findById($id);
//Then bring the episodes of the show
$this->Show->Episode->findByShowId($id);
//Or you can use
$this->Show->find('all', array(
'contain' => array('Episode')),
'conditions' => array('id' => $id)
);
}
}
I have a model, called "Cliente" and this model have a association with another table called ClienteRelFot. I declared that ClienteRelFot has a useTable = 'rel_fot_ec', but the cake are looking for "rel_fots".
The rel_fot_ec table exists on my database because I use to find another data.
Someone have a idea to solve this problem?
I tried clear cache and delete all files from tmp folders.
Below, we have the error:
Error: Table rel_fots for model RelFot was not found in datasource default.
Your associations are trying to pull data from the model 'RelFot' (per the error), not 'ClientRelFot', so declaring that 'ClienteRelFot' uses the table 'rel_fot_ec' will have no effect.
Try adding:
public $useTable = 'rel_fots';
in your 'RelFot' model.
I had this problem too, even though using public $useTable = ...
My data model: Event hasMany > Submissions hasMany > Authors
Cake was telling me [MissingTableException] Table authors for model Author ..., the problem was not in the Author model, but in the Submission model:
class Submissions extends AppModel {
public $hasMany = array(
'Author' => array(
'className' => 'authors', // author should be singular
'foreignKey' => 'submission_id'
)
);
I am trying to implement cakedc search plugin into my cakephp 2 application. I had the plugin working correctly at one point and something else in the application has knocked it off. However I would like to check that I am going about using the search pluging the right way as it could be the method I am using that is causing a conflict or something similar.
The search is only searching for one field which is order_id from the order model within the orders controller.
In my model I have :
// Search Filters
public $filterArgs = array(
array('name' => 'order_id', 'type' => 'like')
);
Within my controller I have:
public $presetVars = true;
public $components = array('Search.Prg', 'RequestHandler');
public $uses = array('order', 'product');
public function find () {
$this->Prg->commonProcess();
//debug($this->Order->parseCriteria($this->passedArgs));
$this->paginate = array('conditions' => $this->Order->parseCriteria($this->passedArgs));
$this->set('orders', $this->paginate());
}
EDIT this is happening because I am using the $uses variable in my class to define the controller models. Does anyone know how to define the cakedc search model. I have tried search, searchable and searchablebehavior
Try to stick to conventions. Note the casing:
public $uses = array('Order', 'Product');.
Also note: The first one will be your primary model here.
How can i call, from a Model, a function present in another model? I would like not to repeat code.
We can use Model relation to call the function in another model. Eg.
$this->Model->ModelOne->find();
$this->Model->ModelOne->customFunc();
If there is no relation in the models, The we can use
$this->loadModel('ModelName');
To use in the model.
In this case you can use
$this->ModelName->function();
directly as you've loaded that model.
You should try to have relationships between your models. There are many types of relationships which you can read here...
If you have above said associations, you can access your associated models using:
$this->Model->OtherModel->function();
If your models are not related in any way, you should use:
ClassRegistry::init('OtherModel')->function();
You can check out my question on this where I obtained great answers
User App::import()
App::import('Model','OtherModel');
$attr = new OtherModel();
$attr->Othermodelfunction();
if there's a (direct or indirect) relationship between the model, you can call the function: $this->Model1->Model2->...->Modeln->function();
use bindModel
no, you should use ClassRegistry like so:
//MessagesController - in my send() method...
$this->set('content', ClassRegistry::init('Content')->find('first', array(
'conditions' => array('Content.id' => 3)
)));
NOTE:this is from my controller but I am pretty sure it works in model too.
In 2.x versions the $this->Model1->Model2 syntax answered above will not work. Calling functions from another models in many cases is the job of a controller, not the model. Consider that, the model methods should be limited to querying and updating data whilst maintaining database integrity.
1st method: using the controller
I'll illustrate this with an example of Firm and User models, while Firm hasMany users. This method is recommended, if you plan to add extra controller functionality inbetween, such as setting flash messages or cookies.
User model:
public function saveRegisteredUsers($user_data,$firm_id){ ... }
--
FirmsController:
public function add(){
if($this->Firm->save($this->request->data)){
// set $this->Firm->id here
$this->loadModel('User');
$this->User->saveRegisteredUsers($this->request->data['User'],
$this->Firm->id);
// ...
}
}
2nd method: using the model
For this you will need to have correct model associations. The table names have to be users and firms conventionally. Following the terminology of the example above your relation should be defined as this in the Firm model:
public $hasMany = array( 'User' => array(
'className' => 'User',
));
In the User model, you have to set up the belongsTo association properly:
public $belongsTo = array(
'Firm' => array(
'className' => 'Firm',
'foreignKey' => 'firm_id',
'dependent' => false
)
);
After this, you can call $this->User->saveRegisteredUsers() directly from any of the Firm model methods.
If you have a model function that you want to call from many models, the best approach is to abstract any references to the model name ($this->alias) and place the function in AppModel. Then it is accessible in any of your models.
class AppModel extends Model{
public function myFunction($options = array(){
do some stuff with $this->alias;
}
}