Get up to 80 % extra points for free! More info:

Lesson 4 - Finishing the calculator in Laravel

In the previous lesson, The first application in Laravel, we developed a simple calculator in Laravel. We created a model, a controller and a view.

In today's lesson, we will connect the individual parts of our application and also look at form validation.

Routing

In order to see how our application currently looks like, we need to access the controller via a URL. We use routing for this, we described its process in the first lesson. Let's now define our first route which connects the controller to an address.

Defined routes for our website can be found in the file routes/web.php. This file is unchanged since installation:

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

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

We have only one default route so far. It display's the main welcome Laravel page via GET (static get() method of the Route class) and is processed by an anonymous function. This way we can process any route. We have already created a controller and we will use it now. At the end of the file we will add our own definition of the GET route, where instead of creating a function we will refer to the action of our controller:

Route::get('calculator', 'CalculatorController@index');

Now if we enter /calculator in the URL of our application, we will see the following calculator:

Calculator in PHP framework Laravel - Laravel Framework for PHP

It's time to get the calculator up and running. Now we return to the controller, where we process the form for POST method.

Form submission processing

In our CalculatorController we define a new method called calculate(). It will accept the requests from the form and then display the result:

/**
 * Process the form request and display the result along with the calculator form.
 *
 * @param  Calculator $calculator
 * @return View
 */
public function calculate(Calculator $calculator): View
{
    $a = request()->input('a');
    $b = request()->input('b');
    $operation = request()->input('operation');
    $result = $calculator->calculate($operation, $a, $b);

    return view('calculator', [
        'operations' => $calculator->getOperations(),
        'result' => $result,
        'a' => $a,
        'b' => $b,
    ]);
}

As with the calculator display, we get an instance of the Calculator model into the $calculator variable via dependency injection. But the interesting part starts inside the method.

To obtain the submitted values, we use the input() method of the Laravel class of the Request class, which we obtain using the helper function request(). Then we'll use the obtained values for our method calculate(), which we defined in the last lesson in the Calculator model. Next, we display the calculator.blade.php view via the helper function view() just like in the index() method. We will pass the available calculator operations to the view, but on top of that we added the result and the numbers sent via the form so we can display them again.

Now we'll create a new route in the routing file of the routes/web.php website as we did above. But now we will add a POST action:

Route::post('calculator', 'CalculatorController@calculate');

Have you noticed that we have defined two routes with the same name, but one is GET and the other POST? Even so, our calculator will work fine. The framework itself determines which request it is and then calls the given method of the controller:

  • The index() method in the CalculatorController is called for display the form (GET).
  • After the form is submitted (POST), method calculate() is called in the same controller.

However, if we try to submit the form now, we will get error 419, even though everything should work. Or not?

CSRF token

Laravel protects our requirements against a CSRF attack. This protection is triggered for all non-read actions (all except GET). And what exactly is the CSRF attack?

Imagine a situation where we created a popular blog and someone would create a completely different page, where they would put a form encouraging the insertion of vulgar posts. However, this form would not allow data to be sent to his site, but to our blog. Unsuspecting users would suddenly write posts on our blog, even if they were not on this page at all and did not know that they were sending something there.

So we need to provide the form with a CSRF token, which verifies that the request was sent through our site and not through other site.

This is done using the Blade directive @csrf, which is converted to {{ csrf_field() }} (this longer notation was used in older versions). The directive will generate a hidden field with a CSRF token for the form. So let's edit the form in the calculator.blade.php view (in the resources/views folder):

<form method="POST" action="/calculator">
    @csrf

    Operation:

If we try to submit the form now, everything will work as we imagined.

CSRF protection with middleware

CSRF protection is provided by one of the middlewares of the Laravel framework. This is the layer by which the request is processed before it reaches the controller. Such middleware handling all actions can be found in the file app/Http/Kernel.php. We have several of them for the web group:

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

Our request will pass through all these middleware before it reaches the method of our controller. We can see that some of them are for encrypting cookies and creating a session. If you ever want to create your own middleware, this is exactly where you will add it. Subsequently, it will be applied to all actions on your website.

Form validation

As a programmer, we must assume that the user does not always fill in the field with what we require. If we try to enter text in the number field, our application will cause an error, because the model can only accept integers:

Laravel calculator error when passing text - Laravel Framework for PHP

We can avoid this by validation. Validation rules can be defined in the controller directly in the method of the given action. We will use only a few rules, all of which can be found in the official documentation. In our case all form fields must be filled in with whole numbers only. Also, the selected operation must be supported by our model. So let's modify the calculate() method in our controller:

/**
 * Process the form request and display the result along with the calculator form.
 *
 * @param  Calculator $calculator
 * @return View
 * @throws ValidationException
 */
public function calculate(Calculator $calculator): View
{
    $this->validate(request(), [
        'a' => ['required', 'integer'],
        'b' => ['required', 'integer', 'not_in:0'],
        'operation' => [
            'required',
            Rule::in(array_keys($calculator->getOperations())),
        ],
    ]);

    $a = request()->input('a');

We start with the annotation, where instead of processing the ValidationException we pass it to the framework. Framework can take care of it by himself, he redirects the user back even with the mistakes he has made.

Then we call the validate() method, which is defined in the Controller class and our controller inherits it. We have to pass an instance of the Request class, which can be obtained again via the helper function request(). As the second parameter, we pass a field with validation rules. These can be defined only as a text. For others, such as the in rule, it is better to use the Rule class. Also note that we have solved the problem for division by zero, where the second number must not be 0.

I think that there is no need to explain the other rules, they are all described in the documentation.

If your environment cannot automatically detect classes from another namespace, be sure to add the following imports to the beginning of the controller class file:

use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;

Listing errors

Now all we have to do is list the errors in our view to inform the user about the mistakes he has made. Errors are contained in the $errors variable, which is automatically passed to all views. There are more such "undefined" variables, but so far only this is enough for us. So we will modify our view and add a list of errors under the title:

<h1>Calculator</h1>

@if ($errors->any())
    <ul>
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
@endif

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

$errors is an instance of the ViewErrorBag class. To find out if there are any error messages at all so that we don't display an empty list, we use the any() method. Then we get all the error messages via the all() method and print them. However, if you only want to get an error message for a specific field, you can use the first() method and pass it the name of the field:

$errors->first('email')

In any case, only a list of errors will suffice for us :)

If we try to enter zero as the second number and create a non-existent calculator operation via the "Inspect element" (F12 key in the browser), we get two error messages:

Error messages in the PHP framework Laravel - Laravel Framework for PHP

Now we have a fully functioning calculator created via Laravel, on which we have shown the very basics of this PHP framework. If you do not understand anything, download the project from the attached archive and look at the solution. You can also ask in the discussion below the article if you are facing a problem. In any case, with the necessary knowledge that I mentioned in the first lesson, everything should be clear after a while.

That's all for this lesson.

In the next lesson, Simple CMS in Laravel - Project structure, we will dive into a new project where we will look at some parts of the framework in more depth.


 

Did you have a problem with anything? Download the sample application below and compare it with your project, you will find the error easily.

Download

By downloading the following file, you agree to the license terms

Downloaded 81x (13.59 MB)
Application includes source codes in language php

 

Previous article
The first application in Laravel
All articles in this section
Laravel Framework for PHP
Skip article
(not recommended)
Simple CMS in Laravel - Project structure
Article has been written for you by Lishaak
Avatar
User rating:
No one has rated this quite yet, be the first one!
Author is interested in programming mostly at web development, sometimes he does funny video edits from his vacations. He also loves memes and a lot of TV series :)
Activities