Parse Dot-Notation Query Params Into Nested Relationship Arrays

📖 2 minutes read

API query parameters like ?include=author,comments.user.profile need to be converted into nested arrays for eager loading. Here’s a minimal recursive approach that handles unlimited nesting depth.

public function parseIncludes(Request $request): array
{
    $includes = explode(',', $request->input('include', ''));
    
    $buildTree = function($relations) use (&$buildTree) {
        $tree = [];
        foreach ($relations as $relation) {
            $parts = explode('.', $relation, 2);
            $key = $parts[0];
            
            if (isset($parts[1])) {
                $tree[$key][] = $parts[1];
            } else {
                $tree[$key] = [];
            }
        }
        
        foreach ($tree as $key => $nested) {
            if (!empty($nested)) {
                $tree[$key] = $buildTree($nested);
            }
        }
        
        return $tree;
    };
    
    return $buildTree(array_filter($includes));
}

This converts comments.user.profile into ['comments' => ['user' => ['profile' => []]]], ready to pass to your eager loading logic:

public function index(Request $request)
{
    $relations = $this->parseIncludes($request);
    
    return Post::query()
        ->when($relations, fn($q) => $q->load($relations))
        ->paginate();
}

The recursive pattern keeps the code under 30 lines while handling any nesting depth. Each iteration splits on the first dot, creating a tree structure where the first level becomes the array key and everything after the dot gets recursively processed.

This is particularly useful for JSON:API implementations or GraphQL-like query patterns where clients specify exactly which relationships they need. Instead of always eager loading everything or writing manual if/else chains, you can dynamically build the relationship tree from user input.

Daryle De Silva

VP of Technology

11+ years building and scaling web applications. Writing about what I learn in the trenches.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *