Skip to content
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

directive @validate not working #190

Open
videni opened this issue May 15, 2020 · 3 comments
Open

directive @validate not working #190

videni opened this issue May 15, 2020 · 3 comments

Comments

@videni
Copy link

videni commented May 15, 2020

Expected Behavior

I want to validate the whole input data.

What happens instead?

{
"code": 0,
"error": "(Railt\SDL\Exceptions\TypeNotFoundException) Type "validate" not found and could not be loaded",
"file": "At /Users/vidy/www/discovery/app/graphql/comment.graphql line 10",
"trace": "#0 /Users/vidy/www/discovery/vendor/railt/railt/src/SDL/Reflection/Loader.php(72)"
}

Steps To Reproduce

@use(class: "App\\Controller\\Admin\\CommentController")
@use(class: "App\\Validator\\CommentValidator", as: "Comment")

type Mutation {
    """
    创建评论
    """
    createComment(
      input: CommentInput!
    ): Comment!
      @route(action: "CommentController@create")
      @validate(use: "Comment")
}

input CommentInput {
   """评论正文"""
  comment: String!
  """父评论ID"""
  parent_id: ID
}

type Comment {
  id: ID!
}

@SerafimArts
Copy link
Member

Have you created a @validate directive type?

@adevyatov
Copy link
Contributor

adevyatov commented Sep 22, 2020

@validate directive is not standard. You should implement it by yourself. You can write your own extension.
@videni This is an example for railt v1.4. You can do this in v1.3, but have to use different events and other railt classes.

  1. define directive validate.graphql
# if you want to use your directive for arguments, then:
directive @validate(action: String!) on ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION
  1. write extension class
use Phplrt\Io\File;
use Phplrt\Io\Readable;
use Railt\Container\ContainerInterface;
use Railt\Foundation\Event\Resolver\FieldResolve;
use Railt\Foundation\Extension\Extension;
use Railt\SDL\Schema\CompilerInterface;

class ValidateExtension extends Extension
{
    public function register(ContainerInterface $container): void
    {
        $this->autoload(__DIR__ . '/validate.graphqls'); // path to your directive file

        // also you can use symfony subscribers $this->subscribe(new MySymfonySubscriber());
        $this->on(FieldResolve::class, function (FieldResolve $resolve) {
            $arguments = $event->getFieldDefinition()->getArguments();
            
            foreach ($arguments as $argument) {
                $value = $event->getInput()->get($argument->getName());

                // here you have to check that this argument or their type contains "validate" directive
                $type = $argument->getTypeDefinition();

                if (!$type instanceof DependentDefinition) {
                    foreach ($type->getDirectives('validate') as $directive) {
                        $validatorOrConstraint = $directive->getPassedArgument('action');
                        $this->validator->validate($validatorOrConstraint, $value);
                    }
                }

                foreach ($argument->getDirectives('validate') as $directive) {
                    $validatorOrConstraint = $directive->getPassedArgument('action');
                    $this->validator->validate($validatorOrConstraint, $value);
                }

                if ($type instanceof HasArguments) {
                    // if you want to validate nested fields that can also contain "validate" directive you should do something like that:
                    foreach ($type->getArguments() as $nestedArgument) {
                        $argumentName = $nestedArgument->getName();
                        if (isset($value[$argumentName])) {
                            $value[$argumentName] = $this->runThisFunctionAgain($nestedArgument, $value[$argumentName]);
                        }
                    }
                }
            }
        });
    }

    /**
     * Add your directive to autoloader
     **/
    protected function autoload(string $pathname): void
    {
        /** @var CompilerInterface $compiler */
        $compiler = $this->app->make(CompilerInterface::class);

        $needle = \pathinfo($pathname, \PATHINFO_FILENAME);

        $compiler->autoload(
            static function (string $haystack) use ($pathname, $needle): ?Readable {
                return $haystack === $needle
                    ? File::fromPathname($pathname)
                    : null;
            }
        );
    }
}
  1. register your extension in composer.json or inject into your railt application
$repository = new \Railt\Foundation\Config\Repository();
$repository->set('extensions', ['your/ext/class']);

// inject your config into discovery
$this->app->get(\Railt\Foundation\Config\Repository::class)->mergeWith($repository);

@vidyli
Copy link

vidyli commented Feb 4, 2021

@adevyatov , thanks, I love this project, creating directive is very easy unlike other alternatives.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants