简体   繁体   中英

Where should I place complex queries in Laravel?

So I've searched the internet for similar cases, and I just got lost from all contradicting answers, and unrelated scenarios. So I thought to put my case hoping to get some specific answers.

I am new to Laravel, and creating small application. In the application I have to search for offeres and show the result in a blade view. Since the query is complex, and output of the search does not belong to a specific Model, I just wish to keep it as a raw query.

I have placed the query in the controller, but I just don't feel it's the right place. Especially if I need to reuse the query in many places.

Here's the method from the OfferController:

public function search(Request $request)
{
    $area =  $request->area;
    $size =  $request->size;

    $sql = "SELECT distinct product_name,product_offer.quantity, product_offer.price
            FROM product
            inner join brand on product.brand_id = brand.brand_id
            inner join brand_area on brand_area.brand_id = brand.brand_id
            inner join area on area.area_id = brand_area.area_id
            inner join product_offer on product_offer.product_id = product.product_id
            where area.area_id = :area
            and  product.size_id = :size ";

    $params = array(
        'area'=>$area,
        'size'=>$size
    );

    $offers = DB::select( DB::raw($sql), $params);

    return view('searchresult')->with($offers);

}

So in short: should I move the query to the model, create DAL class, or keep it here? Baring in mind the project is small scale.

You have a fair point saying it does not look right to place query in the controller. I would offer you to have a look at the concept of Laravel repository pattern:

https://dev.to/asperbrothers/laravel-repository-pattern-how-to-use-why-it-matters-1g9d

Also, I think you could use Laravel DB for this kind of query without the need to write it as a raw query. I do not think there is a huge need to have a raw query here. Laravel DB table() , select() , where() and other methods should be enough.

Actually, you could potentially write this using models and their relationships, but if the query is quite slow, it is better to use query builder for better efficiency.

EDIT:

also for some specific queries which do not belong to anything I remember seeing custom trait used, could also be a solution.

in my opinion, if you are going to reuse it, create a service that will perform that query and gives you back a result, something like SearchService that looks like this:

<?php

class SearchService
{

  public static function perform(array $params){
     $sql = "SELECT distinct product_name,product_offer.quantity, product_offer.price
            FROM product
            inner join brand on product.brand_id = brand.brand_id
            inner join brand_area on brand_area.brand_id = brand.brand_id
            inner join area on area.area_id = brand_area.area_id
            inner join product_offer on product_offer.product_id = product.product_id
            where area.area_id = :area
            and  product.size_id = :size ";

    return DB::select( DB::raw($sql), $params);
  }
}

?>

And by doing so, you can just call

SearchService::perform([...]);

to get the results.
Obviously this is version1.0, you can improve it in a lot of ways, for example making it not static in order to make it testable, and also to allow getter and setter to exists, and a lot of other things, that might be usefull

I'm writing my previous comment as an answer since I think its really what you are looking for:

I suggest you use a Trait to do this. The reason why is that it will keep your code clean and you'll be able to reuse this code later for other uses. A Trait is made for reusable code.

You will create a Trait:

<?php

namespace App\Traits;    // Optional, but you could create a namespace for all your Traits if you need others

trait MyCustomTrait
{
    public function perform(array $params) {
         $sql = "SELECT distinct product_name,product_offer.quantity, product_offer.price
                FROM product
                inner join brand on product.brand_id = brand.brand_id
                inner join brand_area on brand_area.brand_id = brand.brand_id
                inner join area on area.area_id = brand_area.area_id
                inner join product_offer on product_offer.product_id = product.product_id
                where area.area_id = :area
                and product.size_id = :size ";

         return DB::select( DB::raw($sql), $params);
    }
}

To use it, only write: use MyCustomTrait in the scope of your controller and call your function like this: $this->perform([...]) .

Here's some links to learn more about traits:

Hope it helps you!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM