0

I'm converting a page to Laravel. I used to have a PHP script (GET) that handled select queries from any table. All I had to do was sent the table parameter, and it would return the result.

The idea was to have a controller like this:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;
use DB;

class Projects extends Controller
{
    /**
     * Get projects based on the table
     *
     * @return Response
     */
    public function index($table)
    {
        $result = DB::select("SELECT projectid FROM `" . $table . "` WHERE isClass=1 LIMIT 10");

        return view('pages.allviews', ['results' => $result]);
    }
}

The problem is that page will execute this query three times. Happens that, the controller will create the View right after executing, and the only solution would be to repeat the query three times in the controller.

I want to avoid doing that, I want to separate the controller from what the page needs, and be able to execute it the times the page needs. Generalizing is the key.

Is there a way to do this, and keep this abstraction without having to create a new controller?

3
  • Create another class, as long as it's namespaced properly you can refer to it as and when you need. Commented Mar 21, 2016 at 16:58
  • Can you give me an example of how I can refer to it three times for the same View? Commented Mar 21, 2016 at 16:59
  • use \path\for\namespace\classname, then $this->data['grabbed_stuff'] = classname::method(); then view('some.view',$this->data). $grabbed_stuff will be available to your view Commented Mar 21, 2016 at 17:03

1 Answer 1

1

There are many ways to do this but the most important thing is here that, you should extract your query logic from the controller to a separate class so you can re-use the object. Basically, a repository class would be good for this but it would be possible to create a query object as well. Anyways, let's keep it simple. So, as I mentioned that, you have many options and depending on your project, you may decide the strategy.

In your case, you may simply use the DB::table() method and cache it for a while so for the next subsequent calls, the cached result will be returned. See the examle now:

$limit = 10;
$table = 'users';
$select = ['id', 'name'];
$result = \Cache::remember($table, 60, function() use ($table, $select, $limit) {
    return \DB::table($table)->limit($limit)->get($select);
});

Then to access the cached query, you may use this:

if(\Cache::has('users')) {
    $users = \Cache::get('users');
}

So, while this may solve your problem but I suggest you to create a separate class and keep that query logic (with caching) in that class, for example:

namespace Some\Namespace;

use DB, Cache;

class CachedQuery {

    public function getResult($table, $select = '*', $limit = 10, $timeout = 60)
    {
        return Cache::remember($table, $timeout, function() use ($table, $select, $limit) {
            return DB::table($table)->limit($limit)->get($select);
        });
    }
}

Then use it like:

use Some\Namespace\CachedQuery;

class SomeController extends Controller {
    public function index(CachedQuery $cachedQuery, $table)
    {
        // The $table parameter is required, rest are optional
        $result = $cachedQuery->getResult($table, ['projectid']);
    }
}

Also, you can use IoC/Service Container object to store data temporarily. Also, it's possible to create an interface and bind the interface to a class to get it from Service Container but I kept it as simple as I can. Hope you got the idea. Also, check the Cache component.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you, it's useful. But imagine I want to make a lot of queries in a View, all different, and I have one controller for each. How can I call each controller for the same view?
Well, you are not suppose to make queries from within view.
So, taking in consideration this is a normal behaviour and possible common use, how should I do it? Just call a query within the page, whenever I need it? Or is there a way of abstracting it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.