Laravel Foreign key Referencing table in External database? - php

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.

Related

Column not found: Unknown column using Model reference but work with object reference laravel 6

I am updating my user table with validations in controller. I have created the same validation for two tables in the same controller.
When I use this code:
User::where('id',$data->user_id)->update($this->validateField($data->user_id));
it show
Error: Column not found: 1054 Unknown column 'address_name'
Which is right because user table does not have column "address_name" but its works with this code without any error
$user = User::where("id",$data->user_id)->firstOrFail();
$user->update($this->validateField($data->user_id));
What is different between these two codes, why does its not work (show unknown column Error) and why it worked without column Error?
Here is my validateField method
public function validateField($id)
{
return request()->validate([
'address_name' => 'required|string|max:255',
'mobile' => 'required|numeric|digits_between:10,13',
'land_line' => 'required|numeric|digits_between:10,13',
'min_order' => 'required',
'payment_method' => 'required',
'open_time' => 'required',
'close_time' => 'required',
'address'=>'required|string|max:255',
'city'=>'required|string|max:255',
'country'=>'required|string|max:255',
'is_active' => 'required',
'first_name' => 'required|string|max:255',
'last_name' => 'required|string|max:255',
'email' => 'required|email|max:255|unique:users,email,'.$id.',id,deleted,0',
'password' => 'sometimes|required|min:8',
]);
}
my user table
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('first_name');
$table->string('last_name');
$table->string('email');
$table->string('password');
$table->string('mobile');
$table->tinyInteger('user_role')->unsigned();
$table->tinyInteger('is_active')->unsigned()->default(1);
$table->datetime('last_login')->nullable();
$table->tinyInteger('deleted')->unsigned()->default(0);
$table->dateTime('created_at')->nullable();
$table->dateTime('updated_at')->nullable();
$table->integer('updated_by')->nullable();
$table->rememberToken();
});
Well
User::where('id',$data->user_id)->update($this->validateField($data->user_id));
this will update all the records that correspond to the where with the fields passed as parameter to the update function, it's just a case that the where will have just one match (because you are applying the where clause to the primary key), if there were more than one match, all the records will be update.
Keep in mind that the where function will return a Builder, and so the update function is the update of the class Builder: it means that there will be only one query (update ... set ... where id = /*your id*/).
This instead
User::where("id",$data->user_id)->firstOrFail()->update($this->validateField($data->user_id))
will first get the first Record that match the where clause, so there will be a Query like select .. from .. where id= /*your id*/, than on that Model will be called the update function, so the function invoked here id the Model -> update function, where previously was Builder -> update, and so there will be a second query with the update.
The different behavior is caused by the different implementation of the update function in the two classes. Actually, on my server, both the methods will throw an error if some fields inside the array passed to update aren't table fields, don't know why on your the first one works fine

Laravel record being deleted when calling Factory

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:" />

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 create user statement doesn't store specific columns

I am using Laravel version 5.4 . I have a table called Users and each user has the below columns :
Schema::create('users', function (Blueprint $table) {
$defaultValue = 0;
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->string('facebook_id')->unique();
$table->string('avatar');
$table->integer('newsletter')->default($defaultValue); // <-
$table->bigInteger('category_1')->default($defaultValue); // <-
$table->bigInteger('category_2')->default($defaultValue); // <-
$table->bigInteger('category_3')->default($defaultValue); // <-
$table->timestamp('unlocked_tip_of_category_1_at')->nullable();
$table->timestamp('unlocked_tip_of_category_2_at')->nullable();
$table->timestamp('unlocked_tip_of_category_3_at')->nullable();
$table->rememberToken();
$table->timestamps();
});
The problem is that when i use the function to create a user category_1, category_2 and category_3 don't take the new value which is 1.
After taking auth from facebook i use the below to store user's information :
return User::create([
'name' => $facebookUser->name,
'email' => $facebookUser->email,
'facebook_id' => $facebookUser->id,
'avatar' => $facebookUser->avatar,
'newsletter' => 0,
'category_1' => 1,
'category_2' => 1,
'category_3' => 1,
]);
For example name changes to facebook user's name. Also i tried changing
'name' => $facebookUser->name,
to
'name' => $facebookUser->name . " HEY",
Which successfuly stored the name and + " HEY" at the end. (Just to be sure that this runs).
Categories are bigInteger that means a bigint(20) type. I am thinking something happens with the default values which i've set it to 0.
Any ideas? If you need any more information please let me know.
From what i am trying to accomplish the best way to solve this is to change the $defaultvalue to 1, but i don't understand why this doesn't work.
If you're using the default laravel scaffolding then you need to ensure you're updating the default App\User model based on all columns you need to have as fillable:
class User extends Model {
protected $fillable = [
'name', 'email', 'password','facebook_id','avatar','newsletter',
'category_1', 'category_2', 'category_3'
];
...
}
Same applies if you're creating your own model.

Migrate failing in laravel 4.2.*

I'm trying to write a simple REST API for laravel 4.2. Here is my code:
This is the command to generate two tables:
php artisan migrate:make create_users_table --table=users --create
php artisan migrate:make create_urls_table --table=urls --create
Then I added this code in up section of create_users_table.php:
$table->increments('id');
$table->string('username')->unique();
$table->string('password');
$table->timestamps();
I added this code in up section of create_urls_table.php:
$table->increments('id');
$table->integer('user_id');
$table->string('url');
$table->string('description');
$table->timestamps();
My db configurations are like this:
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'read_it_later',
'username' => '<username>',
'password' => '<password>',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
Then I added this to UserTableSeeder.php in seeds folder in database folder:
<?php
class UserTableSeeder extends Seeder {
public function run()
{
DB::table('users')->delete();
User::create(array(
'username' => 'firstuser',
'password' => Hash::make('first_password')
));
User::create(array(
'username' => 'seconduser',
'password' => Hash::make('second_password')
));
}
}
Then I uncommented $this->call('UserTableSeeder') in DatabaseSeeder.php file.
Then I ran this command:
php artisan migrate
And I got the following error:
**************************************
* Application In Production! *
**************************************
Do you really wish to run this command? y
Migration table created successfully.
[Illuminate\Database\QueryException]
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'read_it_later.users' doesn't exist (SQL: alter table `users` add `id` int unsigned not
null auto_increment primary key, add `username` varchar(255) not null, add `password` varchar(255) not null, add `created_at` timestamp default 0
not null, add `updated_at` timestamp default 0 not null)
[PDOException]
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'read_it_later.users' doesn't exist
migrate [--bench[="..."]] [--database[="..."]] [--force] [--path[="..."]] [--package[="..."]] [--pretend] [--seed]
How can I fix this error?
I just found out that I was using wrong command to generate migration tables.
I used the following commands:
php artisan migrate:make create_users_table --create=users
php artisan migrate:make create_urls_table --create=urls
Then I added my code to those files and tried these commands:
php artisan migrate
php artisan db:seed
And it worked

Categories