Search code examples
phplaravelvalidationframeworkstypeerror

How to validate model object instance in Laravel?


I've got the following model:

<?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'
        ];
    }
}

And there's a controller ProductController that has an action 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

It seems pretty clear there's something wrong with the following line: $validator = Validator::make($product, Product::rules()); The simplest cause I can think of, is that the validator simply does not accept objects and only wants arrays. If not, what could be the problem? If Laravel's validation only works with arrays, is it somehow possible to validate an object?


Solution

  •     validator = Validator::make($product, Product::rules());
    

    the problem is not Product::rules() but $product. Product::rules() is correct because it's return an array, but $product is an object instead of an array. You should change/convert $product to an array an example:

        validator = Validator::make((array)$product, Product::rules());