You are on page 1of 113

Table of Contents

1. Getting Started ............................................................................. 8


Setting up a Local Dev Environment ............................................. 8
Composer & The Laravel Installer ............................................... 10
The Laravel Folder Structure ....................................................... 14

2. Routing ........................................................................................ 18
Routing overview ......................................................................... 18
Routing in Laravel ....................................................................... 19
Quick Routing example ............................................................... 21
Route Closures vs Route Controller Actions ................................ 22
Route Parameters ........................................................................ 23

3. Models .......................................................................................... 25
What Are Models? ........................................................................ 25
Eloquent: The Laravel ORM ......................................................... 26

4. Model Relationships .................................................................. 33


Model Relationships ..................................................................... 33

5. Mutators and Accessors ............................................................ 40


Understanding Mutators and Accessors ...................................... 40

6. Views ............................................................................................ 44
Understanding Views ................................................................... 44

7. Blade ............................................................................................ 48
Blade Templating ........................................................................ 48

8. Controllers ................................................................................... 52
Understanding Controllers ........................................................... 52

9. Piecing It Together .................................................................... 56


Piecing It Together ...................................................................... 56

10. Artisan ....................................................................................... 61


Introducing Artisan ...................................................................... 61

11. Middleware ............................................................................... 65


Understanding Middleware .......................................................... 65
Web Middleware .......................................................................... 68
Nesting and Using Multiple Middleware ....................................... 69
Route-Specific Middleware .......................................................... 69
Controller Middleware ................................................................. 69

12. Authentication .......................................................................... 72


Authentication with Laravel Breeze ............................................. 72
1. Setting Up a New Laravel Application: .................................... 72
2. Integrating Laravel Breeze: ..................................................... 72
3. Database Configuration: .......................................................... 73
4. Exploring Authentication: ........................................................ 73
5. Crafting a User Profile: ............................................................ 74
6. Wrapping Up: .......................................................................... 75

13. Requests .................................................................................... 77


Requests ..................................................................................... 77
14. Responses ................................................................................. 82
Responses ................................................................................... 82

15. Migrations ................................................................................. 87


Migrations .................................................................................... 87

16. Seeds ......................................................................................... 94


Seeds & Seeders ......................................................................... 94

17. Security ..................................................................................... 99


Security ....................................................................................... 99

18. Testing ..................................................................................... 104


Testing ...................................................................................... 104

19. Wrapping Up ........................................................................... 111


Wrapping Up .............................................................................. 111
Resources .................................................................................. 111
Words of Encouragement .......................................................... 112
A New Reality ............................................................................ 112
5
Why This Book? Actually, it's not quite a book; it's more of a guide—a
guide to prevent you and others from becoming "zombie developers".

What exactly is a 'zombie developer'? It's a developer, much like us,


who finds themselves mindlessly hacking away on PHP apps, repeating
the same tasks over and over. These repetitive tasks can be incredibly
draining and eventually turn one's brain into mushy goo. When this
happens, developers everywhere transform into mindless zombies with
a thirst for blood and an urge to kill.

However, there's a remedy: the Laravel framework, designed for rapid


application development. By embracing Laravel, you can rediscover
your passion for coding and fend off the "zombie" within. This guide
aims to preserve your sanity, making coding enjoyable once more. And
yes, it might just save lives!

By mastering the basics of Laravel, you can save yourself, and possibly
others, from becoming a mindless zombie developer.

Don't let the inner zombie thrive; keep close the Laravel survival guide.

6
7
1. Getting Started

In this first chapter, we'll explore:

Setting up a Local Dev Environment


Composer & The Laravel Installer
The Laravel Folder Structure

Let's do this!

Setting up a Local Dev Environment

Being aware of one's environment is the key to surviving the zombie


developer apocalypse. To craft exceptional web applications, we first
need to master setting up a local developer environment.

A local environment, often dubbed the "development environment," is


when you develop your web app on your personal computer. Once
you're ready to unveil your creation to the world, you will move your
code to another server, commonly known as the "production
environment".

Below are the instructions on how to add a local environment on your


machine.

Local Development on a Mac

If you are a Mac user it will be scary easy to setup a local development
environment on your machine. Laravel now offers a native application
called Herd. Simply download the application here, install it, and you're
ready to start building.

For Mac users, setting up a local development environment is a breeze.


Laravel introduces a native application called Herd. Simply download

8
the application at https://herd.laravel.com, install, and you're ready to
start building.

Local Development on Windows

The easiest solution on a Windows machine is to use Laragon, a


longtime community favorite. However, there are several other
alternatives worth considering:

https://www.mamp.info/en/
http://www.wampserver.com/en/
https://www.apachefriends.org/

Local Development on Ubuntu

If you are on an Ubuntu machine you can use Xampp, or you may
choose to install all the applications individually. You can learn more
about how to do that from this article here.

To explore other methods of setting up a local environment, refer to the


Laravel installation documentation, there you will find many other
options that may suit your use-case.

It's important to understand the three essential services that are


needed to run a typical local environment:

1. Apache or Nginx (the web server for your application)


2. MySQL (the database for your application)
3. PHP (the server-side scripting language for your application)

Once these services are in place on your machine, you're all set! At the
end of the day there is no right or wrong way to setup a local dev
environment. Find a way that works best for you and you'll be on the
road to creating some killer web applications in no time!

9
Composer & The Laravel Installer

Laravel leverages Composer to manage its external libraries or


packages. Your application's dependencies are defined inside of a file
called composer.json.

Composer

If you're new to the concept of Composer and its functionalities, don't


worry. Let's simplify it with a fun analogy.

Understanding Composer with a Pizza Analogy

Think of Composer as a pizza-making command. If you were to order a


pizza using a command, it might look something like this:

$ composer make pizza

By default, this command gives us a pepperoni pizza. But what if we


wanted a different type of pizza, say, a meat-lovers pizza? We'd specify
our desired toppings like this:

10
{
"toppings" : [
"pepperoni", "ham", "bacon", "beef", "sausage"
]
}

To customize our pizza order, we save this list in a file named


'composer.json' in our current directory. Running the command again:

$ composer make pizza

Voilà! Instead of the default pepperoni pizza, we now have our meat-
lovers pizza!

Composer, in essence, helps manage the components (or toppings)


required to build our applications.

Composer will already be installed if you used Herd or Laragon;


however, if you need to install it manually you can do so by visiting
https://getcomposer.org/download/

The Laravel Installer

The Laravel installer is a tool that allows developers to quickly scaffold


a new Laravel project from the command line. To create a new Laravel
project using the Laravel installer you can run:

laravel new project-name

Replace project-name with the desired name for your new project. This
command will create a directory with the given name and install a fresh
Laravel application inside it.

11
Installing the Laravel Installer

If you've already installed Herd or Laragon, skip this step.

After setting up Composer, it's time to integrate the Laravel Installer.


Execute the following command:

$ composer global require "laravel/installer"

Using the Laravel Installer

To use the Laravel installer, open up a command prompt and type the
following command:

$ laravel new folder_name

When you run this command you'll encounter several prompts; choose
No starter kit, PHPUnit, and No respectively. Also, when asked about
the database, opt for MySQL.

12
_ _
| | | |
| | __ _ _ __ __ ___ _____| |
| | / _` | '__/ _` \ \ / / _ \ |
| |___| (_| | | | (_| |\ V / __/ |
|______\__,_|_| \__,_| \_/ \___|_|

┌ Would you like to install a starter kit? ────────────┐


│ No starter kit │
└──────────────────────────────────────────────────────┘

┌ Which testing framework do you prefer? ──────────────┐


│ PHPUnit │
└──────────────────────────────────────────────────────┘

┌ Would you like to initialize a Git repository? ──────┐


│ ○ Yes / ● No │
└──────────────────────────────────────────────────────┘

┌ Which database will your application use? ───────────┐


│ › ● MySQL │
│ ○ PostgreSQL │
│ ○ SQLite │
│ ○ SQL Server │
└──────────────────────────────────────────────────────┘

You'll now have a new application in the folder_name you specified.


Navigate to this folder using cd folder_name, then launch:

$ php artisan serve

This fires up a local server at http://localhost:8000/. Accessing this URL


displays Laravel's welcome screen.

Note: If you're using Laravel Herd, your new Laravel apps will use the
.test domain. For instance, https://folder_name.test will present the
welcome page.

13
Congrats! You're now ready to start building amazing applications. The
ease of Laravel ensures you can resurrect a new project in mere
moments.

Before we dive into the code let's briefly get acquainted with Laravel's
folder structure.

The Laravel Folder Structure

In a new laravel project you will have the following code structure:

You'll encounter 10 directories:

1. app
2. bootstrap
3. config
4. database
5. public

14
6. resources
7. routes
8. storage
9. tests
10. vendor

We will not go into full detail with all the files; however, it's important to
have a brief understanding of each folder.

App

This is the directory that has all our application logic. In this folder, we
will put all our models, controllers, services, and many other classes.

Bootstrap

This folder is used to bootstrap laravel (startup laravel).

Config

This file will contain many of our global configurations for our
application.

Database

This folder contains our database files such as migrations and seeds.

Public

This public folder contains many of the applications assets such as


images, stylesheets, and scripts.

Resources

We will put our view files in this folder. The views are the pages that a
user sees.

15
Routes

This folder contains all the routes for our application.

Storage

Laravel uses this folder to store sessions, caches, and logs in this folder.

Test

This folder contains files that we use to test the logic of our application.

Vendor

This is the folder that contains our dependencies. When you add new
libraries (toppings) to your app, this is the folder that will contain those
libraries.

Do you recognize the composer.json file from the image above?


Remember this is where we define our dependencies (pizza toppings)
for our app. Another important file is .env, which contains all our
environment variables like debug mode and database credentials.

That's the basic structure of a Laravel application. It will all start


becoming more familiar to you as you continue to work with Laravel.

Great job! You're going to love working with Laravel. Next, let's get our
hands dirty and dig into some code.

16
17
2. Routing

A reliable routing system is crucial for survival. Just as a skilled survivor


finds the right path to safety, a powerful routing system ensures users
never get lost and always reach their desired destination.

Routing overview

Just to be sure everyone is on the same page, let's first define


application routing.

You can think of a route as being similar to a road. For instance, "We
drove down the road (route) to get to the graveyard." A route defines
how you get from one location to another. When you type a website
URL like site.com/graveyard, you are telling the browser that the
graveyard is the route you want to take. The application then says, "Ok,
you want to go to the 'graveyard'? This is the output I have for the
graveyard route."

Creating a route using Laravel is pretty straightforward:

<?php

Route::get('graveyard', function(){
echo 'Welcome to the graveyard!';
});

Here, the route for our graveyard page is defined. The application,
when prompted to 'get' the 'graveyard' pathway, will execute the
function, showcasing the message 'Welcome to the graveyard!'.

18
Routing in Laravel

Our Laravel routing file is located at routes\web.php. This is where we


will be adding all the routes for our application.

Fundamentally, we have four route types: POST, GET, PUT, and


DELETE. They look like the following:

<?php

Route::post('/zombie', function () {
echo "We want to create a new zombie";
});

Route::get('/zombie', function () {
echo 'We want to read or view a zombie';
});

Route::put('/zombie', function () {
echo "We want to update an existing zombie";
});

Route::delete('/zombie', function () {
echo "We want to destroy a zombie";
});

These methods—POST, GET, PUT, and DELETE—are part of a RESTful


architecture, each reflecting a specific action:

POST: To Create an entity. GET: To Read an entity or multiple entities.


PUT: To Update an entity. DELETE: To Delete an entity.

This technique is also referred to as CRUD (Create, Read, Update,


Delete).

Most often we will use the GET method, but there is also a route we can
use to capture any method:

19
<?php

Route::any('/zombie', function () {
echo "Any request from this zombie route";
});

Great!

So, how do we initiate our routes from a browser? For most cases, we'd
use the GET request. Typing in site.com/zombie directs us to the GET
function. But how about POSTing data?

Easy! An HTML form like this would do the trick:

<form method="POST" action="/zombie">


...
<input type="hidden" name="_token" value="' . csrf_token()
. '">
<input type="submit">
</form>

By pressing submit on this form, the data will be posted to the


site.com/zombie POST route.

The hidden input seen above is a security feature provided to us by


Laravel that we will talk about near the end of the book.

For PUT and DELETE methods, a hidden input specifies the intended
method:

20
<!-- PUT METHOD -->
<form method="POST" action="/zombie">
...
<input type="hidden" name="_method" value="PUT">
<input type="hidden" name="_token" value="' . csrf_token()
. '">
<input type="submit">
</form>

<!-- DELETE METHOD -->


<form method="POST" action="/zombie">
...
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="' . csrf_token()
. '">
<input type="submit">
</form>

These forms send data to the PUT and DELETE routes respectively.

Quick Routing example

Imagine you're faced with the task of killing (deleting) a rogue zombie!

First, a form is needed:

<form method="POST" action="/zombie">


<input type="hidden" name="id" value="2">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="' . csrf_token()
. '">
<input type="submit" value="Destroy">
</form>

This displays a 'Destroy' button. For simplicity, we've hard-coded an ID


of 2, which would typically vary based on the zombie in question.

Next, let's draft our route:

21
<?php

use Illuminate\Http\Request;

Route::delete('/zombie', function(Request $request){


$id = $request->id;
Zombie::destroy($id);
});

And just like that, the troublesome zombie with ID 2 is no more! Note
the inclusion of the Request class from Laravel, which captures request
data. You'll have to remember to declare the namespace when you
want to make use of the request object.

Heads up! This example won't be fully operational yet since our
database and models are still in the making. We'll tackle that soon.

We've been using route closures. Next, let's discuss the difference
between route closures and route controllers.

Route Closures vs Route Controller Actions

A route closure is an immediate function containing code, as seen here:

Route::get('/zombie', function(){
echo 'Greetings from the Zombie Page!';
});

For a route controller action, we specify which controller method to


invoke:

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

Accessing /zombie calls the index method within ZombieController.

22
We'll explore Controllers further soon. Keep these distinctions in mind;
they'll become clearer.

Route Parameters

Sometimes, routes require parameters.

For instance, viewing a specific zombie at site.com/zombie/5 requires


a parameter to be included in the route:

Route::get('/zombie/{id}', function($id){
echo "You've encountered a zombie with ID: " . $id;
});

Should our models and database be in place, this will retrieve and
display a specific zombie's details:

Route::get('/zombie/{id}', function($id){
$zombie = Zombie::find($id);
echo 'Name: ' . $zombie->name . '<br />';
echo 'Strength: ' . $zombie->strength . '<br />';
echo 'Health: ' . $zombie->health . '<br />';
});

As a reminder, our setup isn't complete, so this example won't run


perfectly yet. With that said, our next topic will make this all come
together.

23
24
3. Models

Zombie Developers often use complicated queries that can lead to bad
and infectious code. As a Laravel developer we must keep our queries
strong & healthy.

What Are Models?

In Laravel, a model is a PHP class that handles interactions between


your application's code and its database. By extending Laravel's
Eloquent Model class, these interactions become simple and easy to
understand.

The Zombie Model

Take, for instance, the Zombie model, which would be placed at


/app/Models/Zombie.php:

<?php namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Zombie extends Model {


protected $table = 'zombies';
}

This code informs Laravel that the Zombie class corresponds to the
zombies table in your database. A hypothetical zombies table might
resemble:

zombies table

25
| Field | Type | Length |
|-------------|-----------|--------|
| id | INT | 11 |
| name | VARCHAR | 50 |
| strength | VARCHAR | 20 |
| health | INT | 3 |
| updated_at | TIMESTAMP | |
| created_at | TIMESTAMP | |

Pro Tip: Laravel automatically manages the updated_at and


created_at fields if they exist, logging timestamps for newly added
rows and any updates.

Supposing we have this table in our database, we will discuss


migrations in an upcoming chapter, which allow us to seamlessly craft
database tables through our code.

With the aforementioned table in place, we can now interact with the
database using Eloquent.

Eloquent: The Laravel ORM

Eloquent, Laravel's ORM (Object-Relational Mapper), simplifies and


beautifies database operations. Remember the code from the previous
section:

26
<?php

use App\Models\Zombie;

Route::get('/zombie/{id}', function($id){
$zombie = Zombie::find($id);
echo 'Name: ' . $zombie->name . '<br />';
echo 'Strength: ' . $zombie->strength . '<br />';
echo 'Health: ' . $zombie->health . '<br />';
});

Previously, our application couldn't locate the Zombie class, but with
the model in place, we can access it without a hitch.

It's worth noting that when we invoke Zombie, we're specifically


referring to the Zombie class located at App\Models\Zombie. This
concept is known as namespaces, a topic we'll delve into in a
subsequent chapter.

Yet, there's still an obstacle.

Without any zombies in our database, we can't access the route


mentioned above. So, let's construct a new zombie through the route
below:

27
<?php

Route::get('/admin/zombies/create', function(){

echo '<form method="POST" action="/admin/zombies/create">


<input type="text" name="name"
placeholder="Name"><br>
<input type="text" name="strength"
placeholder="Strength"><br>
<input type="text" name="health"
placeholder="Health"><br>
<input type="hidden" name="_token" value="' .
csrf_token() . '">
<input type="submit" value="Create New Zombie">
</form>';

});

Visiting that route in our browser (site.com/admin/zombies/create),


displays a simple form.

On form submission, the data is posted to the


site.com/admin/zombies/create POST route, which should resemble:

<?php

Route::post('/admin/zombies/create', function () {
// create a new zombie
});

By adding the following implementation:

28
<?php

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

Route::post('/admin/zombies/create', function(Request
$request){

// instantiate a new zombie


$zombie = new Zombie();
$zombie->name = $request->name;
$zombie->strength = $request->strength;
$zombie->health = $request->health;
$zombie->save();

echo 'Zombie Created';


});

And then submitting the form with:

Name: Johnny Bullet Holes


Strength: Strong
Health: 70

You'd be greeted with the message 'Zombie Created.' Inspecting our


database reveals the new entry.

Impressive, isn't it? However, rather than manually specifying name,


strength, and health, Laravel allows for a more concise approach:

29
<?php

use App\Zombie;
use Illuminate\Http\Request;

Route::post('/admin/zombies/create', function(Request
$request){

// instantiate a new zombie using posted data


$zombie = Zombie::create($request->all());

echo 'Zombie Created';


});

Trying this route might result in a 'MassAssignmentException'. It means


that we're attempting a mass assignment to our Zombie class without
specifying allowable fields.

Laravel provides this safeguard by default.

To permit mass assignment for the name, strength, and health


attributes in our Zombie class, simply add:

protected $fillable = ['name', 'strength', 'health'];

The refined class looks like:

<?php namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Zombie extends Model {

protected $table = 'zombies';


protected $fillable = ['name', 'strength', 'health'];

Now, without the mass assignment error, another Zombie can be

30
effortlessly created.

Suppose we crafted another zombie:

Name: Ted Manwalking


Strength: Weak
Health: 90

Our database would then showcase the following entries:

Eloquent greatly eases the processes of creating, reading, updating,


and deleting database entries. Up next, we'll explore relationships,
facilitating the binding of data between database tables.

31
32
4. Model Relationships

A zombie developer struggles with relationships, but a Laravel


developer excels at implementing database relationships.

Zombies lack the intelligence to forge meaningful relationships. In


contrast, Laravel's Eloquent class empowers us to effortlessly establish
and utilize relationships between tables.

Model Relationships

Relationships bind data across tables. Imagine you manage a blog with
'posts' and 'comments' tables.

These tables are interconnected. A POST can HAVE MANY COMMENTS,


while a COMMENT will always BELONG TO a POST. These are called
relationships.

Let's craft another table named weapons:

weapons table

| Field | Type | Length |


|-------------|-----------|--------|
| id | INT | 11 |
| zombie_id | INT | 11 |
| name | VARCHAR | 50 |

Note the 'zombie_id' column above. It refers to the 'id' column in the
Zombies table. This connection, known as a Foreign Key, occurs when
one table's row distinctly identifies another table's row. This Foreign
Key solidifies the link between the Weapons and Zombies tables.

Consider two weapons in our database linked to our zombies:

33
Above, you see that we've included an "Axe" for the zombie with ID 2
and a "Shot Gun" for the zombie with ID 1.

Now, let's formulate our Weapon Model to communicate with the


weapons table. The file's path is app/Models/Weapon.php:

<?php namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Weapon extends Model {

protected $table = 'weapons';

To display our zombie's details, including their weapon, we can use this
code:

34
<?php

use App\Models\Zombie as Zombie;


use App\Models\Weapon as Weapon;

Route::get('/zombie/{id}', function($id){
$zombie = Zombie::find($id);
echo 'Name: ' . $zombie->name . '<br />';
echo 'Strength: ' . $zombie->strength . '<br />';
echo 'Health: ' . $zombie->health . '<br />';

$weapon = Weapon::where('zombie_id',
$zombie->id)->first();
echo 'Weapon: ' . $weapon->name . '<br />';
});

We've used Eloquent's where function, a simple way to retrieve data


where a condition is met. Dive deeper into its many uses in Eloquent's
documentation: http://laravel.com/docs/eloquent.

Yet, there's a simpler method! By defining the relationship between


zombies and weapons, we can reduce our code. Our enhanced Zombie
Model looks like this:

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Zombie extends Model {

protected $table = 'zombies';


protected $fillable = ['name', 'strength', 'health'];

public function weapon()


{
return $this->hasOne('App\Weapon');
}
}

Having updated our Zombie Model, let's rework our previous code:

35
<?php

use App\Zombie as Zombie;

Route::get('/zombie/{id}', function($id){
$zombie = Zombie::find($id);
echo 'Name: ' . $zombie->name . '<br />';
echo 'Strength: ' . $zombie->strength . '<br />';
echo 'Health: ' . $zombie->health . '<br />';
echo 'Weapon: ' . $zombie->weapon->name . '<br />';
});

In essence, we've condensed these lines:

$weapon = Weapon::where('zombie_id', $zombie->id)->first();


echo 'Weapon: ' . $weapon->name . '<br />';

Into this singular line:

echo 'Weapon: ' . $zombie->weapon->name . '<br />';

The result? Enhanced readability and efficiency. Accessing


(site.com/zombie/1) should present something like:

For details about our zombie with ID 2, visit (site.com/zombie/2):

36
Lastly, if we possess a weapon's ID and wish to identify its zombie
owner, we can:

Establish the belongsTo relationship in the Weapon class:

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Weapon extends Model {

protected $table = 'weapons';

public function zombie(){


return $this->belongsTo('App\Zombie');
}
}

Then, use the following route:

use App\Weapon as Weapon;

Route::get('/weapon/{id}', function($id){
$weapon = Weapon::find($id);
echo "This " . $weapon->name . " belongs to " .
$weapon->zombie->name;
});

Visiting (site.com/weapon/1) will generate:

37
Laravel's relationship features make data interactions both intuitive and
delightful.

The hasOne and belongsTo connections constitute a One-to-One


relationship. Dive deeper into Laravel's relationship types at
http://laravel.com/docs/eloquent-relationships.

Laravel's models and relationships greatly simplify our development


journey. Instead of devising intricate queries and bulky models, we can
relish the process and craft our application at lightning speed.

Next, we'll delve into mutators, empowering us to modify data before


its storage or retrieval from the database.

38
39
5. Mutators and Accessors

A savvy Laravel developer knows the importance of sanitizing and


manipulating data before storing or retrieving it from the database. This
ensures both data integrity and security, differentiating them from a
'zombie developer' who tends to overlook these crucial details.

Mutators and Accessors in Laravel play a vital role in this differentiation.


They provide an elegant solution to modify data right within our
Eloquent models.

Understanding Mutators and Accessors

Mutators: Allow us to alter data before saving it to the database.


Accessors: Let us transform data after retrieving it from the
database.

Recall the zombies table from our previous chapters. Suppose we aim
for a consistent presentation of zombie names, ensuring each name is
capitalized. This is where Accessors come to our rescue.

For instance, within our Zombie Model, to ensure every retrieved


zombie name is capitalized, we'd define an accessor like so:

protected function name(): Attribute


{
return Attribute::make(
get: fn (string $value) => ucwords($value),
);
}

The name of the function must be the name of the column. We must also
include the Attributes namespace in our model.

40
use Illuminate\Database\Eloquent\Casts\Attribute;

Conversely, using a Mutator to ensure each name is capitalized before


being saved is as follows:

protected function name(): Attribute


{
return Attribute::make(
set: fn (string $value) => ucwords($value),
);
}

Here's how our complete Zombie Model would appear with both the
Mutator and Accessor:

<?php namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;

class Zombie extends Model {

protected $table = 'zombies';

protected function name(): Attribute


{
return Attribute::make(
get: fn (string $value) => ucwords($value),
set: fn (string $value) => ucwords($value),
);
}
}

While it might seem redundant to have both functions performing


similar operations, they serve distinct purposes. Depending on the
scenario, you might lean towards one over the other.

41
Mutators and Accessors are another testament to Laravel's versatility,
making developers' tasks simpler and more intuitive.

Next, Let's dive into views.

42
43
6. Views

A zombie developer entangles logic and HTML elements in the same


page, whereas a Laravel developer separates their views from their
logic.

In this chapter, we're going to talk about using views. Leveraging the
powerful features of Laravel will help us gain a clear VIEW of what we
want to build (sorry for the cheesy pun).

Understanding Views

At their core, views are the HTML and layout elements that construct a
page. Simply put, it's what users see when they access a page.

Wondering how to create a new VIEW for a specific route? Good


news—it's rather intuitive! Recall Chapter 2, where we designed a basic
route within routes\web.php named 'graveyard'. This route merely
displayed a string, like so:

Route::get('graveyard', function(){
echo 'Welcome to the graveyard!';
});

To replicate the above functionality with a view, we'd modify our code
to:

Route::get('graveyard', function(){
return view('graveyard');
});

This would pull up the file found at resources/views/graveyard.php.


Assuming we've crafted that file and inserted:

44
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<p>Welcome to the graveyard!</p>

</body>
</html>

The outcome aligns with the initial view. But, by using the view, we're
incorporating valid HTML, adhering to best practices in code structure
and data presentation.

All view files reside in the resources/views/ directory.

Imagine wanting to retrieve all the zombies from our database and
presenting them in our view. The process is very simple. The route
would appear as:

use App\Zombie as Zombie;

Route::get('zombies', function(){
$data = ['zombies' => Zombie::all()];
return view('zombies', $data);
});

This would forward all our zombies to a view titled zombies.php located
in the resources/views/ folder. We can modify that file and loop
through our zombies like so:

45
<html>
<head>
<title>Zombies</title>
</head>
<body>
<ul>
<?php foreach($zombies as $zombie): ?>
<li><?php echo $zombie->name; ?></li>
<?php endforeach; ?>
</ul>

</body>
</html>

Visiting site.com/zombies via a web browser would then present an


unordered list showcasing our zombie names:

To funnel data into your views, simply pack the variables into an array
and relay it as the second parameter within the view function.

return view('zombies', ['zombies' => Zombie::all()]);

Leveraging views in Laravel is a breeze, especially when combined with


the in-built Blade templating engine. What exactly is the Blade
templating engine? Let's explore that in the next chapter.

46
47
7. Blade

A zombie developer's code has long and combersome syntax, whereas


a Laravel developer's code contains clean and readable views by using
the blade templating engine.

Using Blade Templating in your app will make your views look super
clean and easily readable. Blade templating is optional to use, but after
you get the hang of it, you'll find yourself wanting to use it all the time.

Blade Templating

Blade templating provides a simple way to render your views. It offers a


beautiful syntax that translates into valid PHP code. As an example,
let's consider the foreach loop from our previous chapter, where we
showcased zombies in an unordered list:

<ul>
<?php foreach($zombies as $zombie): ?>
<li><?php echo $zombie->name; ?></li>
<?php endforeach; ?>
</ul>

Using Blade, we can elegantly rephrase the above:

<ul>
@foreach($zombies as $zombie)
<li>{{ $zombie->name }}</li>
@endforeach
</ul>

The refactored version is undoubtedly more concise and reader-


friendly!

48
As demonstrated, rather than traditionally enclosing a foreach loop
within PHP tags, the @ symbol offers a cleaner alternative. Also, the {{
}} syntax auto-renders its content.

To harness Blade, we simply transition our file extensions from .php to


.blade.php. For instance, the file from the preceding chapter at
resources\views\zombies.php should be renamed to
resources\views\zombies.blade.php to enable Blade functionalities.

Let's delve deeper into Blade's syntax. Examine this example:

<?php if($var){ ?>


The statement is true. The variable is equal to <?php echo
$var; ?>
<?php } else { ?>
The statement is false. The variable is equal to <?php
echo $var; ?>
<?php } ?>

This snippet determines the truthiness of a statement and subsequently


displays the variable's value. Using Blade, we can refine it:

@if($var)
The statement is true. The variable is equal to {{ $var }}
@else
The statement is false. The variable is equal to {{ $var
}}
@endif

Notice the refined clarity? That's the power of Blade Templates!

Blade offers a plethora of syntactical shortcuts for layouts, loops,


conditional statements, and so much more. For an exhaustive list and
understanding, refer to the official documentation: Laravel Blade
Documentation.

49
Having grasped the essence of Views in a Laravel application, our next
pit stop is Controllers—the epicenter of our app's functionality.

Let's forge ahead and uncover the intricacies of controllers.

50
51
8. Controllers

A Laravel developer is like a mastermind directing the flow of an


application, while a zombie developer allows logic to roam aimlessly.
Controllers in Laravel ensure that logic remains separate and organized.

Think of controllers as the command center of your application—where


all significant decisions are made.

Understanding Controllers

Models retrieve and store data in our database, Views are responsible
for what the user sees in the browser, and Controllers dictate how
data flows between Models and Views. You'll find the controllers for
your application in the app\Http\Controllers directory.

Recall Chapter 2, where we touched upon Route Closures vs. Route


Controller Actions. A Route Closure defines an anonymous function,
exemplified below:

Route::get('/zombie', function(){
echo 'Welcome to the Zombie Page!';
});

On the other hand, a Route Controller links a route to a specific


controller method:

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

In this instance, the index method of the ZombieController gets


invoked.

52
Let's craft a new file within app\Http\Controllers named
ZombieController.php and populate it with:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ZombieController extends Controller


{
public function index(){
echo 'Welcome to the Zombie Page!';
}
}

By heading to site.com/zombie, you'll see the familiar greeting:


'Welcome to the Zombie Page!'.

While this might seem elementary, controller logic typically carries


more sophistication than illustrated above.

At first glance, Route Closures might seem more straightforward, but as


your application grows in complexity, compartmentalizing logic within
Controllers becomes invaluable. By doing so, you maintain a neat
routes\web.php file and streamline your workflow.

Diving deeper into the ZombieController.php, we start by designating


the namespace:

namespace App\Http\Controllers;

This namespace signifies the residing folder of our class, namely


App\Http\Controllers.

In most controllers we also specify the Request class which will allow us

53
to capture requests from our route (more on this later). The use
keyword specifies the namespace for the Request class.

use Illuminate\Http\Request;

Next, we give our controller a name and specify that we want it to


extend from the default controller:

class ZombieController extends Controller

Lastly, we define our index() method, ushering our message to the


display:

public function index(){


echo 'Welcome to the Zombie Page!';
}

Great! We can map any route to any controller method. This will help
keep our route file clean, and it will put the logic in our controller files.

In the next chapter, we will cover Controllers in a little more depth. You
will see the process of execution from the route to the controller and
then to the view. Let's continue and learn more about how these pieces
come together.

54
55
9. Piecing It Together

A zombie developer might write all logic and views in a single file, but a
Laravel developer segments their app using routes, models, views, and
controllers, resulting in a cleaner, more flexible, and better-organized
application.

Piecing It Together

In our previous chapters, we covered Routes, Models, Views, and


Controllers. Now, let's stitch these elements together. Here, we'll walk
through a demonstration of how to display a list of our current zombies
utilizing routes, models, views, and controllers.

Let's visualize: we navigate to our site.com/zombies route, aiming to


view all our present zombies. To achieve this, we must:

1. Define a route linked to a controller method


2. Create our controller
3. Fetch the zombies from our zombie model via our controller
4. Send our zombie data to our view
5. Present our zombie data within our view

1. Define a route linked to a controller method

This step is straightforward. Within our routes/web.php file, we craft a


route that ties into a controller method:

use App\Http\Controllers\ZombieController;

Route::get('zombies', [ZombieController::class, 'show']);

2. Create our controller

56
Here, we'll create a zombie controller at:

App\Http\Controllers\ZombieController.php. With the following:

<?php

namespace App\Http\Controllers;

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

class ZombieController extends Controller


{
public function show()
{
// Display our zombies
}
}

Notice that instead of the public function index() we used public


function show() because show() is the method that we used in our
route. We specified that when a user visits the zombies route we want
that to point to the ZombieController and the show method.

3. Fetch the zombies from our zombie model via our controller

Within our Zombie Controller, we extract all zombies from the Zombie
model, structuring it as such:

public function show(){


$zombies = Zombie::all();
}

It's important to note that our app might not recognize Zombie::all()
out of context. Remember our zombie model lives within the
App\Models namespace instead of the App\Http\Controllers
namespace. So, we must make sure to specify where our Zombie class

57
is located.

use App\Models\Zombie as Zombie;

Combining this all together, our controller now looks like:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Models\Zombie as Zombie;

class ZombieController extends Controller


{
public function show(){
$zombies = Zombie::all();
}
}

4. Send our zombie data to our view

Passing our zombie data to the view is pretty simple. Within show(), we
invoke a view file, and pass the zombie data:

return view('zombies', compact('zombies'));

The first argument is a string with the view we want to load (located at
resources/views/zombies.blade.php) and the second argument is an
array of data that we wish to pass to our view.

Tip: PHP's compact function quickly transforms named variables into an


array, streamlining our code.

5. Present our zombie data within our view

58
Our view file at resources/views/zombies.blade.php will display our
zombie data, like so:

<html>
<head>
<title>Zombies</title>
</head>
<body>
<ul>
@foreach($zombies as $zombie)
<li>{{ $zombie->name }}</li>
@endforeach
</ul>

</body>
</html>

Above, a simple foreach loop cycles through each zombie, listing their
names. Notably, we are using blade syntax that we covered previously.

Voilà! This section provides an overview of how each piece will work
from your route, model, controller, and view.

Isn't it fascinating?

Now, equipped with an understanding of our app's workings, let's move


on to talking about an excellent helper tool in Laravel called artisan,
that will simplify our development journey.

59
60
10. Artisan

A Laravel developer uses the artisan tool to generate files and


functionality, leaving manual file creation to the zombies.

Would you prefer a shotgun or an axe when facing a zombie?

Most would opt for a shotgun for its efficiency. Similarly, when building
an app, wouldn't you want a tool that speeds up and eases the process?

That's precisely what Laravel's artisan command offers.

Introducing Artisan

Recall from the first chapter where we used the artisan command to
initiate a local server. Specifically, we executed the php artisan serve
command in our Laravel project to start a local dev server.

In essence, artisan is Laravel's command-line interface (CLI) tool. It


simplifies a plethora of tasks: from file generation and configuration
management to running particular PHP commands.

Execute php artisan in your terminal to unveil a list of handy


commands.

This chapter will introduce a few foundational commands. Let's begin by


exploring file creation with artisan.

Generating Files Using Artisan

The php artisan make command facilitates file generation.

In previous chapters, when we needed a new Controller, we manually


created a file and populated it with code. Instead of this manual
approach, we could've employed an artisan command:

61
$ php artisan make:controller ZombieController

Peek inside the App\Http\Controllers directory, and you'll discover a


freshly minted ZombieController.php with the code:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ZombieController extends Controller


{
//
}

Impressive, right? A single command, and we're all set to inject


methods into our controller!

Similarly, to craft our Zombie Model, we could use:

$ php artisan make:model Zombie

A glance inside the app/Models directory will reveal a new Zombie.php


file:

62
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Zombie extends Model


{
//
}

And just like that we've created our model class that can interact with
our zombies table in our database.

Artisan also provides an option to create both a model and its


associated migration with a single command (we'll cover migrations in
Chapter 15):

$ php artisan make:model Zombie --migration

Pro Tip: If you wish for this Model to sync with a different database
table, add a protected variable named $table. For instance,
protected $table = 'zombie_folks'; ensures this model
communicates with the zombie_folks table.

It's amazing how much easier our Laravel programming will be if we


leverage the power of artisan.

Though we've only touched upon the basics with commands like php
artisan make:controller and php artisan make:model, numerous
other artisan commands await your exploration.

To delve deeper, visit Laravel's official documentation on artisan at


https://laravel.com/docs/artisan.

63
Next up, we'll dive into middleware—an efficient mechanism for
executing code between page requests.

64
11. Middleware

Unlike zombie developers who lack the ability to process between page
requests, Laravel developers harness Middleware to enhance their
app's security and flexibility.

Middleware can be imagined as the gatekeeper for requests. Before a


request gets through to our app, it must first gain approval from the
gatekeeper. If access is granted, the app proceeds to the subsequent
request; otherwise, the user's request is halted.

Understanding Middleware

Middleware provides an efficient means to execute functionality


between HTTP requests. For instance, a middleware might restrict users
from accessing certain routes unless they're authenticated.

To illustrate, let's run a functionality to determine whether our user is a


zombie. If the user is identified as a zombie, they won't be able to
access the route. For the sake of this demonstration, we will set a
hardcoded variable to be either true (1) or false (0) based on the
zombie status:

Route::get('arsenal', function(){
$is_zombie = rand(0, 1);

if($is_zombie){
return redirect('/home');
}

// Remaining code is executed if the user is not a zombie


});

In the above code, zombie users are redirected to the homepage. For

65
another route, we could employ similar logic:

Route::get('armory', function(){
$is_zombie = rand(0, 1);

if($is_zombie){
return redirect('/home');
}

// Remaining code is executed if the user is not a zombie


});

However, duplicating this code for every new route can become
tedious. Instead, a Middleware can be crafted to handle this
functionality. Using Laravel's Artisan, generate a new middleware file:

$ php artisan make:middleware isNotZombie

This command will produce a new file at


app/Http/Middleware/isNotZombie.php. It contains:

66
<?php

namespace App\Http\Middleware;

use Closure;

class isNotZombie
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
return $next($request);
}
}

Within the handle function, we will embed our zombie check:

public function handle($request, Closure $next)


{
$is_zombie = rand(0, 1);

if($is_zombie){
return redirect('/home');
}

// If not a zombie, the subsequent code is executed


return $next($request);
}

The final phase is registering our middleware in the app. This involves
naming our middleware class and appending it to the Kernel located in
app/Http/Kernel.php:

67
protected $routeMiddleware = [
// ... (existing middlewares)
'zombie' => \App\Http\Middleware\isNotZombie::class,
];

Once registered, group middleware can be implemented:

Route::group(['middleware' => ['zombie']], function () {


Route::get('arsenal', function(){
// Code executed if user is not a zombie
});
Route::get('armory', function(){
// Code executed if user is not a zombie
});
});

Web Middleware

Within the app/Http/Kernel.php file, a middleware group labeled web


is present:

protected $middlewareGroups = [
'web' => [
// ... (list of middleware classes)
],

'api' => [
// ...
],
];

Laravel equips us with a series of beneficial middleware functions, such


as session initiation, CSRF protection, and cookie management, to
name a few.

68
Nesting and Using Multiple Middleware

Multiple middleware classes can be nested or combined:

Route::group(['middleware' => ['auth', 'zombie']], function ()


{
// Add routes here
});

Route-Specific Middleware

Alternatively, you can assign middleware directly to routes:

Route::get('arsenal', function () {
//
})->middleware(['zombie']);

Controller Middleware

Middleware can also be designated within a controller. If set, all the


methods within that controller will first run the middleware:

namespace App\Http\Controllers;

class WeaponsController extends Controller


{
public function __construct()
{
$this->middleware('zombie');
}
}

Middleware simplifies our code, enhancing flexibility, readability, and

69
enjoyment in coding. As we transition to the topic of Authentication,
we'll explore another middleware example that helps safeguard routes,
ensuring access only for authenticated users.

70
71
12. Authentication

A zombie developer spends a few weeks building authentication into


their apps, whereas a Laravel developer leverages a package to add
authentication to their app in minutes.

During the zombie developer apocalypse you will probably want to


verify a person is not a zombie before allowing them in your home.
Similarly, when building your app you may need to verify users before
granting them access to certain pages.

This is called authentication and it allows or disallows certain types of


users to different sections of your app.

Authentication with Laravel Breeze

Building a web application often requires user authentication. Laravel,


with its extensive ecosystem, provides Breeze – a simple but powerful
toolkit for authentication that fits seamlessly into your application. In
this chapter, we'll explore how to leverage Laravel Breeze to craft a full-
fledged authentication system.

1. Setting Up a New Laravel Application:

Start by creating a new Laravel project:

$ laravel new my-first-authentication


$ cd my-first-authentication

2. Integrating Laravel Breeze:

Laravel Breeze offers a minimal yet adequate starting point for building

72
a Laravel application with authentication.

$ composer require laravel/breeze --dev


$ php artisan breeze:install

With the scaffolding in place, compile the frontend assets:

npm install && npm run dev

3. Database Configuration:

Before diving into the authentication features, ensure your application


is connected to a database. Open your .env file:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=my-first-authentication
DB_USERNAME=root
DB_PASSWORD=your_password_here

Run the migrations to create essential tables:

$ php artisan migrate

4. Exploring Authentication:

With Breeze installed, you now have routes and views for registration,
login, password reset, and more. Visit your app's URL, and you'll
encounter neatly crafted login and registration pages, ready for action!

73
5. Crafting a User Profile:

The beauty of Laravel lies in its simplicity and elegance. Let's create a
user profile display.

Generate a controller:

$ php artisan make:controller UserController

Populate the UserController.php:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class UserController extends Controller


{
public function profile() {
if (Auth::check()) {
$user = Auth::user();
return view('profile', compact('user'));
} else {
return redirect()->route('login');
}
}
}

Then, set the route in routes/web.php:

Route::get('profile',
'UserController@profile')->middleware('auth');

Create the profile.blade.php view:

74
<!DOCTYPE html>
<html>
<head>
<title>{{ $user->name }}'s Profile</title>
</head>
<body>
<p>Welcome, {{ $user->name }}!</p>
<p>Email: {{ $user->email }}</p>
<a href="{{ route('dashboard') }}">Back to Dashboard</a>
</body>
</html>

6. Wrapping Up:

You've now built a modern authentication system in a few commands


and some straightforward coding. Test the system by registering a new
user, logging in, and accessing the profile page.

Using Laravel Breeze, you've achieved a robust authentication system


without the hassle, ensuring users can securely access your app.

I hope you can see the power of quickly building an authentication


system and how much time it will save you in the future. If your app
needs an authentication system, you can have this fully integrated
within minutes thanks to Laravel!

75
76
13. Requests

A zombie developer doesn't handle requests efficiently, whereas a


Laravel developer uses the built-in Request class to handle input
sanitization and security.

Requests allow our app to receive messages from the client. If these are
not handled well or efficiently it can lead to a deteriorating user
experience and could have significant vulnerabilities.

Requests

Laravel is built on top of PHP, which is a server-side scripting language.

This server side language can accept requests from the client (web
browser) such as submitting a form or even requesting a route URL.

When a user types in a URL in their browser, the browser will then
contact or send a request to the server. So, when data is sent from the
browser to the server it is called a Request.

We've used the Request object in a previous chapter. Back in chapter


4, we used it to capture the id of a zombie:

<?php

use Illuminate\Http\Request;

Route::delete('/zombie', function(Request $request){


$id = $request->id;
Zombie::findOrFail($id)->delete();
});

So, whenever we want to use the Request Class we need to make sure
to specify that we want to use the Illuminate\Http\Request

77
namespace, then we can simply pass the (Request $request) object as
a parameter.

The request class offers us a ton of awesome information including:

The Request URI


The Request Method
The Request Input
The Request Cookies
The Request Files

The Request URI

To get the current request URI we could do the following:

$uri = $request->path();

So, if we tried to access the following route: site.com/zombie/1, the


$uri in the above example would be zombie/1. Another cool thing that
we can do is check if we are currently on a particular route, like this:

if ($request->is('zombie/*')) {
// we have hit the zombie/{id} route
}

Inside of the is method we can use an asterisk * as a wildcard.

If we wanted to fetch the full URL instead we could simply get it like
this:

$url = $request->url();

Request Method

78
Now, let's say we wanted to figure out what kind of request our
application is recieving.

Is it a GET, POST, PUT, or DELETE method? Easy peasy, we can do that


like this:

$method = $request->method();

Or we could use the isMethod function to check if it is a certain request:

if ($request->isMethod('post')) {
// we have a post method
}

The Request Input

This is the request method that we have used in the previous chapters.
This is where we get input data submitted by a form:

$zombie_name = $request->input('name', 'defaultName'); // You


can provide a default value as the second parameter

We could simplify this even more and specify $request->name instead


of $request->input('name'), like so:

$zombie_name = $request->name;

We could also get all the input data as an array by doing the following:

$input = $request->all();

Finally, we could do a quick check to see if the request has a certain

79
input value:

if ($request->has('name')) {
// 'name' is present in the request data
}

The Request Cookies

To retrieve a cookie value from our request we could simply do the


following:

$cookie = $request->cookie('name');

The Request Files

We could also use the Request class to retrieve uploaded files like so:

$file = $request->file('photo');

And we could check if the request has a file:

if ($request->hasFile('photo') &&
$request->file('photo')->isValid()) {
// We have a valid file
}

There are a few more request types that are provided by the Laravel
Request class. Be sure to checkout the full documentation
(https://laravel.com/docs/requests) to learn more.

We just learned a few of the awesome things that the Request class
offers and we know how our app can accept requests, but what can it
do after it gets a request? Well, it can also send a response. Let's learn

80
about Responses in the next chapter.

81
14. Responses

A zombie developer does not respond well to their clients, whereas a


Laravel developer sends clear and concise responses.

When we refer to Responses we are primarily referring to the output


that we send to the client. When our Laravel app receives a request, it
can then send a response.

Responses

In the previous chapter, we talked about requests and how our Laravel
app can accept them. In this chapter we are going to cover responses.

When our app get's a request, it can also return a response.

Here's a simple example of a response:

use Illuminate\Support\Facades\Route;

Route::get('/apocalypse', function () {
return 'End of the World!';
});

In the example above our laravel app recieves a GET request to the
/apocalypse route and it returns a string as the response. This is the
simplest form of a response.

So, when we return a response that contains HTML our Laravel app is
essentially returning an HTML document that gets displayed in the
users browser.

Attach a Cookie to a Response

82
In the previous chapter we talked about how your app can retrieve a
cookie, now lets see how we can set a cookie by attaching it to a
response. Remember a cookie is stored on the client side (browser), so
when our app sends a response it will need to attach a cookie to be set
by the browser.

We can easily do this by attaching it to the end of a view response like


so:

use Illuminate\Support\Facades\Route;

Route::get('/set_cookie', function(){
return response()->view('apocalypse')->cookie('name',
'value', 60); // 60 minutes
});

JSON responses

If we wanted to output a JSON response for a particular route we could


use the following syntax:

use Illuminate\Support\Facades\Route;

Route::get('/json-response', function(){
$data = [
'name' => 'Johnny Bullet Holes',
'strength' => 'strong'
];
return response()->json($data);
});

By running the route above, we get a nice JSON output as the response.

Lastly, we can perform a redirect as a response like so:

83
use Illuminate\Support\Facades\Route;

Route::get('/redirect-me', function(){
return redirect()->route('zombie.show', ['id' => 1]);
});

or even simpler, we could create a redirect like so:

Route::redirect('/redirect-me', '/zombie/1');

The route above will redirect to the site.com/zombie/1 route as a


response.

View response

The most common response your app will send is an HTML response
from one of your application views.

When you return a view in your Laravel app, it is essentially the same
thing as returning an HTML response. Here is a quick example from a
few chapters back:

use App\Models\Zombie;

public function show() {


$zombies = Zombie::all();
return view('zombies', ['zombies' => $zombies]);
}

Custom Response Headers

Laravel allows you to add custom headers to your responses. This is


useful for setting meta information, controlling cache, or sending
specific flags for client-side applications.

84
use Illuminate\Support\Facades\Route;

Route::get('/header_response', function () {
return response("With Custom Headers")
->header('X-Custom-Header', 'CustomHeaderValue')
->header('X-Another-Custom-Header',
'AnotherCustomHeaderValue');
});

Download Responses

Laravel facilitates sending downloadable responses, perfect for file-


sharing apps or exporting data:

use Illuminate\Support\Facades\Storage;

Route::get('/download', function () {
return response()->download(Storage::path('file.jpg'),
'user_friendly_name.jpg');
});

The example above will download a file from your storage directory and
send it as a response.

It's pretty straightforward, right? Our application gets a request and


returns a response. There are a few more responses that you may
want learn about by checking out the docs here
https://laravel.com/docs/responses.

Next, let's move on to something exciting called migrations.

Migrations are a way of storing our database schemas in files so they


can easily be versioned, shared, and backed up.

85
86
15. Migrations

A zombie developer exports and imports SQL files, whereas a Laravel


developer uses migrations to import and export database schemas.

Exporting and importing SQL files are dead, anyone who performs these
actions have zombie like tendencies.

There is a new way of doing data backup which is called Migrations.

Migrations

How are migrations helpful? Glad you asked...

Say you are working on a team and someone adds a new row to the
database, they'll have to send you over an updated database schema
which you will have to import and make sure there are no conflicts!

It can get really complicated having to manage multiple iterations of


your database schema by passing files amongst team members!

Well, thanks to migrations, MySQL dumps will be a thing of the past and
sharing your updated schemas with teammates will be super simple. By
using migrations, you can create files in your app that store the
database structure.

If you remember back in chapter 5 we created a zombies table that


looked like the following:

zombies

Field Type Length


id INT 11
name VARCHAR 50

87
Field Type Length
strength VARCHAR 20
health INT 3
created_at TIMESTAMP
updated_at TIMESTAMP

Usually to create a database table we would open up phpMyAdmin,


Sequel Pro, or some other kind of sequel application and add each of
these rows one at a time.

Alternatively if we are using migrations we can leverage our good 'ol


friend artisan to help us with this.

Let's create our first migration using the artisan tool:

$ php artisan make:migration create_zombies_table

After running the following command, you will see a new file that has
been created inside your project located in the database\migrations
folder, and it probably looks something like:

XXXX_XX_XX_XXXXXX_create_zombie_table.php, the X's resemble a


datetimestamp.

Let's open up our new zombie migration file and you should see
something similar to the following:

88
<?php

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

class CreateZombiesTable extends Migration


{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{

}
}

Notice that there are 2 methods available in our new migration class.

We have an up() method and a down() method. The up method is used


to modify something in our database and the down method is used to
reverse what we did in the up method.

Let's add some code to the up() method that looks like the following:

89
public function up()
{
Schema::create('zombies', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('strength');
$table->tinyInteger('health');
$table->timestamps();
});
}

Now, if we have an empty database and we were to run the following


command:

$ php artisan migrate

All our migrations will then be run and we should see a few tables inside
our database including the zombies table.

If we were to add the following to our down function:

public function down()


{
Schema::drop('zombies');
}

And we run:

$ php artisan migrate:rollback

It will run our down() method and we will no longer see our zombies
table in our database.

Migration Status

90
You can check which migrations have been run and which are pending
by using:

$ php artisan migrate:status

Batch Rollbacks & Stepping

Sometimes, you might want to rollback the last couple of migration


batches, or rollback migrations step by step:

$ php artisan migrate:rollback --step=1

The above command will rollback the last batch of migrations.

Refresh & Reseed

If you want to roll back all of your migrations and then run them all from
the start (useful during development):

$ php artisan migrate:refresh --seed

This command is helpful, especially during development, when you


want to reset your database state and reseed it.

Production Precautions

When deploying Laravel applications in production, always ensure you


are using the --force flag since running migrations or seeders can be
destructive:

$ php artisan migrate --force

91
Remember: Always backup your production database before running
migrations!

Migration Squashing

In the latest versions of Laravel, if you have a project that has been
running for a long time, you might end up with many migration files.
Laravel offers a way to squash them into a single SQL file, making it
faster to migrate:

$ php artisan schema:dump


$ php artisan migrate:squash

The first command generates a schema dump, and the second one
squashes the migrations.

Hopefully, you can see the power of migrations. We could easily share a
GitHub repo with another user and they could pull our code down and
create a new database. Then they can run the migrations and they will
have the most up-to-date database schema.

There are many other types of functionality you can run in your up and
down methods, be sure to checkout the full documentation on
migrations at Laravel's documentation to learn more.

Fantastic!

Migrations allow us to save and version our database schema in our


project files! What about the actual data that gets inserted into our
database? What if we had some data that we wanted to seed into our
database schema. Simple enough we can do that by using Seeds. Let's
learn more about these in the next chapter.

92
93
16. Seeds

A zombie developer imports data into their database with an SQL data
dump, whereas a Laravel developer uses Seeds to input default data
into their application.

If you were to build an app that does not have any data, it would look
pretty useless. Luckily we can leverage seeds, which allow us to add
default data into our database schemas. So, when we hand over our
app to another developer we can always make sure there is a little bit
of seed data to work with.

Seeds & Seeders

Laravel allows us to add test data into our application. This is referred
to as seeding the database. In the previous chapter we talked about
migrations and in this chapter we will talk about seeds which is the
data stored in our database.

Let's work off of our previous examples where we had a zombie table.


Inside the database we had 2 test zombies that were:

Johnny Bullet Holes


Ted Manwalking

If we have our database migration for our zombies table we could hand
over our application to another developer and they can run php
artisan migrate and be up and running with the zombies table. Well,
what if we also wanted to include our zombie data in the database?

We can create a Zombie Table Seeder for that.

Let's go ahead and use our friend artisan again:

94
$ php artisan make:seeder ZombieSeeder

After running this command we will see a new file created at


database/seeds/ZombieTableSeeder.php, and the contents of that file
will look similar to the following:

<?php

use Illuminate\Database\Seeder;

class ZombieSeeder extends Seeder


{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
//
}
}

The function that will run when we want to seed the database is the
run() method, and this is where we will put our code. To seed our
zombie database with our two zombies we would add this to our run
method:

95
public function run()
{
$zombies = [
['name' => 'Johnny Bullet Holes', 'strength' =>
'Strong', 'health' => 70],
['name' => 'Ted Manwalking', 'strength' => 'Weak',
'health' => 90]
];
DB::table('zombies')->insert($zombies);
}

What we have done is create an array of zombies containing their


name, strength, and health. We then use the DB class to insert our
zombies into the Zombies table. To run this seeder we will run the
following artisan command:

$ php artisan db:seed --class=ZombieSeeder

Voilà! Our zombies table now houses Johnny and Ted.

Seeder's Superpower: Factories

With Laravel's factories, you can also generate large amounts of test
data using random values. This can be especially handy when testing
features that require varied data sets.

Imagine seeding hundreds of zombies, each with different attributes.


Using factories along with seeders can make this a cinch!

Now we can use version control for our data, so when a new developer
pulls a fresh copy of our app on their computer they will also have the
data from our database.

Gone are the days of passing around an SQL file and now are the days

96
of creating migrations and seeds.

From here on out, feel free to chant this mantra:


ALL HAIL MIGRATIONS AND SEEDS!

This is just another example of how Laravel makes our lives easier. Let's
move on to learning about the built-in security that Laravel provides.

97
98
17. Security

A zombie developer doesn't care about security, whereas a Laravel


developer can rest assure that their app is secure from some of the
most common app vulnerabilities.

We want to make sure that no one can hack into our application, and
luckily Laravel has been built to prevent some of the most common
ways that users hack into systems.

Security

Security is an important thing when it comes to building applications.


Luckily for us, we have decided to use Laravel which includes security
features such as SQL Injection, Cross Site Scripting, and Cross Site
Request Forgery.

Don't worry if you don't know much about any of these protections.
We'll explain them below:

SQL Injection

SQL Injection is when someone tries to hack an input that gets


submitted into the database. Say we were to run a SQL command like
so:

$weapon_name = $_POST['weapon_name'];
$query = 'INSERT INTO weapons VALUES ('1', $weapon_name);

The user could easily enter in a value to the weapon name to Inject SQL
into our query. So, they could potentially run a query and drop a table
or a database.

99
Check out this XKCD.com comic:

Thanks to Laravel and Eloquent we don't have to worry about SQL


injection.

Cross Site Scripting

Cross-site scripting occurs when a hacker adds malicious code in the


form of a client side script. So, pretend you have a comment text area
and someone put in the following and submitted it as a comment:

<script>alert('hello, I just hacked this page');</script>

Now whenever someone visits that page, they will be alerted with this
annoying popup. You can see that this could be dangerous because the
user could even redirect that page to another page.

Thankfully by using the blade templating engine we can output any


data and protect against Cross-site Scripting attacks by using the triple
curly brace syntax:

{{ $user_comment }}

That output above would be sanitized to prevent any Cross-site


Scripting (also referred to as XSS attack).

100
Cross-site Request Forgery

Finally, there is another attack called Cross Site Request Forgery that
Laravel can prevent against. This occurs someone modifies a
POST/PUT/DELETE request being sent to your server.

A possible scenario is a hacker who modifies the data being sent by a


request from the browser to the server. The hacker could intercept the
request and swap out values, causing the web application to perform
functionality that it normally might not have.

Thankfully, Laravel is here to save the day against CSRF attacks.

When you submit a form you can include a hidden input type with a
name of _token and the value of csrf_token() and Laravel will handle
the rest. The form will look similar to the following:

<form method="POST" action="/zombie">


...
<input type="hidden" name="_token" value="{{ csrf_token()
}}">
<input type="submit">
</form>

And Laravel will handle all the rest. If a POST/PUT/DELETE request is


submitted and the security token does not match, the data will not be
posted to the application, which will prevent a hacker from intercepting
the request.

So, now you can sleep peacefully knowing that your site is safe against
any CSRF attacks.

Beyond Laravel's built-in features, always adhere to the following:

Keep your software up-to-date: Always update Laravel and its


dependencies to the latest versions. Security vulnerabilities are

101
patched in newer releases.

Use HTTPS: Always use HTTPS to encrypt data transmitted


between the client and server. This prevents man-in-the-middle
attacks and eavesdropping.

Least Privilege Principle: Always grant the minimum necessary


access rights or permissions to your apps and databases.

Environment Configuration: Never expose your .env file or any


other configuration files. These contain sensitive information that
can compromise your application.

Working on security issues can be time consuming, but thanks to


Laravel we can focus on what we enjoy most, which is building our app.

Security isn't just a feature—it's a priority. And with Laravel, you're not
just coding, you're crafting securely. Dive deeper and continue building
your masterpiece with peace of mind.

102
103
18. Testing

A zombie developer releases code and hopes it doesn't break, whereas


a Laravel developer writes automated tests to guarantee that new code
does not break any functionality in their app.

Say that you are given a few grenades during the zombie apocalypse
and the person giving you these grenades says, "I think they should
work, they've been stored away for many years". Wouldn't you rather
have them say, "These are our finest top of the line, tested to blow the
roof off of anything grenades"

Yeah, of course you would feel better throwing the grenade into a
swarm full of zombies that you know are tested to work. That's why
testing is so important. We want to guarantee that our app works in any
situation.

Testing

Testing your app is essential for ensuring everything works correctly.

I'm sure we've all done some testing to some extent. If we open our
application, look at data, or even click a few links then we have tested
our application. The only problem with manual testing is that it can be
very time consuming.

Imagine for every line of code you change you have to go back and run
through your whole application to make sure it's all functioning
correctly. That would be absurd, right? Only a zombie would mindlessly
perform these repetitive tasks over and over again.

Every developer tests their app to some degree. However, manual


tests, like clicking links and filling forms, are time-consuming.
Automation is about letting machines do repetitive tasks. So, why

104
manually test when Laravel offers tools for automated testing?

Luckily for us we can automate our testing by using PHPUnit that is


included by default with a fresh install of Laravel.

Let's go over an easy example of how testing can help us out. Let's say
that we have a page with a simple link called 'Invetory of Weapons' that
would bring us to a page that says 'Weapons.'

Well, in that case, we would probably have a view file called


artillery.blade.php that contained the following HTML:

<html>
<head>
<title>Artillery</title>
</head>
<body>
<a href="/weapons">Inventory of Weapons</a>

</body>
</html>

So, this page is loaded when we go to site.com/artillery and when


that link is clicked we go to a page at site.com/weapons, so we would
need 2 routes for this, which would look like the following:

Route::get('artillery', function(){
return view('artillery');
});

Route::get('weapons', function(){
return view('weapons');
});

And each of these will load the view. Now, we want to guarantee that
anytime we visit the artillery page we see 'Inventory of Weapons' and
when we click on the link, we then end up on the weapons page.

105
For simplicity sake we will just assume that when you land on the
weapons page (located at resources\views\weapons.blade.php) that
it has the text 'Weapons' on the page, like so:

<html>
<head>
<title>Weapons</title>
</head>
<body>
<h1>Weapons</h1>

</body>
</html>

Next, lets create our first test.

$ php artisan make:test ArtilleryTest

After running the artisan command above, we will end up with the
following code inside of a new file created at
tests\Feature\ArtilleryTest.php:

106
<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class ArtilleryTest extends TestCase


{
/**
* A basic feature test example.
*
* @return void
*/
public function testExample()
{
$response = $this->get('/');

$response->assertStatus(200);
}
}

So, by default, we are given a test example. This test example is just
hard-coded to be true. So, let's run this test by typing in the following
command:

$ vendor/bin/phpunit --filter ArtilleryTest

After running this command you should see a message in your


command line that says something similar to:

OK (1 test, 1 assertion)

Which means that we have run 1 test and 1 assertion and everything
was fine.

107
Why don't we go ahead and add a new method to our ArtilleryTest class
that looks like the following:

public function testArtilleryPage(){


$this->get('/artillery')
->assertSee('Inventory of Weapons');
}

Notice that each function must be prepended with test. Let's run our
test again:

$ vendor/bin/phpunit --filter ArtilleryTest

And we will see a green success message, with the following text:

OK (2 tests, 2 assertions)

Try changing up the text in our test. Say for instance that the link in the
artillery.blade.php file said 'Inventory of Kittens' instead of 'Inventory of
Weapons'. If we run the test again, we will see a red error message
saying that our tests have failed.

Tests: 2, Assertions: 2, Failures: 1.

You can think of this as a game if you like. When we see green we are
currently winning! But if we see red that means we have a problem and
we need to figure out what needs to be fixed to pass our test.

Just imagine every time we make a modification to our code we could


simply run through our tests and guarantee that we have not broken
anything. How much easier would it be to sleep at night knowing that
the code you just pushed didn't break anything?

108
Besides what we've already mentioned, some additional tips for testing
are:

Continuous Integration (CI): Integrate testing into your


deployment pipeline. Platforms like Travis CI, Jenkins, or GitHub
Actions can run your tests every time you push changes.

Test Coverage: Aim for high test coverage but remember, it's not
just about quantity. Quality matters. Some critical parts of your
application might require thorough testing while others might not.

Refactoring with Confidence: With a robust test suite, you can


refactor your code or upgrade dependencies knowing that if
something breaks, you'll be immediately informed.

This was a very simple example just to give you a quick idea of how
tests can work, but there are many more things that you can test
besides text on the screen. Be sure to read up more about Laravel tests
on the documentation page. We'll also provide some awesome
resources you'll want to check out in the next chapter.

109
110
19. Wrapping Up

A zombie developer does not typically read books, whereas a Laravel


developer finishes books they have started and they always continue
learning.

It looks like you're on your way to becoming an awesome Laravel


Developer!

Wrapping Up

Whoa! We made it! You just learned the basics of Laravel, and shortly
you'll be on your way to building the latest and greatest app!

There are so many more fun things to learn about Laravel that we have
not included in this book, so be sure to head over to the Laravel
documentation and give it a read.

It's one of the most enjoyable documentations available.


http://laravel.com/docs

Resources

Laravel has quickly become one of the most popular PHP frameworks
available today. It should be no doubt that there are plenty of resources
out there to further your Laravel knowledge.

Here are some resources that will help you on your way to advancing
your Laravel skills:

https://laravel.com/docs (The Laravel Docs)


https://laracasts.com/ (Best Video Resource for Modern PHP and
Laravel)

111
https://laravel-news.com/ (Latest news on Laravel)
http://devdojo.com/ (Video resource with Dev & Laravel
Screencasts)

Words of Encouragement

Before you set off on your journey to becoming a better PHP developer


and leveraging the powers of Laravel I want to share a bit of wisdom
with you.

Having fellow developers around you can help you grow and increase
your skills; however, there may also be other developers who will tell
you the way you are doing things are wrong and that you should be
doing things this way or that way.

These kinds of people can distract or discourage you from time to time.

So, my words of encouragement when you encounter people like that is


to take what they have to say with a grain of salt. Many people will help
you learn something new, but some may prevent you from growing.

Never be afraid to take chances and to keep pushing the envelope.

My advice is to block out any negativity or discouragement. We are all


in this together and when it comes down to it, there is no right or wrong
way to do things. If a mistake led you to learn and grow, then that
mistake was a necessary step for your progress.

A New Reality

Using Laravel and bettering your knowledge of development will open


up a wide array of opportunities. A new reality will open up, whether
that is to work for yourself one day or to make some extra money on
the side.

112
Being a web developer is an excellent and exciting career choice. The
demand for web developers is at an all time high.

If you are just starting off in web development, I would like to


encourage you to keep on going!

Most people will agree that building and creating something is very
satisfying, and as web developers we get to do just that! We get to take
an idea and make it come to life!

Web development is everchanging, so continue growing, learning,


encouraging, and creating.

113

You might also like