I'm programming a plugin for a CakePHP app that has the following Models:
Preregistry Model
App::uses('PreinscriptionAppModel', 'Preinscription.Model');
class Preregistry extends PreinscriptionAppModel {
public $hasMany = array(
'Relative'
);
public $actsAs = array(
'Date' => array(
'birthday' => array(
'format' => '%d/%m/%Y'
),
'registry_date' => array(
'format' => '%d/%m/%Y'
)
)
);
}
Relative Model
App::uses('PreinscriptionAppModel', 'Preinscription.Model');
class Relative extends PreinscriptionAppModel {
public $name = 'Relative';
public $actsAs = array(
'Date' => array(
'birthday' => array(
'format' => '%d/%m/%Y'
)
)
);
public $belongsTo = array(
'Preregistry'
);
}
The Relevant part of the Controller is:
<?php
App::uses('PreinscriptionAppController', 'Preinscription.Controller');
class PreregistriesController extends PreinscriptionAppController {
public function add() {
$preregistryDateConfig = $this->Preregistry->getDateConfig();
$relativeDateConfig = $this->Preregistry->Relative->getDateConfig();
}
}
The problem i have is when calling $this->Preregistry->Relative->getDateConfig(); the Date Behavior is not loaded on the Relative model so it throws a MySQL error because the model doesn't have a getDateConfig() method.
When i check if the Behavior is loaded with $this->Preregistry->Relative->Behaviors->loaded('Date'); i get FALSE back.
For some reason the Behavior is only loaded in the Preregistry model but not on the Relative model. I also have tried to load the Behavior on the fly to no success.
If someone could tell me a workaround for this problem i will be very glad.
If you need more code or anything feel free to ask.
Thanks!
I'm pretty sure debug($this->Preregistry->Relative) will show that Relative is an instance of AppModel.
This is because you are missing the proper plugin name in your associations, it should be:
public $hasMany = array(
'Preinscription.Relative'
);
and
public $belongsTo = array(
'Preinscription.Preregistry'
);
otherwise CakePHP won't grab the models from the plugin, but create an instance of AppModel for the associations instead (in case there are no Relative respective Preregistry in any of the configured model locations), which is then of course missing your Date behavior.
See also http://book.cakephp.org/2.0/en/plugins.html#plugin-models
Related
I have a model class in CakePHP defined like this:
class Programme extends AppModel {
public $hasOne = array(
'ProgrammeLikes' => array(
'className' => 'ProgrammeLikes',
'fields' => array('likes'));
}
When retrieving my models from the database they are returned as an array with an array keyed to 'Programme' and a separate array keyed to 'ProgrammeLikes' (which contains the 'likes' value correctly). In order to reduce the changes necessary to existing code I want the 'likes' value to be within the 'Programme' array.
Is this possible?
Thanks in advance
Use virtualFields here to get this thing to be done.
class Programme extends AppModel {
public $hasOne = array(
'ProgrammeLikes' => array(
'className' => 'ProgrammeLikes',
'fields' => array('likes')
);
public $virtualFields = array(
'likes' => 'SELECT likes FROM programme_likes AS ProgrammeLikes WHERE ProgrammeLikes.id = Programme.programme_likes_id'
);
// Where programme_likes_id is the foriegnkey for Programme model
}
Note: I assumed programme_likes is your table name for ProgrammeLikes Model and programme_likes_id is the foriegnkey for
Programme Model, so you can arrange the query in your own way that suits your requirement.
Sorry if the Title misses what i'm aiming at, but had no clue how to name this. Here's my Quest:
I have a single Cart, holding multiple Items (1:n) which are belonging to prices (1:1).
The Relations between Items and Prices are working as well:
class Item extends AppModel {
public $hasOne = 'Price';
}
class Price extends AppModel {
public $belongsTo = array(
'Item' => array(
'className' => 'Item',
'foreignKey' => 'id'
)
);
}
But now i make a select (find) of a cart and want those items included, which is also working as well:
class CartItem extends AppModel {
public $useTable = 'cart_items';
public $belongsTo = array('Item', 'Address');
}
But what i really need is to get those prices of each item, which is not working ($result in afterFind()-Callback in Item-Model does not include the assigned prices & afterFind()-Callback in Price-Model is not called when finding a cart)..
what am i missing here?
/EDIT: Recent Changes:
class AppModel extends Model {
var $actsAs = array('Containable');
}
class CartsController extends AppController {
public function getCart() {
$cart = ClassRegistry::init('CartItem')->find('all', array(
'contain' => array(
'Item' => array(
'Price'
),
'Address'
),
'conditions' => array(
'id_cart' => $cart['Cart']['id']
)
));
}
The above changes cause that i'll get a Price into a found Item but only into the last one thats found.
You haven't shown your actual find(), but I suspect you're not setting an appropriate 'recursive' param or are not using 'contain'.
I prefer using the containable behaviour enabled from AppModel:
var $actsAs = array('Containable');
Then you can do something like:
$cartItem = $this->CartItem->find(
'first',
array(
'contain' => array(
'Item' => array(
'Price'
),
'Address'
),
'conditions' => array('CartItem.id' => 123)
)
);
I have a many to many relationship between Profesional and Plan so I wrote the following code:
Profesional.php
class Profesional extends BaseModel {
static $table_name = 'profesionales';
static $primary_key = 'idprofesional';
static $has_many = array(
array(
'_planes',
'class_name' => 'Plan',
'through' => '_profplanes'
),
array(
'_profplanes',
'class_name' => 'ProfPlan',
'foreign_key' => 'profesional'
)
);
}
profplan.php
class ProfPlan extends BaseModel{
static $table_name = 'profplanes';
static $belongs_to = array(
array(
'_plan',
'class_name' => 'Plan',
'foreign_key' => 'plan'
),
array(
'_profesional',
'class_name' => 'Profesional',
'foreign_key' => 'profesional'
)
);
}
plan.php
class Plan extends BaseModel {
static $table_name = 'planes';
static $primary_key = 'idplan';
static $has_many = array(
array(
'_profplanes',
'class_name' => 'ProfPlan',
'foreign_key' => 'plan'
)
);
}
But I get Class Profplane does not exist. Where is the error? What am I doing wrong?
Fix the class / table spellings! it'll be easy to fix early in your code and becomes a maintenance nightmare later on =P! "Plan->Plans' 'Profesional=>Professional', "Professionales->"Professionals".
Honestly the through relationship code in phpactiverecord is annoying, fickle, and really needs to be looked at in general.
You should show how you're actually calling the code, but I'm going to assume you're doing
Professional::find(1)
$professional->_plans, //Error is thrown here
You need to set up your code so that ProfPlan->_plans(or _planes in your case), is definded, and not just ProfPlan->_plan. Phpactiverecord needs to explicitly know the relationship it's going to go through. Let me know if you need a more clear explanation.
I have these models:
class Prefix extends AppModel {
public $displayField = 'prefix';
public $hasMany = array(
'State' => array(
'className' => 'State',
'foreignKey' => 'prefix_id',
'dependent' => false,
),
);
}
class State extends AppModel {
public $displayField = 'name';
public $belongsTo = array(
'Prefix' => array(
'className' => 'Prefix',
'foreignKey' => 'prefix_id',
),
);
}
Then I have this admin_add method, from the automatic scaffolder:
public function admin_add() {
if ($this->request->is('post')) {
$this->Peefix->create();
if ($this->Prefix->save($this->request->data)) {
$this->redirect(array('action' => 'index'));
} else {
// Error message
}
}
$states = $this->Prefix->State->find('list');
$this->set(compact('states'));
}
I also have the list of them in my form:
<?php echo $this->Form->input('State', array('multiple' => 'checkbox', 'type' => 'select',)); ?>
Now I can set the States for the Prefix. However, when I submit the form, the selection disappears. It is not saved in the database.
What did I do wrong?
You linked the models as if there is only one state per prefix, and many prefixes "assigned" to one state. That means you cannot use 'multiple' => 'checkbox'. So either remove this or change model associations to HABTM.
First, both foreign keys for hasMany and belongsTo must be the same. If in the parent model you provided invoice_circle_id as the key, then the same must be provided in the child model also. Obviously, that field must exist in the child table. See this for more info http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
Second - you might want to use the saveAll() or saveAssociated() method for linked model data saving. Again - http://book.cakephp.org/2.0/en/models/saving-your-data.html contains all the ifnormation you need.
As for naming the input fields for hasMany, you name them like this:
$this->Form->input('ParentModel.fieldname');
$this->Form->input('ChildModel.0.fieldname');
I'm trying to retrieve some data through two model relationships with CakePHP. The models and their associations are as follows:
User hasOne Profile HABTM Skill
I would like the user's skills to be returned when I do a find() operation on the User model, and right now it isn't returned. Here's my find call which is being executed against the User model:
$this->paginate = array(
'conditions' => array(
'OR' => array(
'Profile.firstname LIKE' => "%$q%",
'Profile.lastname LIKE' => "%$q%"
)
)
);
It's returning user data and profile data, but not any skill data. I tried setting recursive to 2 or 3, but that doesn't help either. The only way I can get skill data is if I run find() against the Profile model, but I can't do that. For clarification here's the relevant models and their relationships:
// app/Model/User.php
class User extends AppModel {
public $hasOne = 'Profile';
}
// app/Model/Profile.php
class Profile extends AppModel {
public $belongsTo = 'User';
public $hasAndBelongsToMany = 'Skill';
// app/Model/Skill.php
class Skill extends AppModel {
public $hasAndBelongsToMany = 'Profile';
Can anyone help me get the users skills when retrieving user data? Thanks.
Use CakePHP's Containable Behavior. Your find will then look something like this:
$this->User->find('all',array(
'conditions' => array(
'OR' => array(
'Profile.firstname LIKE' => "%$q%",
'Profile.lastname LIKE' => "%$q%"
)
),
'contain' => array(
'Profile' => array(
'Skill'
)
)
));
MUCH simpler, easier to read, and voila - you get the data you want without needing to use the dreaded 'recursive'.