Search code examples
validationlaravellaravel-5uniquepivot-table

unique name rule validation based on pivot table laravel


I have a system where renting companies have cars. A car can be available in many renting companies. So it is a many-to-many relationship.

I want to provide the companies with the possibility to add new cars when they buy them. If the car already exists, the system wouldn't create it, but flash an error message saying they already have that car.

How to use the unique validation rule on the name field of the Car being added? The challenge is that the Car model doesn't have the id of the company, and the pivot table doesn't have the name of the car, it contains just the car_id and the company_id.

Many thanks

My Car Model

class Car extends Model
{
    protected $fillable = ['name'];

    protected $dates = ['purchased_at'];

    public function company(){
        return $this->belongsToMany('App\Company')->withPivot('quantity', 'purchased_at')->withTimestamps();
    }
}

My Company Model

class Company extends Model implements AuthenticatableContract, CanResetPasswordContract
{
    use Authenticatable, CanResetPassword;

    protected $table = 'companies';

    protected $hidden = ['password', 'remember_token'];

    public function setPasswordAttribute($password){
        $this->attributes['password'] = bcrypt($password);
    }

    public function cars(){
        return $this->belongsToMany('App\Car')->withPivot('quantity', 'purchased_at')->withTimestamps();
    }

}

My car Controller

class CarsController extends Controller
{


    public function store(CarRequest $request)
    {
        $car = new Car;
        $car->name = $request->input('name');
        $car->save();
        $car->company()->attach(Auth::user()->id,array('quantity' => $request->input('quantity'),'purchased_at' => \Carbon\Carbon::now()));

        return Redirect('companies/'. Auth::user()->id .'/cars')->with(['success'=>'You have just created a new car!']);
    }
}

My Car Request

class CarRequest extends Request
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'name'          => 'required | unique:car_company,car_id',
            'quantity'      => 'required'
        ];
    }
}

Solution

  • I found a solution. Basically, we can conditionally modify a rule entry. In this case, I look for cars inside the authenticated company, if the car name exists, then I change the rule to be unique on the cars table, which will fail because there is already a car with the same name in this table. Here is my new rules function inside my CarRequest class:

    public function rules()
    {
        $rules = [
            'quantity'      => 'required',
            ]; 
        $car = Auth::user()->cars->where('name', $this->input('name'));
    
        if (count($car) === 0)
        {
            $rules['name'] = 'required';
        }
        else{
            $rules['name'] = 'required | unique:cars';
        }
        return $rules;
    }