I have the following table schema ( legacy system so I can't change it :-( )
admins:
admin_id
...
admin_auths:
admin_id ( connects to admin_id )
id ( connects to user_id )
auth ( only care about when this is 'user' )
...
users:
user_id ( connects to id )
...
Here is how I managed to get the relationship working for users:
User.php
class User extends ActiveRecord\Model {
static $has_many = [
[ 'admin_auths',
'foreign_key' => 'id', # key in linked table
'primary_key' => 'user_id', # key in "parent" (this) table
],
[ 'parents',
'through' => 'admin_auths',
'foreign_key' => 'id', # key in linked table
'primary_key' => 'user_id', # key in "parent" (this) table
'class_name' => 'Admin'
]
];
}
AdminAuth.php
class AdminAuth extends ActiveRecord\Model {
static $belongs_to = [
[ 'admin' ],
[ 'user',
'foreign_key' => 'id', # key in linked (this) table
'primary_key' => 'user_id', # key in "parent" table
]
];
}
If I call $user->parents or $user->admin_auths this works perfectly!
However I cannot seem to get it working in the Admin.php file:
class Admin extends ActiveRecord\Model implements JsonSerializable {
// relationships
static $has_many = [
[ 'admin_auths' ],
[ 'children',
'through' => 'admin_auths',
'class_name' => 'User'
]
];
...
}
The way it is shown above. This runs the following SQL:
SELECT `users`.* FROM `users` INNER JOIN `admin_auths` ON(`users`.user_id = `admin_auths`.user_id) WHERE `admin_id`=?
The problem with this is that I need to get it to join ON(`users`.user_id = `admin_auths`.id) ( there is no user_id column )
I've tried setting both the foreign_key and primary_key columns. foreign_key changes the where section of the query and primary_key runs no query ( Just SHOW COLUMNS on users and admin_auths ).
TL;DR: How to I customize the join on a PHP ActiveRecord has_many association?
Related
I have 3 tree like connected tables. Their schemas as follows:
Member{
//Some column
}
Transactions{
member_id :: foreign key of member table
//Some other column
}
TransactionItems{
transaction_id :: foreign key of Transaction table
//Some other column
}
I define models like this:
class Members extends AppModel {
public $primaryKey = 'id';
public $hasOne = array(
'Transactions' => array(
'className' => 'Transactions',
'foreignKey' => 'member_id',
'dependent' => true
)
);
}
class Transactions extends AppModel {
public $primaryKey = 'id';
public $belongTo = array('Members');
public $hasOne = array(
'TransactionItems' => array(
'className' => 'TransactionItems',
'foreignKey' => 'transaction_id',
'dependent' => true
)
);
}
class TransactionItems extends AppModel {
public $primaryKey = 'id';
public $belongTo = array('Transactions');
public $belongsTo = array(
'Transactions' => array(
'className' => 'Transactions',
'foreignKey' => 'transaction_id'
)
);
}
I have a Data Array which I want to save into database. My scheme is:
Array(
[Members] = [],//Array
[Transactions] = [],//Array
[TransactionItems] = []//Array
)
The problem is that whenever I run $this->Members->saveAll($data). It save data in Member and Transactions table. But do not create data in TransactionItems table. I want to save in all 3 tables at a time.
Any help would be grateful.
Second level (and above) associations must be nested, ie the data structure needs to be:
array(
'Members' => array(),
'Transactions' => array(
'TransactionItems' => array()
)
)
A bit awkward, but that's how it works in 2.x. You can always refer to the structure that is being returned when reading data, it needs to be the same when saving it.
Furthermore you must set the deep option to true in order to be able to save second level and above associations (by default only first level associations are being saved):
$this->Members->saveAll($data, array('deep' => true));
See also
Cookbook > Models > Saving Your Data > Model::saveAssociated()
I am using Kohana 3.3 and am trying to establish relationship on my ORM tables using has_many and belongs_to . I have a users table which is defined as below
I have another table userjobs defined as below. The userjobs have a foreign key referencing user_id from `users.
In the class Model_User (extends Model_Auth_User), I have defined the relationship like
protected $_has_many = array(
'user_tokens' => array('model' => 'user_token'),
'roles' => array('model' => 'role', 'through'=> 'roles_users'),
'jobs' => array('model' => 'Userjob','foreign_key' => 'user_id' ),
);
and in the class Model_Userjob (extends ORM), the following statement is written
protected $_belongs_to = array(
'user' => array('model' => 'user')
);
However, when i try to access the jobs like below, it is throwing an exception which says that jobs is not defined in Model_User
Auth::instance()->get_user()->jobs;
I had tried dumped values of the get_user() it is not showing jobs in the protected $_has_many array.
I even tried removing user_tokens and roles from the $_has_many, but still has_many array still holds the entry for roles and user_tokens when -i printed values of get_user.
I am not sure, but I think that you should set relationship in user model like this:
protected $_has_many = array(
'user_tokens' => array('model' => 'user_token'),
'roles' => array('model' => 'role', 'through'=> 'roles_users')
);
protected $_belongs_to = array(
'jobs' => array('model' => 'userjob','foreign_key' => 'user_id' )
);
and in job model:
protected $_has_one = array(
'user' => array('model' => 'userjob', 'foreign_key' => 'user_id')
);
You need to add '->find_all()' at the end of that line. Otherwise jobs will be seen as a col.
Auth::instance()->get_user()->jobs->find_all();
i'm starting with Kohana 3.3 ORM trying to apply it to an existing internal project.
The project is in use, so i can't change the schema's names. The current schema definition is the following:
Table: utente
idUtente VARCHAR PK
nome VARCHAR
// other fields
Table: sessione
idSessione SERIAL PK
idUtente VARCHAR (FK to utente.idUtente)
// other fields
Table: ruolo
idRuolo SERIAL PK
nome VARCHAR
//other fields
Table: ruoloutente
idRuolo PK (FK to ruolo.idRuolo)
idUtente PK (FK to utente.idUtente)
scadenza DATETIME
// other fields
Now i defined custom table name and custom primary key name into the models and if i use ORM::factory('Utente', 'Marco'); (or any other model) everything is going fine.
class Model_Utente extends ORM {
protected $_table_name ='utente';
protected $_primary_key ='idUtente';
protected $_has_many =
array(
'ruoli' => array(
'model' => 'Ruolo',
'far_key' => 'idRuolo',
'foreign_key' => 'idUtente',
'through' => 'ruoloutente',
),
'sessioni' => array(
'model' => 'Sessione',
'far_key' => 'idSessione',
'foreign_key' => 'idUtente',
),
);
// class logic here
}
class Model_Ruolo extends ORM {
protected $_table_name ='ruolo';
protected $_primary_key ='idRuolo';
protected $_has_many =
array(
'utenti' => array(
'model' => 'Utente',
'far_key' => 'idUtente',
'foreign_key' => 'idRuolo',
'through' => 'ruoloutente',
),
);
// class logic here
}
class Model_Sessione extends ORM {
protected $_table_name ='sessione';
protected $_primary_key ='idSessione';
protected $_belongs_to =
array(
'utente' => array(
'model' => 'Utente',
'far_key' => 'idUtente',
'foreign_key' => 'idUtente',
),
);
// class logic here
}
Now from an instance of Utente i execute $this->ruoli->find_all() and $this->sessioni->find_all() but i obtain an empty model on both..
The generated query is correct on both finding, query executed directly in SQL returns 4 results on ruoli and two results on sessioni..
Found a solution
My problem was that i supposed that find() and find_all() methods would also perisist in the caller object the query results instead of only return the result. Many thanks to every one
I'm using kohana 3.2 and I need help with has_many relationship. The table is written empty data...
So, my User_education model look like: http://gyazo.com/218139e52d85718c0d47bb802f0856fe User_personal model : http://gyazo.com/49fd4ab4fb7506cf8b7c608733a70365
and controller: http://gyazo.com/7d13dd3901870d7ad3d62c09e90a9c14 but fields in database still empty
You should specify the foreign key in your models:
class Model_User_Personal extends ORM
{
protected $_has_many = array(
'educations' => array(
'model' => 'user_education',
'foreign_key' => 'user_personal_id',
),
);
}
The same foreign key should be set in Model_User_Education:
class Model_User_Education extends ORM
{
protected $_belongs_to = array(
'user_personal' => array(
'model' => 'user_personal',
'foreign_key' => 'user_personal_id',
),
);
}
I've got some trouble trying to make this work. I have 2 models, User_Pro and Category. I read the relationships documentation on kohana guide and I understand i need to define a $_has_many relationship on the User_Pro and Category models and create the model user_pro_categories with the belongs_to field.
User_Pro model:
protected $_has_many = array(
'categories' => array(
'model' => 'TM_Category',
'through' => 'user_pro_categories',
'foreign_key' => 'id_user_pro',
),
);
Category model:
protected $_has_many = array(
'users_pro' => array(
'model' => 'TM_User_Pro',
'through' => 'user_pro_categories',
'foreign_key' => 'id_category',
),
);
user_pro_categories model:
protected $_belongs_to = array(
'user_pro' => array(
'model' => 'TM_User_Pro',
'foreign_key' => 'id_user_pro',
),
'category' => array(
'model' => 'TM_Category',
'foreign_key' => 'id_category',
),
);
The error I'm getting is:
Database_Exception [ 1054 ]: Unknown column 'tm3_user_pro_categories.category_id' in
'on clause' [ SELECT `tm3_tm_category`.* FROM `tm3_categories` AS `tm3_tm_category` JOIN
`tm3_user_pro_categories` ON (`tm3_user_pro_categories`.`category_id` = `tm3_tm_category`.`id_category`)
WHERE `tm3_user_pro_categories`.`id_user_pro` = '2' ]
It's like it doesn't care about the fk's i defined and it want's to use the suffix thing... any idea?
Here is the example to give you quick idea how Kohana ORM works. And wish it will be helpful for others too.
Student Model
<?php defined('SYSPATH') or die('No direct script access.');
class Model_Student extends ORM {
protected $_primary_key = 'idstudent'; // take a look
protected $_has_many = array(
'courses'=> array(
'model' => 'course', // Course model
'through' => 'students_courses', // many-to-may through
'far_key' => 'id_for_course', // "column name" relating to the Course Model in "students_courses" table
'foreign_key' => 'id_for_student' // "column name" relating to the Student Model in "students_courses" table
),
);
}
Course Model
<?php defined('SYSPATH') or die('No direct script access.');
class Model_Course extends ORM {
protected $_primary_key = 'idcourse'; // take a look
protected $_has_many = array(
'students'=> array(
'model' => 'student',
'far_key' => 'id_for_student',
'through' => 'students_courses',
'foreign_key' => 'id_for_course'
),
);
}
SQL Script
CREATE TABLE IF NOT EXISTS `students` (
`idstudent` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`idstudent`)
) ENGINE=MyISAM;
INSERT INTO `students` (`idstudent`, `name`) VALUES
(1, 's1'),
(2, 's2');
/* column idcourse and PR idcourseS ? */
CREATE TABLE IF NOT EXISTS `courses` (
`idcourse` int(11) NOT NULL,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`idcourse`)
) ENGINE=MyISAM;
INSERT INTO `courses` (`idcourse`, `name`) VALUES
(1, 'c1'),
(2, 'c2'),
(3, 'c3');
CREATE TABLE IF NOT EXISTS `students_courses` (
`id_for_student` int(10) unsigned NOT NULL,
`id_for_course` int(10) unsigned NOT NULL
) ENGINE=MyISAM;
INSERT INTO `students_courses` (`id_for_student`, `id_for_course`) VALUES
(1, 1),
(1, 3);
$student = new Model_Student(1);
$courses = $student->courses->find_all();
echo Debug::vars($courses);
foreach($courses as $course) {
echo Debug::vars($course->object());
}
Running code above will create following SQL query.
SELECT `course`.* FROM `courses` AS `course` JOIN `students_courses` ON (`students_courses`.`id_for_course` = `course`.`idcourse`) WHERE `students_courses`.`id_for_student` = '1'
You don't need to create a model for pivot table for many-to-many relationship. Just define the through option in both models, make sure your primary/foreign keys follow Kohana convention and you're ready to go. Below example from Kohana ORM User and Role models:
class Model_User
{
protected $_has_many = array(
'roles' => array('model' => 'role', 'through' => 'roles_users'),
);
}
class Model_Role
{
protected $_has_many = array(
'users' => array('model' => 'user', 'through' => 'roles_users')
);
}