Source of file OperationScaffolder.php
Size: 12,603 Bytes - Last Modified: 2021-12-23T10:31:47+00:00
/var/www/docs.ssmods.com/process/src/src/Scaffolding/Scaffolders/OperationScaffolder.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 | <?php namespace SilverStripe\GraphQL\Scaffolding\Scaffolders; use Exception; use InvalidArgumentException; use SilverStripe\Core\Config\Config; use SilverStripe\Core\Extensible; use SilverStripe\Core\Injector\Injector; use SilverStripe\GraphQL\Manager; use SilverStripe\GraphQL\OperationResolver; use SilverStripe\GraphQL\Scaffolding\Interfaces\ConfigurationApplier; use SilverStripe\GraphQL\Scaffolding\Traits\Chainable; use SilverStripe\ORM\ArrayList; /** * Provides functionality common to both operation scaffolders. Cannot * be a subclass due to their distinct inheritance chains. */ abstract class OperationScaffolder implements ConfigurationApplier { use Chainable; use Extensible; /** * Type backing this operation * * @var string */ private $typeName; /** * Name of operation * * @var string */ private $operationName; /** * @var OperationResolver|callable */ private $resolver; /** * List of argument scaffolders * * @var ArrayList|ArgumentScaffolder[] */ protected $args = []; /** * @var string */ protected $description; /** * @return string */ public function getDescription() { return $this->description; } /** * @param string $description * @return OperationScaffolder */ public function setDescription($description) { $this->description = $description; return $this; } /** * @param string $name * @return string|null */ public static function getClassFromIdentifier($name) { $operations = static::getOperations(); return isset($operations[$name]) ? $operations[$name] : null; } /** * @param string|OperationScaffolder $instOrClass * @return string|null */ public static function getIdentifier($instOrClass) { $class = ($instOrClass instanceof OperationScaffolder) ? get_class($instOrClass) : $instOrClass; $operations = static::getOperations(); $operations = array_flip($operations); return isset($operations[$class]) ? $operations[$class] : null; } /** * Gets a map of operation identifiers to their classes * @return array */ public static function getOperations() { $operations = Config::inst()->get(__CLASS__, 'operations', Config::UNINHERITED); $validOperations = []; foreach ($operations as $identifier => $class) { if (!$class) { continue; } $validOperations[$identifier] = $class; } return $validOperations; } /** * OperationScaffolder constructor. * * @param string $operationName * @param string $typeName * @param OperationResolver|callable|null $resolver */ public function __construct($operationName = null, $typeName = null, $resolver = null) { $this->setName($operationName); $this->setTypeName($typeName); $this->args = ArrayList::create([]); if ($resolver) { $this->setResolver($resolver); } } /** * Adds args to the operation * * Ex: * [ * 'MyArg' => 'String!', * 'MyOtherArg' => 'Int', * 'MyCustomArg' => new InputObjectType([ * ] * * @param array $argData * @return $this */ public function addArgs(array $argData) { foreach ($argData as $argName => $type) { $this->removeArg($argName); $this->args->add(new ArgumentScaffolder($argName, $type)); } return $this; } /** * @param string $argName * @param string $typeStr * @param string $description * @param mixed $defaultValue * @return $this */ public function addArg($argName, $typeStr, $description = null, $defaultValue = null) { $this->addArgs([$argName => $typeStr]); $this->setArgDescription($argName, $description); $this->setArgDefault($argName, $defaultValue); return $this; } /** * Sets descriptions of arguments * [ * 'Email' => 'The email of the user' * ] * @param array $argData * @return $this */ public function setArgDescriptions(array $argData) { foreach ($argData as $argName => $description) { /* @var ArgumentScaffolder $arg */ $arg = $this->args->find('argName', $argName); if (!$arg) { throw new InvalidArgumentException(sprintf( 'Tried to set description for %s, but it was not added to %s', $argName, $this->operationName ?: '(unnamed operation)' )); } $arg->setDescription($description); } return $this; } /** * Sets a single arg description * * @param string $argName * @param string $description * @return $this */ public function setArgDescription($argName, $description) { return $this->setArgDescriptions([$argName => $description]); } /** * Sets argument defaults * [ * 'Featured' => true * ] * @param array $argData * @return $this */ public function setArgDefaults(array $argData) { foreach ($argData as $argName => $default) { /* @var ArgumentScaffolder $arg */ $arg = $this->args->find('argName', $argName); if (!$arg) { throw new InvalidArgumentException(sprintf( 'Tried to set default for %s, but it was not added to %s', $argName, $this->operationName ?: '(unnamed operation)' )); } $arg->setDefaultValue($default); } return $this; } /** * Sets a default for a single arg * * @param string $argName * @param mixed $default * @return $this */ public function setArgDefault($argName, $default) { return $this->setArgDefaults([$argName => $default]); } /** * Sets operation arguments as required or not * [ * 'ID' => true * ] * @param array $argData * @return $this */ public function setArgsRequired($argData) { foreach ($argData as $argName => $required) { /* @var ArgumentScaffolder $arg */ $arg = $this->args->find('argName', $argName); if (!$arg) { throw new InvalidArgumentException(sprintf( 'Tried to make arg %s required, but it was not added to %s', $argName, $this->operationName ?: '(unnamed operation)' )); } $arg->setRequired($required); } return $this; } /** * Sets an operation argument as required or not * * @param string $argName * @param boolean $required * @return OperationScaffolder */ public function setArgRequired($argName, $required) { return $this->setArgsRequired([$argName => $required]); } /** * @return string */ public function getName() { return $this->operationName; } /** * @param string $name * @return $this */ public function setName($name) { $this->operationName = $name; return $this; } /** * @return ArrayList */ public function getArgs() { return $this->args; } /** * Type name * * @param string $typeName * @return $this */ public function setTypeName($typeName) { $this->typeName = $typeName; return $this; } /** * @return string */ public function getTypeName() { return $this->typeName; } /** * @param string $arg * @return $this */ public function removeArg($arg) { return $this->removeArgs([$arg]); } /** * @param array $args * @return $this */ public function removeArgs(array $args) { $this->args = $this->args->exclude('argName', $args); return $this; } /** * @return callable|OperationResolver */ public function getResolver() { return $this->resolver; } /** * @param callable|OperationResolver|string $resolver Callable, instance of (or classname of) a OperationResolver * @return $this * @throws InvalidArgumentException */ public function setResolver($resolver) { if (is_callable($resolver) || $resolver instanceof OperationResolver) { $this->resolver = $resolver; return $this; } if (is_subclass_of($resolver, OperationResolver::class)) { $this->resolver = Injector::inst()->create($resolver); return $this; } throw new InvalidArgumentException(sprintf( '%s::setResolver() accepts closures, instances of %s or names of resolver subclasses.', __CLASS__, OperationResolver::class )); } /** * @param array $config * @return $this * @throws Exception */ public function applyConfig(array $config) { if (isset($config['args'])) { if (!is_array($config['args'])) { throw new Exception(sprintf( 'args must be an array on %s', $this->operationName ?: '(unnamed operation)' )); } foreach ($config['args'] as $argName => $argData) { if (is_array($argData)) { if (!isset($argData['type'])) { throw new Exception(sprintf( 'Argument %s must have a type', $argName )); } $scaffolder = new ArgumentScaffolder($argName, $argData['type']); $scaffolder->applyConfig($argData); $this->removeArg($argName); $this->args->add($scaffolder); } elseif (is_string($argData)) { $this->addArg($argName, $argData); } else { throw new Exception(sprintf( 'Arg %s should be mapped to a string or an array', $argName )); } } } if (isset($config['resolver'])) { $this->setResolver($config['resolver']); } if (isset($config['name'])) { $this->setName($config['name']); } if (isset($config['description'])) { $this->setDescription($config['description']); } return $this; } /** * Based on the type of resolver, create a function that invokes it. * * @return callable */ protected function createResolverFunction() { $resolver = $this->resolver; return function () use ($resolver) { $args = func_get_args(); if (is_callable($resolver)) { return call_user_func_array($resolver, $args); } else { if ($resolver instanceof OperationResolver) { return call_user_func_array([$resolver, 'resolve'], $args); } else { throw new \Exception(sprintf( '%s resolver must be a closure or implement %s', __CLASS__, OperationResolver::class )); } } }; } /** * Helper for scaffolding args that require more work than ArgumentScaffolder::toArray() * * @param Manager $manager * @return array */ protected function createDefaultArgs(Manager $manager) { return []; } /** * Parses the args to proper graphql-php spec. * * @param Manager $manager * @return array */ protected function createArgs(Manager $manager) { $args = $this->createDefaultArgs($manager); foreach ($this->args as $scaffolder) { $args[$scaffolder->argName] = $scaffolder->toArray($manager); } $this->extend('updateArgs', $args, $manager); return $args; } } |