Laravel record being deleted when calling Factory - php

I have two tables - Roles and Users. Inside of Roles, I have a single record.
{
id: 1, name: Employee, timestamps: blahblah
}
The strange thing is, whenever I call my User factory (which has a foreign key for field role_id) it deletes the record in the Roles table. It also fails the creation of the factory instantiation, saying that the role_id foreign key constraint fails. I have no idea why this is happening.
Here is the code for the user factory. I've hardcoded values until I can figure it out.
$factory->define(App\User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => Hash::make("12341234"),
'remember_token' => str_random(10),
'company_id' => 1,
'role_id' => 1,
];
});
And the error:
Doctrine\DBAL\Driver\PDOException: SQLSTATE[23000]: Integrity
constraint violation: 1452 Cannot add or update a child row: a foreign
key constraint fails (app.users, CONSTRAINT
users_role_id_foreign FOREIGN KEY (role_id) REFERENCES roles
(id))
Any help would be greatly appreciated.

Your foreign key validation seems to be the issue as you error says.
The given context your role_id seems to be the foreign key and you are just passing an arbitrary value which you will never work.
To resolve you will have to create a factory Method that creates a new role and do the following
$factory->define(App\User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => Hash::make("12341234"),
'remember_token' => str_random(10),
'company_id' => 1,
'role_id' => factory(Role::class)->create()->id,
];
});
PS make sure your mass assignment includes role_id

While I wasn't able to figure out the exact weirdness associated with this, I believe it to be related to the database configuration for PHPUnit. I added the following lines to my phpunit.xml which resolved the issue.
It's also worth mentioning that the role entity was being deleted because the test was using RefreshDatabase.
<env name="DB_CONNECTION" value="sqlite" />
<env name="DB_DATABASE" value=":memory:" />

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!

What's a way around SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry | Laravel 5.8

Error:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry
'7e88079cec' for key 'unique_email_id'
I'm importing data from an API and storing it into a database.
It works on the first try but doesn't update it. I know why wouldn't a "replace" work? Laravel docs don't seem to have a replaceOrUpdate. Do I have to resort to old SQL queries?
$members = Newsletter::getMembers('subscribers');
foreach($members['members'] as $member)
{
DB::table('newsletter')->where('email', $member['email_address'])->updateOrInsert([
'email' => $member['email_address'],
'unique_email_id' => $member['unique_email_id'],
'web_id' => $member['web_id'],
'status' => $member['status'],
'created_at' => $member['timestamp_opt'],
'updated_at' => $member['last_changed']
]);
}
You can use updateOrCreate on the Eloquent instance instead, like this:
foreach($members['members'] as $member)
{
Newsletter::updateOrCreate(['email' => $member['email_address']],
[
'unique_email_id' => $member['unique_email_id'],
'web_id' => $member['web_id'],
'status' => $member['status'],
'created_at' => $member['timestamp_opt'],
'updated_at' => $member['last_changed']
]);
}
So the first param (array) is used as a where clause, if found it will update if not it will create a new record.

Laravel inserting by relationship to composite key table

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'
],
]);

How to dynamically disable and enable foreign key check in laravel?

I am trying to move entries from my old tables to the new one with the updated schema. The problem is, I have to move content from 10 tables with old config to 10 tables with the new config.
I am doing this with the help of console command. When I add the new table and execute the command, I get Duplicate entry error for the tables that already have data which is obvious.
When I try to use DB::connection('mysql_old')->table('users')->truncate();, It throws 1701 Cannot truncate a table referenced in a foreign key constraint Errror which is obvious too!
Here is how I am moving entries from old tables to the new one.
$entries = DB::connection('mysql_old')->table('users')->get();
DB::table('users')->truncate();
foreach($entries as $entry){
$user = \App\User::create([
'name' => $entry->name,
'email' => $entry->email,
'status' => $entry->status,
'credits' => $entry->credits,
'role' => $entry->user_role,
'email_subscription' => $entry->email_subscription,
'activation_key' => $entry->activation_key,
'password' => $entry->password,
'remember_token' => $entry->remember_token,
'created_at' => $entry->created_at,
'updated_at' => $entry->updated_at
]);
}
The only solution is to disable foreign key check before truncate and enable it again after truncate (I think). It is a relational database as obvious. So, is there any better way to complete this task?
I thought about giving a try to move entries from old table to the new one in a relational way but it is not possible in this case.
I can execute the command php artisan migrate:refresh every time the command is executed. But here is the problem with that, There are more than 25 tables and It takes about 20-30 seconds to complete migrate:refresh.
I am really confused how to get this done. Is there any proper or standard way?
You can do this:
Schema::disableForeignKeyConstraints();
// Your database operations go here..
Schema::enableForeignKeyConstraints();
Finally, I found the solution to turn off and turn on the foreign key check. Here is how I moved information from old table to new one.
// Disable foreign key checks!
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
// Move users from old table to the new one
$entries = DB::connection('mysql_old')->table('users')->get();
DB::table('users')->truncate();
foreach($entries as $entry){
$user = \App\User::create([
'name' => $entry->name,
'email' => $entry->email,
'status' => $entry->status,
'credits' => $entry->credits,
'role' => $entry->user_role,
'email_subscription' => $entry->email_subscription,
'activation_key' => $entry->activation_key,
'password' => $entry->password,
'remember_token' => $entry->remember_token,
'created_at' => $entry->created_at,
'updated_at' => $entry->updated_at
]);
}
// Enable foreign key checks!
DB::statement('SET FOREIGN_KEY_CHECKS=1;');
It worked!
if you have migration table just make index to attribut like this:
just make ->index
like this
$table->unsignedBigInteger('city_id')->index();
$table->foreign('city_id')->references('id')
->on('cities')->onDelete('cascade');

Laravel Foreign key Referencing table in External database?

I'm new to Laravel and databases in general. I'm writing a web application for student evaluations. I have an existing MySQL database that contains everything I need already; however, I am using Laravel's auth user table and trying to add a foreign key that references a Teacher table in the MySQL database. I keep getting the following error...
php artisan migrate:fresh
In Connection.php line 664:
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint
(SQL: alter table users add constraint users_teacher_id_foreign
foreign key (teacher_id) references p4j.teacher (teacher_id))
In Connection.php line 458: SQLSTATE[HY000]: General error: 1215 Cannot
add foreign key constraint
My code is as follows...
config/database.php
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DP_PORT', '3306'),
'database' => env('DB_DATABASE', 'p4j'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DP_PASSWORD', '**mypassword**'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
],
database/migrations/2014_10_12_000000_create_users_table.php
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('password');
$table->integer('teacher_id')->unsigned();
$table->rememberToken();
$table->timestamps();
});
Schema::table('users', function (Blueprint $table) {
$table->foreign('teacher_id')->references('teacher_id')->on('p4j.teacher');
});
}
app/User.php
protected $fillable = [
'name', 'email', 'password', 'teacher_id'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
You just need to make sure that the data type of the foreign key (p4j.teacher.teacher_id) corresponds to the same data type of the teacher_id column in your users table.
We need to see the structure of the p4j.teacher table.
Couple possible issues and solutions are that your db engine is not INNODB or loading order of migration files is incorrect. For the first solution you need to add $table->engine = 'InnoDB'; inside of Schema::create and if this doesn't fix the issue, i'll need you to post the names of your users and teacher migrations
Possible fix:
Both PRIMARY KEY constraint and UNIQUE constraint uses to enforce Entity integrity (defines a row as a unique entity for a particular table), but primary keys do not allow null values. Specifies the column that uniquely identifies a row in the table. The identified columns must be defined as NOT NULL.
And since laravel increment function also
Auto-incrementing UNSIGNED INTEGER (primary key) equivalent column.
Simply removing ->default(null); and rerunning migrations should potentially fix the problem.

Categories