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.
Related
I can't figure out what's the problem in the sql query. I'm using the dbforge library in codeigniter 3.
Mysql Version: 8.0
<?php
class Migration_merchant_withdraw_request extends CI_Migration
{
public function up()
{
$this->dbforge->add_field('id');
$this->dbforge->add_field([
'`mitra_id` VARCHAR NOT NULL',
'`amount` INT NOT NULL',
'`password` VARCHAR NOT NULL',
'`status` INT DEFAULT 0',
'`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP',
'`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP',
]);
$this->dbforge->create_table('merchant_withdraw_request');
}
public function down()
{
$this->dbforge->drop_table('merchant_withdraw_request');
}
}
Which generates the sql query.
CREATE TABLE `merchant_withdraw_request` (
`id` INT(9) NOT NULL AUTO_INCREMENT,
`mitra_id` VARCHAR NOT NULL,
`amount` INT NOT NULL,
`password` VARCHAR NOT NULL,
`status` INT DEFAULT 0,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT `pk_merchant_withdraw_request` PRIMARY KEY(`id`)
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci
Yet, I get an error message.
Error Number: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NOT NULL, amount INT NOT NULL, password VARCHAR NOT NULL, status INT DE' at line 3
I tried this style of adding fields in dbforge.
<?php
class Migration_merchant_withdraw_request extends CI_Migration
{
public function up()
{
$this->dbforge->add_field('id');
$this->dbforge->add_field([
'mitra_id' => [
'type' => 'VARCHAR',
],
'amount' => [
'type' => 'INT',
],
'password' => [
'type' => 'VARCHAR',
],
'status' => [
'type' => 'INT',
'default' => 0,
],
'created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP',
'updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP',
]);
$this->dbforge->create_table('merchant_withdraw_request');
}
public function down()
{
$this->dbforge->drop_table('merchant_withdraw_request');
}
}
Yet it produces the same error, what's the problem?
Problem Solved
It turns out that, I have not set the length of the VARCHAR data type. To do this in dbforge, this would be the syntax.
'column_name' => [
'type' => 'VARCHAR',
'constraint' => 64 // Set your wanted length.
]
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
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,
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!
I have an existing web application that I am converting to use CakePHP.
The problem is that the primary keys for most of the tables are in this format "${table_name}_id" (story_id) instead of the CakePHP way of 'id'
When ever I try to update some of the fields for a row in the story table, the Save() function will return false. Is there any way of getting a more detailed error report from the Save() function. ?
When I set Configure::write('debug', 2); in core.php and check the SQL statements I do not see any UPDATE command, only SELECT statements.
I tried to edit the controller adding the following line to manually set the id field for the controller but it did not help.
$this->Story->id = $this->data['Story']['story_id'] ;
I'm running out of ideas. Any suggestions?
I have included the source code that I am using below
Story controller:
function admin_edit($id = null)
{
if (!$id && empty($this->data)) {
$this->Session->setFlash(__('Invalid '. Configure::read('Site.media') , true));
$this->redirect(array('action'=>'index'));
}
$this->layout = 'admin';
if (!empty($this->data)) {
if ($this->Story->save($this->data)) {
$this->Session->setFlash(__('The '. Configure::read('Site.media') .' has been saved', true));
} else {
$this->Session->setFlash(__('The '. Configure::read('Site.media') .' could not be saved. Please, try again.', true));
}
}
$this->data = $this->Story->read(null, $id );
}
Story model:
class Story extends AppModel {
var $name = 'Story';
var $primaryKey = 'story_id';
var $validate = array(
'author_id' => array('numeric'),
'title' => array('notempty'),
'story' => array('notempty'),
'genra' => array('notempty'),
'form' => array('notempty'),
'wordcount' => array('Please enter a number between 1 and 1000' => array(
'rule' => array('range', 1, 1001),
'message' => 'Please enter a number between 1 and 1000' ),
'Required' => array( 'rule' => 'numeric', 'required' => true )
)
);
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $belongsTo = array(
'Author' => array(
'className' => 'Author',
'foreignKey' => 'author_id'
)
);
var $hasMany = array(
'UserNote' => array(
'className' => 'UserNote',
'foreignKey' => 'story_id',
'dependent' => false,
'conditions' => 'UserNote.notes != ""'
)
);
}
Story view:
echo $form->create('Story', array('action' => 'edit' ) );
echo $form->input('story_id',array('type'=>'hidden') );
echo $form->input('title');
echo $form->input('story');
echo $form->input('bio' );
echo $form->end('Update story details');?>
Story table
CREATE TABLE IF NOT EXISTS `stories` (
`story_id` int(11) NOT NULL AUTO_INCREMENT,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`closed` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`author_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL,
`story` text NOT NULL,
`genra` varchar(255) NOT NULL,
`form` varchar(128) DEFAULT NULL,
`wordcount` varchar(255) NOT NULL,
`terms` varchar(255) NOT NULL DEFAULT '0',
`status` varchar(255) NOT NULL DEFAULT 'slush',
`published` date NOT NULL,
`payment` varchar(255) NOT NULL DEFAULT 'none',
`paypal_address` varchar(255) NOT NULL,
`resubmission` tinyint(1) NOT NULL DEFAULT '0',
`bio` text NOT NULL,
`password` varchar(255) NOT NULL DEFAULT 'yyggrrdd',
`comments` text NOT NULL,
PRIMARY KEY (`story_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=10905 ;
You should manually override the primary key field in the model (which is the right place to do this - the name of a primary key field is an attribute of the model, and not something that should be 'fudged' around in the controller.)
class Example extends AppModel { var $primaryKey = 'example_id'; // example_id is the field name in the database}
The above code is from http://book.cakephp.org/view/437/primaryKey
While the suggestion to turn off validation will work, it's not the right way to go about it.
Lastly, if you're setting model variables within a controller, you use $this->Model->set('attributeName',value) rather than $this->Model->attributeName
It looks like the story controller was validating the data, and the data was invalid.
Adding the following line to the controller will stop the validation of the data.
$this->Story->validate = array(); // Stop valadation on the story.
I found this solution on this page
15 essential CakePHP tips