-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nested Input
annotated types within Factory
defined inputs causes type conflicts
#537
Comments
Can you give a code example to better understand the problem? I have many factories in use that map input types to models (without any annotation) just fine. You mentioned in #532 however that the issue could be linked to using input types within input types, so that might be the problematic combination. |
@mdoelker Building off that last example. Here is how it is currently. You cannot mix factories and Input annotated classes together. A factory requires that you annotate the input type class with a #[GraphQLite\Type)
class FooInput
{
public function __construct(
public readonly ID $id,
) {}
}
class FooInputFactory
{
#[GraphQLite\Factory]
public function build(ID $id): FooInput
{
return new FooInput($id);
}
}
#[GraphQLite\Input)
class BarInput
{
public function __construct(
#[GraphQLite\Field]
public readonly ID $id,
#[GraphQLite\Field]
public readonly FooInput $foo,
) {}
} |
This might be a misunderstanding of the role of a factory. Returning an Input-annotated class from a factory does not make much sense to me, as the factory itself represents the GraphQL input type. You use one or the other. Let's imagine your build method would return a Foo class which is a model in your application. Then the parameters of that build method become the fields of the generated input type and its name will be Foo + Input (see https://github.com/thecodingmachine/graphqlite/blob/master/src/NamingStrategy.php#L83). Your mutation just type-hints the model and the factory takes care of creating that instance for you. // This is our plain old model.
class Foo
{
public function __construct(
public readonly string $id,
public readonly string $value,
)
{}
}
// The class holding the factory that represents the GraphQL input type.
// It convert the values from the input type to a Foo instance.
class FooFactory
{
#[Factory]
public function createFoo(ID $id, string $value): Foo
{
return new Foo((string) $id, $value);
}
}
// The class mapping a Foo instance to a GraphQL output type.
#[Type(class: Foo::class)]
class FooType
{
public function getId(Foo $foo): ID
{
return new ID($foo->id);
}
public function getValue(Foo $foo): string
{
return $foo->value;
}
}
// The class holding the mutation. The incoming Foo instance is mapped with FooFactory,
// the returned Foo instance is mapped via FooType.
class Controller
{
#[Mutation]
public function someMutation(Foo $foo): Foo
{
// do something with $foo
return $foo;
}
} Your factory returns an Input-annotated class which is redundant. You should use the FooInput class directly in the method representing your mutation: class Controller
{
#[Mutation]
public function someMutation(FooInput $foo): string
{
return $foo->value;
}
} |
That said, I'm not sure about the |
@mdoelker That's correct. I removed the As for the All of this is a result of factories being the only way you could create input types, initially. The But yea, the issue is when you're mixing them with a nested input, which is what happened in our case as we began slowly migrating from factories to using |
Maybe we should just remove the requirement for a target class to have any annotations at all, and solely rely on the |
In my example above, which represents how I use factories in my codebase, the target class has no annotations and knows nothing about graphqlite. So that works perfectly well already. |
@mdoelker hmm, maybe it was only requiring the annotation because of the nested input then. We've now migrated all our factories over to We need a testcase to replicate this issue. |
Input
typesInput
types with Factory
defined inputs causes type conflicts
Input
types with Factory
defined inputs causes type conflictsInput
annotated types within Factory
defined inputs causes type conflicts
See #532.
Currently, factories require a
Type
annotation on the target class. This is problematic if a field of that class is typed as anInput
type. One possible solution here would be to update the factory logic to require anInput
attribute. To be compatible with the existing input type mapping, we'd need to add a custom parameter on theInput
attribute, to denote that the input type is created with a factory.I also think we could probably just get rid of the
Factory
attribute, altogether and have theInput
property point to the factory method instead.I think for most people, a factory isn't needed at all. A constructor on a DTO style
Input
defined class is more than sufficient.Consider the following, where
factory
takes a callable.The text was updated successfully, but these errors were encountered: