Laravel Tutorial #5: Create the Home Page

Please note that this post may contain affiliate links, and for every purchase you make, at no extra cost to you, a commission fee will be rewarded to me.

Now, it’s time for us to dive into our project. To get familiar with everything, we start by creating only the home page. If you are using Voyager as your admin panel, read through this article, but it’s not necessary to apply anything. Because Voyager has a built-in section for basic site information. We’ll talk about Voyager in the next article.

Create the First Model

First, we create a model named General and corresponding migration file to store basic information about our website.

php artisan make:model General -m

Open the migration file we just created. This is where we define the structure of our database.

database/migrations/2020_10_03_162023_create_generals_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateGeneralsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('generals', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
        });
    }

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

The public function up() creates a database table named generals, and the public function down() drops the database table named generals if it already exists.

Line 17 – 18, these commands create columns inside the database table, and there are lots of other column types available in Laravel. Check out the official documentation.

Now, we can create some other columns for this table.

Schema::create('generals', function (Blueprint $table) {
    $table->id();
    $table->char('website_title', 200);
    $table->string('logo');
    $table->text('description')->nullable();
    $table->timestamps();
});

Line 3, this column stores the title for our website, and the maximum length is set to be 200.

Line 4, this column stores the logo which we’ll upload later. It might seem strange for beginners. The database doesn’t actually store the image you upload, but instead, it stores the path which points to the image you uploaded, so it should be a string type.

And in line 5, you might notice there is something else attached at the end. This is called a column modifier, and it defines extra information about the column. In this case, it makes this description column to be nullable.

Now, we can make some changes to our model.

app/Models/General.php

class General extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'website_title', 'logo', 'description'
    ];
}

We can also define the corresponding database table here. If not defined, Laravel will just look for the database table whose name is the plural form of the model. If you choose to use a different database table, specify it here like this:

protected $table = 'my_table';

Setup Laravel Nova

Next, we can setup Laravel Nova for the General model. Create a new resource:

php artisan nova:resource General

Import some necessary field packages.

use Illuminate\Http\Request;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Fields\Textarea;
use Laravel\Nova\Fields\Image;
use Laravel\Nova\Http\Requests\NovaRequest;

Like we talked about before, Laravel 8 has a new, independent folder for models, so we need to reflect it here, or Nova won’t be able to find it.

    /**
     * The model the resource corresponds to.
     *
     * @var string
     */
    public static $model = \App\Models\General::class;

Change $title into website_title:

    /**
     * The single value that should be used to represent the resource when being displayed.
     *
     * @var string
     */
    public static $title = 'website_title';

And finally, define the fields:

    /**
     * Get the fields displayed by the resource.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return array
     */
    public function fields(Request $request)
    {
        return [
            ID::make(__('ID'), 'id')->sortable(),
            Text::make('Website Title'),
            Image::make('Logo'),
            Textarea::make('Description'),
        ];
    }

Nova will “snake case” the displayable name of the field to determine the underlying database column. However, if necessary, you may pass the column name as the second argument to the field’s make method:

Text::make('Name', 'name_column'),

Now, it’s time to fill out the basic information about our website.

Create the Index Controller

Generate IndexController using the artisan command:

php artisan make:controller IndexController

Create a index() method:

app/Http/Controllers/IndexController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\General;

class IndexController extends Controller
{
    public function index()
    {
        $website = General::query()->first();

        return view('home', [
            'website' => $website
        ]);
    }
}

First, we imported the General model which we need to use in this controller. Inside the index() method, we retrieve the first record in General which we just created. And finally, we return it to the home view which we’ll talk about later.

Routing

This part should be easy, so I won’t go into details.

Route::get('/', [IndexController::class, 'index']);

Create the Home View

To make our website look better, we’ll use Bootstrap here. I assume you are already familiar with CSS and HTML:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="Eric Hu">
    <title>{{$website['website_title']}}</title>

    <!-- Bootstrap core CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
          integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
</head>
<body style="padding-top: 5rem;">
<nav class="navbar navbar-expand-md navbar-light bg-light fixed-top">
    <div class="container">
        <a class="navbar-brand" href="#">
            <img src="{{\Illuminate\Support\Facades\Storage::url($website['logo'])}}" style="max-height: 50px">
            {{$website['website_title']}}
        </a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault"
                aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="navbarsExampleDefault">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item">
                    <a class="nav-link" href="/">Home</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Link</a>
                </li>
            </ul>
            <form class="form-inline my-2 my-lg-0">
                <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
                <button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
            </form>
        </div>
    </div>
</nav>

<main role="main" class="container">

    <div style="padding: 3rem 1.5rem;">
        <h1>Homepage</h1>
        <p>{{$website['description']}}</p>
    </div>

</main><!-- /.container -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"
        integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN"
        crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"
        integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV"
        crossorigin="anonymous"></script>
</body>
</html>

The view is also pretty straightforward. A different syntax, {{$website->website_title}}, which I used in the previous version of this tutorial is also going to work here.

Another thing worth mentioning is in line 19. This is how we can display an image uploaded by the user. Details about file storage are here: https://laravel.com/docs/8.x/filesystem#file-urls

Open your browser and go to http://localhost/

In the next two articles, we will build the core components of our project. Starting from creating models and setting up the admin panel.

Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *