0

Good afternoon to y'all!

Somewhere in the past week, I changed something in the website that caused the following error:

SQLSTATE[HY000]: General error: 1364 Field 'identifier' doesn't have a default value (SQL: insert into `classifieds` (`vehicle_id`, `vehicle_type`, `updated_at`, `created_at`) values (19983, App\Models\Car, 2021-04-27 16:27:56, 2021-04-27 16:27:56))

It's is very weird, because the $fillable is set (and it worked before).

This is the content being used:

enter image description here

Classified Model:

<?php

namespace App\Models;

use App\Http\Controllers\Controller;
use App\Rules\FileUploader;
use App\Rules\VehicleRegDate;
use Auth;
use Cache;
use CyrildeWit\EloquentViewable\Contracts\Viewable;
use CyrildeWit\EloquentViewable\InteractsWithViews;
use Eloquent;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use Rennokki\QueryCache\Traits\QueryCacheable;
use ShiftOneLabs\LaravelCascadeDeletes\CascadesDeletes;
use Throwable;

/**
 * App\Models\Classified
 *
 * @property int $id
 * @property string $identifier
 * @property int|null $vehicle_id
 * @property string|null $vehicle_type
 * @property int $proprietor_id
 * @property string $proprietor_type
 * @property float $price
 * @property Carbon|null $created_at
 * @property Carbon|null $updated_at
 * @property-read Collection|Equipment[] $equipments
 * @property-read int|null $equipments_count
 * @property-read Collection|Media[] $medias
 * @property-read int|null $medias_count
 * @property-read Model|Eloquent $proprietor
 * @property-read Model|Eloquent $vehicle
 * @method static Builder|Classified newModelQuery()
 * @method static Builder|Classified newQuery()
 * @method static Builder|Classified query()
 * @method static Builder|Classified whereCreatedAt($value)
 * @method static Builder|Classified whereId($value)
 * @method static Builder|Classified whereIdentifier($value)
 * @method static Builder|Classified wherePrice($value)
 * @method static Builder|Classified whereProprietorId($value)
 * @method static Builder|Classified whereProprietorType($value)
 * @method static Builder|Classified whereUpdatedAt($value)
 * @method static Builder|Classified whereVehicleId($value)
 * @method static Builder|Classified whereVehicleType($value)
 * @mixin Eloquent
 * @property string|null $identifier_old
 * @property float $lat
 * @property float $lng
 * @property string|null $video_embed
 * @property int|null $phone
 * @property int|null $type
 * @property int $status
 * @property-read Collection|Advertising[] $adverts
 * @property-read int|null $adverts_count
 * @property-read Collection|Feature[] $features
 * @property-read int|null $features_count
 * @property-read Collection|Message[] $messages
 * @property-read int|null $messages_count
 * @property-read Collection|PriceOption[] $price_options
 * @property-read int|null $price_options_count
 * @property-read Sharing|null $sharing
 * @method static Builder|Classified whereIdentifierOld($value)
 * @method static Builder|Classified whereLat($value)
 * @method static Builder|Classified whereLng($value)
 * @method static Builder|Classified wherePhone($value)
 * @method static Builder|Classified whereStatus($value)
 * @method static Builder|Classified whereType($value)
 * @method static Builder|Classified whereVideoEmbed($value)
 */
class Classified extends Model implements Viewable
{
    use CascadesDeletes, QueryCacheable, InteractsWithViews;

    const STATUS_INACTIVE = 0;
    const STATUS_ACTIVE = 1;
    const STATUS_PENDING = 2;
    const STATUS_RETOUCH = 3;
    const STATUS_ARCHIVED = 4;
    const STATUS_REFUSED = 5;
    const STATUS_EXPIRED = 6;

    protected static $flushCacheOnUpdate = true;
    public $cacheFor = 86400;

    protected $fillable = [
        'identifier',
        'identifier_old',
        'proprietor_id',
        'proprietor_type',
        'price',
        'lat',
        'lng',
        'video_embed',
        'phone',
        'type',
        'status',
        'created_at',
        'updated_at'
    ];

    protected $hidden = [
        'id',
        'identifier_old',
        'proprietor_id',
        'proprietor_type',
        'vehicle_id',
        'vehicle_type',
        'lat',
        'lng',
        'phone',
    ];

    protected array $cascadeDeletes = ['medias', 'equipments', 'features', 'price_options', 'messages', 'adverts', 'sharing'];

    public array $rules = [
        'classified',
        'car',
        'motorcycle',
        'bike'
    ];

    public function __construct()
    {
        $this->rules['classified'] = [
            'vehicle_type' => 'required|alpha|in:car,motorcycle,bike',

            'type' => 'required|integer|exists:vehicle_data,id',

            'price' => 'required|numeric|min:1',

            'price_options.*' => 'nullable|integer|min:1',
            'features.*' => 'nullable|integer|exists:vehicle_data,id',
            'equipments.*' => 'nullable|integer|exists:vehicle_data,id',

            'fileuploader-list-files' => ['required', 'json', new FileUploader],

            'phone' => 'nullable|numeric|digits:9',
            'address' => 'nullable|string',

            'terms' => 'required|boolean',
        ];

        $this->rules['car'] = [
            'make' => 'required|integer|exists:vehicle_data,id',
            'model' => 'required|integer|exists:vehicle_data,id',
            'version' => 'nullable|string',

            'fuel' => 'required|integer|exists:vehicle_data,id',
            'firstRegDate' => ['required', new VehicleRegDate()],
            'mileage' => 'required|integer|min:0',

            'displacement' => 'required|integer|min:1',
            'power_kw' => 'nullable|integer|min:1',
            'power_hp' => 'nullable|integer|min:1',

            'bodyType' => 'required|integer|exists:vehicle_data,id',
            'bodyColour' => 'required|integer|exists:vehicle_data,id',
            'vin' => 'nullable|string|min:17|max:17',

            'annotations' => 'nullable|string',

            'transmission' => 'nullable|integer|exists:vehicle_data,id',
            'gears' => 'nullable|integer|exists:vehicle_data,id',
            'doors' => 'nullable|integer|exists:vehicle_data,id',

            'seats' => 'nullable|integer|exists:vehicle_data,id',
            'vehicle_class' => 'nullable|integer|exists:vehicle_data,id',
            'driveTrainType' => 'nullable|integer|exists:vehicle_data,id',

            'maxFuelRange' => 'nullable|numeric|min:1',
            'emission' => 'nullable|numeric|min:0.01',
            'iuc' => 'nullable|numeric|min:1',

            'particleFilter' => 'nullable|boolean',

            'warrantyDate' => 'nullable|date_format:d-m-Y',
            'warrantyKM' => 'nullable|integer|min:1',
            'inspectionDate' => 'nullable|date_format:d-m-Y',

            'registries' => 'nullable|integer|exists:vehicle_data,id',
            'origin' => 'nullable|integer|exists:vehicle_data,id',
            'license' => 'nullable|string',

            'fuelConsumptionCity' => 'nullable|numeric|min:1',
            'fuelConsumptionHighway' => 'nullable|numeric|min:1',
            'fuelConsumptionAverage' => 'nullable|numeric|min:1',

            'vintage' => 'nullable|boolean',

            'video_embed' => 'nullable|string'
        ];

        $this->rules['bike'] = [
            'framework' => 'nullable|string',
            'wheel-size' => 'nullable|numeric|min:1',
            'material' => 'nullable|string',
            'suspension' => 'nullable|string',
            'suspension-travel' => 'nullable|string',
            'shock-absorber' => 'nullable|string',
            'damping-travel' => 'nullable|string',
            'type-of-brake' => 'nullable|string',
            'brakes' => 'nullable|string',
            'speeds' => 'nullable|string',
            'gearshift-lever' => 'nullable|string',
            'rear-change' => 'nullable|string',
            'casset' => 'nullable|string',
            'chain' => 'nullable|string',
            'pedal' => 'nullable|string',
            'roses' => 'nullable|string',
            'cubes' => 'nullable|string',
            'tires' => 'nullable|string',
            'steering-gearbox' => 'nullable|string',
            'advance' => 'nullable|string',
            'guideline' => 'nullable|string',
            'fingers' => 'nullable|string',
            'saddle' => 'nullable|string',
            'seat-post' => 'nullable|string',
            'brand' => 'nullable|string',
            'warranty' => 'nullable|string',
            'hard-tail-full-suspension' => 'nullable|string',
            'year' => 'nullable|integer|min:1990|max:' . date('Y'),
            'engine' => 'nullable|string',
            'battery' => 'nullable|string',
        ];

        parent::__construct();
    }

    public function proprietor(): MorphTo
    {
        return $this->morphTo();
    }

    public function vehicle(): MorphTo
    {
        return $this->morphTo();
    }

    public function equipments(): BelongsToMany
    {
        return $this->belongsToMany(VehicleData::class, 'classified_equipment', 'classified_id', 'equipment_id');
    }

    public function features(): BelongsToMany
    {
        return $this->belongsToMany(VehicleData::class, 'classified_feature', 'classified_id', 'feature_id');
    }

    public function price_options(): BelongsToMany
    {
        return $this->belongsToMany(VehicleData::class, 'classified_price_option', 'classified_id', 'price_option_id');
    }

    public function messages(): HasMany
    {
        return $this->hasMany(Message::class);
    }

    public function adverts(): HasMany
    {
        return $this->hasMany(Advertising::class);
    }

    public function sharing(): MorphOne
    {
        return $this->morphOne(Sharing::class, 'object');
    }

    public function medias(): MorphMany
    {
        return $this->morphMany(Media::class, 'mediable');
    }

    public function getFeaturedMedia($size = null): string
    {
        try {
            if ($media = $this->medias()->orderBy('index', 'ASC')->first())
                return $media->getMediaRoute($size);

            if ($this->video_embed)
                return sprintf("https://i.ytimg.com/vi/%s/hqdefault.jpg", $this->video_embed);

            throw new Exception();

        } catch (Throwable $exception) {
            return asset_cdn('assets/img/default_listing.jpg');
        }
    }

    public function getRoute(): string
    {
        return route("classified.show", [$this->identifier, $this->getSlug()]);
    }

    public function getSlug(): string
    {
        return Str::slug($this->getTitle());
    }

    public function getTitle($size = null)
    {
        try {
            if ($this->isOtherMake() && $this->isOtherModel())
                $title = $this->vehicle->version;
            elseif ($this->isOtherMake())
                $title = $this->getModelName() . " " . $this->vehicle->version;
            else
                $title = $this->getMakeName() . " " . $this->getModelName() . " " . $this->vehicle->version;

            if ($size)
                return Str::limit($title, $size);

            return $title;

        } catch (Throwable $exception) {
            return $this->vehicle->version;
        }
    }

    public function getVehicleType(): ?string
    {
        try {
            return strtolower(explode("\\", $this->vehicle_type)[2]);

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getMakeName()
    {
        try {
            return (new Controller())->getVehicleMakeByAttr($this->getVehicleType(), $this->vehicle->make, 'id', 'value');

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getMakeNameOld()
    {
        try {
            return config('constants.' . $this->getVehicleType() . '.makes.' . $this->vehicle->make);

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getModelName()
    {
        try {
            return (new Controller())->getVehicleModelByModelAttr($this->getVehicleType(), $this->vehicle->make, $this->vehicle->model, 'id', 'value');

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getModelNameOld()
    {
        try {
            return config('constants.' . $this->getVehicleType() . '.models.' . $this->vehicle->make . '.' . $this->vehicle->model);

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getFirstRegDate()
    {
        try {
            return Carbon::parse($this->vehicle->firstRegDate);

        } catch (Throwable $exception) {
            return Carbon::parse($this->vehicle->firstRegDate);
        }
    }

    public function getFuelType()
    {
        $fuelType = Cache::get(sprintf("vehicle_data_%s_%s_%s_leaf", "classified", "fuel", $this->vehicle->fuel));

        try {
            return $fuelType->value;

        } catch (Throwable $exception) {
            return "Outro";
        }
    }

    public function getVersion($size = null)
    {
        try {
            if ($size)
                return Str::limit($this->vehicle->version, $size);
            else
                return $this->vehicle->version;

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getFormattedNumber($number, $decimal = 0)
    {
        return number_format($number, $decimal, ',', ' ');
    }

    public function getBodyTypeName()
    {
        try {
            $bodyType = Cache::get(sprintf("vehicle_data_%s_%s_%s", $this->getVehicleType(), "bodyTypes", $this->vehicle->bodyType));

            return $bodyType->first()->value;

        } catch (Throwable $exception) {
            return "Outro";
        }
    }

    public function getBodyColourName() // Fix
    {
        try {
            $object = VehicleData::findOrFail($this->vehicle->bodyColour);

            return $object->value;

        } catch (Throwable $exception) {
            return "Outro";
        }
    }

    public function getTransmissionName()
    {
        try {
            $object = VehicleData::findOrFail($this->vehicle->transmission);

            return $object->value;

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getGearsNumber()
    {
        try {
            $object = VehicleData::findOrFail($this->vehicle->gears);

            return $object->value;

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getDoorsNumber()
    {
        try {
            $object = VehicleData::findOrFail($this->vehicle->doors);

            return $object->value;

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getClassName()
    {
        try {
            $object = VehicleData::findOrFail($this->vehicle->vehicle_class);

            return $object->value;

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getOriginName()
    {
        try {
            $object = VehicleData::findOrFail($this->vehicle->origin);

            return $object->value;

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getLicenseFormated()
    {
        try {
            $license = strtoupper($this->vehicle->license);

            if (strlen($license) == 6) {
                $parts = str_split($license, 2);
                return implode('-', $parts);
            }

            return $license;

        } catch (Throwable $exception) {
            return "00-00-00";
        }
    }

    public function getDriveTrainTypeName()
    {
        try {
            $object = VehicleData::findOrFail($this->vehicle->driveTrainType);

            return $object->value;

        } catch (Throwable $exception) {
            return null;
        }
    }

    public function getDateFormated($date)
    {
        return Carbon::parse($date)->format('d-m-Y');
    }

    public function getDateStatus($date)
    {
        if (Carbon::parse($this->vehicle->$date) >= Carbon::today()->addDays(30))
            return "warning";
        elseif (Carbon::parse($this->vehicle->$date) < Carbon::today())
            return "danger";
        else
            return "info";
    }

    public function getVehicleTypeClassByName($name, $class = null)
    {
        switch ($name) {
            case "car":
                if (!$class)
                    return "App\Models\Car";
                else
                    return Car::class;
            case "motorcycle":
                if (!$class)
                    return "App\Models\Motorcycle";
                else
                    return Motorcycle::class;
            default:
                return null;
        }
    }

    public function getVehicleTypeByClass()
    {
        switch ($this->vehicle_type) {
            case Car::class:
                return 'car';
            case Motorcycle::class:
                return 'motorcycle';
            default:
                return null;
        }
    }

    public function getVehicleTypeNameByClass()
    {
        switch ($this->vehicle_type) {
            case Car::class:
                return 'Carro';
            case Motorcycle::class:
                return 'Moto';
            default:
                return null;
        }
    }

    public function getPhoneViews()
    {
        return 0;
    }

    public function getStatusElements()
    {
        return config('constants.status.' . $this->status);
    }

    public function getAddress()
    {
        try {
            return (new Controller())->getAddressFromGeoPosition($this->lat, $this->lng, 'city');

        } catch (Throwable $exception) {
            return "";
        }
    }

    public function getArticleCategory()
    {
        switch ($this->vehicle_type) {
            case Car::class:
                return 1;
            case Motorcycle::class:
                return 2;
            default:
                return null;
        }
    }

    public function isOtherMake(): bool
    {
        try {
            $controller = new Controller();

            if ($this->vehicle->make == $controller->getVehicleMakeOtherByVTypeAttr($this->getVehicleType(), 'slug', 'id'))
                return true;

            return false;

        } catch (Throwable $exception) {
            return false;
        }
    }

    public function isOtherModel(): bool
    {
        try {
            if ($this->vehicle->model == 0)
                return true;

            return false;

        } catch (Throwable $exception) {
            return false;
        }
    }

    public function flushCache()
    {
        try {
            Cache::forget('classified_' . $this->identifier);
            Cache::forget('medias_classified_' . $this->identifier);

            Cache::remember('classified_' . $this->identifier, 33600, function () {
                return $this;
            });

            Cache::remember('medias_classified_' . $this->identifier, 33600, function () {
                return $this->medias()->orderBy('index', 'ASC')->get();
            });

        } catch (Throwable $exception) {
        }
    }

    public function isProprietor()
    {
        try {
            if (Auth::check()) {
                if (session()->has('professional_user') && $this->proprietor_type == Branch::class && $this->proprietor_id == session()->get('professional_user'))
                    return true;
                elseif ($this->proprietor_type == User::class && $this->proprietor_id == Auth::id())
                    return true;
                elseif (Auth::user()->isAdmin())
                    return true;
            }

        } catch (Throwable $exception) {
            return false;
        }
    }

    public function getFavourites()
    {
        try {
            return $this->favourites->count();

        } catch (Throwable $exception) {
            return 0;
        }
    }

    public function isMyFavourite(): bool
    {
        try {
            $controller = new Controller();
            if ($this->favourites()->where([
                    'proprietor_id' => $controller->getProprietorId(),
                    'proprietor_type' => $controller->getProprietorType()
                ])->count() > 0)
                return true;

        } catch (Throwable $exception) {
        }

        return false;
    }

    public function favourites()
    {
        return $this->hasMany(ClassifiedFavourite::class);
    }
}

store method:

public function store(Request $request): JsonResponse
    {
        $rules = (new Classified)->rules;
        $request->validate($rules['classified']);
        $request->validate($rules[$request->input('vehicle_type')]);

        DB::beginTransaction();

        try {
            $vehicleData = $request->all();

            $vehicleData['firstRegDate'] = Carbon::createFromFormat('m-Y', $vehicleData['firstRegDate'])->toDateString();

            $vehicle = (new Classified())->getVehicleTypeClassByName($request->input('vehicle_type'))::create($vehicleData);

            if ($request->has('address'))
                $geoData = $this->getGeoPositionFromAddress($request->input('address'));
            else
                $geoData = (object)[
                    "lat" => 0,
                    "lng" => 0
                ];

            $formData = $request->all();
            $formData['identifier'] = $this->generateIdentifier();
            $formData['proprietor_id'] = $this->getProprietorId();
            $formData['proprietor_type'] = $this->getProprietorType();
            $formData['lat'] = $geoData->lat;
            $formData['lng'] = $geoData->lng;
            $formData['video_embed'] = $this->getYoutubeVideoID($request->input('video_embed'));
            $formData['status'] = Classified::STATUS_PENDING;

            $classified = $vehicle->classified()->create($formData);

            $vehicle->classified->price_options()->attach($request->input('price_options'));
            $vehicle->classified->features()->attach($request->input('features'));
            $vehicle->classified->equipments()->attach($request->input('equipments'));

            $medias = json_decode($request->{'fileuploader-list-files'}, true);
            foreach ($medias as $media) {
                $file = Media::where('name', $media->file)->first();
                if ($file) {
                    $file->mediable_id = $vehicle->classified->id;
                    $file->saveOrFail();
                }
            }

            if ($formData['proprietor_type'] == User::class && $request->has('phone') && $request->has('address'))
                $this->updateUserPhoneAndAddress($formData['phone'], $formData['address']);

            $classified->sharing()->create([
                'status' => Sharing::STATUS_PENDING,
            ]);

            if ($classified->status == Classified::STATUS_PENDING)
                $this->adminAlert($classified);

            DB::commit();

            toastr()->success("Anúncio submetido para aprovação.");

            return response()->json([
                'redirect_url' => route('classified.feature', $vehicle->classified->identifier),
            ]);

        } catch (Throwable $exception) {
            DB::rollBack();

            return response()->json([
                'errors' => [trans('custom.error_occurred'), $exception->getMessage()]
            ], 500);
        }
    }

Stack Error: https://pastebin.com/jPypBG8P

Anyone has any idea on may be causing this?

Tomas C. Lopes
  • 89
  • 1
  • 10
  • That is _a lot_ of code... You're probably best to put some breakpoints in your code to see what line is triggering this error (or examine the stack trace to see if it tells you). If you're using Source Code Management (Git, etc), take a look at changes and try to identify any that could potentially cause this issue. Lastly, put a `dd($exception)` in your `catch (Throwable $exception)` block to show you the full error; you're only logging the `getMessage()`, which isn't the most useful thing. Or remove the `catch()` completely and let your code error to see everything. – Tim Lewis Apr 27 '21 at 18:39
  • @TimLewis I've attached a pastebin with the error Stack. Also, I've checked the changes all afternoon, I can't spot anything that might be doing this (from what I have done). I remember updating laravel framework from 8.35 to 8.38, but I also reverted and It didnt work :( – Tomas C. Lopes Apr 27 '21 at 18:45
  • Nice, although I don't see the same error in that PasteBin. Now you have: `2021-04-27 18:38:41] production.ERROR: PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '' for key 'classifieds_identifier_unique'`, which means that `''` (empty) is being inserted into the `identifier` column. – Tim Lewis Apr 27 '21 at 18:47
  • @TimLewis do you have any idea of why the create() method would discard the array content? – Tomas C. Lopes Apr 27 '21 at 18:48
  • After that, what line does this represent? `Http/Controllers/ClassifiedController.php(124):`; your Stack Trace is suggesting your error is happening then. And no, it shouldn't; it's more likely that `['identifier' => '']` is in your `$formData` (via `$this->generateIdentifier()` maybe?) – Tim Lewis Apr 27 '21 at 18:48
  • That represents: ```$classified = $vehicle->classified()->create($formData);```, the weirdest thing, is that I am 1000% sure I didn't change this method for at least a month... – Tomas C. Lopes Apr 27 '21 at 18:50
  • Hmm, and syntax-wise, that line looks totally fine... I bet if you did `dd($formData['identifier'])` right before that line, it would be `''`. Can you share the code for `$this->generateIdentifier()`? Did that line change maybe? – Tim Lewis Apr 27 '21 at 18:52
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/231669/discussion-between-tomas-c-lopes-and-tim-lewis). – Tomas C. Lopes Apr 27 '21 at 18:54

1 Answers1

0

Apparently it was the constructor in the Classified Model that was preventing.

A special Thanks to @Tim Lewis !

Tomas C. Lopes
  • 89
  • 1
  • 10