MVC and You – The Start of Something Great
The Historical Bible App – Part 3
"Commit to the LORD whatever you do, and He will establish your plans." – Proverbs 16 : 3
So your Laravel welcome page is humming on http://localhost:8000. Now what? Time to turn that blank canvas into real tables, models, and endpoints.
1. Databases 101
Option A – SQLite (Fast & Fuss‑Free)
touch database/database.sqlite
In .env:
DB_CONNECTION=sqlite
DB_DATABASE=/absolute/path/to/database/database.sqlite
Ideal for local dev & CI – zero installs beyond PHP.
Option B – Full RDBMS (Production‑Ready)
Laravel 12 supports:
MariaDB 10.3+ * MySQL 5.7+ * PostgreSQL 10+ * SQLite 3.26+ * SQL Server 2017+
Spin up your favourite flavour (Docker, Homebrew, WAMP – dealer's choice) and adjust DB_* in .env.
2. Eloquent & The First Model
Our scoped "People" entity looked like this:
Field Type Notes id bigint PK name, title, alias string gender enum Male/Female nullable date_of_birth, date_of_death date birth_location_id, death_location_id FK -> locations father_id, mother_id FK self era_id FK certainty tinyint 0–100 scale notes text
Generate everything in one go
php artisan make:model People --all
# shorthand: -mfsc (model + factory + seeder + controller)
This scaffolds:
Model (
app/Models/People.php) * Migration (database/migrations/...create_people_table.php) * Factory & Seeder * Policy, Controller, Form Requests
You rarely need every class, but it's a great tour of Laravel's toolbox.
3. Crafting the Migration
database/migrations/xxxx_create_people_table.php
Schema::create('people', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('title')->nullable(); $table->string('alias')->nullable(); $table->enum('gender', ['Male','Female'])->nullable(); $table->date('date_of_birth')->nullable(); $table->date('date_of_death')->nullable(); $table->foreignId('birth_location_id')->nullable()->constrained('locations'); $table->foreignId('death_location_id')->nullable()->constrained('locations'); $table->foreignId('father_id')->nullable()->constrained('people'); $table->foreignId('mother_id')->nullable()->constrained('people'); $table->foreignId('era_id')->nullable()->constrained(); $table->unsignedTinyInteger('certainty')->default(100); $table->text('notes')->nullable(); $table->timestamps();
});
Heads‑up: run migrations in FK order (locations → people) or temporarily comment foreign keys, migrate, then add them in a follow‑up migration.
Execute:
php artisan migrate
4. The Model Class
app/Models/People.php
class People extends Model
{ protected $fillable = [ 'name','title','alias','gender','date_of_birth','date_of_death', 'birth_location_id','death_location_id','father_id','mother_id', 'era_id','certainty','notes' ]; // Relationships public function birthLocation() { return $this->belongsTo(Location::class, 'birth_location_id'); } public function deathLocation() { return $this->belongsTo(Location::class, 'death_location_id'); } public function father() { return $this->belongsTo(People::class, 'father_id'); } public function mother() { return $this->belongsTo(People::class, 'mother_id'); } public function children() { return $this->hasMany(People::class, 'father_id'); } public function era() { return $this->belongsTo(Era::class); } public function events() { return $this->belongsToMany(Event::class); } public function references() { return $this->morphToMany(Reference::class, 'referenceable'); }
}
Grabbing Data (Tinker)
php artisan tinker
>>> People::where('alias','King Sol')->first()->events;
5. Factories & Seeders – Fake It Till You Make It
Generate 50 sample records:
// database/factories/PeopleFactory.php
public function definition(): array
{ return [ 'name' => $this->faker->name, 'title' => $this->faker->title, 'gender'=> $this->faker->randomElement(['Male','Female']), 'certainty' => rand(70,100), ];
}
// database/seeders/PeopleSeeder.php
public function run(): void
{ People::factory(50)->create();
}
Run:
php artisan db:seed --class=PeopleSeeder
6. Policies (Gate‑Keeping)
php artisan make:policy PeoplePolicy --model=People Define view, create, update, delete rules → Laravel auto‑resolves based on logged‑in user.
7. Controllers & Form Requests (CRUD Central)
php artisan make:controller PeopleController --resource --model=People
php artisan make:request StorePeopleRequest
php artisan make:request UpdatePeopleRequest
Inside PeopleController:
public function store(StorePeopleRequest $request)
{ $people = People::create($request->validated()); return redirect()->route('people.show', $people);
}
Add routes in routes/web.php:
Route::resource('people', PeopleController::class);
Boom, RESTful endpoints generated.
8. Up Next…
Front‑end time! In the next post we'll hook these endpoints to Inertia + React and render our first forms & tables.
Until then, may your migrations run forward and never need a --force rollback. ✌️
Tom signing off. Happy building, and remember: solid models make saintly apps.


