Skip to content

Instantly share code, notes, and snippets.

@marcoandre1
Last active November 26, 2022 21:25
Show Gist options
  • Save marcoandre1/13965f148b9430607cfda1a19f312c28 to your computer and use it in GitHub Desktop.
Save marcoandre1/13965f148b9430607cfda1a19f312c28 to your computer and use it in GitHub Desktop.
Pluralsight Laravel tutorial notes

Getting Started wiht Laravel (PHP Framework) - The Basics

Setting up a project with Laravel

  1. PHP Environment Setup : Apache/Nginx, PHP, MySQL
  2. Download Composer : PHP Package Manager
  3. Install Laravel :

composer create-project --prefer-dist laravel/laravel FOLDER
example : composer create-project laravel/laravel getting-started
For more info, go to Laravel Documentation and follow the installation process.

Homestead per project installation (add Homestead)

  1. Run the following command to add Homestead to your project :

composer require laravel/homestead --dev
vendor\\bin\\homestead make

Configuring Homestead

notepad Homestead.yaml

Vagrant

vagrant up
vagrant ssh
vagrant destroy

The Artisan CLI

php artisan COMMAND

  • Quick creation of application components
  • Alternative to manual file creation
  • Utility commands

Views & blade templating engine

  • Display data :
<div>
    <p>Hello {{ $name }}</p>
</div>
  • Layouts, Inheritance & Modules :
@extends('layout')
@section('content')
<div>
    @yield('content')
</div>
@endsection
  • Partial view :
<div>
    @include('header')
</div>
  • Control Structures :
<div>
    @if($id == 5)
        <p>Secret!</p>
    @endif
    <ul>
        @foreach($posts as $post)
            <li>{{ $post }}</li>
        @endforeach
    <ul>
</div>
  • XSS Protection :
<div>
    <p> {{ "<p>Won't work</p>" }}</p>
    <p> {!! "<p>Will work</p>" !!}</p>
</div>

Add layout view

  • Add a layouts folder in resources->views
  • Add a master.blade.php file and place the layout html
  • Add a @yield('content') tag to place the content in the body
  • To use the layouts in the other blade files, just add :
@extends('layouts.master')

@section('content')
    <div>
        Some html content
    </div>
@endsection

Add a partial view

  • Add a partials folder in resources->views
  • Add a header.blade.php file and place the header html
  • To use the header file, add the @include tag :
@include('partials.header')

Add css

  • Add a styles.scss file in resources->sass :
.quote {
    font: 400 72px "Arizonia", Helvetica, sans-serif;
    color: #F4645F;
    text-align: center;
}

.post-title {
    color: #f4645f;
}
  • You can import it to app.scss file with @import "styles"; (sass syntax)
  • To generate the css folder in the public folder, you need to compile the sass with the command line with npm run dev or any other command in the package.json file
  • After compiling sass, you should see the app.css and the styles.css file in the public->cssfolder with the same css
  • Add the link tag to the css file in the master.blade.php as follow :
<link rel="stylesheet" href="{{ URL::to('/css/app.css') }}" type="text/css">

URL::to is a Facades, redirects to a route that only has a destination and is not named

Add routes

  • To add routes, go to the web.phpfile in the routes folder.
  • Add the routes to the folder as follows :
Route::get('/', function () {
    return view('blog.index'); // This indicates that view is in blog->index
})->name('blog.index'); // The name property allows us to use the same name even if the path changes

Route::get is a Facades, that makes easier the process of making routes

  • To add the link to the views, use the route method, which is going to use the name property defined in the route :
<li><a href="{{ route('other.about') }}">About</a></li>

Add routes with parameters

  • To add routes with parameter define a route as follows :
Route::get('post/{id}', function () { // The id is the parameter
   return view('blog.post');
})->name('blog.post');
  • To retrieve that parameter, use the route function, with a parameter :
<p><a href="{{ route('blog.post', ['id' => 1]) }}">Read more...</a></p>

Add post routes

  • To add routes with parameter define a route as follows :
Route::post('admin.create', function () {
    return "It works!";
})->name('admin.create');
  • To retrieve the post, use the route method :
<form action="{{ route('admin.create') }}" method="post">

Be sure to indicate method="post"

Group routes

  • You can group routes with the group function of the Route facade as follow :
Route::group(['prefix' => 'admin'], function() {
    Route::get('', function () {
        return view('admin.index');
    })->name('admin.index');

    Route::get('create', function () {
        return view('admin.create');
    })->name('admin.create');

    Route::post('admin.create', function () {
        return "It works!";
    })->name('admin.create');
});

This is useful if you have a bunch of routes that are prefixed with admin for example, it simplifies renaming of admin too.

Sending data to a view

  • The get method of the Route facades can accept another argument, let's say $id :
Route::get('post/{id}', function ($id) {
    if ($id == 1) {
        $post = [
            'title' => 'Learning Laravel',
            'content' => 'This blog post will get you right on track with Laravel!'
        ];
    } else {
        $post = [
            'title' => 'Something else',
            'content' => 'Some other content'
        ];
    }
    return view('blog.post', ['post' => $post]);
})->name('blog.post');
  • $post can be data from a database, for now it is hardcoded text
  • Depending on the id requested, the post data will be different
  • To pass this data to the view, we need to create an array and named it :
return view('blog.post', ['post' => $post]) // The name of the variable is 'post'
  • The post variable is now available in the php pages, for example in post.blade.php :
@extends('layouts.master')

@section('content')
    <div class="row">
        <div class="col-md-12">
            <p class="quote">{{ $post['title'] }}</p>
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
            <p>{{ $post['content'] }}</p>
        </div>
    </div>
@endsection

Dependency Injection

  • Add dependency injection instead of using Request facade as follows :
Route::post('create', function (\Illuminate\Http\Request $request) {
    return "It works!";
})->name('admin.create');

Dependency Injection vs Facades

function (Request $request)
{
    $request->input('mail');
}

function ()
{
    Request::input('mail');
}

Laravel's CSRF Protection

  • Laravel's comes with cross-site request forgery (CSRF) protection. That means that you need to generate a token for the Route::post method.
  • Add the token in the create.blade.php and èdit.blade.php` files as follows :
// First option
<input type="hidden" name="_token" value="{{csrf_token()}}">

// Second option
{{ csrf_field() }}

Using sessions to show temporary data

  • To use sessions, use the with method :
Route::post('create', function (\Illuminate\Http\Request $request) {
    return redirect()
        ->route('admin.index')
        ->with('info', 'Post created, Title: ' . $request->input('title'));
})->name('admin.create');
  • The above code creates a session object of name info which is a string. The . chains the string with the title which is retrieved from the input of the create.blade.php page.
  • To access the info session, use the Session::get method :
@if(Session::has('info'))
    <div class="row">
        <div class="col-md-12">
            <p class="alert alert-info">{{ Session::get('info') }}</p>
        </div>
    </div>
@endif

use @if(Session::has('info')) to show this section only if the info session exists. Otherwise, the section will appear with no message if the info session doesn't exists.

Use validation

Route::post('create', function (\Illuminate\Http\Request $request, Illuminate\Validation\Factory $validator) { // dependency injection
    $validation = $validator->make($request->all(), [
        'title' => 'required|min:5', // required and min are some buit-in validation. Add as much as you want.
        'content' => 'required|min:10'
    ]);
    if ($validation->fails()) {
        return redirect()->back()->withErrors($validation); // if the validation fails, we create session objects of type error that we can retrieve in our blade page.
    }
    return redirect()
        ->route('admin.index')
        ->with('info', 'Post created, Title: ' . $request->input('title'));
})->name('admin.create');
  • To get the errors from validation, you can add a partial view errors.blade.php and add it where need it with @include('partials.errors') :
@if(count($errors->all())) // if there is any error this section will apear, if there are not, then the section doesn't show
    <div class="row">
        <div class="col-md-12">
            <div class="alert alert-danger">
                <ul>
                    @foreach($errors->all() as $error)
                        <li>{{ $error }}</li> // the error message is listed
                    @endforeach
                </ul>
            </div>
        </div>
    </div>
@endif

The available error messages are in ressources->lang->en->validation.php

Using Controllers and models

  • To add a model, create a new php class in the app folder. For example, Post.php.

Add Controller

vagrant ssh
cd code
php artisan make:controller PostController
php artisan make:controller PostController creates a controller named PostController.php in app\Http\Controllers

Use controllers in Routes

  • The following method can be replaced to use the PostContoller.php as follows :
// original method
Route::get('/', function () {
    return view('blog.index');
})->name('blog.index');

// First method to use controller
Route::get('/', 'PostController@getIndex'})->name('blog.index');

// Alternative method to use controller
Route::get('/', [
    'uses' => 'PostController@getIndex',
    'as' => 'blog.index' // replaces the name method
]);

Add validation to controller

  • Because the PostController class extends the Controller class, we have helpers function that make the validation really easy :
public function postAdminCreate(Store $session, Request $request)
{
    $this->validate($request, [
        'title' => 'required|min:5',
        'content' => 'required|min:10'
    ]);
    $post = new Post();
    $post->addPost($session, $request->input('title'), $request->input('content'));
    return redirect()
        ->route('admin.index')
        ->with('info', 'Post created, Title is: ' . $request->input('title'));
}

Working with Data and Models in Laravel

Models & Migrations

Eloquent model

  • Extend the Model to use eloquent, make sure that you have the appropriate use also :
namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{

}

Using the model

// Creating & inserting data
$post = new Post();
$post->title = 'A new Post';

$post->save();

// Fetching data
$oldPost = Post::where('title', 'old')->first();

Managing migrations (theory)

  • Generate :

php artisan make:model Post -m
php artisan make:migration create_posts_table

Schema::create('table_name', function (Blueprint $table) {
    $table->$string('title'); // 'title' field
}
  • Run :

php artisan migrate

  • Rollback/Refresh :

php artisan migrate:rollback // latest migration
php artisan migrate:reset // all migrations
php artisan migrate:refresh // rollback all & re-run

Create Models and Migrations with Artisan

  • To create models and migrations via artisan, you will need to access the virtual machine :

vagrant ssh
cd code
php artisan make:model Tag -m
php artisan make:model Like -m
php artisan make:migration create_posts_table

  • The model is created with make:model Tag and the migration file is created with the -m tag in the command.
  • The models are added to the app folder (same places as for the php class files) and the migrations files are added to database->migrations
  • If you only want to create migration file, use the make:migration command.

Configure database table

  • By default the migrations comes with the id field and the timestamps field. Add the other fields that you require. For example, you need to add the title and the content to the Post model :
Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->timestamps();
    $table->string('title');
    $table->text('content');
});

Make model mass-fillable

  • To make the model mass-fillable, simply add the $fillable property array to the class. In this case, the Post class :
protected $fillable = ['title', 'content'];

Execute migrations

  • Before running the php artisan migrate command, you can verify your connection and database name by accessing the mysql server :

vagrant up
vagrant ssh
cd code
mysql -u root
SHOW DATABASES
quit

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
  • Once everything is verified, you car run the migrate command in the virtual machine :

php artisan migrate

  • You can verify that the tables where correctly created directly on the terminal (easier than setting phpmyadmin imho) :

mysql -u root
SHOW DATABASES;
USE homestead;
SHOW TABLES;
SELECT * FROM migrations;
DESCRIBE posts;
SELECT * FROM posts;

Write data to database

  • To write on database with Eloquent ORM, you need to change the methods in PostController.php :
// Previous function that stores data in session
public function postAdminCreate(Store $session, Request $request)
{
    $this->validate($request, [
        'title' => 'required|min:5',
        'content' => 'required|min:10'
    ]);
    $post = new Post();
    $post->addPost($session, $request->input('title'), $request->input('content'));
    return redirect()
        ->route('admin.index')
        ->with('info', 'Post created, Title is: ' . $request->input('title'));
}

// New function that stores data in database
public function postAdminCreate(Store $session, Request $request)
{
    $this->validate($request, [
        'title' => 'required|min:5',
        'content' => 'required|min:10'
    ]);
    $post = new Post([
        'title' => $request->input('title'),
        'content' => $request->input('content')
    ]);
    $post->save();
    return redirect()
        ->route('admin.index')
        ->with('info', 'Post created, Title is: ' . $request->input('title'));
}

Query the database

Fetching Data (SELECT)

// Fetch models where 'title' equals 'Title'
$posts = Post::where('title', '=', 'Title')->get();

// Only get first matching entry
$post = Post::where('title', '=', 'Title')->first();

// Get all models
$posts = Post::all();

//Get by ID shortcut
$post = Post::find(10);

Updating Data (UPDATE)

// Update single model
$post = Post::where('title', '=', 'Title')->first();
$post->title = 'New title';
$post->save();

// Updating multiple models at once
Post::where('title', '=', 'Title')->update(['title' => 'New title']);

Deleting Data (DELETE)

// Delete single model
$post = Post::where('title', '=', 'Title')->first();
$post->delete();

// Deleting multiple models at once
Post::where('title', '=', 'Title')->delete();

Soft deleting

Laravel query builder

Seeding the Database

  • The Laravel seeder allows to seed the database with somme data :

php artisan make:seed PostTableSeeder
php artisan make:seed TagTableSeeder

  • PostTableSeeder.php and TagTableSeeder.php added to database->seeds folder
  • Fill the DatabaseSeeder.php file

php artisan db:seed

  • You can use php artisan migrate --seed to migrate and seed the database in one step, or php artisan migrate:refresh --seed if you want to refresh the migrations files.

Working with relationships

One-to-Many

  • One Post may have many Likes, but one Like will only belong to one Post.
// In Posts Model
public function likes() {
    return $this->hasMany('App\Like'); // you can pass another parameter in the hasMany function to specify the column, eg. hasMany('App\Like', 'post_id')
}

// In Like Model
public function post() {
    return $this->belongsTo('App\Post');
}
  • You will also need to create a post_id column in the like migration file.
$table->integer('post_id');

php artisan migrate:refresh --seed

Querying One-to-Many Relationship

// Fetch Data
$likes = Post::find(10)->likes;
$likes = Post::find(10)->likes()->orderBy(...)->get();

// Insert Data
$post = Post::find(10);
$like = new Like();
$post->likes()->save($like);
  • You will need to add a link to add likes to a post in post.blade.php :
<p>
    {{ count($post->likes) }} Likes | <a href="{{ route('blog.post.like'), ['id' => $post->id] }}">Like</a>
</p>
  • Define the new route in web.php : Route::get('post/{id}/like', [ 'uses' => 'PostController@getLikePost', 'as' => 'blog.post.like' ]);
  • Finally, add the new function to save the likes in PostController.php :
public function getLikePost($id)
{
    $post = Post::where('id', $id)->first();
    $like = new Like();
    $post->likes()->save($like);
    return redirect()->back();
}
public function getPost($id)
{
    $post = Post::where('id', $id)->with('likes')->first(); // add the with methods with the likes argument (which refers to the likes method in the Post model)
    return view('blog.post', ['post' => $post]);
}

Many-to-Many relationships

  • One Post may belong to many Tags and one Tag may belong to many Posts.
// In Posts Model
public function tags() {
    return $this->belongsToMany('App\Tag');
}

// In Tag Model
public function posts() {
    return $this->belongsToMany('App\Post');
}
  • We need to create a Pivot table to save the relation with posts and tags

php artisan make:migration create_post_tag_table

  • A new migration file is created, add the post_id and the tag_id columns :
$table->integer('post_id');
$table->integer('tag_id');
  • run the migration

php artisan migrate

  • set the relations in the model
// In Post Model
public function tags() {
    return $this->belongsToMany('App\Tag')->withTimestamps(); // you can pass more arguments in the belongsToMany method, eg. belongsToMany('App\Tag', 'post_tag', 'post_id', 'tag_id');
}

// In Tag Model
public function posts() {
    return $this->belongsToMany('App\Post')->withTimestamps();
}

Querying Many-to-Many Relationships

// Fetch Data
$tags = Post::find(10)->tags;
$tags = Post::find(10)->tags()->orderBy(...)->get();

// Insert Data
$post = Post::find(10);
$tagId = 1;
$post->tags()->attach($tagId);

// Delete Data
$post->tags()->detach($tagId);

Managing Data Input & Output

Defining a Mutator

  • Change the value before storing it to the database :
// In Post Model
// Force title to be lowercase when saving it
public function setTitleAttribute($value) {    // if you have an attribute like first_title, name the function setFirstTitleAttribute
    $this->attributes['title'] = strtolower($value);    // title is the column name in the database
}

Defining an Accessor

  • Change the value when retrieving from the database :
// In Post Model
// Force title to be uppercase when retrieving it
```php
public function getTitleAttribute($value) {
    return strtoupper($value);
}

Pagination

  • You might want a couple of posts instead of an infinite list of posts, that's pagination.
// In Controller
$posts = Post::where('title', 'Title')->paginate(3);

// In View
{{ $posts->links() }}
  • In the PostConroller.php file, change the get() method to paginate(2) in the getindex() method :
public function getIndex()
{
    $posts = Post::orderBy('created_at', 'desc')->get();
    return view('blog.index', ['posts' => $posts]);
}
  • In the index.blade.php file, add the {{ $posts->links() }} to view the pagination :
<div class="row">
    <div class="col-md-12 text-center">
        {{ $posts->links() }}
    </div>
</div>

Customizing laravel's pagination

php artisan vendor:publish --tag=laravel-pagination

  • This will import the pagination folder with the default templates in ressources->views->vendor->pagination.
  • You can then modify the pagination. Take a look at the documentation to see how it is done!

Users and Authentication

Generating authentication components

  • Scaffold Authentication Components
    • Generates signup, signin and password reset functionality
    • Adds required routes
    • Adds main layout and home page
  • Look at the official documentation for Authentication:

Want to get started fast? Install the laravel/ui Composer package and run php artisan ui vue --auth in a fresh Laravel application. After migrating your database, navigate your browser to http://your-app.test/register or any other URL that is assigned to your application. These commands will take care of scaffolding your entire authentication system!

vagrant@getting-started:~/code$ composer require laravel/ui
vagrant@getting-started:~/code$ php artisan ui vue --auth
vagrant@getting-started:~/code$ php artisan migrate
  1. The first command adds the laravel/ui Composer package in the project at vendor->laravel->ui.
  2. You probably need to run npm again (npm install & npm run dev). For windows, run it as admin.
  3. The last command makes sure that we don't forget any migration file.
  • Navigate to the register page! If the style doesn't load up correctly, try another browser (eg. Chrome instead of Firefox)

Tips: Run npm install & npm run dev on windows with admin rights and vagrant disconnected.

  • Also, add sourceMaps and webpackConfig in the webpack.minx.js file :
mix.js('resources/js/app.js', 'public/js')
    .sass('resources/sass/app.scss', 'public/css')
    .sourceMaps(true, 'source-map')
    .webpackConfig({devtool: 'source-map'});

Changing Defaults (theory)

  • Guard & Provider

Change in config/auth.php

  • Database Considerations

password field has at least 60 characters
remember_token field is present

  • Redirection Paths

Overwrite $redirectTo

  • Username

Default: email
Can be overwritten in LoginController

  • Views

Edit in resources/views/auth folder

A Closer Look at the Auth Facade

// Try to authenticate user
Auth::attempt(['email' => $email, 'password' => $password, ...])
// Check if active user is authenticated
Auth::check()
// Get authenticated user
Auth::user()
//Log user out
Auth::logout()

Implementing a custom login

  • Create a new controlle for signin:
vagrant@getting-started:~/code$ php artisan make:controller SigninController
  • Add the signin function:
public function signin (Request $request) {
    $this->validate($request, [
        'email' => 'required|email',
        'password' => 'required'
    ]);
    if (Auth::attempt([
        'email' => $request->input('email'),
        'password' => $request->input('password')
    ], $request->has('remember'))) {
        return redirect()->route('admin.index');
    }
    return redirect()->back()->with('fail', 'Authentication failed!');
}
  • Adjust the login.blade.php page ouput the fail session:
@if (Session::has('fail'))
    <div class="alert alert-danger">
        {{ Session::get('fail') }}
    </div>
@endif
  • Finally, add a new route to use the new login controller:
Route::post('login', [
    'uses' => 'SigninController@signin',
    'as' => 'auth.signin'
]);
  • You can verify, that we are truly accesing the signin function by adding dd('Our own auth!'); at the beginning of the method. If the text appears, it means that we are accessing correctly the function.

User authentication status

  • To avoid unauthorized access to certain parts of the application, simply add the following checks in the methods you want to protect in the PostController.php file:
if (!Auth::check()) {
    return redirect()->back();
}
  • To show only accessible routes in the menu, add the following tags in the header.blade.php file:
@if (!\Illuminate\Support\Facades\Auth::check())
    ...
@else
    ...
@endif

Gate definition (theory)

// In AuthServiceProvider
public function boot() {
    $this->registerPolicies();
    Gate::define('update-post', function($user, $post) {
        return $user->id == $post->user_id;
    });
}

Authorization with gates

  • Add the manipulate-post gate in the boot function, in the AuthServiceProvider.php file:
Gate::define('manipulate-post', function($user, $post) {
    return $user->id == $post->user_id;
});
  • In the PostController.php file, for every method where authorization is required, add the call to the method defined above:
if (Gate::denies('update-post', $post)) {
    return redirect()->back;
}

Don't forget to add the use Illuminate\Support\Facades\Auth; in the PostController.php file

Managing the User Authentication State

  1. Remember users
  2. Reset passwords

Remebering users

  • When clicking on the Remember me checkbox in the login, a remember token is stored in the database.
  • The remember cookie is set and is send to the server when requested.
  • The token and the cookies are hashed and can be seen with the developper tool of any browser.
  • $request->has('remember') in the SigninController.php controller generates the remember_token in the database.

Resetting passwords

Run Table Migrations
Configure Mail Server
Configure Views
Configure Notification

  • The interface of the Auth facade implements the reset password functionnality:
namespace Illuminate\Foundation\Auth;

use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\MustVerifyEmail;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\Authorizable;

class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}
  • To use the Auth facade, you must be sure to extend the Authenticatable in the User model:
class User extends Authenticatable
  • You must be sure to have the password_resets table in the migration folder:
Schema::create('password_resets', function (Blueprint $table) {
    $table->string('email')->index();
    $table->string('token');
    $table->timestamp('created_at')->nullable();
});

Configuring Authentication and Mail for Password resetting

  • You must first create an accoutn at mailtrap.io
  • Click the Demo inbox and copy the user and the password from the smtp protocol in the .env file:
MAIL_USERNAME=**************
MAIL_PASSWORD=**************
  • Next, in config->mail.php, you need to set an address and a name:
'from' => [
    'address' => env('no-reply@test.com', 'hello@example.com'),
    'name' => env('No-reply', 'Example'),
],

In this case the address is no-reply@test.com and the name is No-reply.

  • Now when the user sends a mail from Forgot your password?, you receive a mail in mailtrap
  • Finally, you need to correct the redirect in the ResetPasswordController.php controller:
protected $redirectTo = '/admin';

Customizing the Reset Notification

  • Make sure to visit the notification documentation for more info.
  • You need to make sure that the User model has the Notifiable trait.
  • The built-in function sendPasswordResetNotification is the one responsible for sending the reset password notification:
namespace Illuminate\Auth\Passwords;

use Illuminate\Auth\Notifications\ResetPassword as ResetPasswordNotification;

trait CanResetPassword
{
    /**
     * Get the e-mail address where password reset links are sent.
     *
     * @return string
     */
    public function getEmailForPasswordReset()
    {
        return $this->email;
    }

    /**
     * Send the password reset notification.
     *
     * @param  string  $token
     * @return void
     */
    public function sendPasswordResetNotification($token)
    {
        $this->notify(new ResetPasswordNotification($token));
    }
}
  • You can make a custom trait with the following artisan command:
vagrant@getting-started:~/code$ php artisan make:notification CustomPasswordReset

The command creates a new file in Notifications->CustomPasswordReset.php.

  • In the CustomPasswordReset.php file, customize the toMail function:
public function toMail($notifiable)
{
    return (new MailMessage)
                ->line('Please use the following link to reset your password.')
                ->action('Reset Password', url('password/reset', $this->token))
                ->line('Thank you!');
}

Don't forget to add the $token and modify the __construct function:

public $token;

/**
 * Create a new notification instance.
 *
 * @return void
 */
public function __construct($token)
{
    $this->token = $token;
}
  • Overwrite the sendPasswordResetNotification function in the User model:
public function sendPasswordResetNotification($token)
{
    $this->notify(new CustomPasswordReset($token));
}

Don't forget to add the use App\Notifications\CustomPasswordReset; at the beginning of the User model.

  • Now when you click on Forgot your password?, you receive a custom mail in mailtrap.

Protecting routes with Middleware

Middleware Definition (theory)

  • A Middleware is code between the application and the server which can protects the server by redirecting the user for example.
// Define in app/http/Middleware/AlwaysRedirect.php
class AlwaysRedirect {
    if (true) {
        return redirect('home');
    }
}
// Register in app/http/Kernel.php
protected $middleware = [..\Middleware\AlwaysRedirect::class];

Creating and using a custom middleware

  • Create the middleware with artisan:
vagrant@getting-started:~/code$ php artisan make:middleware AlwaysRedirect

This command generates a new file in app->Http->Middleware->AlwaysRedirect.php.

  • You can modify the AlwaysRedirect middleware to redirect the user to the root page whenever the user clicks in the about link:
public function handle($request, Closure $next)
{
    if ($request->path() == 'about') {
        return redirect('/');
    }
    return $next($request);
}
  • To apply the middleware, you need to add it to the Kernel.php file:
protected $middleware = [
    \App\Http\Middleware\AlwaysRedirect::class
];

Take a look at the middleware documentation for more use cases

Route protection with middleware

  • Remove the authentication check from all methods in PostController.php:
if (!Auth::check()) {
    return redirect()->back();
}
  • We have a built-in middleware for authentication in Kernel.php:
protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
  • To use the middleware, simply add it to the route file in web.php:
// First option
Route::get('', [
    'uses' => 'PostController@getAdminIndex',
    'as' => 'admin.index',
    'middleware' => 'auth'
]);

// Second option
Route::group(['prefix' => 'admin', 'middleware' => 'auth'], function() {
    ...
}

use brackets to apply more than one middleware, eg: 'middleware' => ['auth', 'guest']

Advanced Topics Like Creating an API

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment