Astrotomic / laravel-translatable

A Laravel package for multilingual models
https://docs.astrotomic.info/laravel-translatable/
MIT License
1.22k stars 152 forks source link

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

Closed mialyGit closed 5 months ago

mialyGit commented 5 months ago

Describe the bug It's my first time trying to use this package. When I create a 'Title' model, an error message appears stating that the 'name' field has no default value, even though the 'nom' field has a value as indicated in the code. I have carefully followed the documentation, and I don't understand why this error is occurring.

Screenshots Capture d'écran 2024-01-19 094435

Versions (please complete the following information)

Additional context Route :

Route::get('/', function () {
    $data = [
        'icon' => 'laravel.png',
        'en' => ['name' => 'Fullstack Developer', 'intro' => "I'm Fullstack Developer"],
        'fr' => ['name' => 'Fullstack Dévelopeur', 'intro' => 'Je suis un Développeur Fullstack'],
    ];

    $title = Title::create($data);
    dd($title);

});

Model:

<?php

namespace App\Models;

use Astrotomic\Translatable\Contracts\Translatable as TranslatableContract;
use Astrotomic\Translatable\Translatable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Title extends Model implements TranslatableContract
{
    use HasFactory, Translatable;

    public $translatedAttributes = ['name', 'intro'];

    protected $fillable = ['icon'];
}

Translation

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class TitleTranslation extends Model
{
    use HasFactory;

    public $timestamps = false;

    protected $fillable = ['name', 'intro'];
}

Migration: 2024_01_18_080530_create_titles_table

    public function up(): void
    {
        Schema::create('titles', function (Blueprint $table) {
            $table->increments('id');
            $table->string('icon')->nullable();
            $table->string('name');
            $table->text('intro')->nullable();
            $table->boolean('is_active')->default(false);
            $table->timestamps();
        });
    }
2024_01_18_081249_create_title_translations_table
  Schema::create('title_translations', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('title_id')->unsigned();
            $table->string('locale')->index();
            $table->string('name');
            $table->string('intro')->nullable();

            $table->unique(['title_id', 'locale']);
            $table->foreign('title_id')->references('id')->on('titles')->onDelete('cascade');
        });

Exception SQLSTATE[HY000]: General error: 1364 Field 'name' doesn't have a default value INSERT INTO titles (icon, updated_at, created_at) VALUES (laravel.png, 2024-01-19 06:43:48, 2024-01-19 06:43:48)

Eyad-Bereh commented 5 months ago

Hello there

I've checked your code and I was able to reproduce the issue, and it seems that the issue is unrelated to the package You're defining a name attribute inside your App\Models\Title model, but you're not assigning it any value, leaving it to remain empty, and since you haven't defined a default value to be provided in such scenarios, you get the error.

I think that you may have accidentally defined a name attribute inside the Title model when you meant to use it inside the TitleTranslation model, so I suggest that you double-check your implementation and try again.

mialyGit commented 5 months ago

@Eyad-Mohammed-Osama Which default value that you say ? I've already tried this code as well, and it still doesn't work.

Route::get('/', function () {
    $data = [
        'icon' => 'laravel.png',
        'name' => 'Fullstack Developer',
        'en' => ['name' => 'Fullstack Developer', 'intro' => "I'm Fullstack Developer"],
        'fr' => ['name' => 'Fullstack Dévelopeur', 'intro' => 'Je suis un Développeur Fullstack'],
    ];

    $title = Title::create($data);
    dd($title);

});

In this above code, I've set a default value for 'name,' but it still comes back to the same error

If I don't well understand that you say, please give the correct code

Eyad-Bereh commented 5 months ago

@mialyGit Don't worry, I'll give you the code, but first of all, I want to explain what's going on.

You have a name attribute in both Title and TitleTranslation models, and the package sees that you have defined a name attribute in your $translatedAttributes array property. So when you write something like:

Route::get('/', function () {
    $data = [
        'icon' => 'laravel.png',
        'name' => 'Fullstack Developer',
        'en' => ['name' => 'Fullstack Developer', 'intro' => "I'm Fullstack Developer"],
        'fr' => ['name' => 'Fullstack Dévelopeur', 'intro' => 'Je suis un Développeur Fullstack'],
    ];

    $title = Title::create($data);
    dd($title);
});

The package will take the name field and try to save it to the TitleTranslation model using the default locale, contrary to the expected behavior that it should save it to the Title model. This is because of the way the package use __get() and __set() methods to make read and write operations on translated attributes work in a shorter syntax, that is instead of writing:

$locale = config("translatable.locale"); // get default locale
$intro = $title->translate($locale)->intro;

You will simply write:

$intro = $title->intro;

This way, you can get the translations according to the default locale.

So in summary, the name attribute of the Title model isn't being read or written at all.

Regarding possible solutions, I recommend one of the following solutions:

  1. Remove the name attribute from your Title model, and keep it in your TitleTranslation model.
  2. Give the name attribute on your Title model a different name than the one in your TitleTranslation model.

Some people may suggest you assign the mysql.strict key in your database config file a false value to make the error disappear. While this will silence the MySQL engine from throwing this type of errors, it doesn't solve the problem for you because it will cause the engine to store an empty string '' in the column as a default value.

mialyGit commented 5 months ago

@Eyad-Mohammed-Osama I solved my problem with the first option. I deleted the 'name' attribute from the database. I finally understood how this package works. My migration of 'Title' model now looks like this.

public function up(): void
    {
        Schema::create('titles', function (Blueprint $table) {
            $table->increments('id');
            $table->string('icon')->nullable();
            // $table->string('name'); removed
            // $table->text('intro')->nullable(); removed
            $table->boolean('is_active')->default(false);
            $table->timestamps();
        });
    }

Thank you very much for the explanation and the solution.

Eyad-Bereh commented 5 months ago

@mialyGit You're more than welcome!