Astrotomic / laravel-translatable

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

Reference id is 0 #433

Open nkhoangvu opened 1 month ago

nkhoangvu commented 1 month ago

I don't know this is a bug or I did not find the properly to handle the package. If the id of Post is input manually by form:

class Job extends Model implements TranslatableContract
{
    use SoftDeletes, Translatable;

    public $timestamps = true;
    public $translatedAttributes = ['title', 'content'];
    public $translationForeignKey = 'post_id';
    protected $table = 'posts';  

    protected $primaryKey = 'id';
    protected $keyType = 'string';
    protected $dates = ['deleted_at'];
    protected $fillable = [
        'id',
        'title',
        'category_id',
        'published',
    'user_id',
    ];
}

then:

$input = $request->validated(); 
$post = Post::create($input);

The translation is excuted automatically in the same way with $post = Post::update($input) but the value of post_id cannot get properly, it always is 0, Although at that moment the new record $post was already created in DB. Although I tried:

$input['translation'] = [
            session('locale') => [
                'title' => $request->input('title'),
                'content' => $request->input('content')
            ],
        ];
$post = Post::create($input);

But no success.

How should I overcome this situation. Thank you.

Note: Everything works properly if the id is auto increment.

Versions (please complete the following information)

Oleksandr-Moik commented 1 month ago

Hi, @nkhoangvu!

For your problem, I suggest changing the array format for creating a post or changing the configuration to use a wrapper for transaltions.

If you need more information, see below.


By default, if you need to create a post with translations, you must pass an array with one of the next formats (see more on usage/forms:

1 - using array format

$post->fill([
  'en' => [
    'title' => 'My first edited post',
  ],
  'de' => [
    'title' => 'Mein erster bearbeiteter Beitrag',
  ],
]);

Example from test - https://github.com/Astrotomic/laravel-translatable/blob/main/tests/TranslatableTest.php#L210-L225

2 - using plain (with colon) format

$post->fill([
  'title:en' => 'My first edited post',
  'title:de' => 'Mein erster bearbeiteter Beitrag',
]);

Example from test - https://github.com/Astrotomic/laravel-translatable/blob/main/tests/TranslatableTest.php#L112-L123


From the latest versions of a package, you can use a new format, with a wrapper for translations (see in docs)

$data = [
  'author' => 'Gummibeer',
  'translations' => [
      'en' => ['title' => 'My first post'],
      'fr' => ['title' => 'Mon premier post'],
  ],
];
$post = Post::create($data);

Example from test - https://github.com/Astrotomic/laravel-translatable/blob/main/tests/TranslatableTest.php#L228-L247

nkhoangvu commented 1 month ago

None of above method can help.
I also tried as below but the same failed results:

$input = $request->validated(); 
$published = $request->boolean('published');
$input['published'] = $published ? 1 : 0;
$input['translation'] = [
       session('locale') => ['title' => $request->input('title')]
 ];
$post = Post::create($input);    

and this:

$data = new Post();
$data->fill([
            'id' => $input['id'],
            'category_id' => $input['category_id'],
            'company_id' => $input['company_id'],            
            'published' => $input['published'],
            'user_id' => $input['user_id'],
            session('locale') => ['title' => $input['title'], 'content' => $input['content']],
]);
$data->save();

Note that the post_id is varchar(8) and not auto-increment and I only need to update only one language at a time depend on session language session('locale'). Everything is normal with update. But when create a new post, the post_id is always 0 which causes error because the relationship between posts & post_translation table (SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails)

Below is my Post model:

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Astrotomic\Translatable\Contracts\Translatable as TranslatableContract;
use Astrotomic\Translatable\Translatable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Notification;
use App\Notifications\PostAction;
use RalphJSmit\Laravel\SEO\Support\HasSEO;
use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\Activitylog\LogOptions;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;
use Spatie\Tags\HasTags;

class Post extends Model implements TranslatableContract
{
    use HasSlug, HasTags, LogsActivity;
    use HasSEO, SoftDeletes, Translatable, Notifiable;

    public $timestamps = true;
    public $translatedAttributes = ['title', 'content'];
    protected $table = 'posts';  

    protected $primaryKey = 'id';
    protected $keyType = 'string';
    protected $dates = ['deleted_at'];
    protected $fillable = [
        'id',
        'title',
        'category_id',
        'published',
        'user_id',
    ];

    protected static function sendNotifications($job, $action)
    {
        $recipients = User::whereHasRole('super-admin')->get();
        Notification::send($recipients, new JobAction($job, $action));
    }

    public function getRouteKeyName()
    {
        return 'slug';
    }

    public function scopePublished($query)
    {
        return $query->where('published', true);
    }    

    public function getSlugOptions() : SlugOptions
    {
        return SlugOptions::create()
            ->generateSlugsFrom('title')
            ->saveSlugsTo('slug')
            ->slugsShouldBeNoLongerThan(254);
    }

    /* Activity Log */
    public function getDescriptionForEvent(string $eventName) : string {
        return "A job have been {$eventName}";
    }

    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults()
            ->useLogName('article')
            ->logOnly(['title', 'category_id', 'date', 'published', 'user_id'])
            ->logOnlyDirty();
    }

    public function category()
    {
        return $this->belongsTo(Category::class, 'category_id', 'id');
    }

    public function author()
    {
        return $this->belongsTo(User::class, 'user_id', 'id');
    }

    protected static function boot()
    {
        parent::boot();

        static::created(function ($post) {
            self::sendNotifications($post, 'created');
        });

        static::updated(function ($post) {
            self::sendNotifications($post, 'updated');
        });
    }   
}
Oleksandr-Moik commented 1 month ago

Ok, I will check it later.