how to setup self relation with same table in yii - php

I am using Yii 1.x version.
I am stuck while setting up a relation with same table using two different model. my scenario is something like this.
There are two tables, user and user_friend_list
Two different model for each table User & UserFriendList.
Following are the fields for my table.
User: id, firstname, lastname.
UserFriendList: id, user_id, friend_user_id
I want to set up relation between two model so that i can fetch all friend information of any user. Kindly suggest me what would be best approach to achieve this???
Note:
The User table stores user information.
User Friend List table store friend list of user.

Try -
In User model -
'friends' => array(self::HAS_MANY, 'UserFriendList', 'user_id'),
In UserFriendList model -
'user' => array(self::BELONGS_TO, 'User', 'user_id'),

Two tables - user & friends
CREATE TABLE IF NOT EXISTS `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`password` varchar(50) NOT NULL,
`name` varchar(100) NOT NULL,
`email` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
CREATE TABLE IF NOT EXISTS `friend` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`friend_user_id` int(11) NOT NULL,
`status` varchar(1) NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `friend_user_id` (`friend_user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
--
ALTER TABLE `friend`
ADD CONSTRAINT `friend_ibfk_2` FOREIGN KEY (`friend_user_id`) REFERENCES `user` (`id`),
ADD CONSTRAINT `friend_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`);
Relations I have in my user model
return array(
'friends' => array(self::HAS_MANY, 'Friend', 'friend_user_id'),
'friends1' => array(self::HAS_MANY, 'Friend', 'user_id'),
);
And friend model
return array(
'friendUser' => array(self::BELONGS_TO, 'User', 'friend_user_id'),
'user' => array(self::BELONGS_TO, 'User', 'user_id'),
);
I hope this helps. I found it on yiiforum

Related

Bug when storing sessions in the database (Yii 1)

I have project on yii 1 and when i use DB for saving sessions i received bug. For each query to the site in the database creates a new entry. I don't know why.
Therefore I can not get a variable from the session, becouse after refrtsh page i have a new entry in db.
What i am doing wrong?
Table:
CREATE TABLE `wo_yiisession` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`expire` INT(11) NOT NULL,
`data` TEXT NOT NULL,
PRIMARY KEY (`id`),
INDEX `expire_idx` (`expire`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
session component setings:
'session' => array(
'class' => 'CDbHttpSession',
'connectionID' => 'db',
'sessionTableName' => 'wo_yiisession',
'timeout' => 3600 * 24 * 30,
'autoStart' => 'false',
'cookieMode' => 'only',
),
It looks like your ID field is wrong type. Proposed table structure is:
CREATE TABLE YiiSession
(
id CHAR(32) PRIMARY KEY,
expire INTEGER,
data BLOB
)
See CDbHttpSession

CakePHP save empty model

I have 2 types of users: employees and customers and I need to distinguish between them so I have created 2 separate tables for them. Then I chose CakePHP as my framework and then I wanted to follow Simple Authentication tutorial where is one table for Users. So I have decided to create tables like this:
CREATE TABLE IF NOT EXISTS `users` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`username` varchar(36) COLLATE utf8_czech_ci NOT NULL,
`password` varchar(36) COLLATE utf8_czech_ci NOT NULL,
`role` varchar(30) COLLATE utf8_czech_ci NOT NULL,
`name` varchar(30) COLLATE utf8_czech_ci NOT NULL,
`surname` varchar(40) COLLATE utf8_czech_ci NOT NULL,
`phone` varchar(16) COLLATE utf8_czech_ci NOT NULL,
`email` varchar(40) COLLATE utf8_czech_ci NOT NULL,
`employee_id` int(20) DEFAULT NULL,
`customer_id` int(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `EMAIL` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `employee` (
`id` int(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `customer` (
`id` int(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT AUTO_INCREMENT=1 ;
My models:
Employee
public $hasOne = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'employee_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
User:
public $belongsTo = array(
'Employee' => array(
'className' => 'Employee',
'foreignKey' => 'employee_id',
'conditions' => '',
'fields' => '',
'order' => ''
);
Add User function:
public function add() {
if ($this->request->is('post')) {
$this->User->create();
$roles = array('admin', 'employee');
if (in_array($this->request->data['User']['role'], $roles)) {
if ($this->User->Employee->save($this->request->data))
$this->request->data['User']['employee_id'] = $this->User->Employee->getLastInsertId();
else {
$this->Session->setFlash(__('Employee could not be saved.'));
return;
}
}
else {
$this->User->Customer->save($this->request->data);
$this->request->data['User']['customer_id'] = $this->User->Customer->getLastInsertId();
$this->User->Customer->create();
}
if (!$this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
else {
$this->Session->setFlash(__('The user has been saved.'));
}
//return $this->redirect(array('action' => 'index'));
}
$employees = $this->User->Employee->find('list');
$customers = $this->User->Customer->find('list');
$this->set(compact('employees', 'customers'));
}
I have a feeling that this conceptual model is not right because Employee and Customer tables contain only primary keys.
Also ($this->User->Employee->save($this->request->data) returns false. Is there a problem that CakePHP is not able to save empty model?
Or do you have any better idea how to model these tables?
Thanks.
If you intend to have information specific to an employee type user and a customer type user, the direction you're going in is fine, and you'd add those future fields to the customer and employee tables. If all you need to do is distinguish between an employee type user and a customer type user, then all you need is a field in your user table to distinguish type, such as
is_employee tinyint(1) default 0,

CakePHP linking a hasMany relationship with a different index

I have a table of securities like so:
CREATE TABLE IF NOT EXISTS `securities` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ticker` varchar(36) NOT NULL,
`name` varchar(180) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ticker` (`ticker`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=585 ;
I.e. the primary key is id whilst there is another unique index ticker.
The ticker index refers to my other table, secuity_prices which has this
CREATE TABLE IF NOT EXISTS `security_prices` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`price_date` date NOT NULL,
`ticker` varchar(36) NOT NULL,
`price` decimal(10,6) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=88340 ;
I want to define a hasMany relationship between them such that security hasMany securityPrice [securityPrice belongsTo security].
The problem I am having is that Cake is using the primary key of security to link to the security_prices table instead of the ticker field. How can I get the join to be made via the ticker?
Here are my relationships:
//Security
public $hasMany = array(
'SecurityPrice' => array(
'className' => 'SecurityPrice',
'foreignKey' => 'ticker',
)
);
//SecurityPrice
public $belongsTo = array(
'Security' =>
array(
'className' => 'Security',
'foreignKey' => 'ticker',
)
);
You can't use $hasMany to do this, because those associations require that you follow Cake's naming conventions for the primary key. You are trying to join two tables via non-primary key columns. That can be done, but not via Cake's automatic associations.
You need to add the join conditions when performing a find operation or pagination operation.
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables
$options['joins'] = array(
array('table' => 'security_prices',
'alias' => 'SecurityPrice',
'type' => 'LEFT',
'conditions' => array(
'Security.ticker = SecurityPrice.ticker',
)
)
);
$Security->find('all', $options);
If you have to do this often, then you should create a custom find type.
http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#creating-custom-find-types
class Security extends AppModel {
public $findMethods = array('ticker' => true);
protected function _findTicker($state, $query, $results = array()) {
if ($state === 'before') {
$query['joins'][] = array(
array('table' => 'security_prices',
'alias' => 'SecurityPrice',
'type' => 'LEFT',
'conditions' => array(
'Security.ticker = SecurityPrice.ticker',
)
)
);
return $query;
}
return $results;
}
}
Then later it's easy to find with the join.
$Security->find('ticker',.....);

CodeIgniter - ci_sessions migrations

I was wondering if someone can help out.
Im just getting into using migrations with CodeIgniter, but im having trouble trying to figure out how to convert SQL to the migrations.
Is there anyone out there that could convert this SQL to migrations for me so i can see how its done.
The SQL i have is as follows:
CREATE TABLE IF NOT EXISTS `ci_sessions` (
`session_id` varchar(40) COLLATE utf8_bin NOT NULL DEFAULT '0',
`ip_address` varchar(16) COLLATE utf8_bin NOT NULL DEFAULT '0',
`user_agent` varchar(150) COLLATE utf8_bin NOT NULL,
`last_activity` int(10) unsigned NOT NULL DEFAULT '0',
`user_data` text COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`session_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
Please read the documentation here:
CodeIgniter Migrations
In essence, you will want to use the CodeIgniter dbforge class to create the table. Using your code above:
$this->dbforge->add_field(array(
'session_id' => array(
'type' => 'VARCHAR',
'constraint' => '40'
),
'ip_address' => array(
'type' => 'VARCHAR',
'constraint' => '16'
),
'user_agent' => array(
'type' => 'VARCHAR',
'constraint' => '150'
),
'last_activity' => array(
'type' => 'INT',
'constraint' => '10'
),
'user_data' => array(
'type' => 'TEXT'
)
));
$this->dbforge->add_key('session_id', TRUE);
$this->dbforge->create_table('ci_sessions');
Documentation on dbforge class can be found here:
ellislab.com/codeigniter/user-guide/database/forge.html
Note: I don't recommend messing with the CI Sessions table, though.
You can also simply do this if you've a block of large SQL query you know is "safe" and you want to save time (in my opinion it's a judgement call based on the complexity of the table and the chance of making an error when translating the raw SQL into arrays - after all in migrations everything is hardcoded and you're not worrying about the chances of SQL injection etc.)
$sql = "CREATE TABLE IF NOT EXISTS `ci_sessions` (
session_id varchar(40) DEFAULT '0' NOT NULL,
ip_address varchar(45) DEFAULT '0' NOT NULL,
user_agent varchar(120) NOT NULL,
last_activity int(10) unsigned DEFAULT 0 NOT NULL,
user_data text NOT NULL,
PRIMARY KEY (session_id),
KEY `last_activity_idx` (`last_activity`)
)";
$this->db->query($sql);
However I don't think I'd recommend loading the sessions table as a migration, because if $config['sess_use_database'] in config/config.php is true, when you go to your migration URL it'll fail, as Codeigniter will first try to create a session entry in the database for your browser and the database table doesn't yet exist..
A Database Error Occurred
Error Number: 1146
Table 'characterhub.ci_sessions' doesn't exist
So for it to work, you or whomever is performing the migration has to set sess_use_database to false first, then run the migration, then change it back to true again.

CakePHP HABTM model problem

I have a problem when using CakePHP HABTM.
I have the following models.
class Repositorio extends AppModel{
var $name="Repositorio";
var $hasAndBelongsToMany = array(
'Sesion' =>
array(
'joinTable' => 'sesions_repositorios',
'dependent' => true
)
);
var $order=array('Repositorio.name'=>'ASC');
}
class Sesion extends AppModel{
var $name="Sesion";
var $belongsTo=array(
'SesionsEstado',
'Asignatura',
'User'
);
var $hasAndBelongsToMany = array('Repositorio'=>
array(
'joinTable'=>'sesions_repositorios',
'dependent' => true
)
);
var $order=array('Sesion.ffin'=>'ASC');
}
And the following database tables.
CREATE TABLE sesions (
id INT(11) NOT NULL AUTO_INCREMENT,
user_id INT(11) NOT NULL,
sesions_estado_id INT(11) NOT NULL,
asignatura_id INT(11) NOT NULL,
name VARCHAR(100) NOT NULL,
finicio DATETIME NOT NULL,
ffin DATETIME NOT NULL,
created DATETIME NOT NULL,
modified DATETIME NOT NULL,
PRIMARY KEY(id),
INDEX sesions_FKIndex1(sesions_estado_id),
INDEX sesions_FKIndex2(asignatura_id),
INDEX sesions_FKIndex3(user_id)
);
CREATE TABLE repositorios (
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
created DATETIME NOT NULL,
modified DATETIME NOT NULL,
PRIMARY KEY(id)
);
CREATE TABLE sesions_repositorios (
id INT(11) NOT NULL AUTO_INCREMENT,
sesion_id INT(11) NOT NULL,
repositorio_id INT(11) NOT NULL,
PRIMARY KEY(id),
INDEX sesions_repositorios_FKIndex1(sesion_id),
INDEX sesions_repositorios_FKIndex2(repositorio_id)
);
When I save the data in a repository all work properly, that is, it performs an INSERT on the table "repositorios" and performs the corresponding INSERT on table "sesions_repositorios.
My problem comes when I get a list of repositories for a particular user. The code for this would be.
class RepositoriosController extends AppController{
...
$r=$this->Repositorio->Sesion->find('all', array('conditions'=>array('user_id'=>$this->Session->read('Auth.User.id'))));
var_dump($r);
...
}
The $r variable does not contain the filtered data for user_id, why?, what am I doing wrong?
I have not set foreign key's, could that be the problem?
Thanks for the help.
I believe that you need to add in something like 'recursive' => 1 or whatever depth you want it to search your linked models into your query.
$r=$this->Repositorio->Sesion->find('all', array('conditions'=>array('user_id'=>$this->Session->read('Auth.User.id')),'recursive'=>1));
I'm sorry, the code is actually quite correct. Was failing by other issues.
Thanks for everything.
Greetings!

Categories