Categories: Laravel

Create Your First Laravel Project Step-By-Step Guide

Share your learning

This tutorial will help you to create your first Laravel project from scratch. I will try to serve the best Laravel tutorials for beginners.

I assume that you have basic knowledge of the following:

  • HTML
  • CSS
  • jQuery
  • PHP
  • MySQL
  • Basic of MVC (Model, View and Controller)

In this tutorial, I will show you how to develop a CRUD Laravel app. You can also clone this project, the link is given below at the end of this tutorial.

After this tutorial you will be able to create your first Laravel project.

To start with this tutorial, first we need to describe our goals.

What we are going to build?

I will go with simple progress tracking app in which we will record the tasks and track their status.

This is a simple Laravel application for learning the purpose, you can extend its features if you want. Basic features of this project

  • List the Tasks
  • Add the Task
  • Update the Task
  • Remove the Task

How it will look?

The best approach to proceed with a project is to break the process into small steps.

The process to complete this project

  1. Laravel installation
  2. Migration
  3. Model
  4. Controller
  5. List View file
  6. New task form
  7. Update task form
  8. Routes

Let’s Roll-out!!

Laravel installation

Here I am using XAMPP v3.2.3 in which PHP 7.3.3, But you can also use less at least PHP 7.1 for Laravel 5.8.

Read about laravel installation

Make migration

Run the following command to make migration:

php artisan make:migration create_tasks_table –path=/database/migrations/task
or 
php artisan make:migration create_tasks_table

I always prefer to work with sub-directories inside migrations directory because it helps me to separate all migrations, to achieve this use –path flag.

But you can also go ahead without this approach, means you can create all migrations under the single migrations directory.

Now run the below command to migrate this migration:

php artisan migrate –path=/database/migrations/task
or
php artisan migrate

Make a Model

It’s time to make a model so that we can communicate with the database. Run the following command:

php artisan make:model model/Task

Make a Controller

Now make a Controller. As the name suggests, the controller used to control the process of the application. Run the following command to make controller:

php artisan make:controller Task/TaskController

Create View Files

To create view file, I am going to use following items:

  • Bootstrap 4 used to create flexible and responsive UI.
  • SweetAlerts js plugin used to create confirmation popups like ask for confirmation before removing the task from the list.
  • DataTable js plugin used to create responsive and well-managed tables in which we will have following premade features like:
    • Pagination
    • Record per page
    • Search
    • Sort
    • Count records
  • FontAwesome CSS file used to add icons to the app like edit and remove the task.

Layout

To start with the front end, let’s create a layout first. Go to resources/views and create a folder something like Layout. Then create the following files inside this folder.

  • Header.blade.php
  • Footer.blade.php
  • Navbar.blade.php
  • Main.blade.php

We do not have any sidebar in this project; otherwise, I have to make sidebar.blade.php

Ok, so now add all the CSS files in the header.blade.php file and all script files in footer.blade.php like this:

Header.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>TaskHandler | Dashboard</title>
  <meta content="width=device-width, initial-scale=1.0" name="viewport">
  <meta content="" name="keywords">
  <meta content="" name="description">

  <!-- Favicons -->
  <link href="img/favicon.png" rel="icon">
  <link href="img/apple-touch-icon.png" rel="apple-touch-icon">

  <!-- Google Fonts -->
  <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,500,600,700,700i|Montserrat:300,400,500,600,700" rel="stylesheet">

  <!-- Bootstrap CSS File -->
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
  <link rel="stylesheet" href="{{ URL('/public/assets') }}/font-awesome/css/font-awesome.min.css" />
  <link rel="stylesheet" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" /> 
</head>

<body>

Footer.blade.php
<footer id="footer" class="bg-light text-center mt-5">
    <div class="container">
      <div class="copyright">
            © Copyright <strong>TaskHandler</strong>. All Rights Reserved
      </div>
      <div class="credits">
        Designed by <a href="https://sbsharma.com/">www.sbsharma.com</a>
      </div>
    </div>
</footer><!-- #footer -->

  <a href="#" class="back-to-top"><i class="fa fa-chevron-up"></i></a>
  <!-- Uncomment below i you want to use a preloader -->
  <!-- <div id="preloader"></div> -->

  <!-- JavaScript Libraries -->
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  <script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
  <script src="{{ URL('/public/assets/js') }}/taskApp.js"></script>
  <script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
</body>
</html>
Navbar.blade.php
<!--==========================
  Header
  ============================-->

  <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo03" aria-controls="navbarTogglerDemo03" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <a class="navbar-brand" href="{{ route('tasks.list') }}">Task<span class="text-success">Handler</span></a>

  <div class="collapse navbar-collapse" id="navbarTogglerDemo03">
    <ul class="navbar-nav mr-auto mt-2 mt-lg-0">
      <li class="nav-item active">
        <a class="nav-link" href="{{ route('tasks.list') }}">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item active">
        <a class="nav-link" href="{{ route('tasks.add-form') }}">New Task</a>
      </li>
      
    </ul>
    <form class="form-inline my-2 my-lg-0">
      <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" table-search="tasksList">
      <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
    </form>
  </div>
</nav>
Main.blade.php
@include('layout.header')
@include('layout.navbar')



@yield('content')



@include('layout.footer')

Task Views

After creating the layout files, create a folder /tasks inside the resources/views directory and add these two files:

  • List.blade.php
  • Form.blade.php

Here we are going to use list.blade.php file to show the table of tasks and form.blade.php file to create and update task.

Here we can use a common file to show success and error sessions across the pages.

Success and error Sessions

So, create the folder components inside resources/view directory and create the file success_error_sessions.php, now paste the below code:

@if (session('success'))
<div class="alert alert-success">
  {{ session('success') }}
</div>
@endif
@if (session('error'))
<div class="alert alert-danger">
  {{ session('error') }}
</div>
@endif

Let’s start with list.blade.php and put the below code

list.blade.php
@extends('layout.main')

@section('content')
@include('components.success_error_sessions')
@php
    $i = 1;
@endphp
<div class="container-fluid">
    <div class="card mt-5">
        <div class="card-header text-white bg-info">
            List of Tasks
        </div>
        <div class="card-body">
            <table class="table table-striped table-bordered table-hover table-checkable" id="tasksList">
                <thead>
                    <tr>
                        <th class="col-1"> ID </th>
                        <th class="col-1">Task Number</th>
                        <th class="col-1"> Subject</th>
                        <th class="col-2"> Description </th>
                        <th class="col-2"> Start </th>
                        <th class="col-2"> End </th>
                        <th class="col-1"> Status </th>
                        <th class="col-2"> Action </th>
                    </tr>
                </thead>
                <tbody>
                    @foreach($tasks as $task) 
                    <tr>
                    <td>{{  $i++ }}</td>
                    <td class="text-uppercase">{{ $task->task_number }}</td>
                    <td>{{$task->title}}</td>
                    <td>{{$task->description}}</td>
                    <td> {{ $task->created_at }} </td>
                    
                    <td> @if($task->status == 'start') continue... @else  {{ $task->updated_at }} @endif</td>
                    
                    <td><span class="badge badge-primary">{{$task->status}}</span></td>
                    <td>
                        <a href="{{ route('tasks.update-form', ['id'=>$task->id]) }}" class="btn btn-info btn-sm" title="Update">
                         <i class="fa fa-edit"></i> Update
                        </a>
                        <a href="{{ route('tasks.delete', ['id'=>$task->id]) }}" class="btn btn-danger btn-sm" remove-btn title="Remove">
                         <i class="fa fa-trash"></i> Remove
                        </a>
                    </td>
                    </tr>
                    @endforeach
                </tbody>
            </table>
        </div>
    </div>
</div>
@endsection

Here you can see how we extend the main layout file in which all other files included like header footer and navbar.

The @section(‘content’) provide the content for the main blade file. The content inside the section will use by @yeild(‘content’) in the main blade file. we need to call the dataTable plugin with table ID. For this, I have already added a taskApp.js script file in the footer.blade.php file. So, create a taskApp.js file inside the public/js directory then open it and paste the below code

$(document).ready( function () {
    $('#tasksList').DataTable();
});

Along with this, add sweet alert like this:

How to use Sweet Alerts?
deleteItem('[remove-btn]');

function deleteItem(item){
    $(item).click(function(e){
        e.preventDefault();
        var path = $(this).attr('href');
        SweetDeleteConfirm(path);
    });
  }
  
  
  function SweetDeleteConfirm(url) {
    swal({
        title: "Are you sure?",
        text: "You will not be able to recover!",
        icon: "warning",
        buttons: true,
        dangerMode: true,
      })
      .then((deleteConfirm) => {
        if(deleteConfirm) {
            swal({
                title: "Deleted!",
                text: "It has been deleted!",
                type: "success",
                confirmButtonText: "OK"
            })
            .then((isConfirm) => {
                if (isConfirm) {
                    window.location = url;
                }
            });
        } else {
            swal("Your record is safe!");
        }
    });
  }
Form.blade.php

Now open the form.blade.php file and paste below code, this form will be used to create and update the task.

@extends('layout.main')

@section('content')

@include('components.success_error_sessions')

@php
$task = isset($task) ? $task : [];
    function getValue($task, $form_type, $action) {
        switch($action) {
            case 'action':
            echo $form_type == 'new' ? route('tasks.insert') : route('tasks.update');
            break;

            case 'title':
            echo $form_type == 'new' ? '' : 'value="'.$task->title.'"';
            break; 

            case 'description':
            echo $form_type == 'new' ? '' : $task->description;
            break;

            case 'status-start':
            echo $form_type == 'new' ? '' : ($task->status == 'start' ? 'selected="selected"' : '');
            break;

            case 'status-complete':
            echo $form_type == 'new' ? '' : ($task->status == 'complete' ? 'selected="selected"' : '');
            break;

            case 'status-incomplete':
            echo $form_type == 'new' ? '' : ($task->status == 'incomplete' ? 'selected="selected"' : '');
            break;
            
            case 'submit-btn':
            echo $form_type == 'new' ? 'Add to list' : 'Update Task';
            break;
        }
    }
@endphp



<div class="container">
    <div class="card mt-5">
        <div class="card-header text-white bg-info">
            @if($form_type == 'new') Add New @else Edit @endif Task
        </div>
        <form class="p-5" action="{{ getValue($task, $form_type, 'action') }}" method="POST" enctype="multipart/form-data">
            {{ csrf_field() }}
            @if($form_type == 'edit') <input type="hidden" name="id" value="{{ $task->id }}"/> @endif
            <div class="form-group">
                <label for="title">Title</label>
                <input name="title" type="text" class="form-control" id="title" aria-describedby="titleHelp" placeholder="Enter topic of task" {{ getValue($task, $form_type, 'title') }}>
                <small id="titleHelp" class="form-text text-muted">Example: Reading, Shopping, Playing game, Eating etc.</small>
            </div>
            <div class="form-group">
                <label for="desc">Description</label>
                <textarea name="description" type="text" class="form-control" id="desc"  aria-describedby="detailsHelp" placeholder="Type something more about the task">{{ getValue($task, $form_type, 'description') }}</textarea>
                <small id="detailsHelp" class="form-text text-muted">Example: I am start reading Alchemist Book from page-19</small>
            </div>
            <div class="form-group">
                <select name="status" class="form-control">
                    <option value="start" {{ getValue($task, $form_type, 'status-start') }}>Start</option>
                    <option value="complete" {{ getValue($task, $form_type, 'status-complete') }}>Complete</option>
                    <option value="incomplete" {{ getValue($task, $form_type, 'status-incomplete') }}>Incomplete</option>
                </select>
            </div>
            <button type="submit" class="btn btn-info">{{ getValue($task, $form_type, 'submit-btn') }}</button>
        </form>
    </div>
</div>
@endsection

Make Routes

Now let’s open a route file routes/web.php 

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', 'Task\TaskController@index')->name('tasks.list');
Route::get('tasks/add', 'Task\TaskController@addTaskForm')->name('tasks.add-form');
Route::get('tasks/update/{id}', 'Task\TaskController@updateTaskForm')->name('tasks.update-form');
Route::post('tasks/update/', 'Task\TaskController@updateTask')->name('tasks.update');
Route::post('tasks/insert', 'Task\TaskController@addTask')->name('tasks.insert');
Route::get('tasks/delete/{id}', 'Task\TaskController@deleteTask')->name('tasks.delete');

Task Controller

Now go to App/http/controller/task/TaskController.php

<?php

namespace App\Http\Controllers\Task;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;

use App\model\task;

class TaskController extends Controller
{
    public function __construct() {

    }
    public function index() {
        $data['tasks'] = $this->listTasks();
        return view('tasks.list', $data);
    }
    public function addTaskForm() {
        $data['form_type'] = 'new'; 
        return view('tasks.form', $data);
    }
    public function updateTaskForm($id) {
        $data['form_type'] = 'edit';
        $data['task'] = task::find($id);
        
        return view('tasks.form', $data);
    }
    public function addTask(Request $request) {
        $data = $request->all();
        $validator = Validator::make($data, [
            'title' => 'required|max:100',
            'description'=>'required|max:250'
        ]);
   
        if ($validator->fails()) {
            return back()->with('error', $validator->messages()->first());
        }
        $data['task_number'] = Str::random(16);

        if(task::create($data)){    
            $list['tasks'] = $this->listTasks();
            return redirect('/')->with('success', 'successfully added new task');
        } 
        return back()->with('error', 'Something went wrong!!');
    }
    public function updateTask(Request $request) {
        $data = $request->all();
        $validator = Validator::make($data, [
            'title' => 'required|max:100',
            'description'=>'required|max:250'
        ]);
   
        if ($validator->fails()) {
            return back()->with('error', $validator->messages()->first());
        }
        if(task::find($data['id'])->update($data)){
            $list['tasks'] = $this->listTasks();
            return redirect('/')->with('success', 'successfully updated task');
        }
        return back()->with('error', 'Something went wrong!!');
    }
    public function deleteTask($id){
        if(task::destroy($id)){
            return back()->with('success', 'Successfully delete task');
        }
        return back()->with('error', 'Something went wrong!!');
    }
    private function listTasks() {
        return task::all();
    }
    
}

Get source code

Satpal

Recent Posts

How to Switch PHP Versions in XAMPP Easily: Managing Multiple PHP Versions on Ubuntu

Today we are going to learn about managing multiple PHP versions on ubuntu with xampp.…

1 year ago

How to Use Coding to Improve Your Website’s SEO Ranking?

Let's understand about how to use coding to improve your website's SEO. In today’s computerized…

1 year ago

Most Important Linux Commands for Web Developers

Let's understand the most important linux commands for web developers. Linux, as an open-source and…

1 year ago

Top 75+ Laravel Interview Questions Asked by Top MNCs

Today we are going to discuss top 75+ Laravel interview questions asked by top MNCs.Laravel,…

1 year ago

Mailtrap Integration for Email Testing with Laravel 10

Today we will discuss about the Mailtrap integration with laravel 10 .Sending and receiving emails…

1 year ago

Firebase Cloud Messaging (FCM) with Ionic 6: Push Notifications

Today we are going to integrate FCM (Firebase Cloud Messaging) push notifications with ionic application.Firebase…

1 year ago