Can't insert new row in cakephp 3.0 - cakephp-3.0

I am not able to insert a new row in table and getting the error
2016-04-12 09:23:54 Error: [RuntimeException] Cannot insert row in
"table_name" table, it has no primary key. Request URL:
I am using ORM and my code given below
$entityTable = TableRegistry::get('TableName');
$entity = $entityTable->newEntity();
$entity->name = 'Test Name';
$entity->image = 'test.png';
$entity->type = 1;
if($entityTable->save($entity)) {
$this->Flash->success('Added successfully.');
} else {
$this->Flash->error('Error!.');
}
And my table is
CREATE TABLE `table_name` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`image` text COLLATE utf8_unicode_ci NOT NULL,
`type` int(1) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;

add $this->primaryKey('id');
in src>>Model>>Table>>TableNamesTable...
in your initialize method

Related

Duplicate key entry when updating object

I have a Product object that has multiple Shop objects because a shop can offer the same product at different prices / conditions.
I have an edit view for the products that lists the shops where the product is available.
When I make adjustments to the shops of the product eg. price; I get the error that the shop already exists in the database. I know the product exists, but I need the data to be updated.
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1-1' for key 'PRIMARY'
public function update(Request $request, $slug)
{
$product = Product::with('shops', 'type')->where('slug', $slug)->first();
[... snip ...]
$i = 0;
foreach($product->shops as $shop) {
$shop = request('shop');
$product->shops()->attach($product->id, [
'shop_id' => $shop[$i]['id'],
'price' => $shop[$i]['price'],
'url' => $shop[$i]['url']
]);
$i++;
}
$product->save();
return redirect('/'.$slug)->with('success', 'Product has been updated');
}
$product->update(); yields the same result.
EDIT:
Product.php
class Product extends Model
{
protected $appends = ['lowest_price'];
public function shops(){
return $this->belongsToMany('App\Shop')->withPivot('price','url');
}
public function type(){
return $this->belongsTo('App\Type');
}
public function getLowestPriceAttribute()
{
$lowest_price = NULL;
foreach($this->shops as $shop) {
if(is_null($lowest_price)) {
$lowest_price = (double)$shop->pivot->price;
}
if($lowest_price > (double)$shop->pivot->price) {
$lowest_price = (double)$shop->pivot->price;
}
}
return $lowest_price;
}
}
Shop.php
class Shop extends Model
{
//
}
Shop migration
public function up()
{
Schema::create('shops', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('url');
$table->string('logo');
$table->timestamps();
});
[... snip ...]
}
EDIT2:
More info about the error:
Illuminate \ Database \ QueryException (23000)
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1-1' for key 'PRIMARY' (SQL: insert into `product_shop` (`price`, `product_id`, `shop_id`, `url`) values (500.00, 1, 1, http://test.com))
'CREATE TABLE `products` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`make` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`model` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`description` text COLLATE utf8_unicode_ci NOT NULL,
`image` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`video` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`manufacturer_specs` text COLLATE utf8_unicode_ci NOT NULL,
`top_speed` decimal(8,1) NOT NULL,
`range` decimal(8,1) NOT NULL,
`weight` decimal(8,1) NOT NULL,
`type_id` int(10) unsigned NOT NULL,
`slug` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`lowest_price` decimal(8,1) NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `products_slug_unique` (`slug`),
KEY `products_type_id_index` (`type_id`),
CONSTRAINT `products_type_id_foreign` FOREIGN KEY (`type_id`) REFERENCES `types` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'
'CREATE TABLE `product_shop` (
`product_id` int(10) unsigned NOT NULL,
`shop_id` int(10) unsigned NOT NULL,
`price` decimal(8,2) NOT NULL,
`url` text COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`product_id`,`shop_id`),
KEY `product_shop_product_id_index` (`product_id`),
KEY `product_shop_shop_id_index` (`shop_id`),
CONSTRAINT `product_shop_product_id_foreign` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE,
CONSTRAINT `product_shop_shop_id_foreign` FOREIGN KEY (`shop_id`) REFERENCES `shops` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'
'CREATE TABLE `shops` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`url` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`logo` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'
Edit3:
If I click the update button, I get the error even if I didn't change anything
You are trying to add another product-to-shop relation with the same keys, that's why you are seeing the index violation.
Instead of using attach, you can use sync:
$product->shops()->sync(
[
$shop[$i]['id'] => [
'price' => $shop[$i]['price'],
'url' => $shop[$i]['url']
]
], false);
The important part is the second parameter, which disabled detaching the other related items.
You could also use syncWithoutDetaching.
For details see:
Docs
Api

Field 'foreign key' doesn't have a default value

I developed my backend using nodeJS and MySQL, which I have three tables as below :
Fournisseurs:
CREATE TABLE fournisseurs (
Codef bigint(21) NOT NULL ,
Noment varchar(20) COLLATE utf8_unicode_ci NOT NULL,
Prenomf varchar(20) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (Codef, Prenomf)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Categorie :
CREATE TABLE categorie (
Idcat bigint(21) NOT NULL AUTO_INCREMENT,
Nomcat varchar(20) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (Idcat, Nomcat)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Produits :
CREATE TABLE produits (
Codep bigint(21) NOT NULL AUTO_INCREMENT,
Reference bigint(21) NOT NULL,
Nomp varchar(20) COLLATE utf8_unicode_ci NOT NULL ,
Codef bigint(21) NOT NULL ,
Prenomf varchar(20) COLLATE utf8_unicode_ci NOT NULL,
Idcat bigint(21) NOT NULL ,
Nomcat varchar(20) COLLATE utf8_unicode_ci NOT NULL,
Description varchar(100) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (Codep ),
FOREIGN KEY (Codef, Prenomf) REFERENCES fournisseurs (Codef, Prenomf)
ON DELETE CASCADE
ON UPDATE CASCADE ,
FOREIGN KEY (Idcat, Nomcat) REFERENCES categorie (Idcat, Nomcat)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=10;
I try to insert into Produits table as you see below :
exports.ajouterprod = function(req, res) {
console.log("req", req.body);
var today = new Date();
var produits = {
"Reference": req.body.Reference,
"Nomp": req.body.Nomp,
// "Codef": req.body.Codef,
"Prenomf": req.body.Prenomf,
//"Idcat": req.body.Idcat,
"Nomcat": req.body.Nomcat,
"Description": req.body.Description
}
connection.query('INSERT INTO produits SET ?', produits, function(error, results, fields) {
if (error) {
console.log("error ocurred", error);
res.send({
"code": 400,
"failed": "error ocurred"
})
}
else {
res.send({
"code": 200,
"success": "produit registered sucessfully"
});
}
})
};
when I run it with Postman, I get : "failed": "error ocurred"
and error ocurred { Error: ER_NO_DEFAULT_FOR_FIELD: Field 'Codef' doesn't have a default value on my backend.
As you see Codef is a primary key on my table fournisseurs.
How can I fix that ?
Why this error:
Since you are inserting data to Produits and not specifying any value Codef, this error is generated as foreign key needs a value(can be null as well)
Solution 1:
Alter table structure of Produits to have some default value that is either present in another table(where foreign key is referenced) or a null value.
Solution 2:
Add some default at code level and same in table where foreign key is referenced.

ci hmvc query returns empty result set in model

I recently tried to implement wiredesignz hmvc modular extension for Code igniter 2.2.1 found at https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc/
I followed the instructions in the overview given to install the extension.
My database dump is below:
CREATE TABLE IF NOT EXISTS `admin` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(250) NOT NULL,
`passwd` varchar(50) NOT NULL,
`type` enum('super','sub') NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
--
-- Dumping data for table `admin`
--
INSERT INTO `admin` (`id`, `email`, `passwd`, `type`) VALUES
(1, 'deb.pratyush#gmail.com', 'd84c095fc9614ddd8d6cad216956ba11', 'super');
-- --------------------------------------------------------
--
-- Table structure for table `cms`
--
CREATE TABLE IF NOT EXISTS `cms` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(250) NOT NULL,
`nav` varchar(20) NOT NULL,
`slug` varchar(300) NOT NULL,
`description` varchar(200) NOT NULL,
`keywords` varchar(160) NOT NULL,
`content` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'user id',
`fname` varchar(50) NOT NULL,
`lname` varchar(50) NOT NULL,
`email` varchar(250) NOT NULL,
`addr1` varchar(250) NOT NULL,
`addr2` varchar(250) NOT NULL,
`regdate` date NOT NULL,
`country` varchar(250) NOT NULL,
`pwd` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
I am using a model for authentication in the admin module
application/modules/admin/models/admin_model.php having
class name Admin_model. code for it is
class Admin_model extends CI_Model{
function __construct()
{
parent::__construct();
$this->load->database();
}
function auth_admin($email, $passwd)
{
echo $email.' '.$passwd;
$sql ="SELECT `id`, `email`, `type` FROM admin WHERE email='$email' AND passwd = MD5('$passwd')";
$res=$this->db->query($sql);
echo " res=<pre>".print_r($res, 1)."</pre>";
}
}
Admin controller is at application/modules/admin/controllers/admin.php having class name Admin. code is below:
class Admin extends MX_Controller{
public function __construct()
{
parent::__construct();
$this->load->model('cms/cms_model');
$this->load->model('admin_model');
$this->load->library('session');
}
public function index()
{
$this->load->view('admin_header');
$this->load->view('admin_login');
$this->load->view('admin_footer');
if(!empty($this->input->post('admin_login')))
{
$email = $this->input->post('log');
$passwd = $this->input->post('pwd');
$auth_res = $this->admin_model->auth_admin($email, $passwd);
//print_r($auth_res);
if(!empty($auth_res))
{
}
}
}
}
Note that database library is autoloaded in application/config/autoload.php. Same for the url helper.
The output i am getting is below:
deb.pratyush#gmail.com pratyush res=
CI_DB_mysql_result Object
(
[conn_id] => Resource id #38
[result_id] => Resource id #47
[result_array] => Array
(
)
[result_object] => Array
(
)
[custom_result_object] => Array
(
)
[current_row] => 0
[num_rows] => 1
[row_data] =>
)
So, the debugging gives an empty result set despite the fact that user input sent through the login form is deb.pratyush#gmail.com as the email and pratyush as password (password is MD5 hashed in users table).
I have even tried hardcoding the values 'deb.pratyush#gmail.com' and 'pratyush' as email and password columns respectively but no luck.
I have been stuck for a lot of time with this. Can anyone please help?
If you are using codeignator the use codeignator standered of query
Read Manual CI QUERY
$this->db->where('email', $email);
$this->db->where('passwd', md5($passwd));
$query = $this->db->get('admin');
if (!$this->db->_error_message()) {
if ($query->num_rows() > 1) {
foreach ($query->result() as $row) {
print_r($row);
}
} else {
echo "error";
}
}
In your auth_admin function in the model, I believe you should return the query result to have it accessed in your controller. Right now your $auth_res variable in your controller is empty as there is nothing returned from the function in model.

MySql - can BEFORE INSERT TRIGGER insert into 2 columns?

Can this trigger be changed so that the sortorder table gets 2 column values (sortOrderId, sortOrder) inserted?
How is the value of sortOrder found?
If it is known and can be inserted into image table then can it also be inserted into the sortorder table?
-- Trigger DDL Statements
DELIMITER $$
USE `nextcart`$$
CREATE
DEFINER=`root`#`localhost`
TRIGGER `nextcart`.`insert_sortorderid`
BEFORE INSERT ON `nextcart`.`image`
FOR EACH ROW
BEGIN
INSERT INTO sortorder SET sortOrderId = NULL, sortOrder = NEW.sortOrder;
SET NEW.sortOrderId = (SELECT LAST_INSERT_ID());
END;
$$
CREATE TABLE sortorder:
delimiter $$
CREATE TABLE `sortorder` (
`sortOrderId` int(11) NOT NULL AUTO_INCREMENT,
`sortOrder` tinyint(4) NOT NULL,
PRIMARY KEY (`sortOrderId`),
KEY `sort_order` (`sortOrderId`,`sortOrder`),
CONSTRAINT `fk_sortOrderId` FOREIGN KEY (`sortOrderId`) REFERENCES `image` (`imageId`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8$$
CREATE TABLE image:
delimiter $$
CREATE TABLE `image` (
`imageId` int(11) NOT NULL AUTO_INCREMENT,
`imageFileName` varchar(45) DEFAULT NULL,
`imagePath` varchar(255) DEFAULT NULL,
`imageTitle` varchar(100) DEFAULT NULL,
`imageAlt` varchar(100) DEFAULT NULL,
`imageWidth` int(11) DEFAULT NULL,
`imageHeight` int(11) DEFAULT NULL,
`classId` int(11) DEFAULT NULL,
`imageSizeId` tinyint(4) NOT NULL,
`isImageEnabled` bit(1) DEFAULT b'0',
`sortOrderId` int(11) DEFAULT NULL,
PRIMARY KEY (`imageId`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8$$
ERROR MESSAGE:
Error 1054: Unknown column 'sortOrder' in 'NEW' SQL Statement:
CREATE TRIGGER insert_sortorderid BEFORE INSERT ON image FOR EACH
ROW BEGIN INSERT INTO nextcart.sortorder SET sortOrderId = NULL,
sortOrder = NEW.sortOrder; SET NEW.sortOrderId = ( SELECT
LAST_INSERT_ID()); END; Error when running failback script. Details
follow. Error 1050: Table 'image' already exists SQL Statement: CREATE
TABLE image ( imageId int(11) NOT NULL AUTO_INCREMENT,
imageFileName varchar(45) DEFAULT NULL, imagePath varchar(255)
DEFAULT NULL, imageTitle varchar(100) DEFAULT NULL, imageAlt
varchar(100) DEFAULT NULL, imageWidth int(11) DEFAULT NULL,
imageHeight int(11) DEFAULT NULL, classId int(11) DEFAULT NULL,
imageSizeId tinyint(4) NOT NULL, isImageEnabled bit(1) DEFAULT
b'0', sortOrderId int(11) DEFAULT NULL, PRIMARY KEY (imageId)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8
There is no column named sortOrder in the image table.
So, the reference to NEW.sortOrder (on the insert statement in the trigger) is invalid.
To answer your first question: No. Since there is no value supplied for that in the INSERT statement (which fires the BEFORE INSERT TRIGGER), you don't really have a source for that value.
The easy option is to provide a default value for it.
If you want to supply a value for the sortOrder column, then one option is to add a sortOrder column to the image table, and then the value can be supplied in the INSERT INTO image statement. Then it would available in the trigger.
(The purpose of the sortorder table is not at all clear.)

how to create few tables in a single query. MySQL

I need to create 5-10 tables in mysql using php, but i think there is better way than the create 10 queries, so my question is, how to do this with a single query? is it psosible? Every table is different.
$sql = "CREATE TABLE IF NOT EXISTS `db_countries` (
`countrykey` int(11) NOT NULL,
`countrynamelat` varchar(500) NOT NULL default '',
PRIMARY KEY (`countrykey`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8";
mysql_query($sql);
$sql2 = "CREATE TABLE IF NOT EXISTS `db_city`(
`city_key` int(11) NOT NULL,
`city_name` varchar(500) NOT NULL,
`city_code` int(11) NOT NULL,
`city_country_key` int(11) NOT NULL,
PRIMARY KEY(`city_key`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8";
mysql_query($sql2) or die(mysql_error());
You can create a Stored Procedure that creates all your tables:
DELIMITER $$
CREATE PROCEDURE `localhost`.`sp_CreateTables` ()
BEGIN
CREATE TABLE IF NOT EXISTS `db_countries` (
`countrykey` int(11) NOT NULL,
`countrynamelat` varchar(500) NOT NULL default '',
PRIMARY KEY (`countrykey`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `db_city`(
`city_key` int(11) NOT NULL,
`city_name` varchar(500) NOT NULL,
`city_code` int(11) NOT NULL,
`city_country_key` int(11) NOT NULL,
PRIMARY KEY(`city_key`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
END
Then just call the stored procedure from PHP:
$sql = "call sp_CreateTables()";
mysql_query($sql) or die(mysql_error());