Skip to content

Commit 8cae67e

Browse files
authored
Merge pull request #9 from moufmouf/extend_type_and_porpaginas
Extend types and porpaginas support
2 parents 9a12c46 + 7957bef commit 8cae67e

File tree

12 files changed

+263
-56
lines changed

12 files changed

+263
-56
lines changed

DependencyInjection/Configuration.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,16 @@ public function getConfigTreeBuilder()
1919
//->scalarNode('types_namespace')->defaultValue('App\\Types')->end()
2020
->arrayNode('namespace')->isRequired()
2121
->children()
22-
->scalarNode('controllers')->isRequired()->cannotBeEmpty()->end()
23-
->scalarNode('types')->isRequired()->cannotBeEmpty()->end()
22+
->arrayNode('controllers')
23+
->requiresAtLeastOneElement()
24+
->beforeNormalization()->castToArray()->end()
25+
->scalarPrototype()->cannotBeEmpty()->end()
26+
->end()
27+
->arrayNode('types')
28+
->requiresAtLeastOneElement()
29+
->beforeNormalization()->castToArray()->end()
30+
->scalarPrototype()->cannotBeEmpty()->end()
31+
->end()
2432
->end()
2533
->end()
2634
->arrayNode('debug')

DependencyInjection/GraphqlControllersCompilerPass.php

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
namespace TheCodingMachine\Graphql\Controllers\Bundle\DependencyInjection;
55

66
use function class_exists;
7-
use function dirname;
87
use Doctrine\Common\Annotations\AnnotationException;
98
use Doctrine\Common\Annotations\AnnotationReader as DoctrineAnnotationReader;
109
use Doctrine\Common\Annotations\AnnotationRegistry;
@@ -15,6 +14,7 @@
1514
use GraphQL\Type\Definition\ObjectType;
1615
use Psr\Container\ContainerInterface;
1716
use ReflectionClass;
17+
use function str_replace;
1818
use function strpos;
1919
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
2020
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -28,10 +28,12 @@
2828
use TheCodingMachine\GraphQL\Controllers\FieldsBuilderFactory;
2929
use TheCodingMachine\GraphQL\Controllers\InputTypeGenerator;
3030
use TheCodingMachine\GraphQL\Controllers\InputTypeUtils;
31+
use TheCodingMachine\GraphQL\Controllers\Mappers\GlobTypeMapper;
3132
use TheCodingMachine\GraphQL\Controllers\Mappers\RecursiveTypeMapperInterface;
3233
use TheCodingMachine\GraphQL\Controllers\Mappers\StaticTypeMapper;
3334
use TheCodingMachine\GraphQL\Controllers\NamingStrategy;
3435
use TheCodingMachine\GraphQL\Controllers\TypeGenerator;
36+
use TheCodingMachine\GraphQL\Controllers\Types\MutableObjectType;
3537
use TheCodingMachine\GraphQL\Controllers\Types\ResolvableInputObjectType;
3638

3739
/**
@@ -66,21 +68,39 @@ public function process(ContainerBuilder $container)
6668

6769
$namingStrategy = new NamingStrategy();
6870
$reader = $this->getAnnotationReader();
69-
$inputTypeUtils = new InputTypeUtils($reader, $namingStrategy);
71+
//$inputTypeUtils = new InputTypeUtils($reader, $namingStrategy);
7072

7173
// Let's scan the whole container and tag the services that belong to the namespace we want to inspect.
72-
$controllersNamespace = $container->getParameter('graphql_controllers.namespace.controllers');
73-
$typesNamespace = $container->getParameter('graphql_controllers.namespace.types');
74+
$controllersNamespaces = $container->getParameter('graphql_controllers.namespace.controllers');
75+
$typesNamespaces = $container->getParameter('graphql_controllers.namespace.types');
7476

7577
foreach ($container->getDefinitions() as $id => $definition) {
7678
if ($definition->isAbstract() || $definition->getClass() === null) {
7779
continue;
7880
}
79-
if (strpos($definition->getClass(), $controllersNamespace) === 0) {
80-
$definition->addTag('graphql.annotated.controller');
81+
$class = $definition->getClass();
82+
foreach ($controllersNamespaces as $controllersNamespace) {
83+
if (strpos($class, $controllersNamespace) === 0) {
84+
$definition->addTag('graphql.annotated.controller');
85+
}
8186
}
82-
if (strpos($definition->getClass(), $typesNamespace) === 0) {
83-
$definition->addTag('graphql.annotated.type');
87+
88+
foreach ($typesNamespaces as $typesNamespace) {
89+
if (strpos($class, $typesNamespace) === 0) {
90+
//$definition->addTag('graphql.annotated.type');
91+
// Set the types public
92+
$reflectionClass = new ReflectionClass($class);
93+
if ($this->getAnnotationReader()->getTypeAnnotation($reflectionClass) !== null || $this->getAnnotationReader()->getExtendTypeAnnotation($reflectionClass) !== null) {
94+
$definition->setPublic(true);
95+
} else {
96+
foreach ($reflectionClass->getMethods() as $method) {
97+
$factory = $reader->getFactoryAnnotation($method);
98+
if ($factory !== null) {
99+
$definition->setPublic(true);
100+
}
101+
}
102+
}
103+
}
84104
}
85105
}
86106

@@ -120,8 +140,9 @@ public function process(ContainerBuilder $container)
120140
$container->setDefinition($controllerIdentifier, $queryProvider);
121141
}
122142
}
123-
143+
/*
124144
foreach ($container->findTaggedServiceIds('graphql.annotated.type') as $id => $tag) {
145+
$used = false;
125146
$definition = $container->findDefinition($id);
126147
$class = $definition->getClass();
127148
if ($class === null) {
@@ -148,6 +169,7 @@ public function process(ContainerBuilder $container)
148169
$inputTypes[$inputClassName] = $objectTypeIdentifier;
149170
$typesByName[$inputName] = $objectTypeIdentifier;
150171
172+
$used = true;
151173
}
152174
}
153175
@@ -158,27 +180,38 @@ public function process(ContainerBuilder $container)
158180
$objectType = new Definition(ObjectType::class);
159181
$objectType->setPrivate(false);
160182
$objectType->setFactory([self::class, 'createObjectType']);
161-
$objectType->addArgument(new Reference($id));
183+
$objectType->addArgument($id);
162184
$objectType->addArgument(new Reference(TypeGenerator::class));
163185
$objectType->addArgument(new Reference(RecursiveTypeMapperInterface::class));
164186
$container->setDefinition($objectTypeIdentifier, $objectType);
165187
166188
$types[$typeAnnotation->getClass()] = $objectTypeIdentifier;
167189
$typesByName[$namingStrategy->getOutputTypeName($class, $typeAnnotation)] = $objectTypeIdentifier;
168190
//$definition->addTag('graphql.annotated_type');
191+
192+
$used = true;
193+
}
194+
195+
// If the service is used for GraphQL, since it is referenced by service name in the factories, let's make it public
196+
if ($used) {
197+
$container->findDefinition($id)->setPublic(true);
169198
}
170199
}
171200
172201
$containerFetcherTypeMapper = $container->getDefinition(ContainerFetcherTypeMapper::class);
173202
$containerFetcherTypeMapper->replaceArgument(1, $types);
174203
$containerFetcherTypeMapper->replaceArgument(2, $inputTypes);
175204
$containerFetcherTypeMapper->replaceArgument(3, $typesByName);
176-
/*$containerFetcherTypeMapper = new Definition(ContainerFetcherTypeMapper::class);
177-
$containerFetcherTypeMapper->addArgument($container->getDefinition('service_container'));
178-
$containerFetcherTypeMapper->addArgument($types);
179-
$containerFetcherTypeMapper->addArgument([]);
180-
$containerFetcherTypeMapper->addTag('graphql.type_mapper');
181-
$container->setDefinition(ContainerFetcherTypeMapper::class, $containerFetcherTypeMapper);*/
205+
*/
206+
207+
foreach ($typesNamespaces as $typesNamespace) {
208+
$definition = new Definition(GlobTypeMapper::class);
209+
$definition->addArgument($typesNamespace);
210+
$definition->setAutowired(true);
211+
$definition->addTag('graphql.type_mapper');
212+
$container->setDefinition('globTypeMapper_'.str_replace('\\', '__', $typesNamespace), $definition);
213+
}
214+
182215

183216
// Register custom output types
184217
$taggedServices = $container->findTaggedServiceIds('graphql.output_type');
@@ -218,20 +251,20 @@ public static function createQueryProvider($controller, FieldsBuilderFactory $fi
218251
}
219252

220253
/**
221-
* @param object $typeClass
254+
* @param string $typeClass
222255
*/
223-
public static function createObjectType($typeClass, TypeGenerator $typeGenerator, RecursiveTypeMapperInterface $recursiveTypeMapper): ObjectType
256+
/*public static function createObjectType(string $typeClass, TypeGenerator $typeGenerator, RecursiveTypeMapperInterface $recursiveTypeMapper): MutableObjectType
224257
{
225258
return $typeGenerator->mapAnnotatedObject($typeClass, $recursiveTypeMapper);
226-
}
259+
}*/
227260

228261
/**
229262
* @param object $factory
230263
*/
231-
public static function createInputObjectType($factory, string $methodName, InputTypeGenerator $inputTypeGenerator, RecursiveTypeMapperInterface $recursiveTypeMapper): InputObjectType
264+
/*public static function createInputObjectType($factory, string $methodName, InputTypeGenerator $inputTypeGenerator, RecursiveTypeMapperInterface $recursiveTypeMapper): InputObjectType
232265
{
233266
return $inputTypeGenerator->mapFactoryMethod($factory, $methodName, $recursiveTypeMapper);
234-
}
267+
}*/
235268

236269
/**
237270
* Returns a cached Doctrine annotation reader.

DependencyInjection/GraphqlControllersExtension.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ public function load(array $configs, ContainerBuilder $container)
3434
//$config = $this->processConfiguration($this->getConfiguration($config, $container), $config);
3535
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config/container'));
3636

37-
$namespaceController = rtrim($configs[0]['namespace']['controllers'], '\\') . '\\';
38-
$namespaceType = rtrim($configs[0]['namespace']['types'], '\\') . '\\';
37+
$namespaceController = array_map(function($namespace) { return rtrim($namespace, '\\') . '\\'; }, $configs[0]['namespace']['controllers']);
38+
$namespaceType = array_map(function($namespace) { return rtrim($namespace, '\\') . '\\'; }, $configs[0]['namespace']['types']);
3939

4040
$container->setParameter('graphql_controllers.namespace.controllers', $namespaceController);
4141
$container->setParameter('graphql_controllers.namespace.types', $namespaceType);

Mappers/ContainerFetcherTypeMapper.php

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44
namespace TheCodingMachine\Graphql\Controllers\Bundle\Mappers;
55

66
use GraphQL\Type\Definition\InputObjectType;
7+
use GraphQL\Type\Definition\NamedType;
78
use GraphQL\Type\Definition\ObjectType;
89
use GraphQL\Type\Definition\Type;
910
use GraphQL\Type\Definition\InputType;
1011
use GraphQL\Type\Definition\OutputType;
1112
use Psr\Container\ContainerInterface;
1213
use TheCodingMachine\GraphQL\Controllers\Mappers\CannotMapTypeException;
14+
use TheCodingMachine\GraphQL\Controllers\Mappers\CannotMapTypeExceptionInterface;
1315
use TheCodingMachine\GraphQL\Controllers\Mappers\RecursiveTypeMapperInterface;
1416
use TheCodingMachine\GraphQL\Controllers\Mappers\TypeMapperInterface;
17+
use TheCodingMachine\GraphQL\Controllers\Types\MutableObjectType;
1518

1619
/**
1720
* A type mapper that fetches types from the container that is directly injected in the type mapper.
@@ -67,17 +70,22 @@ public function canMapClassToType(string $className): bool
6770
}
6871

6972
/**
70-
* Maps a PHP fully qualified class name to a Graphql type.
73+
* Maps a PHP fully qualified class name to a GraphQL type.
7174
*
72-
* @param string $className
75+
* @param string $className The exact class name to look for (this function does not look into parent classes).
76+
* @param OutputType|null $subType An optional sub-type if the main class is an iterator that needs to be typed.
7377
* @param RecursiveTypeMapperInterface $recursiveTypeMapper
74-
* @return ObjectType
75-
* @throws CannotMapTypeException
78+
* @return MutableObjectType
79+
* @throws CannotMapTypeExceptionInterface
7680
*/
77-
public function mapClassToType(string $className, RecursiveTypeMapperInterface $recursiveTypeMapper): ObjectType
81+
public function mapClassToType(string $className, ?OutputType $subType, RecursiveTypeMapperInterface $recursiveTypeMapper): MutableObjectType
7882
{
79-
if (isset($this->types[$className])) {
80-
return $this->container->get($this->types[$className]);
83+
$key = $className;
84+
if ($subType instanceof NamedType && $subType !== null) {
85+
$key .= '____'.$subType->name;
86+
}
87+
if (isset($this->types[$key])) {
88+
return $this->container->get($this->types[$key]);
8189
}
8290
throw CannotMapTypeException::createForType($className);
8391
}
@@ -143,4 +151,56 @@ public function mapNameToType(string $typeName, RecursiveTypeMapperInterface $re
143151
}
144152
throw CannotMapTypeException::createForName($typeName);
145153
}
154+
155+
/**
156+
* Returns true if this type mapper can extend an existing type for the $className FQCN
157+
*
158+
* @param string $className
159+
* @param MutableObjectType $type
160+
* @param RecursiveTypeMapperInterface $recursiveTypeMapper
161+
* @return bool
162+
*/
163+
public function canExtendTypeForClass(string $className, MutableObjectType $type, RecursiveTypeMapperInterface $recursiveTypeMapper): bool
164+
{
165+
return false;
166+
}
167+
168+
/**
169+
* Extends the existing GraphQL type that is mapped to $className.
170+
*
171+
* @param string $className
172+
* @param MutableObjectType $type
173+
* @param RecursiveTypeMapperInterface $recursiveTypeMapper
174+
* @throws CannotMapTypeExceptionInterface
175+
*/
176+
public function extendTypeForClass(string $className, MutableObjectType $type, RecursiveTypeMapperInterface $recursiveTypeMapper): void
177+
{
178+
throw CannotMapTypeException::createForType($className);
179+
}
180+
181+
/**
182+
* Returns true if this type mapper can extend an existing type for the $typeName GraphQL type
183+
*
184+
* @param string $typeName
185+
* @param MutableObjectType $type
186+
* @param RecursiveTypeMapperInterface $recursiveTypeMapper
187+
* @return bool
188+
*/
189+
public function canExtendTypeForName(string $typeName, MutableObjectType $type, RecursiveTypeMapperInterface $recursiveTypeMapper): bool
190+
{
191+
return false;
192+
}
193+
194+
/**
195+
* Extends the existing GraphQL type that is mapped to the $typeName GraphQL type.
196+
*
197+
* @param string $typeName
198+
* @param MutableObjectType $type
199+
* @param RecursiveTypeMapperInterface $recursiveTypeMapper
200+
* @throws CannotMapTypeExceptionInterface
201+
*/
202+
public function extendTypeForName(string $typeName, MutableObjectType $type, RecursiveTypeMapperInterface $recursiveTypeMapper): void
203+
{
204+
throw CannotMapTypeException::createForName($typeName);
205+
}
146206
}

0 commit comments

Comments
 (0)