Astrotomic / laravel-translatable

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

Creating Fake Data with the Factory #364

Closed Dezmonter closed 12 months ago

Dezmonter commented 1 year ago

Please tell me how can I create a factory with Product (id) and ProductDescription (product_id, name) models using your wonderful package. Is there a macro in the package for this?

PavelZanek commented 1 year ago

Would this guide at PavelZanek.com be of any help to you?

Dezmonter commented 1 year ago

Yes, I tried it, but unfortunately I get an error and I don’t know what to do ((

 `  TypeError

  Illuminate\Database\Grammar::parameterize(): Argument #1 ($values) must be of type array, int given, called in E:\OSPanel\domains\lik\vendor\laravel\framework\src\Illuminate\Database\Query\Grammars\Grammar.php on line 1047

  at vendor\laravel\framework\src\Illuminate\Database\Grammar.php:175
    171▕      *
    172▕      * @param  array  $values
    173▕      * @return string
    174▕      */
  ➜ 175▕     public function parameterize(array $values)
    176▕     {
    177▕         return implode(', ', array_map([$this, 'parameter'], $values));
    178▕     }
    179▕

  1   vendor\laravel\framework\src\Illuminate\Database\Query\Grammars\Grammar.php:1047
      Illuminate\Database\Grammar::parameterize()

  2   [internal]:0
      Illuminate\Database\Query\Grammars\Grammar::Illuminate\Database\Query\Grammars\{closure}()`
PavelZanek commented 1 year ago

Can you please share what your models (Product and ProductDescription) and the ProductFactory look like?

Dezmonter commented 1 year ago

Yes, of course, my model Doctor

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use App\Models\Scopes\CityScope;
use App\Services\TranslatableService;

class Doctor extends Model
{
    use HasFactory, TranslatableService;

    public $sortables = ['id', 'start_year'];

    protected $fillable = [
        'city_id',
        'degree',
        'qualification',
        'start_year',
        'viewed',
        'status',
        'image',
        'sort_order',
    ];

    public $translatedAttributes = [
        'slug',
        'name',
        'description',
        'education',
        'meta_title',
        'meta_description',
        'meta_keywords',
    ];
}

My model DoctorTranslation

<?php

namespace App\Models;

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

class DoctorTranslation extends Model
{
    use HasFactory;

    public $timestamps = false;

    protected $fillable = [
        'slug',
        'name',
        'description',
        'education',
        'meta_title',
        'meta_description',
        'meta_keywords',
    ];
}

And finally my factory DoctorFactory

<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use App\Models\City;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Doctor>
 */
class DoctorFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        $locales = ['uk', 'ru'];

        $translations = collect($locales)->mapWithKeys(function($locale) {
            return [
                $locale => [
                    'slug' => fake()->unique()->randomNumber(4) . '-' . fake()->slug(3),
                    'name' => fake()->unique()->name(),
                    'description' => fake()->text(),
                    'education' => fake()->text(),
                ]
            ];
        })->toArray();

        return array_merge([
            'city_id' => City::get()->random()->id,
            'degree' => fake()->numberBetween(1, 2),
            'qualification' => fake()->numberBetween(1, 3),
            'start_year' => fake()->year(),
            'viewed' => fake()->numberBetween(50, 5500),
            'status' => true,
            'image' => fake()->imageUrl(250, 250),
            'sort_order' => fake()->numberBetween(0, 10),
            'created_at' => fake()->dateTimeBetween('-4 week', '-3 week'),
            'updated_at' => fake()->dateTimeBetween('-2 week', '-1 week'),
        ], $translations);
    }
}
PavelZanek commented 1 year ago

If I use the below solution everything works for me. First, I created probably similar migrations to yours.

translatable.php:

    ...
    'locales' => [
        'uk',
        'ru',
    ],
    ...

City Table:

<?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('cities', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
    }

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

Doctor Table:

<?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('doctors', function (Blueprint $table) {
            $table->id();
            $table->foreignId('city_id')->constrained();
            $table->integer('degree');
            $table->integer('qualification');
            $table->integer('start_year');
            $table->integer('viewed');
            $table->boolean('status')->default(false);
            $table->string('image');
            $table->integer('sort_order');
            $table->timestamps();
        });
    }

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

DoctorTranslation Table:

<?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('doctor_translations', function (Blueprint $table) {
            $table->id();

            $table->foreignId('doctor_id')->constrained();
            $table->string('locale')->index();

            $table->string('slug');
            $table->string('name');
            $table->text('description');
            $table->text('education');

            $table->unique(['doctor_id', 'locale']);
        });
    }

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

City model:

<?php

namespace App\Models;

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

class City extends Model
{
    use HasFactory;

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

Doctor 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 Doctor extends Model implements TranslatableContract
{
    use HasFactory, Translatable;

    protected $fillable = [
        'city_id',
        'degree',
        'qualification',
        'start_year',
        'viewed',
        'status',
        'image',
        'sort_order',
    ];

    public $translatedAttributes = [
        'slug',
        'name',
        'description',
        'education',
        'meta_title',
        'meta_description',
        'meta_keywords',
    ];
}

DoctorTranslation model:

<?php

namespace App\Models;

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

class DoctorTranslation extends Model
{
    use HasFactory;

    public $timestamps = false;

    protected $fillable = [
        'slug',
        'name',
        'description',
        'education',
        'meta_title',
        'meta_description',
        'meta_keywords',
    ];
}

CityFactory:

<?php

namespace Database\Factories;

use App\Models\City;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\City>
 */
class CityFactory extends Factory
{
    protected $model = City::class;

    public function definition(): array
    {
        return [
            'name' => fake()->city(),
        ];
    }
}

DoctorFactory:

<?php

namespace Database\Factories;

use App\Models\City;
use App\Models\Doctor;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Doctor>
 */
class DoctorFactory extends Factory
{
    protected $model = Doctor::class;

    public function definition(): array
    {
        $locales = ['uk', 'ru'];

        $translations = collect($locales)->mapWithKeys(function($locale) {
            return [
                $locale => [
                    'slug' => fake()->unique()->randomNumber(4) . '-' . fake($locale)->slug(3),
                    'name' => fake($locale)->unique()->name(),
                    'description' => fake($locale)->text(),
                    'education' => fake($locale)->text(),
                ]
            ];
        })->toArray();

        return array_merge([
            'city_id' => City::factory(),
            'degree' => fake()->numberBetween(1, 2),
            'qualification' => fake()->numberBetween(1, 3),
            'start_year' => fake()->year(),
            'viewed' => fake()->numberBetween(50, 5500),
            'status' => fake()->boolean(),
            'image' => fake()->imageUrl(250, 250),
            'sort_order' => fake()->numberBetween(0, 10),
            'created_at' => fake()->dateTimeBetween('-4 week', '-3 week'),
            'updated_at' => fake()->dateTimeBetween('-2 week', '-1 week'),
        ], $translations);
    }
}

Seeder:

<?php

namespace Database\Seeders;

use App\Models\Doctor;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        Doctor::factory()->count(10)->create();
    }
}
github-actions[bot] commented 1 year ago

This issue is stale because it has been open 21 days with no activity. Remove stale label or comment or this will be closed in 7 days