The function gets data table, passes to recursive function to get associative array back. 
Encodes the array to JSON and returns back to user:
public function getCategoryTreeJSON()
{
    $query = "  SELECT
                    c1.id,
                    c1.name,
                    c1.parent_id,
                    (
                        SELECT
                            COUNT(c2.id) 
                        FROM
                            categories AS c2 
                        WHERE
                            c2.parent_id = c1.id
                    )
                    AS children_count 
                FROM
                    categories AS c1";
    $categoryDetails = json_decode(json_encode(DB::select($query)), true);
    
    $array_tree = $this->getCategoryTreeArray($categoryDetails);
    return json_encode($array_tree);
}
Recursive function that returns multi level associative array.
Base case: when 
children_count
 is equal to zero.
public function getCategoryTreeArray($items, $parent_id = 0)
{
    $branch = [];
    $array_JSON = [];  
    foreach ($items as $item) {
        if ($item['parent_id'] == $parent_id) {
            if ($item['children_count'] > 0) {
                
                $array_JSON[] = [
                    'id'=>$item['id'],
                    'title'=>$item['name'],
                    'subs'=>$this->getCategoryTreeArray($items, $item['id'])
                ];
                
            } else {
                
                $array_JSON[] = [
                    'id'=>$item['id'],
                    'title'=>$item['name']
                ];
            }
            
        }
    }
    return $array_JSON;
}