Powerful Applications with Laravel — Routes and Controllers

Gabriel Meireles
dev.meireles
Published in
5 min readMar 10, 2023
Photo by Kamil S on Unsplash

MVC is a shortening for Model, View, and Controller that appears 70s late on Smalltalk-80 by Xerox PARC emphasizing that a controller is an intermediary layer responsible for receive commands from an user interacting with the application.

When building interactive applications, as with other programs, modularity of components has enormous benefits. Isolating functional units from each other as much as possible makes it easier for the application designer to understand and modify each particular unit without having to know everything about the other units. — A Cookbook for Using View-Controller User the Model Interface Paradigm in Smalltalk-80 — Glenn E. Krasner and Stephen T. Pope

Majority the frameworks entry points are on routes and for Laravel it isn’t different, as example, when working for web you probably have seen addresses like example.com/product/1 or example.com/product/nice-new-laptop and for web application it usually means there are a route that’ll receive a request whether GET, POST, no matter the verb, then deal as it must be dealt and the responsible for handle these requests are the controllers, instead of execute all business logic directly in a route we can transfer this responsibility to a controller and is it how Laravel works.

Generating Controllers

You can easily generate controllers using Artisan, so let’s create an initial one:

docker exec -it laravel-powerful-apps-php-1 php artisan make:controller ProductController

Which will generate a ProductController.php file on src/app/Http/Controllers:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ProductController extends Controller
{
//
}

Quite simple, doesn’t? You can also generate controllers with CRUD functionalities already placed using --resource (remember to remove the current ProductController.php before executing the following command)

docker exec -it laravel-powerful-apps-php-1 php artisan make:controller ProductController --resource

It’ll generate the following structure:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ProductController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//
}

/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}

/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}

/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}

/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}

/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}

/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}

Once you already have an initial controller, let’s create a route to operate them, so your src/routes/web.php must looks like:

<?php

use App\Http\Controllers\ProductController;
use Illuminate\Support\Facades\Route;


Route::name('product.')->group(function () {
Route::get('/products', [ProductController::class, 'index'])->name('list');
Route::get('/products/{id}', [ProductController::class, 'show'])->name('show');
Route::post('/products', [ProductController::class, 'store'])->name('save');
Route::put('/products/{id}', [ProductController::class, 'update'])->name('update');
Route::delete('/products/{id}', [ProductController::class, 'destroy'])->name('remove');
});

There are a lot of possibilities when dealing with routes, one of them is using the resource option that’ll compile all possible verbs together:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/

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

Route::resource('products', ProductController::class);

Let’s keep the first routing option, it’ll be util thereafter.

Then backing to ProductController.php let’s add some lines of code to see the products route working, it must return a JSON response containing a list of products:

class ProductController extends Controller
{

private $products = [];

function __construct()
{
$this->products = [
(object)[
'id' => 1,
'name' => 'New Shoes'
],
(object)[
'id' => 2,
'name' => 'Cool T-shirt'
],
];
}

/**
* Display a listing of the resource.
*/
public function index()
{
return response()->json($this->products);
}

Accessing http://localhost/products you’ll see the JSON response:

{
"success": true,
"data": [
{
"id": 1,
"name": "New Shoes"
},
{
"id": 2,
"name": "Cool T-shirt"
}
]
}

Following the same example, now we can get an item by id, so let’s implement it on ProductController:

public function show(int $id)
{
$search = array_filter($this->products, fn ($item) => $item->id === $id);
$product = reset($search);

return response()->json([
'success' => true,
'data' => $product,
]);
}

Accessing to http://localhost/products/1 the result must be:

{
"success": true,
"data": {
"id": 1,
"name": "New Shoes"
}
}

To do read, update and delete operations you must have some permissions controlled by CSRF token, so for now just to test these features let’s do some changes aiming to forgive temporally the token process, so on src\app\Http\Middleware\VerifyCsrfToken.php add the following change:

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array<int, string>
*/
protected $except = [
'*'
];
}

Then backing to controller implement the create function:

public function store(Request $request)
{
$product = new stdClass();
$product->name = $request->input('name');
$product->id = date_timestamp_get(date_create());

array_push($this->products, $product);

print_r($this->products);

return response()->json([
'success' => true,
'data' => $product,
]);
}

With that a new product value will be place on $this->products variable, you can use some automated testing software such as Postman, Inmsomina or even Thunder Client if you’re using VS Code.

A pretty similar process must be done to update a product value according to the id, so on update function let’s implement:

public function update(Request $request, int $id)
{
$search = array_filter($this->products, fn ($item) => $item->id === $id);
$product = reset($search);

$product->name = $request->input('name');

return response()->json([
'success' => true,
'data' => $product,
]);
}

And finally for remove an item by id let’s implement the destroy function:

public function destroy(int $id)
{
$search = array_filter($this->products, fn ($item) => $item->id === $id);
$key = array_key_first($search);
unset($this->products[$key]);

var_dump($this->products);
}

I really recommend you to take a look on Routes section under Laravel documentation

And here other important resources:

All these changes are placed on GitHub, feel free to explore.

--

--