I'm using Datamapper ORM for the first time together with the array and htmlforms extensions for CRUD. So far both extensions worked well for all my models but today I'm facing a weird problem for one model.
When I try to save an object I get this SQL error:
A Database Error Occurred
Error Number: 1054
Unknown Column 'orderitems.orderitem_id' in where clause
SELECT COUNT(*) AS `numrows` FROM (`orderitems`) WHERE `orderitems`.`order_id` = 2 AND `orderitems`.`orderitem_id` NOT IN (8, 9)
Filename: libraries/datamapper.php
Line Number: 2526
I think the correct SQL should be ...AND orderitems.id NOT IN (...) becasue the Orderitem model is referencing itself and not another related model. This error is triggered inside the count() method which is triggered by the save() method which is triggered by the from_array() method of the array DM extension.
Here is my controller code
//Get order
$order = new Order(2);
//Fields to render in the form
$fields = array('orderitem');
//Save changes from $_POST
if($post = $this->input->post())
{
$order->trans_begin();
if ( ! $order->from_array($post, $fields, TRUE) OR $order->trans_status() === FALSE)
$order->trans_rollback();
else
$order->trans_commit();
}
//Load view
$data = array(
'order' => $order,
'fields'=> $fields,
);
$this->load->view('order/edit', $data);
Here is my view code
echo $order->render_form($fields);
And here are the implied models
class Order extends DataMapper {
public $has_one = array('orderstatus', 'place', 'user', 'paymenttype');
public $has_many = array('orderitem');
...
/*SQL:
CREATE TABLE IF NOT EXISTS orders (
id mediumint(4) unsigned NOT NULL auto_increment PRIMARY KEY,
user_id mediumint(1) unsigned, FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE RESTRICT,
orderstatus_id tinyint(1) unsigned, FOREIGN KEY (orderstatus_id) REFERENCES orderstatuses(id) ON UPDATE CASCADE ON DELETE RESTRICT,
place_id tinyint(1) unsigned, FOREIGN KEY (place_id) REFERENCES places(id) ON UPDATE CASCADE ON DELETE SET NULL,
paymenttype_id tinyint(1) unsigned, FOREIGN KEY (paymenttype_id) REFERENCES paymenttypes(id) ON UPDATE CASCADE ON DELETE SET NULL,
total float NOT NULL DEFAULT 0
) ENGINE = InnoDB;
*/
class Orderitem extends DataMapper {
public $has_one = array('order', 'orderitemstatus');
public $has_many = array('orderitemextra');
...
/*SQL:
CREATE TABLE IF NOT EXISTS orderitems (
id int(1) unsigned NOT NULL auto_increment PRIMARY KEY,
order_id mediumint(1) unsigned, FOREIGN KEY (order_id) REFERENCES orders(id) ON UPDATE CASCADE ON DELETE CASCADE,
orderitemstatus_id tinyint(1) unsigned, FOREIGN KEY (orderitemstatus_id) REFERENCES orderitemstatuses(id) ON UPDATE CASCADE ON DELETE RESTRICT,
name varchar(128) NOT NULL,
price float NOT NULL,
) ENGINE = InnoDB;
*/
As I said I had no problems with other models so I don't know if it's a DM problem or a problem with my code or any of my models definitions.
I'll appreciate any kind of help.
Thanks!
Related
I am trying to assign a role named 'admin' (already present in auth_item table in database) during signup in yii2. signup() is present inside SignupForm model in common models.
$auth = Yii::$app->authManager;
$authorRole = $auth->getRole('admin');
$auth->assign($authorRole, $user->getId());
but it is throwing an error at vendor\yiisoft\yii2\rbac\DbManager.php as Trying to get property 'name' of non-object .
public function assign($role, $userId)
{
$assignment = new Assignment([
'userId' => $userId,
'roleName' => $role->name,
'createdAt' => time(),
]);
.....
}
this is the function where the error is getting triggered
Implementing a role based access control is a very easy process and you can even load your roles from the database if you want.
Step1: Creating necessary tables in the database [ You can also apply
migrations with console command yii migrate instead of step 1 ]
The first step is to create necessary tables in the database.Below is the sql you need to run in the database.
drop table if exists `auth_assignment`;
drop table if exists `auth_item_child`;
drop table if exists `auth_item`;
drop table if exists `auth_rule`;
create table `auth_rule`
(
`name` varchar(64) not null,
`data` text,
`created_at` integer,
`updated_at` integer,
primary key (`name`)
) engine InnoDB;
create table `auth_item`
(
`name` varchar(64) not null,
`type` integer not null,
`description` text,
`rule_name` varchar(64),
`data` text,
`created_at` integer,
`updated_at` integer,
primary key (`name`),
foreign key (`rule_name`) references `auth_rule` (`name`) on delete set null on update cascade,
key `type` (`type`)
) engine InnoDB;
create table `auth_item_child`
(
`parent` varchar(64) not null,
`child` varchar(64) not null,
primary key (`parent`, `child`),
foreign key (`parent`) references `auth_item` (`name`) on delete cascade on update cascade,
foreign key (`child`) references `auth_item` (`name`) on delete cascade on update cascade
) engine InnoDB;
create table `auth_assignment`
(
`item_name` varchar(64) not null,
`user_id` varchar(64) not null,
`created_at` integer,
primary key (`item_name`, `user_id`),
foreign key (`item_name`) references `auth_item` (`name`) on delete cascade on update cascade
) engine InnoDB;
Step2: Setting up the config file
Now you can set up the config file to use the authmanager as DbManager. This is done by adding the following lines to the components section of your config file
'authManager' => [
'class' => 'yii\rbac\DbManager',
'defaultRoles' => ['guest'],
],
Step3: Adding and assigning roles.
Now you can add roles by simply writing the following code to your corresponding controller.
use yii\rbac\DbManager;
$r=new DbManager;
$r->init();
$test = $r->createRole('test');
$r->add($test);
And you can assign it to the users by
$r->assign($test, 2);
http://www.yiiframework.com/doc-2.0/guide-security-authorization.html
Same answer has been provided here: Yii2 role management with rbac and database storage
I faced the same problem, the reason is because getRole() method returns null as you can see in your app.log file yii\rbac\DbManager->assign(NULL, 1222049)
SOLUTION
Use $auth->getPermission('admin') instead of $auth->getRole('admin')
Hi I have these two tables that I want to join using relations in Yii, The problem is Im having a hard time figuring out how Yii relation works.
picturepost
id
title
link_stat_id
linkstat
id
link
post_count
I also have a working SQL query. This is the query I want my relation to result when I search when I want to get picturepost
SELECT picturepost.id, picturepost.title,linkstat.post_count
FROM picturepost
RIGHT JOIN linkstat
ON picturepost.link_stat_id=linkstat.link;
I want something like this when I search for a post.
$post = PicturePost::model() -> findByPk($id);
echo $post->linkCount;
Here's my table for extra info:
CREATE TABLE IF NOT EXISTS `picturepost` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`title` text COLLATE utf8_unicode_ci DEFAULT NULL,
`link_stat_id` char(64) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=MyISAM;
CREATE TABLE IF NOT EXISTS `linkstat` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`link` char(64) COLLATE utf8_unicode_ci NOT NULL,
`post_count` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `post_count` (`post_count`),
KEY `link_stat_id` (`link`)
) ENGINE=InnoDB;
Thanks in advance I hope I explained it clearly.
There are a few tutorial regarding this, and I won't repeat them, but urge you to check them out.
The easiest starting point will be to create your foreign key constraints in the database, then use the Gii tool to generate the code for the model, in this case for the table picturepost.
This should result in a class Picturepost with a method relations(),
class Picturepost extends {
public function relations()
{
return array(
'picturepost_linkstats' => array(self::HAS_MANY,
'linkstat', 'link_stat_id'),
);
}
This links the 2 tables using the *link_stat_id* field as the foreign key (to the primary key of the linked table).
When you are querying the table picturepost, you can automatically pull in the linkstat records.
// Get the picturepost entry
$picturepost = PicturePost::model()->findByPk(1);
// picturepost_linkstats is the relationship name
$linkstats_records = $picturepost->picturepost_linkstats;
public function relations()
{
return array(
'linkstat' => array(self::HAS_ONE, 'Linkstat', array('link_stat_id'=>'link')),
);
}
More on yii relations.
This assumes that you have an active record model Linkstat that represents data in table linkstat.
I have a view created using Bake that has the following:
<fieldset>
<legend><?php echo __('Edit Device'); ?></legend>
<?php
echo $this->Form->input('DeviceID');
echo $this->Form->input('DeviceTypeID');
echo $this->Form->input('UserID');
echo $this->Form->input('Type');
echo $this->Form->input('KeyPadID');
echo $this->Form->input('Version');
echo $this->Form->input('Description');
echo $this->Form->input('UpdateID');
?>
</fieldset>
Which saves to the table:
CREATE TABLE `device` (
`DeviceID` VARCHAR(255) NOT NULL ,
`DeviceTypeID` INT(11) NOT NULL ,
`UserID` INT(10) NOT NULL ,
`Type` VARCHAR(10) NULL DEFAULT NULL ,
`KeyPadID` INT(10) NULL DEFAULT NULL ,
`Version` VARCHAR(255) NULL DEFAULT NULL ,
`Description` TINYBLOB NULL ,
`UpdateID` INT(11) NULL DEFAULT NULL ,
PRIMARY KEY (`DeviceID`),
INDEX `FK_USER` (`UserID`),
INDEX `FK_devices_updates` (`UpdateID`),
INDEX `FK_device_devicetype` (`DeviceTypeID`),
CONSTRAINT `FK_device_devicetype` FOREIGN KEY (`DeviceTypeID`) REFERENCES `devicetype` (`DeviceTypeID`),
CONSTRAINT `FK_devices_updates` FOREIGN KEY (`UpdateID`) REFERENCES `update` (`ID`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `FK_USER` FOREIGN KEY (`UserID`) REFERENCES `user` (`UserID`) ON UPDATE CASCADE ON DELETE CASCADE
)
My problem is that when the form is displayed, it shows DeviceTypeID and UserID as well as UpdateID as the foreign key value instead of a drop down with the caption being the text and the value being the ID column. How would I go about setting a field from the foreign table to be the display field and the id as being the value?
Update 11-02-2013
First of all I strongly suggest to convert your primary and foreign keys accordingly
so that they meet the CakePHP naming conventions.
This means that:
DeviceID should be id.
DeviceTypeID should be device_type_id
UserID should be user_id
Also all primary keys in your tables should be named as id.
This way you will never have to worry about anything, concerning your models etc.
After that, all your tables must be in plural form. This means that device table should be devices, so you should rename it also.
I assume that you also have the following tables: devices_types and users.
At this point, I should notice that I would prefer to have a table named devicetype. I avoid underscored names, because it's very easy to make mistakes using the correct form for each object, class etc. So I don't have to worry whether I should use the CamelCase or not.
Anyway
Your Device model should be something like that:
<?php
/** Device.php **/
class Device extends AppModel {
public $name = 'Device';
public $belongsTo = array(
'DeviceType' => array(
'className' => 'DeviceType',
'foreignKey' => 'device_type_id'
/** Specify other keys that meet your needs **/
),
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id'
)
);
};
?>
Also your DeviceType model should be similar to
<?php
/** DeviceType.php **/
class DeviceType extends AppModel {
public $name = 'DeviceType';
};
In your edit() method, you should query your DeviceType in something like this:
...
$devicetypes = $this->Device->DeviceType->find('list', array('id', 'caption'));
$this->set(compact('devicetypes'));
...
This way in your view the respective form element sets the <select> menu correctly.
PS: You should follow the CakePHP conventions about model-naming etc... Mine was just an example.
Adding new record it gives an error:
1452 Cannot add or update a child row: a foreign key constraint fails
public function relations()
{
return array(
'data' => array(self::HAS_ONE, 'Data', 'id'),
);
}
Here is my code for adding a new record:
public function actionAdd_Record()
{
$users = new Users();
$data = new Data();
if (isset($_POST['Users']) && isset($_POST['Data'])) {
if(!empty($_POST['Users_password'])) $_POST['Users']['password']=md5($_POST['Users_password']);
$users->created_date=date('Y-m-d H:i:s');
CActiveForm::validate(array($users, $data));
$users->attributes = $_POST['Users'];
$data->attributes = $_POST['Data'];
$valid=$users->validate();
$valid=$data->validate() && $valid;
if($valid){
$users->save();
$data->save();
$this->redirect(
array('view_record',
'id'=> $users->id)
);
}
}
$this->render(
'add_record', array(
'users'=> $users,
'data'=>$data
)
);
}
Here is the first table:
CREATE TABLE IF NOT EXISTS `data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`investment_amount` float DEFAULT '0' COMMENT '投資額',
`withdrawals` float DEFAULT '0' COMMENT '引出額',
`investment_yield` float DEFAULT '0' COMMENT '運用利回り',
`account_balance` float DEFAULT '0' COMMENT '口座残高',
`status_account` enum('open','closed') DEFAULT 'open',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;
and the second table:
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(128) NOT NULL,
`password` varchar(128) NOT NULL,
`name` varchar(300) NOT NULL COMMENT '氏名',
`email` varchar(200) NOT NULL,
`user_type` enum('normal','admin') NOT NULL DEFAULT 'normal',
`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;
and it gives this error:
CDbCommand failed to execute the SQL statement: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (money_investment.data, CONSTRAINT FK_data_users FOREIGN KEY (id) REFERENCES users (id)). The SQL statement executed was: INSERT INTO data (investment_amount, withdrawals, investment_yield, account_balance, status_account) VALUES (:yp0, :yp1, :yp2, :yp3, :yp4)
This isn't a yii or PHP issue, but a database issue.
You're trying to insert a record that violates the relationships you've defined regarding primary keys. Things to check would be the relationships, as well as the field lengths.
It looks like you may still have a relationship defined on a column that doesn't exist (money_investment?)
Thank you for help, I fixed my problem.
I added $data->id=$users->id; because second table had no idea about the id. See here.
if($valid){
$users->save();
$data->id=$users->id;
$data->save();
$this->redirect(
array('view_record',
'id'=> $users->id)
);
}
foreign key constraints do not allow you to enter data in child before parents..
sometimes sql engines innoDb and MyIsam ..
read out its functionality u will come to know what sql engine would be preferred to use under foreign key constraint's coming issues....
you surly update your tables.
Best way is to See in Model
public function relations()
and compare these relations with your tables.
Any additional or wrong relation might create such problem.
I'm new to zend framework, i'm trying to understand how table relationships work. I have two tables and i'm trying to link them and get their data in a list.
CREATE TABLE `relationship` (
`relationship_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`relationship_name` varchar(45) NOT NULL,
`relationship_group_id` int(10) unsigned NOT NULL,
`display` int(10) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`relationship_id`),
KEY `FK_relationship_1` (`relationship_group_id`),
CONSTRAINT `FK_relationship_1` FOREIGN KEY (`relationship_group_id`) REFERENCES `relationship_group` (`relationship_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `relationship_group` (
`relationship_group_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`relationship_group_name` varchar(45) NOT NULL,
`display` int(10) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`relationship_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
In my relationship table class, I have:
class Relationship_Table extends Zend_Db_Table_Abstract
{
protected $_rowClass = 'Relationship';
protected $_name = 'relationship';
In my relationship group table class I have:
class Relationship_Group_Table extends Zend_Db_Table_Abstract
{
protected $_name = 'relationship_group';
protected $_rowClass = ' Relationship_Group';
I am not sure what my $_referenceMap and $_dependentTables should say, and if I need to state them in both classes or just one?
Also how do I get a list from my relationships table with the corresponding relationship_group data included.
Any help is appreciated.
Here is a pretty good primer on table relationships.
Mat McCormisck on Table relationships in Zend Framework
The actual answer to your question is:
It depends on what you need to accomplish and how do you want to accomplish it.
$_dependentTables aren't required in your case (using InnonDB).
Zend References
Note: Skip declaration of $_dependentTables if you use referential integrity constraints in the RDBMS server to implement cascading operations
Your $_referenceMap should link FOREIGN KEY in a dependent table to the PRIMARY KEY in the parent table and it's only required in the dependent table.
The rest is as RockyFord suggested in his link :).