Laravel, phpunit fails due to empty foreign key - php

I'm getting this error while running a phpunit test:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'profile_id' cannot be null (SQL: insert into `comments` (`description`, `status`, `profile_id`, `project_id`, `updated_at`, `created_at`) values (Awesome Comment, active, , 21, 2016-01-29 00:05:21, 2016-01-29 00:05:21))
As you can see it is sending an empty id for the profile_id and I'm creating the profile before creating the comment. Here is the code of my test:
public function testProjectCommentCreation()
{
$category = factory(\App\Category::class)->create();
$category->projects()->save(factory(\App\Project::class)->make());
$profile = factory(\App\Profile::class)->make([
'name' => 'John',
'last_name' => 'Snow',
'skills' => 'php'
]);
$category->projects[0]->comments()->save(factory(\App\Comment::class)->make([
'description'=>'Awesome Comment',
'status'=>'active',
'profile_id'=>$profile->id
]));
$this->post(route('api.projects.comments.store', ["projects" => $category->projects[0]->id]), $category->projects[0]->comments->jsonSerialize(), $this->jsonHeaders)
->seeInDatabase('comments', ['project_id' => $category->projects[0]->id])
->assertResponseOk();
}
A Project belongs to a Category and a Comment belongs to a Project and a Profile, so I need to send both foreign keys values profile_id and project_id, the problem is that I'm not sure how to retrieve the id of the profile I created.
These are the factories I use:
$factory->define(App\Profile::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'last_name' => $faker->name,
'status' => 'active',
'avatar' => str_random(10),
'skills'=> str_random(10),
'notifications'=>'on'
];
});
$factory->define(App\Comment::class, function (Faker\Generator $faker) {
return [
'description' => str_random(10),
'status' => 'active',
'profile_id' => 1,
'project_id' => 1
];});
$factory->define(App\Category::class, function (Faker\Generator $faker) {
return [
'description' => str_random(10),
'status' => 'active'
];});
$factory->define(App\Project::class, function (Faker\Generator $faker) {
return [
'description' => str_random(10),
'status' => 'active',
'privacy' => 'false'
];});
I've tested the construction of each type of Object and it is working, what I'm failing is to create a Comment since I need to create a Profile first and retrieve the id and for some reason using $profile->id is pulling null

The problem is that your profile is not saved to the database, when using make().
For you to be able to use/assign the foreign key profile_id from $profile, you need to create() the factory model, and not just make() it.
$profile = factory(\App\Profile::class)->create([
'name' => 'John',
'last_name' => 'Snow',
'skills' => 'php'
]);
That should do the trick.

Related

Laravel: Handle unique on Update

I'm using the validation for the employee records during an update. There are some fields which should be unique. But during an update of the employee records, the validation for the unique field is being done. I have researched and tried out the solution as well.
But I'm getting this error:
Error Code : 904 Error Message : ORA-00904: "ID": invalid identifier
Position : 71 Statement : select count() as aggregate from
"EMPLOYEES" where " EMAIL" = :p0 and "ID" <> :p1 Bindings :
[ad#sdfdsf.com,3336] (SQL: select count() as aggregate from
"EMPLOYEES" where " EMAIL" = ad#sdfdsf.com and "ID" <> 3336)
Here is my attempt for the solution:
public function update(Request $request, int $employee_id) {
$this->validate ( $request, [
'first_name' => "required|max:220|regex:/[a-z]/",
'middle_name' => "max:120",
'last_name' => "required|max:220|regex:/[a-z]/",
'email' => "required|unique:employees, email, $employee_id|regex:/[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}/",
'home_phone' => "unique:employees,home_phone, $employee_id|numeric|regex:/^[09][0-9]{8,9}$/",
'mobile' => "unique:employees,mobile, $employee_id|numeric|regex:/(9)[0-9]{9}/",
'job_id' => 'required',
'department_id' => 'required',
'group_id' => 'required',
'node' => 'required',
'branch' => 'required',
'username' => "required|unique:employees,username, $employee_id|regex:/[A-Za-z0-9][.][A-Za-z0-9]/",
'exchange_username' => "required|unique:employees,exchange_username, $employee_id|regex:/[A-Za-z0-9][.][A-Za-z0-9]/",
'extension' => "unique:employees,extension, $employee_id|numeric|regex:/[0-9]{4}/",
] );
Employee::where ('employee_id', $employee_id )->update ( $request->only ( [
'first_name',
'middle_name',
'last_name',
'email',
'address',
'home_phone',
'mobile',
'job_id',
'department_id',
'group_id',
'branch',
'node',
'name',
'username',
'type',
'exchange_username',
'toggle_ivr_access',
'extension',
'attributed_team',
'cable_team_id',
'disable',
] ) );
Session::flash ( 'message', 'The Employee is Successfully Updated.' );
return redirect ()->route ( 'employees.index' );
}
Forcing A Unique Rule To Ignore A Given ID:
Sometimes, you may wish to ignore a given ID during the unique check.
For example, consider an "update profile" screen that includes the
user's name, e-mail address, and location. Of course, you will want to
verify that the e-mail address is unique. However, if the user only
changes the name field and not the e-mail field, you do not want a
validation error to be thrown because the user is already the owner of
the e-mail address.
To instruct the validator to ignore the user's ID, we'll use the Rule
class to fluently define the rule. In this example, we'll also specify
the validation rules as an array instead of using the | character to
delimit the rules:
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
]);
I figured out the mistake and successfully find out the solution. Here is the working solution in case anyone is facing the similar problem. I had to pass the employee_id of the single user whereas I was passing the employee_id of the multiple users.
public function update(Request $request, int $employee_id) {
$this->validate ( $request, [
'first_name' => "required|max:220|regex:/[a-z]/",
'middle_name' => "max:120",
'last_name' => "required|max:220|regex:/[a-z]/",
'email' => "required|unique:employees,email,".$employee_id.',employee_id|regex:/[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}/',
'home_phone' => "unique:employees,home_phone,$employee_id,employee_id|numeric",
'mobile' => "required|unique:employees,mobile,$employee_id,employee_id|numeric",
'job_id' => 'required',
'department_id' => 'required',
'group_id' => 'required',
'node' => 'required',
'branch' => 'required',
'username' => "required|unique:employees,username,".$employee_id.',employee_id|regex:/[A-Za-z0-9][.][A-Za-z0-9]/',
'exchange_username' => "required|unique:employees,exchange_username,".$employee_id.',employee_id|regex:/[A-Za-z0-9][.][A-Za-z0-9]/',
'extension' => "required|unique:employees,mobile,$employee_id,employee_id|numeric|regex:/[0-9]{4}/",
] );
Employee::where ('employee_id', $employee_id )->update ( $request->only ( [
'first_name',
'middle_name',
'last_name',
'email',
'address',
'home_phone',
'mobile',
'job_id',
'department_id',
'group_id',
'branch',
'node',
'name',
'username',
'type',
'exchange_username',
'toggle_ivr_access',
'extension',
'attributed_team',
'cable_team_id',
'disable',
] ) );
Session::flash ( 'message', 'The Employee is Successfully Updated.' );
return redirect ()->route ( 'employees.index' );
}

Creating relations using Laravel model factories

I am trying to create a user using model factories but I am having an error with the relationships. In the User model, I have created a belongsTo relationship levels for the model JobLevel. In the ModelFactory.php I have the following code.
use App\User;
use App\JobLevel;
$factory->define(JobLevel::class, function (Faker\Generator $faker) {
return [
'name' => $faker->word,
'rank' => $faker->randomDigit,
];
});
$factory->define(User::class, function (Faker\Generator $faker) {
return [
'firstname' => $faker->name,
'middlename' => $faker->name,
'lastname' => $faker->name,
'email' => $faker->email,
'job_level_id' => factory(JobLevel::class)->create()->id,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
Then I am in my test class I use the factory as follows.
/** #test */
public function login_a_user()
{
$user = factory(User::class)->create();
...
}
When I run phpunit I get the following error
Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity
constraint violation: 1452 Cannot add or update a child row: a foreign key
constraint fails (`testing_db`.`user`, CONSTRAINT `fk_user_job_level1`
FOREIGN KEY (`job_level_id`) REFERENCES `job_level` (`id`) ON DELETE NO
ACTION ON UPDATE NO ACTION) (SQL: insert into `user` (`updated_at`,
`created_at`) values (2016-11-08 12:01:14, 2016-11-08 12:01:14))
Could you, for testing purposes try this?
$factory->define(User::class, function (Faker\Generator $faker) {
return [
'firstname' => $faker->name,
'middlename' => $faker->name,
'lastname' => $faker->name,
'email' => $faker->email,
'job_level_id' => 1,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
public function login_a_user()
{
$job = factory(JobLevel::class)->create();
$user = factory(User::class)->create();
...
}
I am not sure you can embed those factories.

How to input user_id in different table (laravel 5.2)

I have 2 tables.
users (id, name, username, email, password, admin, remember_token)
dosen (iddosen, user_id, namadosen, birthdate, address)
How to insert user_id and namadosen same as in table users?
My method :
public function store(CreateDosenRequest $request)
{
$user = User::create([
'name' => $request->input('name'),
'username' => $request->input('username'),
'email' => $request->input('email'),
'password' => bcrypt($request->input['password']),
'admin' => $request->input('admin')
]);
$dosen = Dosen::create([
'iddosen' => $request->input('iddosen'),
'name' => $request->input('namadosen'),
'user_id' => $user->id,
'address' => $request->input('address'),
'birthdate' => $request->input('birthdate'),
]);
return redirect('admin')->with('message', 'Success!');
}
following code doesn't work
'user_id' => $user->id,
Just answering this for consistency sake.
As stated in the comments, the issue was that user_id wasn't specified as a $fillable field inside the Dosen model.
Adding user_id to the $fillable array solved the issue for OP.

Laravel mass assignment not saving fields

I have 2 tables within one function that I'd like to save data to. One is the Users table, and the second one is a Clinic table.
My user's table is currently working correctly, but I'm unsure if it's 'best practice':
$user = User::create([
'name' => Str::title($request->get('name')),
'email' => $request->get('email'),
'password' => bcrypt($request->get('password'))
])
->clinic()->create($request->only([
'name' => Str::title('clinic_name'),
'telephone',
'address_1',
'address_2',
'city',
'postcode'
]));
My problem occurs at the 'name' column of the Clinic table. It just doesn't save it, even though it's in the $fillable array in my Clinic column:
protected $fillable = ['user_id', 'name', 'telephone'', 'address_1',
'address_2', 'city', 'postcode'];
I have attempted to 'Chain' the methods together, as I want to save the 'user_id' within the Clinic table because they're related.
Many thanks for your help.
You're overriding the name key in your $request->only() call:
$user = User::create([
'name' => Str::title($request->get('name')),
'email' => $request->get('email'),
'password' => bcrypt($request->get('password'))
])->clinic()->create($request->only([
'name' => Str::title('clinic_name'), // This is overriding your 'name' field.
'telephone',
'address_1',
'address_2',
'city',
'postcode'
]));
If you want to run Str::title() over the requests clinic_name, you'll need to assign the attributes manually like so:
$user = User::create([
'name' => Str::title($request->get('name')),
'email' => $request->get('email'),
'password' => bcrypt($request->get('password'))
])->clinic()->create([
'name' => Str::title($request->get('clinic_name')),
'telephone' => $request->get('telephone'),
'address_1' => $request->get('address_1'),
'address_2' => $request->get('address_2'),
'city' => $request->get('city'),
'postcode' => $request->get('postcode'),
]);
Note: Just as a tip, you can also just retrieve request input as a property like so:
->create([
'name' => $request->name // Performs $request->get('name').
])
You can't have 'name' => Str::title('clinic_name') when using create(), it must be a single key as 'name'.
You can use the following before creating the user:
$request->replace('name' => Str::title('clinic_name'));

Insert record Many to Many relation in laravel at same time

I have three tables users,roles and role_user I want to insert record on that tables with minimum query using eloquent. My current code of insertation
User::create([
'name' => 'admin',
'email' => 'admin#test.pk',
'password' => bcrypt('admin123'),
]);
//create default roles while installation of application
$roles = array(
array('name' => 'admin', 'display_name' => 'Administrator User', 'description' => 'system admin user'),
array('name' => 'registered', 'display_name' => 'Registered User', 'description' => 'free user')
);
foreach ($roles as $key => $role)
{
Role::create($role);
}
//relation between users and roles
User::find(1)->roles()->attach(1);
In above code i am creating a user then creating two roles then inserting record in pivot table(role_user). I want to know is there any otherway that i insert the record on these table at same time with one eloquent query Or there is anyother better way?
Unfortunately it is not possible to insert rows in more than one table at the same time.
Best what I can think of is that:
$user = User::create([
'name' => 'admin',
'email' => 'admin#test.pk',
'password' => bcrypt('admin123'),
]);
//create default roles while installation of application
$roles = [
['name' => 'admin', 'display_name' => 'Administrator User', 'description' => 'system admin user'],
['name' => 'registered', 'display_name' => 'Registered User', 'description' => 'free user']
];
Role::insert($roles);
//relation between users and roles
$user->roles()->attach(1);
With this example You save two queries:
Laravel calls only one insert query, instead of two when inserting roles;
Laravel does not select User from database - using variable instead;

Categories