Laravel inserting by relationship to composite key table - php

I have these tables currently:
User table
id (primary key), name, email
User Model
protected $fillable = ['name', 'email'];
protected $visible = ['id','name','email'];
//Relationship
public function customAttributes()
{
return $this->hasMany('App\Models\UserAttribute');
}
UserAttribute Table
user_id, attribute_id, value //user_id and attribute_id is a composite key, both foreignkeys acting as primary keys establishing an unique combination
UserAttribute Model
protected $fillable = ['user_id', 'attribute_id','value'];
protected $visible = ['user_id', 'attribute_id','value'];
I'll use the following example to explain the issue:
$user = $this->user->create(['name' => 'admin', 'email' => 'admin#admin.com']);
//This works
$user->customAttributes()->save(new \App\Models\UserAttribute(['user_id' => $user->id, 'attribute_id' => 1, 'value' => 'Just a custom1']));
//This does not work
$user->customAttributes()->create([new \App\Models\UserAttribute(['user_id' => $user->id, 'attribute_id' => 1, 'value' => 'Just a custom1'])]);
I could just repeat the save for every custom that I want since it works, but I'm trying to figure out why create doesn't work.
The error I'm getting when I use create is (and yes, I've checked the record exists in the table that isn't listed here):
Cannot add or update a child row: a foreign key constraint fails (`testdatabase`.`user_attributes`,
CONSTRAINT `user_attributes_attribute_id_foreign` FOREIGN KEY (`attribute_id`) REFERENCES `attributes` (`id`))
This is the query it's trying to execute:
insert into `user_attributes` (`user_id`) values (1)
I'm just curious at why this doesn't work with create, I'm not sure if it's something related to this specific scenario (create to a composite key table by relationship). It's somewhat ignoring the value and attribute_id field in the query that is executing

try this:
$user->customAttributes()->create(['user_id' => $user->id, 'attribute_id' => 1, 'value' => 'Just a custom1']);

customAttributes() already returns you instance of UserAttribute model, you don't need to enject that dependency when you use create() method via that relation
your query should be like below;
$user->customAttributes()->insert([
[
'user_id' => $user->id,
'attribute_id' => 1,
'value' => 'Just a custom1'
],
[
'user_id' => $user->id,
'attribute_id' => 2,
'value' => 'Just a custom2'
],
]);

Related

CakePHP buildRules not firing on hasMany nested assocation delete

I am having issue with build rules not firing deleting 1 element from a HasMany association on a model in CakePHP 3. My base table (Settings) is structured with the following association:
<?php
// SettingsTable.php
public function initialize(array $config)
{
parent::initialize($config);
$this->hasMany('Mappings', [
'foreignKey' => 'mappings_id',
'saveStrategy' => 'replace'
]);
}
The associated mappings table has custom rule in it's model that checks for the existence of children in the values table, prior to letting a mapping be deleted:
<?php
// MappingsTable.php
public function initialize(array $config)
{
parent::initialize($config);
$this->hasMany('Values', [
'foreignKey' => 'values_id',
'saveStrategy' => 'replace'
]);
}
public function buildRules(RulesChecker $rules): RulesChecker
{
$rules->addDelete(/* Has children rule, prevents deletion if children are found in Values table */);
}
I am using the following to update the settings table, and delete a nested mapping table entry (id 3):
<?php
$requestData = [
'title' => 'A new updated title',
'mappings' => [
['id' => 1, 'sort_order' => '5'],
['id' => 2, 'sort_order' => '10'],
// mappings id 3 was previously defined, but removed to make patchEntity() / save() delete it
]
];
$settingsTable->patchEntity($settingEntity, $requestData, [
'associated' => ['Mappings', 'Mappings.Values']
]);
$settingsTable->save($settingEntity);
Based on what I read about setting the saveStradegy key to replace for the hasMany association in the cake docs here, it seems like this should work.
The delete on the mapping with id 3 does fire in cake using this code, but for some reason the buildRules() call in the 2nd code spinet never fires. $rules->addDelete() never fires if there are child values on a mapping, and cake is forced to default to show the MySQL foreign key constraint failure message, rather than a cleaner build rule failure:
"SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`db`.`values`, CONSTRAINT `values_fk` FOREIGN KEY (`field_id`) REFERENCES `fields` (`id`))"
What do I need to do to get the buildRules() on MappingsTable to fire when when a mapping is removed from a setting, like I am above?
Any help is appreciated!

laravel 8 Composite primary key with updateOrCreate

I just want to ask why upset method in eloquant ORM we can update records with "Composite" primary keys, and we can not do that with updateOrCreate ? !!! I have a table that users insert and update in most of times and it's not a good idea to have one Primary Key "id" !!
if you are not using the model events you can Mute events for your action to avoid the error.
https://laravel.com/docs/8.x/eloquent#muting-events
ModelName::withoutEvents(function (){
ModelName::updateOrCreate(
[
'id' => 'test',
'second_id' => 0
],
[
'data' => 'some data'
]
);
});

Laravel inserting parent child fails inside transaction

I am trying to perform 2 inserts, in 2 tables table are constrained via a foreign key. These 2 operations MUST be performed inside a transaction to prevent eventual failures. (In reality I need to perform more inserts on more tables so transactions are important; but the 2 tables in this example are enough to replicate the problem)
The database driver is pgsql
SomeRepo.php (Tried it with the the transaction closure variant as well)
DB::beginTransaction();
try {
$parentData = [
'name' => 'Parent name'
];
$parent = new Parent($parentData);
$parent->save();
$childData = [
// Tried it with and without setting "parent_id" here
'parent_id' => $parent->id,
'name' => 'Child name'
];
$child = new Child($childData);
$parent->children()->save($child);
DB::commit();
} catch (Exception $e) {
DB::rollback();
}
Parent.php
protected $fillable = [
'name'
];
public function children()
{
return $this->hasMany(Child::class);
}
Child.php
protected $fillable = [
'name', 'parent_id'
];
Execution fails when trying to insert the child row, with the return parent id.
insert or update on table "child" violates foreign key constraint "child_parent_id_foreign"
EDIT
Child table SQL:
DROP TABLE IF EXISTS "public"."child";
CREATE TABLE "public"."child" (
"id" int4 NOT NULL DEFAULT nextval('child_id_seq'::regclass),
"parent_id" int4 NOT NULL,
"is_read" bool NOT NULL DEFAULT false,
"created_at" timestamp(0) DEFAULT now(),
"updated_at" timestamp(0),
"deleted_at" timestamp(0)
)
;
ALTER TABLE "public"."child" OWNER TO "my_user";
-- ----------------------------
-- Primary Key structure for table child
-- ----------------------------
ALTER TABLE "public"."child" ADD CONSTRAINT "child_pkey" PRIMARY KEY ("id");
-- ----------------------------
-- Foreign Keys structure for table child
-- ----------------------------
ALTER TABLE "public"."child" ADD CONSTRAINT "child_parent_id_fkey" FOREIGN KEY ("parent_id") REFERENCES "public"."parent" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED;
To save data in related table use this
Parent::create(['name'=>'parent name']); //save in parent table
$lastId = Parent::query()->max('id'); //get last inserted row id
$parent = App\Parent::find($lastId);
$child = $parent->children()->create([
'message' => 'A new comment.',
]);
You can also use createMany method
$parent = App\Parent::find($lastId);
$parent->children()->createMany([
[
'message' => 'A new comment.',
],
[
'message' => 'Another new comment.',
],
]);
Try it with this code by using create and createMany on the relation of the Parent model:
// Create the parent object.
$parent = Parent::create([
'name' => 'Parent 1'
]);
// Insert one.
$child = $parent->children()->create([
'name' => 'Child 1',
]);
// Insert many.
$parent->children()->createMany([
[
'name' => 'Child 2',
],
[
'name' => 'Child 3',
],
]);
You can try this one
try {
DB::beginTransaction();
$parent = Parent::create([
'name' => 'Parent name'
]);
$parent->children()->create([
'parent_id' => $parent->id,
'name' => 'Child name'
]);
DB::commit();
} catch (Exception $e) {
DB::rollback();
}
alter the foreign key-- run this sql on the database
alter table child drop constraint child_parent_id;
alter table child add foreign key (parent_id) references parent(id) deferrable initially deferred;
This will allow you to create the child or parent in either order and the constraint will not be validated until the commit. It should not be necessary in this case-- however, It does depend on how your IDs are generated.
children function needs a middle table change it to :
public function children()
{
return $this->belongsToMany(Child::class);
}
and don't do this $parent->children()->save($child);.
or if you want to go that way make child_parent table, with 2 fields child_id and parent_id.

CODEIGNITER how to insert user_ID to mySQL when that user_ID is logged in

this is the error page
Cannot add or update a child row: a foreign key constraint fails (latihan_ci.adventure, CONSTRAINT adventure_ibfk_1 FOREIGN KEY (user_id) REFERENCES users (user_id) ON UPDATE CASCADE)
INSERT INTO adventure (name, category, place, state) VALUES ('semeru', 'gunung', 'asa', 'asd')
and this is my controller
public function addTrip(){
$this->load->model('userModel');
$newTrip = ['name' => $this->input->post('name'),
'category' => $this->input->post('category'),
'place' => $this->input->post('place'),
'state' => $this->input->post('state'),
];
$data['users'] = $this->userModel->getUserId()->result();
$this->db->insert('adventure',$newTrip);
$this->db->insert('adventure',$data);
redirect('userController/profile');
}
and this is my Model
public function getUserId()
{
return $this->db->get('users',['user_id']);
}
so how to add the user_ID to the mySQL when the value is user_ID that is already login..Thanks alot
when you are login at that time user_id store in session after use
controller
$newTrip = ['name' => $this->input->post('name'),
'category' => $this->input->post('category'),
'place' => $this->input->post('place'),
'state' => $this->input->post('state'),
'user_id'=>$this->session->userdata('userdata'),
];

yii migration return 1215 mysql error

After searching and checking my code over & over, now I want to ask.
I have 2 table umessage and ureply, when I want to add foreign key from ureply refrence to umessage I got 1215 mysql error.
Codes in file m140602_080318_create_table_umessage.php which create umessage table:
public function safeUp()
{
/*
* Create table umessage, this is connection way between customer & seller about specific object
* Add foreign key to table user and it's column id with sender column
* Add foreign key to table object and it's column id with objId column
*/
$this->createTable('tbl_umessage', array(
'id' => 'pk',
'time' => 'INT(15) NOT NULL',
'body' => 'TEXT NOT NULL',
'status' => 'TINYINT NOT NULL DEFAULT 0',
'visibleToS' => 'TINYINT NOT NULL DEFAULT 0',
'visibleToR' => 'TINYINT NOT NULL DEFAULT 0',
'sender' => 'INT(11)',
'objId' => 'INT(11) NOT NULL',
), 'ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci');
}
And codes in file m140602_080329_create_table_ureply.php which create ureply table:
public function safeUp()
{
/*
* Create table ureply which store all replies to exact message
* Add foreign key to table umessage and it's column id with msgId column
*/
$this->createTable('tbl_ureply', array(
'id' => 'pk',
'time' => 'INT(15) NOT NULL',
'body' => 'TEXT NOT NULL',
'isSender' => 'TINYINT NOT NULL DEFAULT 0',
'msgId' => 'INT(11) NOT NULL',
), 'ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci');
$this->addForeignKey('fk_ureply_umessage', 'tbl_ureply', 'msgId', 'umessage', 'id', 'CASCADE', 'CASCADE');
}
1215 error is for adding fk_ureply_umessage foreign key and I can't find my goofs.
Any help will be appreciated. thanks in advance.
You have a mistake in addForeignKey method:
$this->addForeignKey('fk_ureply_umessage', 'tbl_ureply', 'msgId', 'umessage', 'id', 'CASCADE', 'CASCADE');
the table that the foreign key references to should be tbl_umessage not umessage:
$this->addForeignKey('fk_ureply_umessage', 'tbl_ureply', 'msgId', 'tbl_umessage', 'id', 'CASCADE', 'CASCADE');
The error is related to foreign key references check the data type is equivalent between the foreign key and its reference

Categories