Skip to content

Commit ef7210c

Browse files
committed
working with lighthouse 5
1 parent 27940d0 commit ef7210c

File tree

3 files changed

+220
-51
lines changed

3 files changed

+220
-51
lines changed

readme.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Laravel Actions Lighthouse
2+
3+
Create Actions with `lorisleiva/laravel-actions` that are resolved by `nuwave/lighthouse` allowing a GraphQL query/mutation to hit an action directly.
4+
5+
## Install
6+
7+
```
8+
composer require petecoop/laravel-actions-lighthouse
9+
```
10+
11+
## GraphQL Actions
12+
13+
Add the `AsGraphQL` trait to your action:
14+
15+
```php
16+
use Petecoop\LaravelActionsLighthouse\AsGraphQL;
17+
18+
class SomeAction
19+
{
20+
use AsAction, AsGraphQL;
21+
}
22+
```
23+
24+
This is resolved based on name of the query in your schema.graphql:
25+
26+
```gql
27+
type Query {
28+
someAction: SomeResult
29+
}
30+
```
31+
32+
Ensure you register the path to the handler in `config/lighthouse.php` this may need to be published first: `php artisan vendor:publish --tag=lighthouse-config`
33+
34+
If adding a mutation then add to mutations - this needs to be done for each folder of actions
35+
```php
36+
[
37+
'namespaces' => [
38+
'queries' => [
39+
'App\\GraphQL\\Queries',
40+
'App\\Actions',
41+
'App\\Actions\\User',
42+
],
43+
]
44+
]
45+
```
46+
47+
You can then use the args from GraphQL directly in your handler:
48+
49+
```php
50+
class SomeAction
51+
{
52+
use AsAction, AsGraphQL;
53+
54+
public function handle(array $args)
55+
{
56+
57+
}
58+
}
59+
```
60+
61+
Or use `asGraphQL` to pull out args from the graphql query:
62+
63+
```php
64+
class SomeAction
65+
{
66+
use AsAction, AsGraphQL;
67+
68+
public function handle(int $userId)
69+
{
70+
//...
71+
}
72+
73+
public function asGraphQL($_, $args)
74+
{
75+
return $this->handle($args['user_id']);
76+
}
77+
}
78+
```
79+
80+
## Validation
81+
82+
You can use [Laravel Action Validation Rules](https://laravelactions.com/2.x/add-validation-to-controllers.html#adding-validation-rules) by using the `@actionValidator` directive.
83+
84+
for example:
85+
86+
```gql
87+
type Mutation {
88+
updateUserName(id: ID!, name: String!): User! @actionValidator
89+
}
90+
```
91+
92+
`rules()`, `getValidationMessages()` and `getValidationAttributes()` currently work.
93+
94+
```php
95+
class UpdateUserName
96+
{
97+
use AsAction, AsGraphQL;
98+
99+
public function handle(array $args)
100+
{
101+
//...
102+
}
103+
104+
public function rules(): array
105+
{
106+
return [
107+
'name' => ['required', 'min:3'],
108+
];
109+
}
110+
}
111+
```

src/ActionValidationDirective.php

Lines changed: 0 additions & 51 deletions
This file was deleted.

src/ActionValidatorDirective.php

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
3+
namespace Petecoop\LaravelActionsLighthouse;
4+
5+
use ReflectionFunction;
6+
use GraphQL\Language\Parser;
7+
use GraphQL\Language\AST\Node;
8+
use Nuwave\Lighthouse\Schema\AST\ASTHelper;
9+
use GraphQL\Language\AST\FieldDefinitionNode;
10+
use Nuwave\Lighthouse\Schema\AST\DocumentAST;
11+
use Nuwave\Lighthouse\Schema\Values\TypeValue;
12+
use Nuwave\Lighthouse\Schema\Values\FieldValue;
13+
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
14+
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
15+
use Nuwave\Lighthouse\Support\Contracts\FieldManipulator;
16+
use Nuwave\Lighthouse\Support\Contracts\ArgumentSetValidation;
17+
18+
class ActionValidatorDirective extends BaseDirective implements ArgumentSetValidation, FieldManipulator
19+
{
20+
protected $action;
21+
22+
public static function definition(): string
23+
{
24+
return /** @lang GraphQL */ <<<'GRAPHQL'
25+
directive @actionValidator(class: String) on FIELD_DEFINITION
26+
GRAPHQL;
27+
}
28+
29+
public function rules(): array
30+
{
31+
$action = $this->action();
32+
if (method_exists($action, 'rules')) {
33+
return $action->rules();
34+
}
35+
36+
return [];
37+
}
38+
39+
public function messages(): array
40+
{
41+
$action = $this->action();
42+
if (method_exists($action, 'getValidationMessages')) {
43+
return $action->getValidationMessages();
44+
}
45+
46+
return [];
47+
}
48+
49+
public function attributes(): array
50+
{
51+
$action = $this->action();
52+
if (method_exists($action, 'getValidationAttributes')) {
53+
return $action->getValidationAttributes();
54+
}
55+
56+
return [];
57+
}
58+
59+
protected function action()
60+
{
61+
if ($this->action === null) {
62+
$this->action = app($this->directiveArgValue('class'));
63+
}
64+
65+
return $this->action;
66+
}
67+
68+
/**
69+
* Give the validator the action class to use later
70+
*/
71+
public function manipulateFieldDefinition(
72+
DocumentAST &$documentAST,
73+
FieldDefinitionNode &$fieldDefinition,
74+
ObjectTypeDefinitionNode &$parentType
75+
) {
76+
$type = new TypeValue($parentType);
77+
$fieldValue = new FieldValue($type, $fieldDefinition);
78+
$fieldValue->useDefaultResolver();
79+
$actionClosure = $fieldValue->getResolver();
80+
81+
$reflect = new ReflectionFunction($actionClosure);
82+
$decorator = $reflect->getClosureThis();
83+
$action = $decorator->getAction();
84+
85+
$this->setFullClassnameOnDirective($fieldDefinition, get_class($action));
86+
}
87+
88+
/**
89+
* Set the full classname of the validator class on the directive.
90+
*
91+
* This allows accessing it straight away when resolving the query.
92+
*
93+
* @param (\GraphQL\Language\AST\TypeDefinitionNode&\GraphQL\Language\AST\Node)|\GraphQL\Language\AST\FieldDefinitionNode $definition
94+
*/
95+
protected function setFullClassnameOnDirective(Node &$definition, string $class): void
96+
{
97+
// @phpstan-ignore-next-line The passed in Node types all have the property $directives
98+
foreach ($definition->directives as $directive) {
99+
if ($directive->name->value === $this->name()) {
100+
$directive->arguments = ASTHelper::mergeUniqueNodeList(
101+
$directive->arguments,
102+
[Parser::argument('class: "'.addslashes($class).'"')],
103+
true
104+
);
105+
}
106+
}
107+
}
108+
109+
}

0 commit comments

Comments
 (0)