TutanRamon's avatar

Question about a dashboard controller

I've a couple of years PHP experience (spaghetti style ;-)). At the moment I am building my first MVC application using Laravel.

I am writing a dashboard page with lots of different kind of information, ie "Amount of visitors", "Amount of sold products", "catalogue size", "newest product" etc. etc. Back in the 'old days', I usually had a functions.php with all kinds of functions to retrieve this information. Then, I called these functions from the actual dashboard page template. I know, that's not the nicest way and a horror for other developers. That's one of the reasons why I wanted to go for Laravel.

I defined the template, the basic controllers and models for Product, Transaction, Visitor etc. But now I am kinda stuck. What's the best practice for sending all this data to the view? After reading on the web I concluded I have two possibilities:

  • Writing a dashboard controller with all kind of methods to retrieve the data needed
  • Making use of a facade which retrieves the data for me (from all the other controllers) and sends one(??) object with all the info to the view

Is one of the above the right approach for my 'challenge'?

0 likes
8 replies
Khare's avatar
Khare
Best Answer
Level 7

Hi.

The best practice to send this to the view is to try to get as many of these properties with scopes or methods on your models I think. This way you can pass through the object to the view and call methods on them within blade to retrieve this information. This keeps your controller nice and clean while keeping the logic related to the model where it should be.

Also, you should set up relationships so that you can retrieve other related objects. This way you limit the data you need to pass in the view to your controller.

Take newest product for example:

On Product Model:

public function category 
{
    return $this->belongsTo(Category::class);
}

public function scopeLatestFirst($query, $categoryId)
{
    return $query->where('category_id', $categoryId)-> orderBy('created_at', 'desc')->get();
}

In controller:

public function index()
{
    $products = Product::latestFirst('insert wanted categoryid');

    return view('products.someview', compact('products'));
}

In view:

  @foreach ($products as $product)
  <h1>{{ $product->title }}</h1>
 <h2> {{ $product->category->title }}</h2>
 @endforeach
TutanRamon's avatar

Hi Khare,

Thanks for your prompt reply. I think I understand what you are doing, but you say "In controller" as a title above the example code. Which controller are you refering to? Is that the new 'dashboardController' or the 'productController'? I think it's the dashboardController. If so, can I then simply do this for other info for example?

public function index()
{
    $products = Product::latestFirst('insert wanted categoryid');
    return view('products.someview', compact('products'));

    $catalogueSize = Product::count('category..');
    return view('products.someview', compact('catalogueSize'));

    $transactions = Transaction::latestFirst();
    return view('products.someview', compact('transactions'));
}

Or am I wrong at this?

Khare's avatar

I guess this depends on how you have structured your project. I generally like to keep my controllers responsible for one class. So I would have one ProductsController and one TransactionsController (depending on the complexity of the controllers).

So if you want to pass that data to your view in the example you gave I would do it like this:

public function index()
{
    $products = Product::latestFirst($categoryId);
    $transactions = Transaction::latestFirst();
    $catalogueSize = $products->count();

    return view('products.someview, compact('products', 'transactions', 'catalogueSize'));
}

Note that you can access the catalogue size in your view without having to make a new variable in your controller explicitly for that. Just do {{ $products->count() }}

This saves some code in your controller, and you can do this because your scope already limits the products to the categoryId that you pass in, so you would only get the products in that category.

TutanRamon's avatar

OK, so this is the dashboardController. Thanks. I only need to add some "use App\Product" and "use App\Transaction" at the top of this controller, right?

TutanRamon's avatar

Just to be sure: I don't need a Dashboard model, do I?

Khare's avatar

Not unless you have a database tabel named dashboard that you need to manage.

You do however need to do some basic things to get relationships up and going like setting up a foreign key on your database table and setting up the inverse relationship on the category model.

On category model:

use App\Product;

public function products() 
{
    return $this->hasMany(Product::class);
}

on products table:

$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('products');

Now when you create a new instance of product you can reference the relationship and Laravel will automatically associate the product with the category.

Please or to participate in this conversation.