Skip to content

Commit

Permalink
Minor API & docs changes
Browse files Browse the repository at this point in the history
  • Loading branch information
guym4c committed Nov 27, 2019
1 parent 0b336a9 commit 7d13cde
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 24 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# doctrine-graphql-helper

Easily create a GraphQL schema from Doctrine entities.
Generate a PSR-7 GraphQL API server from an instance of the Doctrine ORM in just a few lines of PHP, with permissions and custom mutation resolvers available out-of-the-box.

## Install
Via Composer:
Expand All @@ -9,7 +9,7 @@ composer install guym4c/doctrine-graphql-helper
```

## Usage
This package is a helper package for [`graphql-php`](https://github.com/webonyx/graphql-php) and [`graphql-doctrine`](https://github.com/ecodev/graphql-doctrine), which install automatically with it. Entities used with this package must be graphql-doctrine-compatible. Refer to these packages’ documentation for more details.
This package is a helper package for [`graphql-php`](https://github.com/webonyx/graphql-php) and [`graphql-doctrine`](https://github.com/ecodev/graphql-doctrine), which install automatically with it. Entities used with this package must be `graphql-doctrine`-compatible. Refer to these packages’ documentation for more details.

### `GraphQLEntity`
Any entities which you wish to use in your API must extend `GraphQLEntity` and implement the required methods.
Expand Down Expand Up @@ -46,6 +46,8 @@ If you wish to use permissions, you may also provide the EntitySchemaBuilder con
### Running queries
You may use your built schema in a GraphQL server of your choice, or use the helper’s integration with `graphql-php` to retrieve a server object already set up with your schema and any permissions settings you have defined by calling `getServer()`.

The server object returned accepts a request object in its `executeRequest()` method. In some cases you may wish to run a JSON payload through the server - to do this you can parse the JSON to a format which the server will accept as a parameter to `executeRequest()` by calling `EntitySchemaBuilder::jsonToOperation($json)`.

### Using permissions
If you have set the schema builder’s permissions during instantiation, provide the permitted scopes (as an array) and the user’s identifier to the `getServer()` method to execute the query with permissions enabled.
The schema generator generates four queries for each provided entity, which have parallels to the HTTP request methods used in REST: a simple `GET` query, and `POST` (create), `UPDATE` and `DELETE` mutators. You may define the permissions at method-level granularity using the scopes array, provided to the builder’s constructor.
Expand Down Expand Up @@ -85,7 +87,7 @@ An asterisk (\*) is a wildcard, indicating full permissions are given for this s
* **All:** Accessible to all users with this scope
* **None:** Not accessible to users with this scope
* **Permissive:** Users permissions with this scope are resolved in the entity’s `hasPermission()` method. If you don’t wish to use permissive, but are running the server with permissions enabled, simply implement the method with a return true.
The `hasPermission()` static is called for all methods that are defined as permissive, and you are passed an instance of the Doctrine entity manager, an instance of your API user class as `ApiUserInterface`, and the ID of the entity that is being queried by the user. You are not given an instantiated version of the entity class being called: if you wish, you must retrieve this from the entity manager manually using the provided entity ID.
The `hasPermission()` method is called for all methods that are defined as permissive, and you are passed an instance of the Doctrine entity manager and an instance of your API user class as `ApiUserInterface`.

## Using custom mutators
The schema generator exposes a simple API for adding your own mutators, and a class (`Mutation`). This wraps some advanced functionality of graphql-doctrine, and so reference to that package’s documentation may or will be required using this feature.
Expand All @@ -108,7 +110,7 @@ There are two methods of hydrating the new `Mutation` returned by the factory: u
## Methods exposed by the builder
The schema builder exposes a variety of methods which may be of use when writing resolver functions. You may wish to consult the documentation of `graphql-php` and `graphql-doctrine` for more information on the values that some of these methods return.

**`immutableListOf()`:** When given an entity’s class name, returns a GraphQL return type of a list of the entity.
**`listOfType()`:** When given an entity’s class name, returns a GraphQL return type of a list of the entity.

**`resolveQuery()`:** Resolves a query using the entity manager. Requires the args array given with the query, and the class name of the root entity being queried. You may also pass in an instance of the entity as the third parameter to fully resolve and then return this entity.

Expand Down
4 changes: 1 addition & 3 deletions src/ApiUserInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@

namespace GraphQL\Doctrine\Helper;

interface ApiUserInterface extends DoctrineUniqueInterface {

}
interface ApiUserInterface extends DoctrineUniqueInterface {}
33 changes: 17 additions & 16 deletions src/EntitySchemaBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public function build(array $entities): self {
'mutation' => new ObjectType([
'name' => 'mutation',
'fields' => array_merge(
$this->getAllMutators(array_values($entities)),
$this->generateMutatorsForEntities(array_values($entities)),
$parsedMutators),
]),
]);
Expand All @@ -111,7 +111,7 @@ public function build(array $entities): self {
private function getAllQueries(array $entities) {
$queries = [];
foreach ($entities as $key => $entity) {
$queries[$key] = $this->listOf($entity);
$queries[$key] = $this->listOfQuery($entity);
}
return $queries;
}
Expand All @@ -127,9 +127,9 @@ private function getAllQueries(array $entities) {
*
* @return array The field entry within ObjectType.fields
*/
private function listOf(string $entity): array {
private function listOfQuery(string $entity): array {
return [
'type' => Type::listOf($this->types->getOutput($entity)),
'type' => $this->listOfType($entity),
'args' => [
[
'name' => 'filter',
Expand Down Expand Up @@ -161,7 +161,7 @@ private function listOf(string $entity): array {
];
}

public function immutableListOf(string $entity): Type {
public function listOfType(string $entity): Type {
return Type::listOf($this->types->getOutput($entity));
}

Expand Down Expand Up @@ -218,7 +218,7 @@ public function resolveQuery(array $args, string $entity, ?DoctrineUniqueInterfa
* @param string $entity The entity type class name that the mutators should act upon.
* @return array A list of mutator types
*/
private function getMutators(string $entity): array {
private function generateMutatorsForEntity(string $entity): array {

try {
$entityName = (new ReflectionClass($entity))->getShortName();
Expand Down Expand Up @@ -254,10 +254,10 @@ private function getMutators(string $entity): array {
* @return array A list of mutator types
* @see self::getMutators()
*/
private function getAllMutators(array $entities): array {
private function generateMutatorsForEntities(array $entities): array {
$mutators = [];
foreach ($entities as $entity) {
$mutators = array_merge($mutators, $this->getMutators($entity));
$mutators = array_merge($mutators, $this->generateMutatorsForEntity($entity));
}
return $mutators;
}
Expand Down Expand Up @@ -310,9 +310,12 @@ public function isPermitted(array $args, array $context, string $entity, string
break;

case PermissionLevel::PERMISSIVE:
$permitted = call_user_func($entity . '::hasPermission', $this->em,
$this->em->getRepository($this->userEntity)->find($context['user']),
$this->em->getRepository($entity)->find($args['id']));
/** @var GraphQLEntity $entityObject */
$entityObject = $this->em->getRepository($entity)->find($args['id']);
/** @var ApiUserInterface $user */
$user = $this->em->getRepository($this->userEntity)->find($context['user']);

$permitted = $entityObject->hasPermission($this->em, $user);
break;

case PermissionLevel::NONE:
Expand Down Expand Up @@ -340,9 +343,7 @@ public function isPermitted(array $args, array $context, string $entity, string
*/
private function mutationResolver(array $args, array $context, string $entity, string $method) {

$permitted = $this->isPermitted($args, $context, $entity, $method);

if (!$permitted) {
if (!$this->isPermitted($args, $context, $entity, $method)) {
return [403];
}

Expand Down Expand Up @@ -464,10 +465,10 @@ public function mutation(string $name): Mutation {
return $mutation;
}

public static function createServerOperation(array $json): OperationParams {
public static function jsonToOperation(array $json): OperationParams {
return OperationParams::create([
'query' => $json['query'],
'variables' => $json['variabes'] ?? null,
'variables' => $json['variables'] ?? null,
]);
}
}
2 changes: 1 addition & 1 deletion src/GraphQLEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public static function buildFromJson(EntityManager $em, array $input) {
return $entity;
}

public static function hasPermission(EntityManager $em, ApiUserInterface $user, string $entityId): bool {
public function hasPermission(EntityManager $em, ApiUserInterface $user): bool {
return true;
}

Expand Down

0 comments on commit 7d13cde

Please sign in to comment.