简体   繁体   中英

How create validation of nested model to call in request in Laravel

I have a database table structure like the following (in laravel):

  • user 1-1 profile
  • partner 1-1 profile
  • user 1-N department

I want to send a save request (post) and have the user validated in UserRequest and have this class call a ProfileRequest.

  • Is this possible to do?
  • Is there any way to perform validations of related models?

Class of User request example:


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

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [

            'name' => 'required|string',
            'lastname' => 'required|string',
            'user' => [
                'required',
                Rule::unique('users')->ignore($this),
            ],
            'email' => 'required|string|email|unique:users',
            'password' => 'required|string|confirmed',
            'headquarter_id' => 'required'

            //Validation of profile

        ];
    }
}

Example of controller User

    public function store(AdAszaUserRequest $request)
    {
        $input = $request->all();
        $validated = $request->validated();
        $input['password'] = \Hash::make($request['password']);
        //   

        $departmentidList = array_column($input['departments'], 'id');        

        $AszaUser = AdAszaUser::create($input);  

        $models = [];
        foreach ($input['departments'] as $model) {
            $models[] = new AdDepartment($model);
        }

///important: this line add departments without validation
        $AszaUser->departments()->saveMany($models);
        $AszaUser->departments()->sync($departmentidList);


        return response($AszaUser, 201);
    }

And Request Of deparment:

<?php

namespace App\Http\Requests\AD;

use Illuminate\Foundation\Http\FormRequest;

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

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

Example of Json send in post:

{
    "id":2,
    "name": "Admin2",
    "email": "test@gmail.com",
    "lastname": "test",
    "user": "test",
    "password": "test",
    "password_confirmation": "test",
    "headquarter_id": 1,
    "lastname":"test",
    "remember_token": "1",
    "email_verified_at": "test",
    "headquarter": {
            "id": 1,
            "name": "ASZA ZARAGOZA",
            "description": "Sede en Zaragoza",
        },
         "departments": [
            {
                "id": 1,
                "name": "Intérpretes",
                "internal_name": "Interprete",
                "description": "Departamento de Intérpretes",
                "display_id": "01",
                "pivot": {
                    "user_id": 1,
                    "department_id": 1
                }
            },
            {
                "id": 10,
                "name": "Psicología"
            }
        ]
}

Can I call the DepartmentRequest to validate the elements passed in the department array?

UPDATE: 1 I don't think it is necessary, but of course it is possible

    public function store(AdAszaUserRequest $request)
    {
        $input = $request->all();
        $validated = $request->validated();
        $input['password'] = \Hash::make($request['password']);
        //   

        $departmentidList = array_column($input['departments'], 'id');        

        $AszaUser = AdAszaUser::create($input);  

        $models = [];
        foreach ($input['departments'] as $model) {
            /** To check validation for single item */
            $validator = Validator::make($model, (new StoreEventRequest)->rules());
            if (!$validator->fails()) {
                $models[] = new AdDepartment($model);
            } else {
                /** Something wrong */
                /** $errors = $validator->errors(); */
            }
        }

        /** To check validation for array of data
        $validator = Validator::make($request->only(['departments']), collect(array_map(function ($rules, $field): array {
            return ['departments.*.' . $field => $rules];
        }, (new StoreEventRequest)->rules()))
            ->collapse()
            ->toArray()); */

        /**
         * And then do what you want to do with this object
         * $errors = $validator->errors();
         *
        if ($validator->fails()) {
            return redirect('some_url')
                ->withErrors($validator);
        } */

        $AszaUser->departments()->saveMany($models);
        $AszaUser->departments()->sync($departmentidList);


        return response($AszaUser, 201);
    }

For more information see documentation https://laravel.com/docs/6.x/validation#manually-creating-validators

UPDATE: 2 If you need to separate your request classes, you also can do it like so

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

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return array_merge([

            'name' => 'required|string',
            'lastname' => 'required|string',
            'user' => [
                'required',
                Rule::unique('users')->ignore($this),
            ],
            'email' => 'required|string|email|unique:users',
            'password' => 'required|string|confirmed',
            'headquarter_id' => 'required'

            //Validation of profile

            /** Validate of departments */
            'departments' => 'nullable|array',
        ], collect(array_map(function ($rules, $field): array {
            return ['departments.*.' . $field => $rules];
        }, (new StoreEventRequest)->rules()))
            ->collapse()
            ->toArray())
            ->toArray();
    }
}

Yes you can do it like this

public function rules() {
        return [
            'name' => 'required|string',
            'lastname' => 'required|string',
            'user' => [ 'required', Rule::unique('users')->ignore($this), ],
            'email' => 'required|string|email|unique:users',
            'password' => 'required|string|confirmed',
            'headquarter_id' => 'required',
            //Validation of profile
            'profile.some_field' => 'required',
            //For array of objects
            'profile.*.some_field' => 'required',
        ];
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM