In building our forum the first thing we are going to need is a database to hold all of our threads, users, replies, and so on. In a prior lesson, we took the time to set up a nice installation of PhpMyAdmin using homestead so that we could easily create new databases. In addition we can drop databases, or edit data directly right in the GUI. We can create a new database named forumio to get going.
Make Laravel Connect To The Database
We need to update the .env file of course, so let’s go ahead and do that right away.
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=forumio DB_USERNAME=homestead DB_PASSWORD=secret
What Do We Want?
When beginning any project, a considerable amount of time has to be spent thinking about what you will need for various components of your application. To get started building this forum, we will need a few main ideas. In a sense, your thinking about your Models and how they will be represented. So for this we will have the following.
- Thread
- Reply
- User
- A Thread is created by a user
- A reply belongs to a thread, and belongs to a user
Make your first Model
We can now start building. Put your safety glasses on. The first thing we will do is to make a model named Thread. We will add the flags to also create a migration file and a resourceful controller. We do this like so:
vagrant@homestead:~/Code/forumio$ php artisan make:model Thread -mr Model created successfully. Created Migration: 2017_12_05_174156_create_threads_table Controller created successfully. vagrant@homestead:~/Code/forumio$
This step created 3 files for us. We now have a Model, a Controller, as well as a migration file.
Configure The Migration File
Let’s go ahead and edit the migration file so that it will create the fields we need to hold data in our forum.
<?php
use IlluminateSupportFacadesSchema;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;
class CreateThreadsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('threads', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('threads');
}
}
In the above snippet we add just a few things to the boilerplate. A thread can belong to a User, so we add the integer value of user_id to support that. A thread will also have a title and body where we use a string and text data type to hold this information.
With these pieces in place lets run php artisan migrate now.
vagrant@homestead:~/Code/forumio$ php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table Migrating: 2017_12_05_174156_create_threads_table Migrated: 2017_12_05_174156_create_threads_table
Make The Reply Model
We also need to make a model for the Reply with a migration and a controller.
vagrant@homestead:~/Code/forumio$ php artisan make:model Reply -mc Model created successfully. Created Migration: 2017_12_05_185134_create_replies_table Controller created successfully.
Let’s now update the migration for the replies table here. So we must ask what a reply will consist of. A reply is going to belong to a thread, and it will also belong to a user. As such we add a thread_id and user_id to this table. We also add a text field for the body of the reply. Those edits are seen here.
<?php
use IlluminateSupportFacadesSchema;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;
class CreateRepliesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('replies', function (Blueprint $table) {
$table->increments('id');
$table->integer('thread_id');
$table->integer('user_id');
$table->text('body');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('replies');
}
}
Go ahead and run that migration one more time.
vagrant@homestead:~/Code/forumio$ php artisan migrate Migrating: 2017_12_05_185134_create_replies_table Migrated: 2017_12_05_185134_create_replies_table vagrant@homestead:~/Code/forumio$
Creating a New Model Factory
In order to populate the database with some fake data to work with, we can make use of a Model Factory like so:
<?php
use FakerGenerator as Faker;
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/
$factory->define( AppUser::class, function ( Faker $faker ) {
static $password;
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt( 'secret' ),
'remember_token' => str_random( 10 ),
];
} );
$factory->define( AppThread::class, function ( $faker ) {
return [
'user_id' => function () {
return factory( 'AppUser' )->create()->id;
},
'title' => $faker->sentence,
'body' => $faker->paragraph
];
} );
What we do in the snippet above is to add a Thread factory to the standard User Factory that Laravel provides. Now, in the threads table, we know that it needs a user_id, a title, and a body. Therefore, we populate those options in this Thread factory as we see. With this in place, we can use Tinker to actually fire off the command to populate the database with some entries.
vagrant@homestead:~/Code/forumio$ php artisan tinker Psy Shell v0.8.15 (PHP 7.1.2-3+deb.sury.org~xenial+1 â cli) by Justin Hileman >>> factory('AppThread', 50)->create();
Once this command is run, we now have 50 random threads and also 50 random users seeded into the database.
50 Random Threads
50 Random Users
Oops! We still need to add replies to the database and we forgot that. No worries, go ahead and run php artisan migrate:refresh.
vagrant@homestead:~/Code/forumio$ php artisan migrate:refresh Rolling back: 2017_12_05_185134_create_replies_table Rolled back: 2017_12_05_185134_create_replies_table Rolling back: 2017_12_05_174156_create_threads_table Rolled back: 2017_12_05_174156_create_threads_table Rolling back: 2014_10_12_100000_create_password_resets_table Rolled back: 2014_10_12_100000_create_password_resets_table Rolling back: 2014_10_12_000000_create_users_table Rolled back: 2014_10_12_000000_create_users_table Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table Migrating: 2017_12_05_174156_create_threads_table Migrated: 2017_12_05_174156_create_threads_table Migrating: 2017_12_05_185134_create_replies_table Migrated: 2017_12_05_185134_create_replies_table
A Reply belongs to a User but also belongs to a Thread, so we can set this factory up as follows.
<?php
use FakerGenerator as Faker;
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/
$factory->define( AppUser::class, function ( Faker $faker ) {
static $password;
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt( 'secret' ),
'remember_token' => str_random( 10 ),
];
} );
$factory->define( AppThread::class, function ( $faker ) {
return [
'user_id' => function () {
return factory( 'AppUser' )->create()->id;
},
'title' => $faker->sentence,
'body' => $faker->paragraph
];
} );
$factory->define( AppReply::class, function ( $faker ) {
return [
'thread_id' => function () {
return factory( 'AppThread' )->create()->id;
},
'user_id' => function () {
return factory( 'AppUser' )->create()->id;
},
'body' => $faker->paragraph
];
} );
With our corrected model factory, let’s go ahead and populate the database via Tinker one more time.
vagrant@homestead:~/Code/forumio$ php artisan tinker Psy Shell v0.8.15 (PHP 7.1.2-3+deb.sury.org~xenial+1 â cli) by Justin Hileman >>> $threads = factory('AppThread', 50)->create(); >>> $threads->each(function ($thread) { factory('AppReply', 10)->create(['thread_id' => $thread->id]); });
This time around, we create our 50 threads and users as normal, but we store the result in a variable. From there we can filter through all the threads and create 10 replies to each thread. For each thread, we will create 10 different replies, and associate that reply with the current thread. Our threads and users tables are now populated, but we also now have the replies table populated as well as we see here now:
Setting Up A Database With Seeding Summary
This was a nice little tutorial that got us set up with the basics for our forum project. We created some models, set up our migration files, made some new model factories, and finally populated the database with the fake data we’ll need to keep building. Awesome!