如何验证 Laravel 中的模型对象实例?

How to validate model object instance in Laravel?

我有以下型号:

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    protected $guarded = ['id'];
    
    public static function rules() 
    {   
        return [
            'created_at'    => 'nullable',
            'updated_at'    => 'nullable',
            'name'          => 'required|string|between:1,255',
            'description'   => 'required|string|between:1,255',
            'date_added'    => 'nullable',
            'date_edited'   => 'nullable',
            'unit'          => 'required|string|between:1,255',
            'unit_type'     => 'required|integer',
            'stock'         => 'nullable|string|between:0,255',
            'barcode'       => 'nullable|string|between:0,32',
            'tax'           => 'nullable|float',
            'price'         => 'nullable|float',
            'category_id'   => 'required|integer|gt:0'
        ];
    }
}

还有一个控制器 ProductController 有一个动作 insertProduct

class class ProductController extends ApiController { // controller class

    public function insertProduct(Request $request) {
        
        $inputJson = $request->input('data_json', null);
        
        if(empty($inputJson)) {
            $inputJson = $request->getContent();
            if(empty($inputJson)) {
                return $this->errorResponse(
                    'Either data_json formdata parameter or request body should contain a JSON string.'
                );
            }
        }
        
        try {
            $product = $this->extractProductFromJSON($inputJson);
        } catch(\Exception $e) {
            return $this->errorResponse($e->getMessage(), 400);
        }
        
        // When I dump the Product ($product) instance using dd(), it is just as expected and its
        // properties contain the right values.

        $validator = Validator::make($product, Product::rules());
        /* Above line causes exception:
         TypeError: Argument 1 passed to Illuminate\Validation\Factory::make() must be of the type 
         array, object given, 
         called in /.../vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php 
         on line 261 in file /.../vendor/laravel/framework/src/Illuminate/Validation/Factory.php 
         on line 98
        */
        
        if($validator->fails()) {
            return $this->errorResponse($validator->errors()->first());
        }
        
        // ...
    }


    
    // How I extract the data from the JSON string (which is input).
    // Although I don't think this has anything to do with my problem.
    
    private function extractProductFromJSON(string $json) {
        
        $data = \json_decode($json);
        
        if(\json_last_error() != JSON_ERROR_NONE) {
            throw new \Exception('Error parsing JSON: ' . \json_last_error_msg());
        }
        
        try {
            
            $productData = $data->product;

            $productId = empty($productData->id) ? null : $productData->id;
            // Product id is allowed to be absent

            $product = new Product(); // My \App\Product model instance.
            $product->id = $productId;
            $product->name = $productData->name;
            $product->description = $productData->description;
            $product->date_added = $productData->date_added;
            $product->date_edited = $productData->date_edited;
            $product->unit = $productData->unit;
            $product->unit_type = $productData->unit_type;
            $product->stock = $productData->stock;
            $product->barcode = $productData->barcode;
            $product->tax = $productData->tax;
            $product->price = $productData->price;
            $product->category_id = $productData->category_id;

            return $product;
        
        } catch(\Exception $e) {
            echo 'EXCEPTION...';
        }
    }

} // end of controller class

很明显下面一行有问题: $validator = Validator::make($product, Product::rules()); 我能想到的最简单的原因是验证器根本不接受对象而只需要数组。 如果不是,可能是什么问题? 如果 Laravel 的验证仅适用于数组,是否有可能以某种方式验证 对象

是的!你是对的。如果我们查看 make 方法,我们可以看到它接受规则作为数组。

     * @param array $data
     * @param array $rules
     * @param array $messages
     * @param array $customAttributes
     * @return \Illuminate\Validation\Validator 
     * @static 
     */ 
    public static function make($data, $rules, $messages = [], $customAttributes = [])
    {
                    /** @var \Illuminate\Validation\Factory $instance */
                    return $instance->make($data, $rules, $messages, $customAttributes);
    }

我通常直接在控制器中验证数据

    $validator = Validator::make($info, [
        'shortDescription' => 'required',
        'description' => 'required',
        'countryId' => 'required',
        'cities' => 'required | array | min:1',
    ]);
    validator = Validator::make($product, Product::rules());

问题不是 Product::rules(),而是 $productProduct::rules() 是正确的,因为它是 return 一个数组,但是 $product 是一个对象而不是数组。你应该 change/convert $product 给一个数组一个例子:

    validator = Validator::make((array)$product, Product::rules());
class Cliente extends Eloquent
{
    public static $autoValidates = true;
    protected static $rules = [];
    protected static function boot()
    {
        parent::boot();
        // or static::creating, or static::updating
        static::saving(function($model)
        {
            if ($model::$autoValidates) {
                return $model->validate();
            }
        });
    }
    public function validate()
    {
    }
}