Search code examples
phplaravellaravel-backpack

Backpackforlaravel SQLSTATE[HY000]: General error: 1364 Field 'produit_type_id' doesn't have a default value


When I create a new product, it tells me:

Illuminate  \  Database  \  QueryException PHP 8.2.0 10.23.1 SQLSTATE[HY000]: General error: 1364 Field 'produit_type_id' doesn't have a default value INSERT INTO produits (nom, description, quantite, updated_at, created_at) VALUES (TEtrdesfddfsdf, dsfdfsdf, 10, 2023-09-26 14:39:57, 2023-09-26 14:39:57)

It looks like, same if I have FILLABLE or GUARDED, it do not care about adding the field in the request. I dont understand why. I absolutely do not want that column to be NULL. I precise that it works only when the SELECT is filled with IDS (for exemple, select_from_array [1,2,3,4] etc).

I am trying to create a product in my database with a product_type relationship one-to-one with Backpackforlaravel.

I have these migrations:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('produits', function (Blueprint $table) {
            $table->id();
            $table->string('nom')->nullable(false);
            $table->string('quantite')->default(0);
            $table->longText('description')->nullable();
            $table->unsignedBigInteger('produit_type_id')->nullable(false);
            $table->foreign('produit_type_id')->references('id')->on('produit_types');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('produits');
    }
};
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('produit_types', function (Blueprint $table) {
            $table->id();
            $table->string('nom')->nullable(false);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('produit_types');
    }
};

I have these models:

<?php

namespace App\Models;

use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

class Produits extends Model
{
    use CrudTrait;
    use HasFactory;

    protected $guarded = [];

    protected $table = 'produits';

    public function produitType(): HasOne
    {
        return $this->hasOne(ProduitTypes::class, 'id', 'produit_type_id');
    }
}
<?php

namespace App\Models;

use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

class ProduitTypes extends Model
{
    use CrudTrait;
    use HasFactory;

    protected $guarded = [];

    protected $table = 'produit_types';

    public function produits(): BelongsToMany
    {
        return $this->belongsToMany(Produits::class);
    }
}

I have this crud controller:

<?php

namespace App\Http\Controllers\Admin;

use App\Http\Requests\ProduitsRequest;
use App\Models\ProduitTypes;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\CRUD\app\Library\CrudPanel\CrudPanelFacade as CRUD;

/**
 * Class ProduitsCrudController
 * @package App\Http\Controllers\Admin
 * @property-read \Backpack\CRUD\app\Library\CrudPanel\CrudPanel $crud
 */
class ProduitsCrudController extends CrudController
{
    use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;

    /**
     * Configure the CrudPanel object. Apply settings to all operations.
     *
     * @return void
     */
    public function setup()
    {
        CRUD::setModel(\App\Models\Produits::class);
        CRUD::setRoute(config('backpack.base.route_prefix') . '/produits');
        CRUD::setEntityNameStrings('produit', 'produits');
    }

    /**
     * Define what happens when the List operation is loaded.
     *
     * @see  https://backpackforlaravel.com/docs/crud-operation-list-entries
     * @return void
     */
    protected function setupListOperation()
    {
        CRUD::setFromDb(); // set columns from db columns.

        /**
         * Columns can be defined using the fluent syntax:
         * - CRUD::column('price')->type('number');
         */
    }

    /**
     * Define what happens when the Create operation is loaded.
     *
     * @see https://backpackforlaravel.com/docs/crud-operation-create
     * @return void
     */
    protected function setupCreateOperation()
    {
        $this->crud->addField([
            'name' => 'nom',
            'label' => 'Nom',
            'type' => 'text',
            'placeholder' => 'Nom du produit',
            'validationRules' => 'required|min:3'
        ]);

        $this->crud->addField([
            'label' => 'Type de produit',
            'type' => 'select',
            'name' => 'produit_type_id',
            'entity' => 'produitType',
            'attribute' => 'nom',
            'model' => "App\Models\ProduitTypes",
        ]);

        $this->crud->addField([
            'name' => 'description',
            'label' => 'Description',
            'type' => 'textarea',
            'placeholder' => 'Description du produit',
            'validationRules' => 'required'
        ]);

        $this->crud->addField([
            'name' => 'quantite',
            'label' => 'Quantité',
            'type' => 'number',
            'value' => '0',
            'validationRules' => 'required'
        ]);


    }

    /**
     * Define what happens when the Update operation is loaded.
     *
     * @see https://backpackforlaravel.com/docs/crud-operation-update
     * @return void
     */
    protected function setupUpdateOperation()
    {
        $this->setupCreateOperation();
    }
}

Solution

  • What you have there is a BelongsTo relation, not an HasOne.

    For it to be an Product HasOne ProductType the product_types table would need the product_id.

    What you have is that a Product BelongsTo ProductType, because you have the product_type_id in the products table.

    Fixing that should make it work just fine.

    Cheers