Skip to content

Commit

Permalink
API Customise type names and operation names (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron Carlino authored and Damian Mooyman committed Mar 20, 2018
1 parent e277f19 commit 87afe84
Show file tree
Hide file tree
Showing 26 changed files with 446 additions and 101 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ before_script:
- export PATH=~/.composer/vendor/bin:$PATH
- composer validate
- composer install --prefer-dist
- composer require --prefer-dist --no-update silverstripe/recipe-core:2.x-dev silverstripe/versioned:2.x-dev --prefer-dist
- composer require --prefer-dist --no-update silverstripe/recipe-core:1.2.x-dev silverstripe/versioned:1.2.x-dev --prefer-dist
- composer update
- if [[ $DB == PGSQL ]]; then composer require silverstripe/postgresql:3.x-dev --prefer-dist; fi
- if [[ $DB == PGSQL ]]; then composer require silverstripe/postgresql:2.1.x-dev --prefer-dist; fi
- if [[ $PHPCS_TEST ]]; then composer global require squizlabs/php_codesniffer:^3 --prefer-dist --no-interaction --no-progress --no-suggest -o; fi

script:
Expand Down
48 changes: 46 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ composer require silverstripe/graphql
- [Adding arbitrary queries and mutations](#adding-arbitrary-queries-and-mutations)
- [Dealing with inheritance](#dealing-with-inheritance)
- [Querying types that have descendants](#querying-types-that-have-descendants)
- [Customising the names of types and operations](#customising-the-names-of-types-and-operations)
- [Versioned content](#versioned-content)
- [Version-specific-operations](#version-specific-operations)
- [Version-specific arguments](#version-specific-arguments)
Expand Down Expand Up @@ -1466,8 +1467,10 @@ $scaffolder
->type('SilverStripe\CMS\Model\RedirectorPage')
->addFields(['ID', 'ExternalURL', 'Content'])
->operation(SchemaScaffolder::READ)
->setName('readRedirectors')
->end()
->operation(SchemaScaffolder::CREATE)
->setName('createRedirector')
->end()
->end()
->type('Page')
Expand Down Expand Up @@ -1522,7 +1525,7 @@ input SiteTreeCreateInputType {
# all fields from SiteTree
}

query readRedirectorPages {
query readRedirectors {
RedirectorPage
}

Expand All @@ -1534,7 +1537,7 @@ query readSiteTrees {
SiteTreeWithDescendants
}

mutation createRedirectorPage {
mutation createRedirector {
RedirectorPageCreateInputType
}

Expand Down Expand Up @@ -1570,6 +1573,47 @@ query readSiteTrees {
}
}
```

#### Customising the names of types and operations

By default, the scaffolder will generate a type name for you based on the dataobject's `$table_name`
setting and the output of its `singular_name()` method. Often times, these are poor proxies for
a canonical name, e.g. `readMy_Really_Long_NameSpaced_BlogPosts`. To customise the type name, simply map a name to it in the `SilverStripe\GraphQL\Scaffolding\Schema`
class.

```yaml
SilverStripe\GraphQL\Controller:
schema:
typeNames:
My\Really\Long\Namespaced\BlogPost: Blog
```
Note that `typeNames` is the mapping of dataobjects to the graphql types, whereas the `types`
config is the list of type creators for non-scaffolded types, backed by php classes.
`typeNames` is also used (and required by) scaffolding, whether via PHP or YML.

Operations names are expressed using the type name of the dataobject they serve. That type name
may be customised or computed automatically, as described above. For a deeper level of control, you can
name the operation using the `name` property.

```yaml
...
operations:
read:
name: currentBlogs
```

The name of the operation has been fully customised to `currentBlogs`, returning the type `Blog`.

```yaml
...
operations:
read: true
```

Otherwise, the name of the read operation, given the `Schema` config above, will be `readBlogs`.


### Versioned content

If the `silversrtripe/versioned` module is installed in your project (as it is with a default CMS install),
Expand Down
5 changes: 5 additions & 0 deletions _config.php
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
<?php

// Set to 3.0.0 to show APIs marked for removal at that version
use SilverStripe\Dev\Deprecation;

Deprecation::notification_version('2.0.0', 'silverstripe/graphql');
8 changes: 7 additions & 1 deletion src/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Error\Error;
use GraphQL\Type\Definition\Type;
use SilverStripe\GraphQL\Scaffolding\StaticSchema;
use SilverStripe\ORM\ValidationException;
use SilverStripe\Security\Member;
use SilverStripe\GraphQL\Scaffolding\Interfaces\ScaffoldingProvider;
Expand Down Expand Up @@ -68,6 +69,11 @@ class Manager
*/
public static function createFromConfig($config)
{
// Bootstrap schema class mapping from config
if ($config && array_key_exists('typeNames', $config)) {
StaticSchema::inst()->setTypeNames($config['typeNames']);
}

/** @var Manager $manager */
$manager = Injector::inst()->create(Manager::class);

Expand Down Expand Up @@ -257,7 +263,7 @@ public function getType($name)
}

/**
* @param string $name
* @param string $name
*
* @return boolean
*/
Expand Down
4 changes: 2 additions & 2 deletions src/Scaffolding/Extensions/TypeCreatorExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use SilverStripe\ORM\DataExtension;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\GraphQL\Scaffolding\Interfaces\TypeParserInterface;
use SilverStripe\GraphQL\Scaffolding\Util\ScaffoldingUtil;
use SilverStripe\GraphQL\Scaffolding\StaticSchema;
use SilverStripe\GraphQL\Manager;
use Exception;

Expand All @@ -32,7 +32,7 @@ public function createTypeParser()
return Injector::inst()->createWithArgs(
TypeParserInterface::class . '.array',
[
ScaffoldingUtil::typeName(get_class($this->owner)),
StaticSchema::inst()->typeName(get_class($this->owner)),
$type
]
);
Expand Down
18 changes: 11 additions & 7 deletions src/Scaffolding/Scaffolders/CRUD/Read.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use SilverStripe\ORM\DataList;
use SilverStripe\GraphQL\Scaffolding\Scaffolders\UnionScaffolder;
use SilverStripe\GraphQL\Scaffolding\Scaffolders\ListQueryScaffolder;
use SilverStripe\GraphQL\Scaffolding\Util\ScaffoldingUtil;
use SilverStripe\GraphQL\Scaffolding\StaticSchema;
use SilverStripe\GraphQL\Manager;
use SilverStripe\Core\ClassInfo;
use Exception;
Expand Down Expand Up @@ -43,14 +43,14 @@ protected function getType(Manager $manager)
array_shift($descendants);
$union = [$this->typeName];
foreach ($descendants as $descendant) {
$typeName = ScaffoldingUtil::typeNameForDataObject($descendant);
$typeName = StaticSchema::inst()->typeNameForDataObject($descendant);
if ($manager->hasType($typeName)) {
$union[] = $typeName;
}
}
if (sizeof($union) > 1) {
return (new UnionScaffolder(
$this->typeName . 'WithDescendants',
$this->typeName.'WithDescendants',
$union
))->scaffold($manager);
}
Expand All @@ -68,14 +68,18 @@ protected function getResults($args)
}

/**
*
* @return string
*/
protected function createOperationName()
{
$typeName = $this->getDataObjectInstance()->plural_name();
$typeName = str_replace(' ', '', $typeName);
$typeName = ucfirst($typeName);
return 'read' . $typeName;
$typeName = $this->typeName();

// Ported from DataObject::plural_name()
if (preg_match('/[^aeiou]y$/i', $typeName)) {
$typeName = substr($typeName, 0, -1) . 'ie';
}
return 'read' . ucfirst($typeName . 's');
}

/**
Expand Down
8 changes: 4 additions & 4 deletions src/Scaffolding/Scaffolders/DataObjectScaffolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use SilverStripe\GraphQL\Scaffolding\Traits\Chainable;
use SilverStripe\GraphQL\Scaffolding\Traits\DataObjectTypeTrait;
use SilverStripe\GraphQL\Scaffolding\Util\OperationList;
use SilverStripe\GraphQL\Scaffolding\Util\ScaffoldingUtil;
use SilverStripe\GraphQL\Scaffolding\StaticSchema;
use SilverStripe\ORM\ArrayLib;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataList;
Expand Down Expand Up @@ -363,7 +363,7 @@ public function nestedQuery($fieldName, QueryScaffolder $queryScaffolder = null)
);
}

$typeName = ScaffoldingUtil::typeNameForDataObject($result->dataClass());
$typeName = StaticSchema::inst()->typeNameForDataObject($result->dataClass());

$queryScaffolder = (new ListQueryScaffolder(
$fieldName,
Expand Down Expand Up @@ -679,7 +679,7 @@ protected function createFields(Manager $manager)

foreach ($this->fields as $fieldData) {
$fieldName = $fieldData->Name;
if (!ScaffoldingUtil::isValidFieldName($instance, $fieldName)) {
if (!StaticSchema::inst()->isValidFieldName($instance, $fieldName)) {
throw new InvalidArgumentException(
sprintf(
'Invalid field "%s" on %s',
Expand Down Expand Up @@ -712,7 +712,7 @@ protected function createFields(Manager $manager)
}

foreach ($extraDataObjects as $fieldName => $className) {
$typeName = ScaffoldingUtil::typeNameForDataObject($className);
$typeName = StaticSchema::inst()->typeNameForDataObject($className);
$description = $this->getFieldDescription($fieldName);
$fieldMap[$fieldName] = [
'type' => $manager->getType($typeName),
Expand Down
14 changes: 14 additions & 0 deletions src/Scaffolding/Scaffolders/OperationScaffolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,17 @@ public function getName()
return $this->operationName;
}

/**
* @param $name
* @return $this
*/
public function setName($name)
{
$this->operationName = $name;

return $this;
}

/**
* @return ArrayList
*/
Expand Down Expand Up @@ -326,6 +337,9 @@ public function applyConfig(array $config)
if (isset($config['resolver'])) {
$this->setResolver($config['resolver']);
}
if (isset($config['name'])) {
$this->setName($config['name']);
}

return $this;
}
Expand Down
8 changes: 4 additions & 4 deletions src/Scaffolding/Scaffolders/SchemaScaffolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use SilverStripe\GraphQL\Scaffolding\Interfaces\ManagerMutatorInterface;
use SilverStripe\GraphQL\Scaffolding\Interfaces\ResolverInterface;
use SilverStripe\GraphQL\Scaffolding\Util\OperationList;
use SilverStripe\GraphQL\Scaffolding\Util\ScaffoldingUtil;
use SilverStripe\GraphQL\Scaffolding\StaticSchema;
use SilverStripe\ORM\ArrayLib;
use SilverStripe\View\ViewableData;

Expand Down Expand Up @@ -161,7 +161,7 @@ public function query($name, $class, $resolver = null)

$operationScaffold = (new ListQueryScaffolder(
$name,
ScaffoldingUtil::typeNameForDataObject($class),
StaticSchema::inst()->typeNameForDataObject($class),
$resolver
))->setChainableParent($this);

Expand All @@ -188,7 +188,7 @@ public function mutation($name, $class, $resolver = null)

$operationScaffold = (new MutationScaffolder(
$name,
ScaffoldingUtil::typeNameForDataObject($class),
StaticSchema::inst()->typeNameForDataObject($class),
$resolver
))->setChainableParent($this);

Expand Down Expand Up @@ -377,7 +377,7 @@ protected function registerPeripheralTypes(Manager $manager)
$ancestorType = $this->type($class);
$inst = $ancestorType->getDataObjectInstance();
foreach ($exposedFields as $field) {
if (ScaffoldingUtil::isValidFieldName($inst, $field->Name)) {
if (StaticSchema::inst()->isValidFieldName($inst, $field->Name)) {
$ancestorType->addField($field->Name, $field->Description);
}
}
Expand Down
16 changes: 8 additions & 8 deletions src/Scaffolding/Scaffolders/UnionScaffolder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use SilverStripe\Core\ClassInfo;
use SilverStripe\GraphQL\Manager;
use SilverStripe\GraphQL\Scaffolding\Interfaces\ScaffolderInterface;
use SilverStripe\GraphQL\Scaffolding\Util\ScaffoldingUtil;
use SilverStripe\GraphQL\Scaffolding\StaticSchema;
use SilverStripe\ORM\DataObject;

class UnionScaffolder implements ScaffolderInterface
Expand All @@ -24,7 +24,7 @@ class UnionScaffolder implements ScaffolderInterface
protected $types = [];

/**
* @param string $baseType
* @param string $name
* @param array $types
*/
public function __construct($name, $types = [])
Expand Down Expand Up @@ -55,17 +55,17 @@ public function scaffold(Manager $manager)
$ancestry = array_reverse(ClassInfo::ancestry($obj));
foreach ($ancestry as $class) {
if ($class === DataObject::class) {
throw new Exception(sprintf(
'There is no type defined for %s, and none of its ancestors are defined.',
get_class($obj)
));
break;
}

$typeName = ScaffoldingUtil::typeNameForDataObject($class);
$typeName = StaticSchema::inst()->typeNameForDataObject($class);
if ($manager->hasType($typeName)) {
return $manager->getType($typeName);
}
}
throw new Exception(sprintf(
'There is no type defined for %s, and none of its ancestors are defined.',
get_class($obj)
));
}
]);
}
Expand Down
Loading

0 comments on commit 87afe84

Please sign in to comment.