For this dictionary system scaffolding we are going to use of 11 tables and they are mentioned below
1. roles [ Registered users will have role of admin, editor and normal user ]
2. permissions [ set of resources of the system ]
3. permission_role [ which users have what resource permission ]
4. users [ application users ]
5. parts_of_speeches [ a collection of category to which words are assigned ]
6. words [ the actual words ]
7. parts_of_speech_word [ breezing table between parts_of_speeches and words ]
8. synonyms [ collection references of synonym words from words table ]
9. antonyms [ collection references of antonym words from words table ]
10. sentences [ potential sentences that can be made up referencing words ]
11. user_favorites [ references to words that user makes favorite ]
Now for all those tables above we can proceed to making migrations, models, factories and seeders
1. roles table
// migration Schema::create('roles', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); }); // model class Role extends Model { use HasFactory; protected $fillable = ['name']; public function permissions() { return $this->belongsToMany(Permission::class); } } // seeder class RoleSeeder extends Seeder { /** * Run the database seeds. */ public function run(): void { $admin = Role::create(['name' => 'Administrator']); $admin->permissions()->attach(Permission::pluck('id')); $editor = Role::create(['name' => 'User']); $editor->permissions()->attach( Permission::where('name', '=', 'dictionary.view')->pluck('id') ); } }
2. permissions table
// migration Schema::create('permissions', function (Blueprint $table) { $table->id(); $table->string('name'); $table->timestamps(); }); // model class Permission extends Model { use HasFactory; protected $fillable = ['name']; public function roles(){ return $this->belongsToMany(Role::class); } } //migration for breezing table permission_role since there is a belongsToMany
// relationship between roles and permissions table. This would also help to create seeding data on RoleSeeder.php for this breezing table with relationship. Schema::create('permission_role', function (Blueprint $table) { $table->id(); $table->foreignId('permission_id')->constrained(); $table->foreignId('role_id')->constrained(); $table->timestamps(); });
3. parts_of_speeches table
//migration Schema::create('parts_of_speech_word', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('word_id'); $table->unsignedBigInteger('parts_of_speech_id'); $table->foreign('word_id')->references('id')->on('words')->onDelete('cascade'); $table->foreign('parts_of_speech_id')->references('id')->on('parts_of_speeches')->onDelete('cascade'); $table->timestamps(); }); //model PartsOfSpeech.php class PartsOfSpeech extends Model { use HasFactory; protected $fillable = ['name']; public function words() { return $this->belongsToMany(Word::class); } } //factory PartsOfSpeechFacrory.php public function definition(): array { return [ 'name' => fake()->name(), ]; } //seeder PartsOfSpeechSeeder.php public function run(): void { PartsOfSpeech::factory(5)->create(); }
4. words table
//migration Schema::create('words', function (Blueprint $table) { $table->id(); $table->string('word'); $table->text('definition'); $table->text('definition_en'); $table->timestamps(); }); //model Word.php class Word extends Model { use HasFactory; protected $fillable = ['word', 'definition', 'definition_en']; public function parts_of_speeches() { return $this->belongsToMany(PartsOfSpeech::class); } public function synonyms(){ return $this->hasMany(Synonym::class, 'word_id'); } public function antonyms(){ return $this->hasMany(Antonym::class, 'word_id'); } public function sentences() { return $this->hasMany(Sentence::class ); } } //factory WordFactory.php public function definition(): array { return [ 'word' => fake()->name(), 'definition' => fake()->name(), 'definition_en' => '', ]; } //seeder WordSeeder.php public function run(): void { // Word::factory(5)->create()->each( function ($word) { $word->parts_of_speeches()->attach( PartsOfSpeech::pluck('id')->random(3) ); for( $i = 0; $i < 2; $i++ ) { $word->sentences()->save( Sentence::factory()->create() ); } }); }
5. synonyms table
// migration public function up(): void { Schema::create('synonyms', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('word_id'); $table->unsignedBigInteger('synonym_word_id'); $table->foreign('word_id')->references('id')->on('words')->onDelete('cascade'); $table->foreign('synonym_word_id')->references('id')->on('words')->onDelete('cascade'); $table->timestamps(); }); } //model Synonym.php class Synonym extends Model { use HasFactory; public function real_word(){ return $this->belongsTo(Word::class, 'word_id'); } public function synonym_word(){ return $this->belongsTo(Word::class, 'synonym_word_id'); } } //seeder SynosynSeeder.php public function run(): void { for( $i=0; $i < 20 ; $i++ ) { \App\Models\Synonym::firstOrCreate([ 'word_id' => Word::all()->random()->id, 'synonym_word_id' => Word::all()->random()->id, ]); } }
6. antonyms table
//migration public function up(): void { Schema::create('antonyms', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('word_id'); $table->unsignedBigInteger('antonym_word_id'); $table->foreign('word_id')->references('id')->on('words')->onDelete('cascade'); $table->foreign('antonym_word_id')->references('id')->on('words')->onDelete('cascade'); $table->timestamps(); }); } //model class Antonym extends Model { use HasFactory; public function real_word(){ return $this->belongsTo(Word::class, 'word_id'); } public function antonym_word(){ return $this->belongsTo(Word::class, 'antonym_word_id'); } } //seeder public function run(): void { for( $i=0; $i < 20 ; $i++ ) { \App\Models\Antonym::firstOrCreate([ 'word_id' => Word::all()->random()->id, 'antonym_word_id' => Word::all()->random()->id, ]); } }
7. sentences table
//migration public function up(): void { Schema::create('sentences', function (Blueprint $table) { $table->id(); $table->string('sentence'); $table->unsignedBigInteger('word_id'); $table->foreign('word_id')->references('id')->on('words')->onDelete('cascade'); $table->timestamps(); }); } //model class Sentence extends Model { use HasFactory; protected $fillable = [ 'sentence', 'word_id' ]; public function word() { return $this->belongsTo(Word::class); } } //seeder //For seeding data in sentences table we have used WordSeeder.php file to do this using relationship //between words and sentences table which is hasMany.
8. user_favorites table
<?php //migration public function up(): void { Schema::create('user_favorites', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('word_id'); $table->unsignedBigInteger('user_id'); $table->foreign('word_id')->references('id')->on('words')->onDelete('cascade'); $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->timestamps(); }); } //model class UserFavorite extends Model { use HasFactory; protected $fillable = [ 'word_id', 'user_id', ]; public function word(){ return $this->belongsTo(Word::class,); } public function user(){ return $this->belongsTo(User::class); } } //seeder //For seeding data to this table we have used UserSeeder.php to do this
9. users table
//migration public function up(): void { Schema::create('users', function (Blueprint $table) { $table->id(); $table->foreignId('role_id')->constrained(); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } //model class User extends Authenticatable { use HasApiTokens, HasFactory, Notifiable; /** * The attributes that are mass assignable. * * @var array<int, string> */ protected $fillable = [ 'name', 'email', 'password', ]; public function role() { return $this->belongsTo(Role::class); } public function favoriteWords(){ return $this->hasMany( UserFavorite::class ); } } //factory public function definition(): array { return [ 'name' => fake()->name(), 'email' => fake()->unique()->safeEmail(), 'email_verified_at' => now(), 'role_id' => Role::all()->random()->id, 'password' => static::$password ??= Hash::make('password'), 'remember_token' => Str::random(10), ]; } //seeder public function run(): void { // User::factory(5)->create()->each( function($user) { for( $i = 0; $i < 3; $i++ ) { $user->favoriteWords()->firstOrCreate(['word_id' => Word::pluck('id')->random() ]); } }); }
At last we need to setup DatabaseSeeder.php to finally run the seeding
public function run(): void { $this->call(PermissionSeeder::class); $this->call(RoleSeeder::class); $this->call(PartsOfSpeechSeeder::class); $this->call(WordSeeder::class); $this->call(SynonymSeeder::class); $this->call(AntonymSeeder::class); $this->call(UserSeeder::class); }
Now we will have both database tables and data created with scaffolding if we run laravel artisan command
php artisan migrate:fresh --seed