The Controllers: Retrieving the list of products

Intro: Things are getting exciting, we have added products to our database, now it’s time to retrieve and display those products on the website. I have added a few more products to the database to have something to display, you can do the same too. Almost all the images of the products are downloaded from unsplash.com.

Now let’s start retrieving the products. Let me break the process down into the following steps:

  1. Create a function inside ProductsController
  2. Retrieve all the items of the products list
  3. Update the route to invoke this function
  4. Display the fetched items in the products view

Steps:

First, open the ProductsController file

Create a new function, lets name it index public function index() { }

Inside this function, we shall call the function all() of the model Product. This returns a Collection, so we shall create a variable to hold it, let’s name it $products. public function index() { $products=Product::all(); }

Pass this collection $products to the products view. Add a return statement, call the function view() pass the name of the view, call the function with()…. the first parameter of this function is the name of the variable by which we shall access the data inside the view, and the second parameter is the data itself.
public function index()
{
$products=Product::all();
return view('products')->with('products',$products);
}

Update the route, until now we have been returning the products view from the route file itself. And technically there is nothing wrong, in fact, we can handle all the HTTP requests inside the route file itself without creating the controllers but we shall end up with some unorganized code. Using controllers helps us organize better, it helps us write more maintainable code. So let us replace the closure of the second parameter with a call to the function index() of the ProductsController. Route::get('/',[ProductsController::class,'index'] );

Now try to load the website, and the product list page is getting loaded without any error. This means that all we have done till now is working properly. We now have to display the items of the products collection inside the view replacing these static content.

So open the file products.blade.php

Here we can access the data passed to it by the name that we have provided while returning this view from the index() function of the ProductsController. A foreach loop will be more convenient than this for loop here. So let’s replace this for loop with a foreach loop. Notice the syntax of the foreach loop, inside the brackets first we have to specify the collection to iterate through and after the keyword as we have to add a variable to hold the individual items of the collection, let’s name it $p

<x-base-layout>
      <!-- Main Content -->
      <div class="grid grid-cols-4 gap-4 p-4">
        @foreach($products as $p)
        <a href="/product/1">
          <div class="bg-white rounded shadow overflow-hidden">
            <img src="https://images.unsplash.com/photo-1505740420928-5e560c06d30e?ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8cHJvZHVjdHxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=60"/>
            <div class="p-4">
              <div class="font-semibold text-sm">Headphone</div>
              <div class="text-xs text-gray-500">Excellent quality Headphone at a low price</div>
            </div>
            <div class=" border-t px-4 py-2 font-bold text-sm">$20</div>
          </div>
        </a>
        @endforeach
      </div>
</x-base-layout>

Now replace the static texts with the data of the variable $p, On the URL of the href attribute replace the static id with the {{$p→id}} . Don’t miss these curly brackets, these are required to print variables in Laravel.
<a href="/product/{{$p->id}}">
Replace the static text “Headphone” with the actual title {{$p→title}}
<div class="font-semibold text-sm">{{$p->title}}</div>
Use {{$p→short_desc}} for the short description.
<div class="text-xs text-gray-500">{{$p->short_desc}}</div>
Replace the number 20 by {{$p→price}} , keep the dollar sign
<div class=" border-t px-4 py-2 font-bold text-sm">${{$p->price}}</div>
And also provide the actual image URL to the img element
<img src="{{$p->image_url}}"/>

Now the complete code looks like this:

<x-base-layout>
      <!-- Main Content -->
      <div class="grid grid-cols-4 gap-4 p-4">
        @foreach($products as $p)
        <a href="/product/{{$p->id}}">
          <div class="bg-white rounded shadow overflow-hidden">
            <img src="{{$p->image_url}}"/>
            <div class="p-4">
              <div class="font-semibold text-sm">{{$p->title}}</div>
              <div class="text-xs text-gray-500">{{$p->short_desc}}</div>
            </div>
            <div class=" border-t px-4 py-2 font-bold text-sm">${{$p->price}}</div>
          </div>
        </a>
        @endforeach
      </div>
</x-base-layout>

And our products page look like this,

But this is not what we expected right! This has happened because the location of our images is not publicly accessible from the browser. To make it accessible we have to create a symbolic link from the public folder to the one where we have kept the images. A symbolic link is a file that contains a reference to another file or folder.

We can create a symbolic link from the public/storage to storage/app/public with this artisan command. php artisan storage:link If you run this command you’ll notice that a special type of folder named storage with a logo that looks a little different gets created inside the public folder. This is a link to the folder storage/app/public, but we have kept the images inside a different folder storage/app/product_images. So let us define a new link. Open the file filesystems.php that is inside the folder config. This file contains the filesystem-related configurations as the name suggests. To the bottom of this file, you’ll find an array of symbolic links named ‘links’. Notice how the default link is defined here … public_path(‘storage’) => storage_path(‘app/public’), We shall add another symbolic link here , so copy this line and paste it once. Pass ‘product_images’ to the function public_path() and ‘app/product_images’ to the function on the right hand side of the fat arrow, storage_path().

'links' => [
        public_path('storage') => storage_path('app/public'),
        public_path('product_images') => storage_path('app/product_images'),
    ],

Now run the command php artisan storage:link again. Now we have a new folder named product_images.

Now, let us come back to the view products. (NOT MENDATORY) And we shall pass the image URL to the img element. Laravel provides a helper function named asset() to create a URL for an asset, let’s use it.
<img src="{{asset($p->image_url)}}"/>
$p->image_url gives us the image path as stored on the database.

<x-base-layout>
      <!-- Main Content -->
      <div class="grid grid-cols-4 gap-4 p-4">
        @foreach($products as $p)
        <a href="/product/{{$p->id}}">
          <div class="bg-white rounded shadow overflow-hidden">
            <img src="{{asset($p->image_url)}}"/>
            <div class="p-4">
              <div class="font-semibold text-sm">{{$p->title}}</div>
              <div class="text-xs text-gray-500">{{$p->short_desc}}</div>
            </div>
            <div class=" border-t px-4 py-2 font-bold text-sm">${{$p->price}}</div>
          </div>
        </a>
        @endforeach
      </div>
</x-base-layout>

Now, reload the page….and we have the images. It looks beautiful.

Conclusion: But, if you click on an item of this list the details page still looks the same. So in the next video we shall add a new controller function to retrieve the data of a particular product by id and replace the static content of the details page with the product information from the database.

Leave a Reply

Your email address will not be published.