Laravel 5 validation in model

36,407

Solution 1

I solve it

public function store(Request $request)
{
  $test=new test; /// create model object
    $validator = Validator::make($request->all(),$test->rules);
    if ($validator->fails()) {
        return view('test')->withErrors($validator)
    }
    test::create($request->all());
}

Solution 2

You are doing it the wrong way. The rules array should either be in your controller or better in a Form Request.

Let me show you a better approach:

Create a new Form Request file with php artisan make:request TestRequest.

Example TestRequest class:

namespace App\Http\Requests;

use App\Http\Requests\Request;

class TestRequest extends Request
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation messages.
     *
     * @return array
     */
    public function messages()
    {
        return [
            'title.required'    => 'A title is required.',
            'name.required'    => 'The name field is required'
        ];
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'title' => 'required',
            'name' => 'required',
        ];
    }
}

Inject the request object into your controller method.

public function store(TestRequest $request)
{
    // You don't need any validation, this is already done
    test::create($request->all());
}

Solution 3

You could also look at validating in your model and throwing a ValidationException which will be handled as usual in your controller (with the error bag etc). E.g:

abstract class BaseModel extends Model implements ModelInterface {
    protected $validationRules = [];

    /**
     * Validate model against rules
     * @param array $rules optional array of validation rules. If not passed will validate against object's current values
     * @throws ValidationException if validation fails. Used for displaying errors in view
     */
    public function validate($rules=[]) {
        if (empty($rules))
            $rules = $this->toArray();

        $validator = \Validator::make($rules,$this->validationRules);
        if ($validator->fails())
            throw new ValidationException($validator);
    }

    /**
     * Attempt to validate input, if successful fill this object
     * @param array $inputArray associative array of values for this object to validate against and fill this object
     * @throws ValidationException if validation fails. Used for displaying errors in view
     */
    public function validateAndFill($inputArray) {
        // must validate input before injecting into model
        $this->validate($inputArray);
        $this->fill($inputArray);
    }
}

Then in my Controller:

public function store(Request $request) {
    $person = $this->personService->create($request->input());

    return redirect()->route('people.index', $person)->with('status', $person->first_name.' has been saved');
}

Finally in my base service class

abstract class BaseResourceService {
    protected $dataService;
    protected $modelClassName;

    /**
     * Create a resource
     * @param array $inputArray of key value pairs of this object to create
     * @returns $object
     */
    public function create($inputArray) {
        try {
            $arr = $inputArray;
            $object = new $this->modelClassName();
            $object->validateAndFill($arr);
            $this->dataService->create($object);
            return $object;
        }
        catch (Exception $exception) {
            $this->handleError($exception);
        }
    }

If the model validates it continues as usual. If there's a validation error it goes back to the previous page with the validation errors in the flash data/error bag.

I will most probably move the $person->validate() method to my service class, however it will still work as outlined above.

Solution 4

You can simply make your validation by writing in Model.

In your Model File

i.e. Models\Test.php

public static $createRules = [
   'name'=>'required|max:111',
   'email'=>'required|email|unique:users',
];

In Controller

public function store(Request $request)
{
     $request->validate(ModalName::$createRules);
     $data = new ModelName();
}

Just do this. Everything will be fine.

Share:
36,407
paranoid
Author by

paranoid

I am beginner in laravel .

Updated on July 09, 2022

Comments

  • paranoid
    paranoid almost 2 years

    I have model like this

    class test extends Model
    {
    
    public   $rules = [
        'title' => 'required',
        'name' => 'required',
    ];
    protected $fillable = ['title','name'];
    }
    

    And controller like this

    public function store(Request $request)
    {
        $test=new test; /// create model object
            $validator = Validator::make($request->all(), [
                 $test->rules
            ]);
            if ($validator->fails()) {
                return view('test')->withErrors($validator)
            }
            test::create($request->all());
     }
    

    Validation show error like this

    The 0 field is required.

    I want show this

    The name field is required.
    The title field is required.

  • Matt Catellier
    Matt Catellier over 7 years
    why is it bad to store the rules with the model? why create an extra object with the request with validation login in there?
  • Jing
    Jing over 7 years
    I'm from a Ruby on Rails background and have used Laravel for a couple of years, personally, I prefer the approach to validate in the model level for two main reasons: 1. Models can be changed from many places other than user inputs, to maintain the integrity of data isn't for only frontend user but everybody, including the all the developers in the project. 2. Custom Request and Validators are only for attributes that you got from controllers, they don't validate all attributes of the model, say, what if a valid purchase of 2 items makes the inventory become -1.
  • Sabrina Leggett
    Sabrina Leggett over 7 years
    I would also love to know why Laravel does it this way. While I think that this answer is good in general I marked down for saying that way is "better" - "better" is subjective
  • Niladri Banerjee - Uttarpara
    Niladri Banerjee - Uttarpara about 7 years
    Here the user wanted to put the rules into model and not into controller or form request. Because, mostly, we write rules into models, as the frameworks suggested.
  • Veer Shrivastav
    Veer Shrivastav almost 7 years
    What if I want to make this generic (like API) so that it can be called from any view . How would I pass it to the same view (without knowing).
  • user3791372
    user3791372 almost 7 years
    According to Jeffrey Way, this is the 'preferred' method as it also allows authorisation checking. However there's no reason why the above rules method can't retrieve its rules from a static property of the model. So instead of public $rules it would become public static $rules and the above method would just return MyModel::$rules
  • Hackbard
    Hackbard about 6 years
    @VeerShrivastav maybe you can write yourself a helper class?
  • Nate I
    Nate I about 3 years
    I know this is old, but still applicable today. Gotta say, this answer is fundamentally wrong. The approach of storing rules on a model is not "worse", let alone "the wrong way". OOP is all about re-use, and if you're redefining rules all over the place, there's a foundational problem with your code. With a tiny bit of code, you can ensure that your rules are followed throughout the entire application, no matter the entry point (including tinker). Providing a single source of truth is always favorable over loads of redefinition throughout an application.