Create Your First Laravel Project Step-By-Step Guide
This tutorial will help you to create your first Laravel project from scratch. I will try to serve t
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
- Laravel installation
- Migration
- Model
- Controller
- List View file
- New task form
- Update task form
- 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, t
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
- 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
<!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(); } }