Search code examples
phpmysqllaravelunique

custom validation about unique of more than one field in laravel


I have a table tanks

+----+----------+-------+-------+
| id | capacity | model | width |
+----+----------+-------+-------+
|  1 |     1000 |    15 |   960 |
|  2 |    50000 |    30 |   200 |
|  3 |      100 |    15 |    12 |
|  4 |    80000 |    40 |   100 |
|  5 |     1000 |    30 |   123 |
|  6 |      500 |     5 |  1213 |
|  7 |     1000 |    22 |  2234 |
+----+----------+-------+-------+

And I added the unique property in my table

ALTER TABLE `tanks`
ADD UNIQUE `capacity_model_width` (`capacity`, `model`, `width`);

And my function to store values is like this

public function store(Request $request) {

        $image = new tank();

        $this->validate($request, [
                'capacity' => 'required|numeric',
                'model' => 'required|numeric',
                'width' => 'required|numeric',
            ]                
                );

        $image->capacity = $request->capacity;
        $image->model = $request->model;
        $image->width = $request->width;
        $image->save();

        return redirect()->route('tank.index')
                        ->with('success', 'Tank created successfully');
    }

Now when I insert below error shows

Integrity constraint violation: 1062 Duplicate entry 
'1000-22-2234' for key 'capacity_model_width'

I need to show the error message in my submit if they are unique. I am new to Laravel, How can add a custom validation and error message inside the store function


Solution

  • Add this to your code

    We are going to check to see if the fields we need exist first then we will concatenate them and add them to the request. From there we can now run our unique validation

    public function store(Request $request) {
        $image = new tank();
        //Check to see if fields exist then validate after concatenation
    
        if(isset($request->capacity) && isset($request->model) && isset($request->width) ){
             $request->request->add(['my_key' => ['capacity' => $request->capacity, 'model' => $request->model, 'width' => $request->width] ]);
        }
        $this->validate($request, [
                'capacity' => 'required|numeric',
                'model' => 'required|numeric',
                'width' => 'required|numeric',
                'my_key' => 'required|uniqueCapacity',
            ]                
                );
    
        $image->capacity = $request->capacity;
        $image->model = $request->model;
        $image->width = $request->width;
        $image->save();
    
        return redirect()->route('tank.index')
                        ->with('success', 'Tank created successfully');
    }
    

    Adding a custom validator

    Firstly access your AppServiceProvider and add the following

    class AppServiceProvider extends ServiceProvider
    {
        /**
         * Bootstrap any application services.
         *
         * @return void
         */
        public function boot()
        {
            Validator::extend('uniqueCapacity', function ($attribute, $value, $parameters, $validator) {
           $value_array = explode("-", $value);
            $items = DB::select("SELECT count(*) as aggregate FROM tanks WHERE capacity ='$value_array[0]' AND model='$value_array[1]' AND width='$value_array[2]' "); 
            $number=$items[0]->aggregate;
            if ($number > 0) {
                return false;
            } else {
                return true;
            }
            });
        }
    
        /**
         * Register the service provider.
         *
         * @return void
         */
        public function register()
        {
            //
        }
    }