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.
Related
I'm having a very strange issue. I'm working with XAMPP on my local computer, and everything works perfect. But when I upload it to my server, suddenly ContainableBehavior stops recognizing associations.
Cake's version: 2.5.6
Here's XAMPP's phpinfo(): http://pastebin.com/DeZWMh42
And here's my server's phpinfo(): http://pastebin.com/rtZ0kTAM
Both locations have the exact same files and databases.
This is the error(s) I'm getting:
Warning (512): Model "Certificado" is not associated with model
"Usuario" [CORE/Cake/Model/Behavior/ContainableBehavior.php, line 342]
Warning (512): Model "Certificado" is not associated with model
"Alumno" [CORE/Cake/Model/Behavior/ContainableBehavior.php, line 342]
Warning (512): Model "Certificado" is not associated with model
"Usuario" [CORE/Cake/Model/Behavior/ContainableBehavior.php, line 342]
Warning (512): Model "Certificado" is not associated with model
"Alumno" [CORE/Cake/Model/Behavior/ContainableBehavior.php, line 342]
Basically, an Impresion belongs to an Usuario and to a Certificado, the latter also belongs to an Usuario (may be a different one) and to an Alumno. Obviously I cut out all the irrelevant parts (let me know if you need more.)
This is where I'm using ContainableBehavior (Impresion's Controller):
(I'm getting the error on /impresions/index)
class ImpresionsController extends AppController {
public $components = array('Paginator');
public $uses = array('Usuario', 'Alumno', 'Certificado', 'Impresion');
public function index(){
$this->paginate = array(
'limit' => 10,
'order' => array('fecha_creacion' => 'desc'),
'contain'=>array(
'Usuario',
'Certificado' => array(
'Usuario',
'Alumno'
)
),
);
$results = $this->paginate('Impresion');
$this->set('impresiones',$results);
}
}
And in the view I just use a foreach($impresiones).
Impresion's Model:
class Impresion extends AppModel {
public $actsAs = array('Containable');
public $belongsTo = array(
'Certificado' => array(
'className' => 'certificado',
'foreignKey' => 'certificado_id',
),
'Usuario' => array(
'className' => 'Usuario',
'foreignKey' => 'usuario_id',
'fields' => array('nombre','codigo')
),
);
}
Usuario's Model:
class Usuario extends AppModel {
public $hasMany = array('Certificado','Impresion');
public $actsAs = array('Containable');
}
Certificado's Model:
class Certificado extends AppModel {
public $actsAs = array('Containable');
public $belongsTo = array(
'Usuario' => array(
'className' => 'Usuario',
'foreignKey' => 'usuario_id',
),
'Alumno' => array(
'className' => 'Alumno',
'foreignKey' => 'alumno_id',
)
);
public $hasMany = 'Impresion';
}
Alumno's Model:
class Alumno extends AppModel {
public $actsAs = array('Containable');
public $hasMany = 'Certificado';
}
Local query: http://pastebin.com/B5MRp3FS
Server's query: http://pastebin.com/J2H4U6Ge
I'm completely lost here. Why does it work perfectly fine on my computer, but breaks on the server? Everything else works, it's just ContainableBehavior that's having problems.
I can't believe it.
Disregard everything.
This:
'className' => 'certificado',
Should've been this:
'className' => 'Certificado',
Sorry for wasting your time, I'm an idiot
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
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 weird problem with the Kohana (3.2) ORM query builder and i can't figure out what is wrong. I get "Incorrect table name" exception:
Database_Exception [ 1103 ]: Incorrect table name '' [ SELECT ``.* FROM `` JOIN `user_plugins` ON (`user_plugins`.`plugin_id` = ``.`id`) WHERE `user_plugins`.`user_id` = '9' ]
As you can see the table is empty in the query.
Controller:
$user = ORM::factory('user', Auth::instance()->get_user()->id);
if ($user->loaded() )
{
$result = $user->plugin->find_all();
}
User model:
class Model_User extends Useradmin_Model_User
{
protected $_has_many = array(
'plugin' => array( 'through' => 'user_plugins'),
);
...
user_plugin Model
class Model_user_plugin extends ORM
{
protected $_belongs_to = array(
'plugin' => array(),
'user' => array()
);
...
plugin Model
class Model_Plugin extends ORM
{
protected $_has_many = array(
'user' => array('through' => 'user_plugins')
);
...
Anyone got any idea what could be wrong here?
Any help is very appreciated!
This is how User Model should be
class Model_User extends Useradmin_Model_User
{
protected $_has_many = array(
'plugin' => array('model' => 'plugin', 'through' => 'user_plugins'),
);
...
This is how Plugin Model should be
class Model_Plugin extends ORM
{
protected $_has_many = array(
'user' => array('model' => 'user', 'through' => 'user_plugins')
);
You don't need user_plugin Model at all, the "user_plugins" in both models refers to the table name, not the model name. Just make sure you have the table with user_plugins that have following fields,
id, user_id, plugin_id
I hope this helps.
The $_has_many, by convention, must always use plural names, unless you specify the name in $_object_name in the target model. So it should be:
class Model_Plugin extends ORM
{
protected $_has_many = array(
'users' => array('through' => 'users_plugins')
);
//...
class Model_User extends ORM
{
protected $_has_many = array(
'plugins' => array('through' => 'users_plugins')
);
//...
class Model_user_plugin extends ORM
{
protected $_belongs_to = array(
'plugin' => array(),
'user' => array()
);
//...
i have multiple php classes
// a Base class
abstract class Base_Page {
protected static $config = array(
'status' => 'int',
);
}
// an inheriting class
class Page extends Base_Page{
protected static $config = array(
'title' => 'varchar',
'description' => 'text',
);
// and one more level of inheritance
class Page_Redirect extends Base_Page {
protected static $config = array(
'href' => 'http://domain.com',
);
}
now id'd like to do this:
$page_redirect = new Page_Redirect();
$page_redirect->getConfig(); // which i assume to be implemented (this is my problem)
// should return:
// array(
// 'status' => 'int',
// 'title' => 'varchar',
// 'description' => 'text',
// 'href' => 'http://domain.com',
// )
Due to the fact that the variable gets overwrote by the extending class a dont't get how to accomplish this. Thanks for your look at it.
You cannot do this with a bare property. It would be much better to use methods instead:
abstract class Base_Page {
protected function getConfig() {
return array('status' => 'int');
}
}
// an inheriting class
class Page extends Base_Page{
protected function getConfig() {
return array(
'title' => 'varchar',
'description' => 'text',
) + parent::getConfig();
}
}
// and one more level of inheritance
class Page_Redirect extends Base_Page {
protected function getConfig() {
return array(
'href' => 'http://domain.com',
) + parent::getConfig();
}
}
Of course now you have lost the ability to get the configuration statically, but it's highly likely that this does not matter. If it does (i.e. you need to know the configuration without having an instance at hand, and it is meaningless to create one on a whim) then the code needs further refactoring.
<?php
// a Base class
abstract class Base_Page {
protected static $config = array(
'status' => 'int',
);
}
// an inheriting class
class Page extends Base_Page {
protected static $config = array_merge(
parent::$config,
array(
'title' => 'varchar',
'description' => 'text',
)
);
}
Try something like this.