hfalucas's avatar

Using cursors with fractal to paginate content

So I am using the fractal package to build an API and recently having trouble with pagination. I'll try to give a basic but accurate example of my code. The Cursor implementation is working fine and all the problem is in the query I think.

So basically I have this:

public function trainers($query, Request $options)
{
        $howMany = $options->get('howMany', 20);
        $current = base64_decode( (string) $options->get('cursor', false));
        $country = $options->get('country', '*');

        $tableJoins = $this->defineTableJoins($country);
        $filteredResults = $this->resolveSearchFilters($tableJoins, $options);

        $trainers = $this->makeSearch($filteredResults, $query, $howMany);
        
        if( ! $current ) return $trainers->get( $this->fieldsToDisplay() );

        return $trainers->where('users.created_at', '>', $current)->get( $this->fieldsToDisplay() );
}

private function defineTableJoins($country)
{
        return User::isActive()
                    ->whereHas('roles', function($query){
                        $query->where('name', 'trainer');
                    })
                    ->join('trainers', 'users.userable_id', '=', 'trainers.id')
                    ->leftJoin('city_trainer', 'trainers.id', '=', 'city_trainer.trainer_id')
                    ->leftJoin('cities', 'cities.id', '=', 'city_trainer.city_id')
                    ->join('regions', 'regions.id', '=', 'trainers.region_id')
                    ->join('countries', 'users.country_id', '=', 'countries.id')
                    ->where('regions.country_code', $country);
}

private function matchSearchQuery($query)
{
        $results = function($q) use ($query) {
            $q->where('users.name', 'LIKE', "%{$query}%")
              ->orWhere('regions.name', $query)
              ->orWhere('cities.name', 'LIKE', "%{$query}%")
              ->orWhere('trainers.zip_code', $query);
        };

        return $results;
}

private function makeSearch($filteredResults, $query, $howMany)
{
        $result = $filteredResults->where( $this->matchSearchQuery($query) )
                                  ->distinct()
                                  // ->orderBy('trainers.pro_member', 'DESC');
                                  // ->orderBy('users.is_atiiv', 'DESC')
                                  // ->orderBy('trainers.pro_member', 'DESC')
                                  ->orderBy('users.created_at', 'ASC')
                                  ->take($howMany);

        return $result;
}

private function fieldsToDisplay()
{
        return [
            'users.*',
            'regions.name as region',
            'countries.printable_name as country',
            'trainers.accepting_clients as accepting_clients',
            'trainers.pro_member as pro_member' 
        ];
}

In the trainers() function the cursor that I'm using is the created_atfield (transformed to a string with Carbon). So if the cursor is defined I try to fetch the next 20 trainers that have a created_atdate bigger then the one provided. Then the makeSearch() method orders the results by the created_at field and everything works fine.

The problem is when I add another orderBy, to show first the pro_members.

If I first order by the created_at date the pro members will not show up in first and if I order by pro_membersfirst I won´t be able to get all records.

Pleaase help, going crazy with this ...

0 likes
0 replies

Please or to participate in this conversation.