Laravel – My Journey – Part 3 – Controllers

Controllers

In MVC architecture, controllers interact with data (via models) based on a user’s request and pass it to a view so that data can be displayed to the user. In my application, a user may request a list of products. Laravel will route this  request to a controller.  The controller will request all the products from the database and then return the results back to the user via a view.

In this article, I’ll look at the controllers required for my Laravel Shopping List application. I’ll also touch upon routing as this is integral to the application flow.

Previous articles in this series:
Important Note/Disclaimer
This is not a tutorial, nor an example of best practice. The techniques described in this article are not to be taken as efficient or secure. At the time of writing, I am a relative newcomer to Laravel, object-oriented programming, and the MVC paradigm. I won't be explaining every detail. I don't know all the theory. I'll probably get stuff to work and not know how I did it. I'll probably write things that are clearly untrue or, at best, inaccurate. This is me just finding my way ...
Resource Controllers

In a typical web application, users will need to create, read, update and delete resources (also known as CRUD). I have two resources (shopping lists and products) that I can apply these CRUD actions to.

Handily, Laravel offers us resource controllers. These are classes that can be generated using Artisan commands and include all the method boilerplates required to implement CRUD functionality.

For instance, I can use the following Artisan command to generate a resource controller for my Product model:

$ php make:controller ProductController --model=Product

Specifying the model name in the above commands type-hints the resource controller.

To illustrate, here is an excerpt from ProductController.php showing the edit() method with type-hinted model instance:

/**
  * Show the form for editing the specified resource.
  *
  * @param  \App\Product  $product
  * @return \Illuminate\Http\Response
  */

 public function edit(Product $product)
 {
     //
 }

The following table shows all of the actions handled by a resource controller:

VerbPathActionRoute Name
GET/productindexproduct.index
Note: Display a listing of all instances of the resource.
GET/product/createcreateproduct.create
Note: Show the form for creating a new resource.
POST/productstoreproduct.store
Note: Store a newly created resource in storage. Accept form submission from the create form.
GET/product/{product}showproduct.show
Note: Display one instance of the specified resource.
GET/product/{product}/editeditproduct.edit
Note: Show the form for editing one instance of the specified resource.
PUT/PATCH/product/{product}updateproduct.update
Note: Update the specified resource in storage. Accept form submission from the edit form.
DELETE/product/{product}destroyproduct.destroy
Note: Remove one instance of the specified resource from storage.
Resourceful Routes

We have seen how Laravel can generate a resource controller with all the methods common to CRUD functionality. But how are those methods called? Enter routing.

 

MVC architecture

As you can see in the above diagram, Laravel’s routing mechanism takes requests from the user (such as a request for the application’s home page) and routes them to a controller. A typical route might look like this:

Route::get('/home', 'HomeController@index');

Requests for /home will be routed to the index() method of the HomeController controller.

However, with resource controllers, rather than specifying a route for each of the seven methods offered by a resource controller (see above table), Laravel offers resourceful routing:

Route::resource('product', 'ProductController');

This one route declaration will handle all the requests for my products e.g. adding new products, deleting products, viewing products, etc.

Find out more about resource controllers and resourceful routing from the horse’s mouth.

Product CRUD

We now have our resourceful routes and resource controller in place. The controller has our seven methods in place with boilerplate code in place (or stubbed), ready to be populated with code that actually does stuff. But what code?

The remainder of this article will outline the basic code required to fulfil the CRUD requirements of my Laravel application for the product resource. The code will be stripped down to the basics. I’ve removed niceties, such as flash messaging and form validation. I’m covering views in the next article but have commented the code to point our where a view is used. You’ll see references to the logged-in user; user authentication may be covered in a separate article. A screenshot of the end result (in terms of what is presented to the user) is included (if applicable).

index() method

VerbPathActionRoute Name
GET/productindexproduct.index
Note: Display a listing of all instances of the resource.

End result:

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
 public function index()
 {
     // Get logged in user
     $user = auth()->user();
     // Get user's products, paginate
     $products = $user->products()->orderBy('title')->paginate(10);
     // Load view and pass through products collection
     return view('products.index', compact('products'));
 }

create() method

VerbPathActionRoute Name
GET/product/createcreateproduct.create
Note: Show the form for creating a new resource.

End result:

/**
 * Show the form for creating a new resource.
 *
 * @return \Illuminate\Http\Response
 */
 public function create()
 {
     // Load view
     return view('products.create');
 }

store() method

VerbPathActionRoute Name
POST/productstoreproduct.store
Note: Store a newly created resource in storage. Accept form submission from the create form.
/**
 * Store a newly created resource in storage.
 *
 * @param \Illuminate\Http\Request $request
 * @return \Illuminate\Http\Response
 */
 public function store(ProductCreateRequest $request)
 {
     // Create a new product
     $product = Product::create([
         'user_id' => auth()->id(),
         'title' => ucwords(request('title')),
         'essential' => request('essential') ? 1 : 0
     ]);
     // Populate product table
     $product->save();
     // Redirect to view
     return redirect()->route('product.index');
 }

show() method

VerbPathActionRoute Name
GET/product/{product}showproduct.show
Note: Display one instance of the specified resource.

End result:

/**
 * Display the specified resource.
 *
 * @param int $id
 * @return \Illuminate\Http\Response
 */
 public function show(Product $product)
 {
     // Load view
     return view('products.show', compact('product'));
 }

edit() method

VerbPathActionRoute Name
GET/product/{product}/editeditproduct.edit
Note: Show the form for editing one instance of the specified resource.

End result:

/**
 * Show the form for editing the specified resource.
 *
 * @param int $id
 * @return \Illuminate\Http\Response
 */
 public function edit(Product $product)
 {
     // Load view
     return view('products.edit', compact('product'));
 }

update() method

VerbPathActionRoute Name
PUT/PATCH/product/{product}updateproduct.update
Note: Update the specified resource in storage. Accept form submission from the edit form.
/**
 * Update the specified resource in storage.
 *
 * @param \Illuminate\Http\Request $request
 * @param int $id
 * @return \Illuminate\Http\Response
 */
 public function update(ProductUpdateRequest $request, Product $product)
 {
     $product->title = request('title');
     $product->essential = request('essential') ? 1 : 0;
     $product->save();
     // Redirect to view
     return redirect('/product');
 }

destroy() method

VerbPathActionRoute Name
DELETE/product/{product}destroyproduct.destroy
Note: Remove one instance of the specified resource from storage.

End result:

/**
 * Remove the specified resource from storage.
 *
 * @param int $id
 * @return \Illuminate\Http\Response
 */ 
 public function destroy(Product $product)
 {
     $product->delete();
     // Redirect to view
     return redirect('/product');
 }

That rounds it up for my whistle-stop tour of resource controllers and resourceful routing. As a Laravel beginner, I’m always looking for feedback on how I can improve and refactor my code. If you have any thoughts on this article, I’d be pleased to hear them; please comment below.

Next, I’ll be looking at the final element of MVC architecture: Views. I’ll be introducing Blade – Laravel’s templating system –  to demonstrate how views interact with controllers to provide the front-end to my Laravel Shopping List application.

Leave a Reply