Writing your first Laravel app - Part Three

Writing your first Laravel app - Part Three

Rai Omido

Howdy! It's Rai Here.

# Introduction

This lesson continues where part two left off. We are going to play with the database API for a little while before we proceed.

Now that we are familiar with the workings of the database in Laravel, let's try to use what we have learned to create something useful.

# Creating Blog Posts

The goal of this tutorial was to create a blog. Let's go ahead and create a few blog posts. But first, let's try to define the structure of our posts.

Laravel ships with the model, migrations, seeder, and the Factory for creating Users.

So on our part, we will, first of all, create post categories. Each category will have the following fields;

id
title

We will then create posts that will belong to a user and a category. It will have the following fields.

id
user_id
category_id
title
body
active
~Creating and writing migrations

As we mentioned earlier, apart from their own properties, our posts will also have a user (author) and a category. Since user migrations already exist, we only need to create migrations for the categories and posts respectively.

php artisan make:migration create_categories_table

php artisan make:migration create_posts_table

Writing our migrations

Go to database/migrations and open **create_categories_table.php.

Now, we need to add a few table columns. But before we do this, we need to revisit a few things about database column types. For instance, for the categories, we have;

  • id - Autoincrementing integer
  • title - String
  • active - Boolean

Good enough for us though, Laravel has supports most of the column types out of the box. The full list can be found on the official Laravel documentation. So, our categories migration file will be as follows;

...

public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->boolean('active')->default(false);
$table->timestamps();
});
}

...

Similarly, create the posts migration and update it as follows;

...

public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->foreignId('category_id')->constrained()->cascadeOnDelete();
$table->string('title');
$table->text('body');
$table->boolean('active')->nullable();
$table->timestamps();
});
}

...

As you may have noted, Laravel makes it easy to handle foreign keys in a less verbose manner. This greatly improves our developer experience.

~Creating and writing Factories

Factories will help us to add some users, posts, and categories to the database.

To create a factory, we do;

php artisan make:factory CategoryFactory --model=Category

php artisan make:factory PostFactory --model=Post

This creates the CategoryFactory and PostFactory is the database/factories directory.

The --model option allows us to specify a model to be created by the factory. The model will also be pre-filled in the Factory.

After creating the above two factories, it time we define some data. For instance, our CategoryFactory should look like so;

<?php

namespace Database\Factories;

use App\Models\Category;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class CategoryFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Category::class;

/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'title' => $this->faker->sentense(2, true),
'active' => true,
];
}
}

Before you proceed further, please check the app/Models directory to see if the Category and Post models were created. If not, go ahead and create them.

php artisan make:model Category

php artisan make:model Post

You may have noted the faker property. Laravel factories use the Faker PHP library to generate random data for testing.

Likewise, the PostFactory factory could be like so;

<?php

namespace Database\Factories;

use App\Models\Category;
use App\Models\Post;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class PostFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = Post::class;

/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'title' => $this->faker->sentence(6),
'user_id' => $this->faker->randomElement(User::pluck('id')->toArray()),
'category_id' => $this->faker->randomElement(Category::pluck('id')->toArray()),
'body' => $this->faker->paragraph(),
'active' => true,
];
}
}

The User::pluck('id')->toArray() returns an array of user ids from which Faker picks one at random and assigns it as the value for the user_id element. If you'd like to learn more about Eloquent methods, you can read more in the Laravel Documentation.

~Creating and writing Seeders

Whereas Factories define our data, Seeders are responsible for storing the data in the database.

To create seeders, we use the make:seeder artisan command.

php artisan make:seeder UserSeeder
php artisan make:seeder CategorySeeder
php artisan make:seeder PostSeeder

Writing Seeders

The UserSeeder may look like;

<?php

namespace Database\Seeders;

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

class UserSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
User::factory()->times(10)->create();
}
}

The CategorySeeder may look like;

<?php

namespace Database\Seeders;

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

class CategorySeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Category::factory()->times(4)->create();
}
}

The PostSeeder class may look like below;

<?php

namespace Database\Seeders;

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

class PostSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Post::factory()->times(10)->create();
}
}
~Calling and Running Seeders

After creating our seeders, we need to regenerate composer's autoloader using the dump-autoload command.

composer dump-autoload

Next up, we need to call our newly created seeders in the database/seeders/DatabaseSeeder.php file.

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$this->call([
UserSeeder::class,
CategorySeeder::class,
PostSeeder::class,
]);
}
}

The order is very key. You must start with the UserSeeder or CategorySeeder, followed by the PostSeeder. This is because each post has a user_id and a category_id which are references to the users and categories tables respectively. Therefore, records must be present in the users and categories tables before we attempt to create post records.

Before we proceed to run our seeders, we need to ensure our tables are created in the database. Let's go ahead and run our migrations first.

php artisan migrate

This should produce the following output;

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (42.12ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (38.63ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (40.55ms)
Migrating: 2020_09_12_182949_create_categories_table
Migrated:  2020_09_12_182949_create_categories_table (17.95ms)
Migrating: 2020_09_12_185521_create_posts_table
Migrated:  2020_09_12_185521_create_posts_table (161.16ms)

Now, let us run the seeders.

php artisan db:seed

This should produce an output as shown below;

Seeding: Database\Seeders\UserSeeder
Seeded:  Database\Seeders\UserSeeder (120.02ms)
Seeding: Database\Seeders\CategorySeeder
Seeded:  Database\Seeders\CategorySeeder (28.08ms)
Seeding: Database\Seeders\PostSeeder
Seeded:  Database\Seeders\PostSeeder (117.68ms)
Database seeding completed successfully.
~Playing with our newly created records

Laravel ships with a powerful REPL called Tinker. We are going to utilize this to print out results from our database just to see our data.

The first step is to start Tinker.

php artisan tinker

This should start the Tinker shell like so;

C:\xampp\htdocs\blog>php artisan tinker
Psy Shell v0.10.4 (PHP 7.4.9 — cli) by Justin Hileman
>>> 

Let's now try to dump a few results in our shell;

>>> User::take(2)->get()
[!] Aliasing 'User' to 'App\Models\User' for this Tinker session.
=> Illuminate\Database\Eloquent\Collection {#3905
     all: [
       App\Models\User {#3907
         id: 1,
         name: "Jarod Boyle",
         email: "keenan.gottlieb@example.org",
         email_verified_at: "2020-09-12 20:42:26",
         created_at: "2020-09-12 20:42:27",
         updated_at: "2020-09-12 20:42:27",
       },
       App\Models\User {#3906
         id: 2,
         name: "Erin Kub",
         email: "colby.homenick@example.org",
         email_verified_at: "2020-09-12 20:42:26",
         created_at: "2020-09-12 20:42:27",
         updated_at: "2020-09-12 20:42:27",
       },
     ],
   }
>>> User::count()
=> 10
>>> Category::take(2)->get()
[!] Aliasing 'Category' to 'App\Models\Category' for this Tinker session.
=> Illuminate\Database\Eloquent\Collection {#3973
     all: [
       App\Models\Category {#3183
         id: 1,
         title: "Quam ut.",
         active: 1,
         created_at: "2020-09-12 20:42:27",
         updated_at: "2020-09-12 20:42:27",
       },
       App\Models\Category {#4116
         id: 2,
         title: "Magni aut.",
         active: 1,
         created_at: "2020-09-12 20:42:27",
         updated_at: "2020-09-12 20:42:27",
       },
     ],
   }
>>> Category::count()
=> 4
>>> Post::take(2)->get()
[!] Aliasing 'Post' to 'App\Models\Post' for this Tinker session.
=> Illuminate\Database\Eloquent\Collection {#4063
     all: [
       App\Models\Post {#3184
         id: 1,
         user_id: 6,
         category_id: 4,
         title: "Delectus quos quos totam veritatis.",
       body: "Dolorum et expedita odit ipsum consectetur",
         active: 1,
         created_at: "2020-09-12 20:42:27",
         updated_at: "2020-09-12 20:42:27",
       },
       App\Models\Post {#3179
         id: 2,
         user_id: 6,
         category_id: 3,
         title: "Aut sunt totam qui ut adipisci voluptatum.",
       body: "Reprehenderit recusandae rerum fugit ...",
         active: 1,
         created_at: "2020-09-12 20:42:27",
         updated_at: "2020-09-12 20:42:27",
       },
     ],
   }
>>> Post::count()
=> 10
>>>

Yebo!

# Conclusion

Our next task is to run through Laravel's Eloquent ORM, to see how we can leverage this powerful tool to manage our data better. You may proceed to lesson four.