1
<?php
2

3
namespace Nuwave\Lighthouse\OrderBy;
4

5
use GraphQL\Language\AST\FieldDefinitionNode;
6
use GraphQL\Language\AST\InputValueDefinitionNode;
7
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
8
use GraphQL\Language\Parser;
9
use Nuwave\Lighthouse\Schema\AST\ASTHelper;
10
use Nuwave\Lighthouse\Schema\AST\DocumentAST;
11
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
12
use Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective;
13
use Nuwave\Lighthouse\Support\Contracts\ArgDirectiveForArray;
14
use Nuwave\Lighthouse\Support\Contracts\ArgManipulator;
15
use Nuwave\Lighthouse\Support\Contracts\FieldBuilderDirective;
16
use Nuwave\Lighthouse\Support\Traits\GeneratesColumnsEnum;
17

18
class OrderByDirective extends BaseDirective implements ArgBuilderDirective, ArgDirectiveForArray, ArgManipulator, FieldBuilderDirective
19
{
20
    use GeneratesColumnsEnum;
21

22 1
    public static function definition(): string
23
    {
24
        return /** @lang GraphQL */ <<<'GRAPHQL'
25 1
"""
26
Sort a result list by one or more given columns.
27
"""
28
directive @orderBy(
29
    """
30
    Restrict the allowed column names to a well-defined list.
31
    This improves introspection capabilities and security.
32
    Mutually exclusive with the `columnsEnum` argument.
33
    Only used when the directive is added on an argument.
34
    """
35
    columns: [String!]
36

37
    """
38
    Use an existing enumeration type to restrict the allowed columns to a predefined list.
39
    This allowes you to re-use the same enum for multiple fields.
40
    Mutually exclusive with the `columns` argument.
41
    Only used when the directive is added on an argument.
42
    """
43
    columnsEnum: String
44

45
    """
46
    The database column for which the order by clause will be applied on.
47
    Only used when the directive is added on a field.
48
    """
49
    column: String
50

51
    """
52
    The direction of the order by clause.
53
    Only used when the directive is added on a field.
54
    """
55
    direction: OrderByDirection = ASC
56
) on ARGUMENT_DEFINITION | FIELD_DEFINITION
57

58
"""
59
Options for the `direction` argument on `@orderBy`.
60
"""
61
enum OrderByDirection {
62
    """
63
    Sort in ascending order.
64
    """
65
    ASC
66

67
    """
68
    Sort in descending order.
69
    """
70
    DESC
71
}
72
GRAPHQL;
73
    }
74

75
    /**
76
     * Apply an "ORDER BY" clause.
77
     *
78
     * @param  \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder  $builder
79
     * @param  array<array<string, string>>  $value
80
     * @return \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder
81
     */
82 1
    public function handleBuilder($builder, $value): object
83
    {
84 1
        foreach ($value as $orderByClause) {
85 1
            $builder->orderBy(
86 1
                $orderByClause['column'],
87 1
                $orderByClause['order']
88
            );
89
        }
90

91 1
        return $builder;
92
    }
93

94 1
    public function manipulateArgDefinition(
95
        DocumentAST &$documentAST,
96
        InputValueDefinitionNode &$argDefinition,
97
        FieldDefinitionNode &$parentField,
98
        ObjectTypeDefinitionNode &$parentType
99
    ): void {
100 1
        if ($this->hasAllowedColumns()) {
101 1
            $restrictedOrderByName = ASTHelper::qualifiedArgType($argDefinition, $parentField, $parentType).'OrderByClause';
102 1
            $argDefinition->type = Parser::typeReference("[$restrictedOrderByName!]");
103 1
            $allowedColumnsEnumName = $this->generateColumnsEnum($documentAST, $argDefinition, $parentField, $parentType);
104

105
            $documentAST
106 1
                ->setTypeDefinition(
107 1
                    OrderByServiceProvider::createOrderByClauseInput(
108 1
                        $restrictedOrderByName,
109 1
                        "Order by clause for the `{$argDefinition->name->value}` argument on the query `{$parentField->name->value}`.",
110 1
                        $allowedColumnsEnumName
111
                    )
112
                );
113
        } else {
114 1
            $argDefinition->type = Parser::typeReference('['.OrderByServiceProvider::DEFAULT_ORDER_BY_CLAUSE.'!]');
115
        }
116
    }
117

118
    /**
119
     * @param  \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder  $builder
120
     * @return \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder
121
     */
122 1
    public function handleFieldBuilder(object $builder): object
123
    {
124 1
        return $builder->orderBy(
125 1
            $this->directiveArgValue('column'),
126 1
            $this->directiveArgValue('direction', 'ASC')
127
        );
128
    }
129
}

Read our documentation on viewing source code .

Loading