Installation:
composer require lastdragon-ru/lara-asp-graphql
Ensure your composer.json meets the PHP/Laravel version requirements.
Publish Config (Optional):
php artisan vendor:publish --provider="LastDragon\LaraAspGraphQL\LaraAspGraphQLServiceProvider" --tag="config"
Modify config/lara-asp-graphql.php if needed (e.g., custom operators, default behavior).
First Use Case:
Define a GraphQL type with @searchBy and @sortBy directives. Example:
type User @model {
id: ID! @searchBy
name: String @searchBy
email: String @searchBy(operators: ["=", "!=", "contains"])
posts: [Post!]! @searchBy(relation: "posts")
}
Query with filtering:
query {
users @searchBy(where: { email: { _eq: "test@example.com" } }) {
id
name
}
}
Searching with @searchBy:
_eq, _neq, _gt, _lt, etc. for field comparisons.
users @searchBy(where: { age: { _gt: 25 } })
posts @searchBy(where: { author: { _eq: { id: 1 } } })
and/or/not.
users @searchBy(where: {
and: [
{ name: { _contains: "John" } },
{ not: { active: { _eq: false } } }
]
})
type UserStatus @enum {
ACTIVE
INACTIVE
}
# Query:
users @searchBy(where: { status: { _eq: ACTIVE } })
Sorting with @sortBy:
users @sortBy(orderBy: [{ field: "name", direction: ASC }])
posts @sortBy(orderBy: [{ field: "author.name", direction: DESC }])
Streaming with @stream:
users @stream(first: 10) {
id
name
}
Lighthouse Schema:
Extend existing Lighthouse types without breaking changes. Use @searchBy on existing fields or add new ones.
type User @model {
# Existing fields...
createdAt: DateTime @searchBy(format: "Y-m-d")
}
Dynamic Directives:
Use resolve functions to dynamically apply directives based on runtime logic (e.g., role-based filtering).
type Query {
adminUsers: [User!]! @searchBy(where: { role: { _eq: "admin" } })
}
Performance:
@searchBy are indexed.@field or @resolve to avoid N+1 queries with relations.
type User @model {
posts: [Post!]! @field(resolve: "postsWithPagination")
}
Type Mismatches:
@searchBy enforces strict typing. Ensure query operators match field types (e.g., _contains for String, not Int).Mixed type sparingly; prefer explicit types like String! or Int!.Relation Ambiguity:
author.posts.title) may fail if intermediate relations lack proper @searchBy definitions.@searchBy on all intermediate relation fields or use dot notation carefully.Operator Overload:
_startsWith) must be registered in the config or schema. Undefined operators throw errors.config/lara-asp-graphql.php:
'operators' => [
'string' => [
'startsWith' => 'like',
'endsWith' => 'like',
],
],
Pagination Conflicts:
@stream may conflict with Lighthouse’s default pagination. Ensure first/after args are consistent.config/lighthouse.php if using @stream.Case Sensitivity:
_contains/_startsWith. MySQL’s utf8mb4_general_ci is case-insensitive; utf8mb4_bin is strict._icontains (if supported) or standardize case in queries.Query Validation Errors: Use GraphQL Playground/Altair to inspect errors. Enable Lighthouse’s debug mode:
'debug' => env('APP_DEBUG', false),
in config/lighthouse.php.
SQL Logging: Enable Laravel’s query logging to verify generated SQL:
DB::enableQueryLog();
// Execute query...
dd(DB::getQueryLog());
Directive Resolution: Override directive resolvers in a custom service provider:
public function boot()
{
$this->app->extend('lighthouse.directives.searchBy', function ($resolver) {
return new CustomSearchByResolver($resolver);
});
}
Custom Operators:
Extend the package by adding operators in config/lara-asp-graphql.php:
'operators' => [
'string' => [
'customOp' => 'raw', // Uses raw SQL
],
'callback' => [
'isActive' => function ($query, $value) {
return $query->where('status', 'active')->orWhere('suspended_at', '>', now());
},
],
],
Custom Directives: Create reusable directives by extending the base classes:
namespace App\GraphQL\Directives;
use LastDragon\LaraAspGraphQL\Directives\BaseDirective;
class CustomSearch extends BaseDirective
{
protected function resolve(): void
{
// Custom logic
}
}
Register in config/lara-asp-graphql.php:
'directives' => [
'customSearch' => \App\GraphQL\Directives\CustomSearch::class,
],
Relation Handling: Override relation resolution for complex cases:
type User @model {
orders: [Order!]! @searchBy(
relation: "orders",
resolver: "customOrderResolver"
)
}
Define resolver in a Lighthouse resolver class.
Performance Hooks:
Use Laravel’s model events to preload relations before @searchBy executes:
User::addGlobalScope('preloadRelations', function (Builder $builder) {
$builder->with(['posts.author']);
});
Reusable Fragments:
Define GraphQL fragments for common @searchBy queries:
fragment UserFilter on User @searchBy {
id: ID @searchBy(operators: ["=", "!="])
name: String @searchBy(operators: ["_contains"])
}
API Versioning:
Use @deprecated alongside @searchBy to phase out old fields:
field oldName: String @searchBy @deprecated(reason: "Use 'name' instead")
Testing: Mock directives in PHPUnit:
$this->app->instance('lighthouse.directives.searchBy', $mockResolver);
How can I help you explore Laravel packages today?