3
\$\begingroup\$

I want to pass the param from the request on the scope method in the model and serve it as json to be rendered by select2. Which is better?

1. Pass request from the controller like this

controller:

public function selectJson(Request $request)
{

    $request = Customer::getSelect2($request)


    return \Response::json($request);
}

model:

public function scopeGetSelect2($query, $request)
{
    $customers = $query->select('id','name')->orderBy('name','asc')->where("name", "like", "%".$request->q."%");

    if($request->city_id)
    {
        $customers = $query->where("city_id", $request->city_id);

    }
    $customers = $customers->limit(5)->get();
    $formatted_tags = [];

    foreach ($customers as $customer) {
        $formatted_tags[] = ['id' => $customer->id, 'text' => $customer->name];
    }

    return $formatted_tags;
}

2. Use request() helper in the model

Controller:

public function selectJson()
{

    $request = Customer::getSelect2()


    return \Response::json($request);
}

Model:

public function scopeGetSelect2($query)
{
    $customers = $query->select('id','name')->orderBy('name','asc')->where("name", "like", "%".request()->q."%");

    if($request->city_id)
    {
        $customers = $query->where("city_id", request()->city_id);

    }
    $customers = $customers->limit(5)->get();
    $formatted_tags = [];

    foreach ($customers as $customer) {
        $formatted_tags[] = ['id' => $customer->id, 'text' => $customer->name];
    }

    return $formatted_tags;
}

Which is better in performance and best practice? And should I format the return in the model like above codes or in the controller like below:

public function selectJson()
{

    $customers = Customer::getSelect2()->limit(5)->get();
    $formatted_tags = [];

    foreach ($customers as $customer) {
        $formatted_tags[] = ['id' => $customer->id, 'text' => $customer->name];
    }

    return \Response::json($formatted_tags);
}

Or any other method or concern that I need to know?

Thanks in advance

\$\endgroup\$
0
\$\begingroup\$

Laravel scopes are not a way to create static methods, they should be used to add parts to a database query. They should always return a query builder.

Aim to make your scopes as small as possible so you can then combine them together to make more complex queries.

It doesn't matter if you use the Request passed in to the controller or the request() helper, use whichever you prefer.

If you aren't going to reuse the getSelect2() method you don't need to add it to the model, just do the query in the controller. If you do need to repeat the query elsewhere you can make a new class that can build the options ($formatted_tags).

class Customer extends Model
{
    // ...

    public function scopeNameLike($query, $name): void
    {
        $query->orderBy('name','asc')->where("name", "like", "%{$name}%");
    }

    // ...
}
class Controller
{
    public function selectJson(Request $request)
    {
        return Customer::nameLike($request->q)
            ->when($request->city_id, function ($query, $value) {
                $query->where('city_id', $value);
            })
            ->limit(5)
            ->get(['name', 'id'])
            ->map(function ($item) {
                return ['id' => $item->id, 'text' => $item->name];
            });
    }
}

Is return something in scope really bad practice? What about the normal method in the model? I have so many tables/models that I need to format to select2 format. Am I need to format it in every controller? – Muhammad Dyas Yaskur

I was mistaken that scopes shouldn't return a value, as per the Laravel documentation they should return a query builder instance. It would be bad practice to return any other value from a scope.

If you need many of these types of queries for different models you can create a helper class that can then be reused.

class Select2
{
    public static function customer(Request $request)
    {
        // Query moved from controller
    }
}
class Controller
{
    public function selectJson(Request $request)
    {
        return Select2::customer($request);
    }
}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Is return something in scope really bad practice? What about the normal method in the model? I have so many tables/models that I need to format to select2 format. Am I need to format it in every controller? \$\endgroup\$ – Muhammad Dyas Yaskur Jun 17 at 20:58
  • \$\begingroup\$ okay, thank for your explanation, I have so many models that I need to select2 format, should I declare static method every model? What about using a trait like on my another question? codereview.stackexchange.com/questions/244071/… \$\endgroup\$ – Muhammad Dyas Yaskur Jun 17 at 21:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.