From e7e982a68f1d2eb4721eedc7461d6c202c83aba8 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Wed, 28 Aug 2024 14:11:33 +1200 Subject: [PATCH] API Update API to reflect changes to CLI interaction --- _config/dev.yml | 17 +- _config/logging.yml | 2 +- src/Dev/Build.php | 100 +++++++----- src/Dev/DevelopmentAdmin.php | 146 ------------------ ...uildExtension.php => DbBuildExtension.php} | 13 +- .../TestSessionEnvironmentExtension.php | 7 + src/Schema/Logger.php | 60 +++++-- 7 files changed, 130 insertions(+), 215 deletions(-) delete mode 100644 src/Dev/DevelopmentAdmin.php rename src/Extensions/{DevBuildExtension.php => DbBuildExtension.php} (80%) diff --git a/_config/dev.yml b/_config/dev.yml index c19ab4e1..3ce2d860 100644 --- a/_config/dev.yml +++ b/_config/dev.yml @@ -1,19 +1,10 @@ --- Name: graphql-dev --- -SilverStripe\ORM\DatabaseAdmin: +SilverStripe\Dev\Command\DbBuild: extensions: - - SilverStripe\GraphQL\Extensions\DevBuildExtension + - SilverStripe\GraphQL\Extensions\DbBuildExtension SilverStripe\Dev\DevelopmentAdmin: - registered_controllers: - graphql: - controller: SilverStripe\GraphQL\Dev\DevelopmentAdmin - links: - graphql: 'List GraphQL development tools' -SilverStripe\GraphQL\Dev\DevelopmentAdmin: - registered_controllers: - build: - controller: SilverStripe\GraphQL\Dev\Build - links: - build: Build the GraphQL schema + commands: + 'graphql/build': 'SilverStripe\GraphQL\Dev\Build' diff --git a/_config/logging.yml b/_config/logging.yml index e19a72a8..0de75516 100644 --- a/_config/logging.yml +++ b/_config/logging.yml @@ -4,7 +4,7 @@ after: '#logging' --- SilverStripe\Core\Injector\Injector: - # Omits the HTTPOutputHandler from the logger so errors won't appear in output + # Omits the ErrorOutputHandler from the logger so errors won't appear in output Psr\Log\LoggerInterface.graphql-quiet: type: singleton class: Monolog\Logger diff --git a/src/Dev/Build.php b/src/Dev/Build.php index 97eb2b07..e2e1b9a6 100644 --- a/src/Dev/Build.php +++ b/src/Dev/Build.php @@ -4,11 +4,10 @@ namespace SilverStripe\GraphQL\Dev; use Psr\Log\LoggerInterface; -use SilverStripe\Control\Controller; -use SilverStripe\Control\Director; -use SilverStripe\Control\HTTPRequest; use SilverStripe\Core\Injector\Injector; -use SilverStripe\Dev\DebugView; +use SilverStripe\Dev\Command\DevCommand; +use SilverStripe\Dev\DevelopmentAdmin; +use SilverStripe\HybridExecution\HybridOutput; use SilverStripe\GraphQL\Schema\DataObject\FieldAccessor; use SilverStripe\GraphQL\Schema\Exception\EmptySchemaException; use SilverStripe\GraphQL\Schema\Exception\SchemaBuilderException; @@ -18,38 +17,44 @@ use SilverStripe\GraphQL\Schema\SchemaBuilder; use SilverStripe\GraphQL\Schema\Storage\CodeGenerationStore; use SilverStripe\ORM\Connect\NullDatabaseException; +use SilverStripe\Security\PermissionProvider; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; -class Build extends Controller +class Build extends DevCommand implements PermissionProvider { - private static $url_handlers = [ - '' => 'build' - ]; + protected static string $commandName = 'graphql:build'; + + protected static string $description = 'Build the GraphQL schema(s)'; - private static $allowed_actions = [ - 'build' + private static array $permissions_for_browser_execution = [ + 'CAN_DEV_GRAPHQL', ]; - /** - * @throws SchemaBuilderException - * @throws SchemaNotFoundException - */ - public function build(HTTPRequest $request): void + public function getTitle(): string { - $isBrowser = !Director::is_cli(); - if ($isBrowser) { - $renderer = DebugView::create(); - echo $renderer->renderHeader(); - echo $renderer->renderInfo("GraphQL Schema Builder", Director::absoluteBaseURL()); - echo "
"; - } - $clear = true; - - $this->buildSchema($request->getVar('schema'), $clear); + return 'GraphQL Schema Builder'; + } - if ($isBrowser) { - echo "
"; - echo $renderer->renderFooter(); + protected function execute(InputInterface $input, HybridOutput $output): int + { + $originalLogger = Injector::inst()->get(LoggerInterface::class . '.graphql-build'); + try { + $logger = Logger::singleton(); + $logger->setOutput($output); + Injector::inst()->registerService($logger, LoggerInterface::class . '.graphql-build'); + $this->buildSchema($input->getOption('schema'), true, $output); + } finally { + // Restore default logger back to its starting state + Injector::inst()->registerService($originalLogger, LoggerInterface::class . '.graphql-build'); } + return Command::SUCCESS; + } + + protected function getHeading(): string + { + return ''; } /** @@ -97,15 +102,15 @@ public function buildSchema(string $key = null, bool $clear = true): void break; } } - $logger->warning(" - Your schema configuration requires access to the database. This can happen + $logger->warning( + "Your schema configuration requires access to the database. This can happen when you add fields that require type introspection (i.e. custom getters). It is recommended that you specify an explicit type when adding custom getters - to your schema."); + to your schema." + ); if ($candidate) { $logger->warning(sprintf( - " - This most likely happened when you tried to add the field '%s' to '%s'", + "This most likely happened when you tried to add the field '%s' to '%s'", $candidate['args'][1], get_class($candidate['args'][0]) )); @@ -114,9 +119,32 @@ public function buildSchema(string $key = null, bool $clear = true): void throw $e; } - $logger->info( - Benchmark::end('build-schema-' . $key, 'Built schema in %sms.') - ); + $logger->info(Benchmark::end('build-schema-' . $key, 'Built schema in %sms.')); } } + + public function getOptions(): array + { + return [ + new InputOption( + 'schema', + null, + InputOption::VALUE_REQUIRED, + 'The name of the schema to be built. If not passed, all schemas will be built', + suggestedValues: array_keys(Schema::config()->get('schemas') ?? []) + ) + ]; + } + + public function providePermissions(): array + { + return [ + 'CAN_DEV_GRAPHQL' => [ + 'name' => _t(__CLASS__ . '.CAN_DEV_GRAPHQL_DESCRIPTION', 'Can view and execute /dev/graphql'), + 'help' => _t(__CLASS__ . '.CAN_DEV_GRAPHQL_HELP', 'Can view and execute GraphQL development tools (/dev/graphql).'), + 'category' => DevelopmentAdmin::permissionsCategory(), + 'sort' => 80 + ], + ]; + } } diff --git a/src/Dev/DevelopmentAdmin.php b/src/Dev/DevelopmentAdmin.php deleted file mode 100644 index d1e29cc0..00000000 --- a/src/Dev/DevelopmentAdmin.php +++ /dev/null @@ -1,146 +0,0 @@ - 'index', - '$Action' => 'runRegisteredController', - ]; - - private static $init_permissions = [ - 'ADMIN', - 'ALL_DEV_ADMIN', - 'CAN_DEV_GRAPHQL', - ]; - - protected function init() - { - parent::init(); - - if (RootDevelopmentAdmin::config()->get('deny_non_cli') && !Director::is_cli()) { - return $this->httpError(404); - } - - if (!$this->canInit()) { - Security::permissionFailure($this); - } - - // Define custom logger - $logger = Logger::singleton(); - Injector::inst()->registerService($logger, LoggerInterface::class . '.graphql-build'); - } - - public function index(HTTPRequest $request) - { - // Web mode - if (!Director::is_cli()) { - $renderer = DebugView::create(); - echo $renderer->renderHeader(); - echo $renderer->renderInfo("Silverstripe CMS GraphQL Tools", Director::absoluteBaseURL()); - $base = Director::baseURL(); - - echo '