ErrorException Array to string conversion in Controller file - php

Hello guys please I'm having this laravel error in my controller and I need help
Here's my controller
public function expectingpost(Request $request)
{
DB::table('expectings') ->insert([
$validatedData = $request->validate([
"time" => 'required|date_format:H:i',
"day" => 'required|date_format:Y-m-d',
"name" => 'required'
]).
"time" => $request->time,
"day" => $request->date,
"name" => $request->name
]);
return back() -> with('expecting', $request->input('name') . ' has been added as your guest');
}
}
PLease guys I seriously need fast responses because this has kept me on deck for long. Thank you

You shouldn't validate your data inside your insert, this should be first validating your data, then use it to create your model. Another improvement use Eloquent models, there is no reason not to if you are just starting out.
public function expectingpost(Request $request)
{
$validatedData = $request->validate([
'time' => 'required|date_format:H:i',
'day' => 'required|date_format:Y-m-d',
'name' => 'required'
]).
Expecting::create($validatedData);
return back()->with('expecting', $validatedData['name'] . ' has been added as your guest');
}
The Eloquent Model you need.
use Illuminate\Database\Eloquent\Model;
class Expecting extends Model {
protected $fillable = ['time', 'day', 'name'];
}

Related

Laravel - adding relationships to a factory-created model

I am testing an eager loading relationship which contains many to many relations. Right now I have the queries and attachments within the test. I'm wondering if there is a way to move them into the factory, rather than including it as part of your test. This would limit the size of the test and then these relations could be created and used every time a film factory is created.
test
public function grabFilmTest()
{
$film = factory(Film::class)->create();
$categories = Category::where('main-cat', 'Science')->where('sub-cat', 'Fiction')->first();
$languages = Languages::where('name', 'english')->first();
$film->categories()->attach($categories->id);
$film->languages()->attach($languages->id);
$response = $this->json('GET', '/film/' . $film->id)
->assertStatus(200);
$response
->assertExactJson([
'id' => $film->id,
'name' => $film->name,
'description' => $film->description,
'categories' => $film->categories->toArray(),
'languages' => $film->languages->toArray()
}
filmFactory
$factory->define(\App\Models\Film::class, function (Faker $faker){
return [
'id' => $faker->uuid,
'name' => $faker->text,
'description' => $faker->paragraph,
];
});
If anyone could help with how i could do this or an example it would be great :D
You could use factory states and factory callbacks.
$factory->define(\App\Models\Film::class, function (Faker $faker){
return [
'id' => $faker->uuid,
'name' => $faker->text,
'description' => $faker->paragraph,
];
});
$factory->define(\App\Models\Category::class, function (Faker $faker){
return [
// Category fields
];
});
$factory->define(\App\Models\Language::class, function (Faker $faker){
return [
// Language fields
];
});
$factory->afterCreatingState(\App\Models\Film::class, 'with-category', function (\App\Models\Film $film) {
$category = factory(\App\Models\Category::class)->create();
$film->categories()->attach($category->id);
});
$factory->afterCreatingState(\App\Models\Film::class, 'with-language', function (\App\Models\Film $film) {
$language = factory(\App\Models\Language::class)->create();
$film->categories()->attach($language->id);
});
Then you can use in tests like this:
public function grabFilmTest()
{
$film = factory(Film::class)->create();
$filmWithCategory = factory(Film::class)->state('with-category')->create();
$filmWithLanguage = factory(Film::class)->state('with-language')->create();
$filmWithCategoryAnLanguage = factory(Film::class)->states(['with-category', 'with-language'])->create();
// ...
}
PS: I don't recommend using existing data. From experience, I can tell you that can become really painful.
You can use factory callbacks to do it in the factory file:
<?php
use \App\Models\Film;
use \App\Models\Category;
use \App\Models\Languages;
$factory->define(Film::class, function(Faker $faker){
return [
'id' => $faker->uuid,
'name' => $faker->text,
'description' => $faker->paragraph,
];
});
$factory->afterCreating(Film::class, function(Film $film, Faker $faker) {
$category = Category::where('main-cat', 'Science')->where('sub-cat', 'Fiction')->first();
$language = Languages::where('name', 'english')->first();
$film->categories()->attach($category);
$film->languages()->attach($language);
});

Laravel - Trying to get property "id" of non-object while using POST Method

Am writing an endpoint with Laravel using using. When I tested on postman using POST Method, I got this error:
ErrorException: Trying to get property 'id' of non-object in file C:\xampp\htdocs\testing-file\testing\app\Http\Controllers\ApiController.php on line 912
Controller
public function storeBilling(Request $request)
{
// $billing = Billing::create($request->all());
// return response()->json(['success' => $billing], $this-> successStatus);
$validator = Validator::make($request->all(), [
'network' => 'required'
]);
if ($validator->fails()) {
return response()->json($validator->errors(), 422);
}
// Creating a record in a different way
$createBilling = Billing::create([
'user_id' => $request->user()->id,
'network' => $request->network,
'sender' => $request->sender,
'recipient' => $request->recipient,
'message' => $request->message,
'amount' => $request->amount,
'billing_type' => $request->billing_type,
]);
return new BillingResource($createBilling);
}
Model
class Billing extends Model
{
protected $table = 'billing';
protected $fillable = [
'network' ,
'sender',
'recipient',
'message',
'timestamp',
'created_at',
'updated_at',
'amount',
'billing_type',
'user_id',
'service_name',
'package',
'email',
'user_id'
];
public function user() {
return $this->belongsTo('App\User');
}
}
Resource
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Billing;
class BillingResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'network' => $this->network,
'sender' => $this->sender,
'recipient' => $this->recipient,
'message' => $this->message,
'amount' => $this->amount,
'billing_type' => $this->billing_type,
'email' => $this->email,
'user' => $this->user,
'service' => $this->service,
'package' => $this->package,
// Casting objects to string, to avoid receive create_at and update_at as object
'timestamp' => (string) $this->timestamp,
'created_at' => (string) $this->created_at,
'updated_at' => (string) $this->updated_at
];
}
}
If I use this POST Method:
http://localhost/testing-file/stesting/api/storeBilling?network=100
It suppose to post into the database, but I got this error:
ErrorException: Trying to get property 'id' of non-object in file C:\xampp\htdocs\testing-file\testing\app\Http\Controllers\ApiController.php on line 912
'user_id' => $request->user()->id
Your error is saying that $request->user() is not an object, so you cannot access its parameters using object notation, e.g. ->id.
If you dd($request->user) you may see that you are not getting what you thought you were getting - it may be an array, or it may not be the right value at all.
If it is an array, you can access the value like $request['user']['id']. It really depends what you are passing in your POST request.
$request->user()->id is incorrect.
If you want the current user you can use Auth::user().
In the beginning of your question you said you are trying to build an endpoint using Lravel ..
Postman will not have access to the user object unless authenticated, if authenticated then this should work ::
$request->user()->id or Auth::user()->id or $request["user"]["id"]
on you
public function storeBilling(Request $request)
You write $createBilling = Billing::create([
'user_id' => $request->user()->id, and this create error.
Or is preferable to have $createBilling = Billing::create([
'user_id' => Auth::user()->id, to find the id of the user authentificate.
don't forget to add use Auth; at the beginning of the controller
Going through a same Hassle it's happening because relationship finding its relation with billing table but it did not find so giving this error please check your database have related entry's and try again and make sure you have right relationship with table.

Saving multiple records in a laravel eloquent create

I'm trying to save multiple records via
AppSettings::create(
[
'name' => 'mail_host',
'type' => $emailsettingstype->id,
'value' => '',
],
[
'name' => 'mail_port',
'type' => $emailsettingstype->id,
'value' => '',
],
[
'name' => 'mail_username',
'type' => $emailsettingstype->id,
'value' => '',
],
);
But from the above, only the first array is getting created. Where am i going wrong? Any help is appreciated.
I think this should do
AppSettings::createMany([
[
'name'=>'mail_host',
'type'=>$emailsettingstype->id,
'value'=>'',
],
[
'name'=>'mail_port',
'type'=>$emailsettingstype->id,
'value'=>'',
],
[
'name'=>'mail_username',
'type'=>$emailsettingstype->id,
'value'=>'',
],
]);
Make sure you're passing an array of arrays, not a params of array.
UPDATE, you can use Model::insert() although according to what I've read, that method doesn't create/update the timestamps.
You can just use Eloquent::insert() link as below:
AppSettings::insert([
[
'name'=>'mail_host',
'type'=>$emailsettingstype->id,
'value'=>'',
],
[
'name'=>'mail_port',
'type'=>$emailsettingstype->id,
'value'=>'',
],
[
'name'=>'mail_username',
'type'=>$emailsettingstype->id,
'value'=>'',
],
]);
The problem with above is that it won't update timestamps, find examples here
The Create many Method createMany is available on relationship check reference to this link and this documentation from laravel
so far my example look like this.
I have two models Pricing and AvailableService Model
Pricing Model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Pricing extends Model
{
protected $fillable = ["name", "price"];
public function available(){
return $this->hasMany(AvailableService::class, "pricing_id", "id");
}
}
And the AvailableServiceMode look like this
namespace App;
use Illuminate\Database\Eloquent\Model;
class AvailableService extends Model
{
protected $fillable = ["pricing_id", "service_id"];
public function service(){
return $this->belongsTo(Service::class, "service_id", "id");
}
}
So createMany operation look like this
$insertMany = Pricing::create(['name'=>request('name')]);
$insertMany->available()->createMany([
['service_id'=>1],
['service_id'=>2],
['service_id'=>3],
['service_id'=>4],
['service_id'=>5],
]);
And it works for, you can give it a try too. THANKS
If you want to store multiple record in seeder use this method instead of insert because in my case I want to slug automatically created using spatie/laravel-sluggable pkg. If you used the insert or DB technique then you have to give the value for slug field also.
CategorySeeder
<?php
namespace Database\Seeders;
use App\Servcategory;
use Illuminate\Database\Seeder;
class CategorySeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
$categories = [
[
'name' => 'Automotive',
// 'slug' => 'automotive',
],
[
'name' => 'Business Services',
// 'slug' => 'business-services',
],
[
'name' => 'Computer, Telecom & IT Services',
// 'slug' => 'computer-telecom-&-it-services',
],
[
'name' => 'Education & Training',
// 'slug' => 'education-&-training',
],
[
'name' => 'Finance',
// 'slug' => 'finance',
],
[
'name' => 'Hospitals, Clinic, Medical',
// 'slug' => 'hospitals-clinic-medical',
],
[
'name' => 'Real Estate, Construction, Property',
// 'slug' => 'real-estate-construction-property',
],
[
'name' => 'Travel,Toursim & Hotels',
// 'slug' => 'travel-toursim-&-hotels',
],
];
// Servcategory::insert($categories);
collect($categories)->each(function ($category) { Servcategory::create($category); });
}
}
In case some one searching for eloquent model, I used the following method:
foreach($arCategories as $v)
{
if($v>0){
$obj = new Self(); // this is to have new instance of own
$obj->page_id = $page_id;
$obj->category_id = $v;
$obj->save();
}
}
$obj = new Self(); is a must otherwise it only saves single record when $this is used.
in seeder create an array and do foreach with Model::create(). All your records will be with timestamps
protected $array = [
[...],
[...],
[...]
];
public function run()
{
foreach ($this->array as $value) {
Model::create($value);
}
}

How do I get ONLY the validated data from a laravel FormRequest?

Lets say I have the following Custom Request:
class PlanRequest extends FormRequest
{
// ...
public function rules()
{
return
[
'name' => 'required|string|min:3|max:191',
'monthly_fee' => 'required|numeric|min:0',
'transaction_fee' => 'required|numeric|min:0',
'processing_fee' => 'required|numeric|min:0|max:100',
'annual_fee' => 'required|numeric|min:0',
'setup_fee' => 'required|numeric|min:0',
'organization_id' => 'exists:organizations,id',
];
}
}
When I access it from the controller, if I do $request->all(), it gives me ALL the data, including extra garbage data that isn't meant to be passed.
public function store(PlanRequest $request)
{
dd($request->all());
// This returns
[
'name' => 'value',
'monthly_fee' => '1.23',
'transaction_fee' => '1.23',
'processing_fee' => '1.23',
'annual_fee' => '1.23',
'setup_fee' => '1.23',
'organization_id' => null,
'foo' => 'bar', // This is not supposed to show up
];
}
How do I get ONLY the validated data without manually doing $request->only('name','monthly_fee', etc...)?
$request->validated() will return only the validated data.
Example:
public function store(Request $request)
{
$request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
$validatedData = $request->validated();
}
Alternate Solution:
$request->validate([rules...]) returns the only validated data if the validation passes.
Example:
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
}
OK... After I spent the time to type this question out, I figured I'd check the laravel "API" documentation: https://laravel.com/api/5.5/Illuminate/Foundation/Http/FormRequest.html
Looks like I can use $request->validated(). Wish they would say this in the Validation documentation. It makes my controller actions look pretty slick:
public function store(PlanRequest $request)
{
return response()->json(['plan' => Plan::create($request->validated())]);
}
This may be an old thread and some people might have used the Validator class instead of using the validator() helper function for request.
To those who fell under the latter category, you can use the validated() function to retrieve the array of validated values from request.
$validator = Validator::make($req->all(), [
// VALIDATION RULES
], [
// VALIDATION MESSAGE
]);
dd($validator->validated());
This returns an array of all the values that passed the validation.
This only starts appearing in the docs since Laravel 5.6 but it might work up to Laravel 5.2

Laravel: Validation unique on update

I know this question has been asked many times before but no one explains how to get the id when you're validating in the model.
'email' => 'unique:users,email_address,10'
My validation rule is in the model so how do I pass the ID of the record to the validation rule.
Here is my models/User
protected $rules_update = [
'email_address' => 'required|email|unique:users,email_address,'.$id,
'first_name' => "required",
'last_name' => "required",
'password' => "required|min:6|same:password_confirm",
'password_confirm' => "required:min:6|same:password",
'password_current' => "required:min:6"
];
models/BaseModel
protected $rules = array();
public $errors;
/*
* #data: array, Data to be validated
* #rules: string, rule name in model
*/
public function validate($data, $rules = "rules") {
$validation = Validator::make($data, $this->$rules);
if($validation->passes()) {
return true;
}
$this->errors = $validation->messages();
return false;
}
Just a side note, most answers to this question talk about email_address while in Laravel's inbuilt auth system, the email field name is just email. Here is an example how you can validate a unique field, i.e. an email on the update:
In a Form Request, you do like this:
public function rules()
{
return [
'email' => 'required|email|unique:users,email,'.$this->user->id,
];
}
Or if you are validating your data in a controller directly:
public function update(Request $request, User $user)
{
$request->validate([
'email' => 'required|email|unique:users,email,'.$user->id,
]);
}
Update:
If you are updating the signed in user and aren't injecting the User model into your route, you may encounter undefined property when accessing id on $this->user. In that case, use:
public function rules()
{
return [
'email' => 'required|email|unique:users,email,'.$this->user()->id,
];
}
A more elegant way since Laravel 5.7 is:
public function rules()
{
return [
'email' => ['required', 'email', \Illuminate\Validation\Rule::unique('users')->ignore($this->user()->id)]
];
}
P.S: I have added some other rules, i.e. required and email, in order to make this example clear for newbies.
One simple solution.
In your Model
protected $rules = [
'email_address' => 'sometimes|required|email|unique:users',
..
];
In your Controller, action:update
...
$rules = User::$rules;
$rules['email_address'] = $rules['email_address'] . ',id,' . $id;
$validationCertificate = Validator::make($input, $rules);
There is an elegant way to do this. If you are using Resource Controllers, your link to edit your record will look like this:
/users/{user}/edit OR /users/1/edit
And in your UserRequest, the rule should be like this :
public function rules()
{
return [
'name' => [
'required',
'unique:users,name,' . $this->user
],
];
}
Or if your link to edit your record look like this:
/users/edit/1
You can try this also:
public function rules()
{
return [
'name' => [
'required',
'unique:users,name,' . $this->id
],
];
}
From Laravel 5.7, this works great
use Illuminate\Validation\Rule;
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($user->id),
],
]);
Forcing A Unique Rule To Ignore A Given ID:
Test below code:
'email' => 'required|email|unique:users,email_address,'. $id .'ID'
Where ID is the primary id of the table
If i understand what you want:
'email' => 'required|email|unique:users,email_address,'. $id .''
In model update method, for exemple, should receive the $id with parameter.
Sorry my bad english.
Here is the solution:
For Update:
public function controllerName(Request $request, $id)
{
$this->validate($request, [
"form_field_name" => 'required|unique:db_table_name,db_table_column_name,'.$id
]);
// the rest code
}
That's it. Happy Coding :)
The Best Option is here try just once no need more code when unique validation on updating data
'email' => 'unique:users,email_address,' . $userId,
hereemailis field name and users is table name and email_address is table attribute name which you want unique and $userid is updating row id
public function rules()
{
switch($this->method())
{
case 'GET':
case 'DELETE':
{
return [];
}
case 'POST':
{
return [
'name' => 'required|unique:permissions|max:255',
'display_name' => 'required',
];
}
case 'PUT':
case 'PATCH':
{
return [
'name' => 'unique:permissions,name,'.$this->get('id').'|max:255',
'display_name' => 'required',
];
}
default:break;
}
}
an even simpler solution tested with version 5.2
in your model
// validator rules
public static $rules = array(
...
'email_address' => 'email|required|unique:users,id'
);
You can try this.
protected $rules_update = [
'email_address' => 'required|email|unique:users,email_address,'. $this->id,
'first_name' => "required",
'last_name' => "required",
'password' => "required|min:6|same:password_confirm",
'password_confirm' => "required:min:6|same:password",
'password_current' => "required:min:6"
];
In Laravel 8.x you can use Rule::unique method as well
Forcing A Unique Rule To Ignore A Given ID:
use Illuminate\Validation\Rule;
public function update(Request $request, Post $post)
{
$validatedData = $request->validate([
'name' => ['required', 'max:60', Rule::unique('posts')->ignore($post->id)],
]);
$post->update($validatedData);
return redirect(route('posts.index'))->with('status', 'post updated successfully');
}
Do One step in controller
Works Fine with Laravel 9
$request->validate([
'name'=>'required|unique:categories,name,'.$id,
]);
If you have a separate rules method. You can use easier the following syntax.
public function rules()
{
return [
'email' => "required|unique:users,email,{$this->id}"
];
}
$rules = [
"email" => "email|unique:users, email, '.$id.', user_id"
];
In Illuminate\Validation\Rules\Unique;
Unique validation will parse string validation to Rule object
Unique validation has pattern: unique:%s,%s,%s,%s,%s'
Corresponding with: table name, column, ignore, id column, format wheres
/**
* Convert the rule to a validation string.
*
* #return string
*/
public function __toString()
{
return rtrim(sprintf('unique:%s,%s,%s,%s,%s',
$this->table,
$this->column,
$this->ignore ?: 'NULL',
$this->idColumn,
$this->formatWheres()
), ',');
}
There is a simple and elegant way to do this. If you are passing the user_id in a body request or through a query parameter.
e.g
/update/profile?user_id=
Then in your request rules
public function rules(Request $request)
{
return [
'first_name' => 'required|string',
'last_name' => 'required|string',
'email' => ['required','email', 'string', Rule::unique('users')->ignore($request->user_id )],
'phone_number' => ['required', 'string', Rule::unique('users')->ignore($request->user_id )],
];
}
Better Still, you can pass in auth->id() in place of $request->user_id to get the login user id.
Found the easiest way, working fine while I am using Laravel 5.2
public function rules()
{
switch ($this->method()) {
case 'PUT':
$rules = [
'name' => 'required|min:3',
'gender' => 'required',
'email' => 'required|email|unique:users,id,:id',
'password' => 'required|min:5',
'password_confirmation' => 'required|min:5|same:password',
];
break;
default:
$rules = [
'name' => 'required|min:3',
'gender' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|min:5',
'password_confirmation' => 'required|min:5|same:password',
];
break;
}
return $rules;
}
i would solve that by doing something like this
public function rules()
{
return [
'name' =>
'required|min:2|max:255|unique:courses,name,'.\Request::get('id'),
];
}
Where you get the id from the request and pass it on the rule
You can also use model classpath, if you don't want to hard code the table name.
function rules(){
return [
'email' => ['required','string',
Rule::unique(User::class,'email')->ignore($this->id)]
];
}
Here $this->id is either 0 or the record Id to be updated.
Use for Laravel 6.0
use Illuminate\Validation\Rule;
public function update(Request $request, $id)
{
// Form validation
$request->validate([
'category_name' => [
'required',
'max:255',
Rule::unique('categories')->ignore($id),
]
]);
}
After researching a lot on this laravel validation topic including unique column, finally got the best approach. Please have a look
In your controller
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class UserController extends Controller
{
public function saveUser(Request $request){
$validator = Validator::make($request->all(),User::rules($request->get('id')),User::$messages);
if($validator->fails()){
return redirect()->back()->withErrors($validator)->withInput();
}
}
}
saveUser method can be called for add/update user record.
In you model
class User extends Model
{
public static function rules($id = null)
{
return [
'email_address' => 'required|email|unique:users,email_address,'.$id,
'first_name' => "required",
'last_name' => "required",
'password' => "required|min:6|same:password_confirm",
'password_confirm' => "required:min:6|same:password",
'password_current' => "required:min:6"
];
}
public static $messages = [
'email_address.required' => 'Please enter email!',
'email_address.email' => 'Invalid email!',
'email_address.unique' => 'Email already exist!',
...
];
}
This is what I ended up doing. I'm sure there is a more efficient way of doing this but this is what i came up with.
Model/User.php
protected $rules = [
'email_address' => 'sometimes|required|email|unique:users,email_address, {{$id}}',
];
Model/BaseModel.php
public function validate($data, $id = null) {
$rules = $this->$rules_string;
//let's loop through and explode the validation rules
foreach($rules as $keys => $value) {
$validations = explode('|', $value);
foreach($validations as $key=>$value) {
// Seearch for {{$id}} and replace it with $id
$validations[$key] = str_replace('{{$id}}', $id, $value);
}
//Let's create the pipe seperator
$implode = implode("|", $validations);
$rules[$keys] = $implode;
}
....
}
I pass the $user_id to the validation in the controller
Controller/UserController.php
public function update($id) {
.....
$user = User::find($user_id);
if($user->validate($formRequest, $user_id)) {
//validation succcess
}
....
}
While updating any Existing Data Write validator as following:
'email' => ['required','email', Rule::unique('users')->ignore($user->id)]
This will skip/ignore existing user's id's unique value matching for the specific column.
Test below code:
$validator = Validator::make(
array(
'E-mail'=>$request['email'],
),
array(
'E-mail' => 'required|email|unique:users,email,'.$request['id'],
));
Since you will want to ignore the record you are updating when performing an update, you will want to use ignore as mentioned by some others. But I prefer to receive an instance of the User rather then just an ID. This method will also allow you to do the same for other models
Controller
public function update(UserRequest $request, User $user)
{
$user->update($request->all());
return back();
}
UserRequest
public function rules()
{
return [
'email' => [
'required',
\Illuminate\Validation\Rule::unique('users')->ignoreModel($this->route('user')),
],
];
}
update: use ignoreModel in stead of ignore
Very easy to do it ,
Write it at your controller
$this->validate($request,[
'email'=>['required',Rule::unique('yourTableName')->ignore($request->id)]
]);
Note : Rule::unique('yourTableName')->ignore($idParameter) , here $idParameter you can receive from get url also you can get it from hidden field.
Most important is don't forget to import Rule at the top.
If a login user want to update the email then auth() helper function will give us the login user id auth()->user()->id
Laravel helpers#method-auth
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore(auth()->user()->id),
],
]);
if Admin want to change the specific user information from User list then validation will be like this :
Validator::make($data, [
'email' => [
'required',
Rule::unique('users')->ignore($request->user),
],
Laravel validation#rule-unique
$request object contain the current route related model objects. Which gives the model.
Try dd($request)
Most answers to this question refer to email_address, but in Laravel's inbuilt authentication system, the email field name is just email. Here is an example of validating a unique field, i.e. an email on the update:
Form Requests look like this:
public function rules()
{
return [
'email' => [ 'required','email', Rule::unique('users')->ignore($this->id ?? 0)]];
}
?? 0 If you use this then if hare id does not exist this request will not give you an error
Save
Whenever you access the id property of $this->user, you may encounter an undefined property if you haven't injected the User model into your route. If that is the case, use:
public function rules()
{
return [
'email' => 'required|email|unique:users,email,'.$this->user()->id ?? 0,
];
}
?? 0 If you use this then if hare id does not exist this request will not give you an error
My solution:
$rules = $user->isDirty('email') ? \User::$rules : array_except(\User::$rules, 'email');
Then in validation:
$validator = \Validator::make(\Input::all(), $rules, \User::$messages);
The logic is if the email address in the form is different, we need to validated it, if the email hasn't changed, we don't need to validate, so remove that rule from validation.
For unique rule in the controller - which obviously will be different for the store method and the update method, I usually make a function within the controller for rules which will return an array of rules.
protected function rules($request)
{
$commonRules = [
'first_name' => "required",
'last_name' => "required",
'password' => "required|min:6|same:password_confirm",
'password_confirm' => "required:min:6|same:password",
'password_current' => "required:min:6"
];
$uniqueRules = $request->id
//update
? ['email_address' => ['required', 'email', 'unique:users,email' . $request->get('id')]]
//store
: ['email_address' => ['required', 'email', 'unique:users,email']];
return array_merge($commonRules, $uinqueRules);
}
Then in the respective store and update methods
$validatedData = $request->validate($this->rules($request));
This saves from defining two different rule sets for store and update methods.
If you can afford to compromise a bit on readability, it can also be
protected function rules($request)
{
return [
'first_name' => "required",
'last_name' => "required",
'password' => "required|min:6|same:password_confirm",
'password_confirm' => "required:min:6|same:password",
'password_current' => "required:min:6",
'email_address' => ['required', 'email', 'unique:users,email' . $request->id ?: null]
];
}

Categories