Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ultrawelfare's avatar

Modular Laravel Query Questions

I recently watched the modular laravel series from Laracasts. It was an amazing series but it kinda missed a point for me on the topic of querying.

In terms of business-logic it revolves around Actions (or Commands). But when it comes to query how do you handle it ?

I'd bet you can create a similar kind of class QueryProductsForUser(int $userId) but what does that return ? Do you return an Eloquent Model ( / Collection of them), or do you return a Collection of ProductDtos?

If you return DTOs, what happens if the Product DTO grows in terms of relationships? You'd definitely not want to load all of the relationships for each case a caller has. Is it better to have multiple DTOs for each query class? QueryProductsForUser -> QueryProductsForUserDto QueryUserById -> QueryUserByIdDto

Also, what about laravel views and API Resources?

For laravel views, you'd have to pass the DTOs into blade (or transform them into a ViewModel to pass into blade?) For API's, I'd bet you won't need API Resources since the DTO is already pretty much good to go. Unless there's differences or you want to keep your endpoint schema organized in which that case you could have a ...Response class that can be created from the DTO.

What's your opinions on these?

0 likes
1 reply
LaryAI's avatar
Level 58

When it comes to handling queries in a modular Laravel application, there are several approaches you can take, and the best one often depends on the specific needs of your application and your personal preferences. Here's a breakdown of the options you mentioned and some considerations for each:

Returning Eloquent Models or Collections

Returning Eloquent models or collections directly from your query classes is the simplest approach and works well for straightforward use cases. However, it tightly couples your query logic to the Eloquent ORM and can lead to issues if you need to change your data source or structure in the future.

Returning Data Transfer Objects (DTOs)

Using DTOs can help decouple your application logic from the database layer and provide a more flexible way to handle data transformation. Here's an example of how you might implement a query class that returns DTOs:

class QueryProductsForUser
{
    public function execute(int $userId): Collection
    {
        $products = Product::where('user_id', $userId)->get();

        return $products->map(function ($product) {
            return new ProductDto($product);
        });
    }
}

If your ProductDto grows in terms of relationships, you can indeed create multiple DTOs for different use cases. This allows you to tailor the data you load and transform to the specific needs of each case, which can improve performance and reduce overhead.

Laravel Views and API Resources

For Laravel views, you can pass DTOs directly to Blade templates, or you can transform them into ViewModels if you need to add presentation logic that shouldn't be in the DTO. Here's an example of passing a DTO to a Blade view:

public function showProductsForUser(int $userId)
{
    $query = new QueryProductsForUser();
    $productDtos = $query->execute($userId);

    return view('products.index', ['products' => $productDtos]);
}

For APIs, while you could use DTOs directly, API Resources provide a standardized way to format and control the output of your API responses. They can be particularly useful if you need to apply specific transformations or if you want to maintain a consistent API response structure.

Here's an example of how you might use an API Resource:

use App\Http\Resources\ProductResource;

public function apiProductsForUser(int $userId)
{
    $query = new QueryProductsForUser();
    $productDtos = $query->execute($userId);

    return ProductResource::collection($productDtos);
}

In this case, the ProductResource would be responsible for transforming the ProductDto into the desired JSON structure for the API response.

Conclusion

Ultimately, the approach you choose should be guided by the needs of your application and your team's preferences. Using DTOs can provide a clean separation of concerns and flexibility, while leveraging Laravel's built-in features like API Resources can help maintain consistency and reduce boilerplate code. It's also perfectly fine to mix and match these approaches as needed.

Please or to participate in this conversation.