Skip to content

Commit 9517295

Browse files
committed
Implement simple create mutation on a per template basis.
1 parent 6956cf1 commit 9517295

File tree

5 files changed

+228
-7
lines changed

5 files changed

+228
-7
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
3+
namespace ProcessWire\GraphQL\Field\Mutation;
4+
5+
use Youshido\GraphQL\Field\AbstractField;
6+
use Youshido\GraphQL\Execution\ResolveInfo;
7+
use Youshido\GraphQL\Exception\ValidationException;
8+
use Youshido\GraphQL\Config\Field\FieldConfig;
9+
use Youshido\GraphQL\Field\InputField;
10+
11+
use ProcessWire\Template;
12+
use ProcessWire\Page;
13+
use ProcessWire\NullPage;
14+
use ProcessWire\Field;
15+
use ProcessWire\FieldtypePage;
16+
17+
use ProcessWire\GraphQL\Type\Object\TemplatedPageType;
18+
use ProcessWire\GraphQL\Type\Input\TemplatedPageInputType;
19+
20+
class CreateTemplatedPage extends AbstractField {
21+
22+
protected $template;
23+
24+
public function __construct(Template $template)
25+
{
26+
$this->template = $template;
27+
parent::__construct([]);
28+
}
29+
30+
public function getName()
31+
{
32+
$typeName = ucfirst(TemplatedPageType::normalizeName($this->template->name));
33+
return "create{$typeName}";
34+
}
35+
36+
public function getType()
37+
{
38+
return new TemplatedPageType($this->template);
39+
}
40+
41+
public function getDescription()
42+
{
43+
return "Allows you to create Pages with template `{$this->template->name}`.";
44+
}
45+
46+
public function build(FieldConfig $config)
47+
{
48+
$config->addArgument(new InputField([
49+
'name' => 'page',
50+
'type' => new TemplatedPageInputType($this->template),
51+
]));
52+
}
53+
54+
public function resolve($value, array $args, ResolveInfo $info)
55+
{
56+
// prepare neccessary variables
57+
$pages = \ProcessWire\wire('pages');
58+
$sanitizer = \ProcessWire\wire('sanitizer');
59+
$fields = \ProcessWire\wire('fields');
60+
$values = (array) $args['page'];
61+
62+
/*********************************************\
63+
* *
64+
* Don't ever take sides against the family! *
65+
* *
66+
\*********************************************/
67+
// can new pages be created for this template?
68+
if ($this->template->noParents === 1) throw new ValidationException("No new pages can be created for the template `{$this->template->name}`.");
69+
// if there could be only one page is there already a page with this template
70+
if ($this->template->noParents === -1 && !$pages->get("template={$this->template}") instanceof NullPage) throw new ValidationException("Only one page with template `{$this->template->name}` can be created.");
71+
// find the parent, make sure it exists
72+
$parentSelector = $values['parent'];
73+
$parent = $pages->find($sanitizer->selectorValue($parentSelector))->first();
74+
// if no parent then no good. No child should born without a parent!
75+
if (!$parent || $parent instanceof NullPage) throw new ValidationException("Could not find the `parent` page with `$parentSelector`.");
76+
// make sure it is allowed as a parent
77+
$parentTemplates = $this->template->parentTemplates;
78+
if (count($parentTemplates) && !in_array($parent->template->id, $parentTemplates)) throw new ValidationException("`parent` is not allowed as a parent.");
79+
// make sure parent is allowed to have children
80+
if ($parent->template->noChildren === 1) throw new ValidationException("`parent` is not allowed to have children.");
81+
// make sure the page is allowed as a child for parent
82+
$childTemplates = $parent->template->childTemplates;
83+
if (count($childTemplates) && !in_array($this->template->id, $childTemplates)) throw new ValidationException("not allowed to be a child for `parent`.");
84+
85+
// check if the name is valid
86+
$name = $sanitizer->pageName($values['name']);
87+
if (!$name) throw new ValidationException('value for `name` field is invalid,');
88+
$taken = $pages->find("parent=$parent, name=$name")->count();
89+
if ($taken) throw new ValidationException('`name` is already taken.');
90+
91+
// create the page
92+
$p = new Page();
93+
$p->of(false);
94+
$p->template = $this->template;
95+
$p->parent = $parent;
96+
$p->name = $name;
97+
98+
// set the values from client
99+
unset($values['parent']);
100+
unset($values['name']);
101+
foreach ($values as $fieldName => $value) {
102+
$field = $fields->get($fieldName);
103+
if (!$field instanceof Field) continue;
104+
switch ($field->type->className()) {
105+
case 'FieldtypePage':
106+
$p->setFieldValue($fieldName, implode('|', $value));
107+
break;
108+
default:
109+
$p->setFieldValue($fieldName, $value);
110+
break;
111+
}
112+
}
113+
114+
// save the page to db
115+
if ($p->save()) return $p;
116+
117+
// If we did not return till now then no good!
118+
throw new ResolveException("Could not create page `$name` with template `{$this->template->name}`");
119+
}
120+
121+
}

src/Field/Page/Fieldtype/AbstractFieldtype.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,23 @@ public function getType()
2323
return $this->getDefaultType();
2424
}
2525

26+
public function getInputfieldType($type = null)
27+
{
28+
if (is_null($type)) return $this->getType();
29+
if ($this->field->required) return new NonNullType($type);
30+
return $type;
31+
}
32+
2633
public function getName()
2734
{
2835
return $this->field->name;
2936
}
3037

3138
public function getDescription()
3239
{
33-
return $this->field->description;
40+
$desc = $this->field->description;
41+
if ($desc) return $desc;
42+
return "Field with the type of {$this->field->type}";
3443
}
3544

3645
public function resolve($value, array $args, ResolveInfo $info)
@@ -39,4 +48,4 @@ public function resolve($value, array $args, ResolveInfo $info)
3948
return $value->$fieldName;
4049
}
4150

42-
}
51+
}

src/Field/Page/Fieldtype/FieldtypePage.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace ProcessWire\GraphQL\Field\Page\Fieldtype;
44

5-
use Youshido\GraphqL\Execution\ResolveInfo;
5+
use Youshido\GraphQL\Execution\ResolveInfo;
6+
use Youshido\GraphQL\Type\ListType\ListType;
7+
use Youshido\GraphQL\Type\Scalar\IntType;
68
use ProcessWire\Template;
79
use ProcessWire\FieldtypePage as PWFieldtypePage;
810
use ProcessWire\GraphQL\Type\Object\PageArrayType;
@@ -24,6 +26,11 @@ public function getDefaultType()
2426
return new PageArrayType();
2527
}
2628

29+
public function getInputfieldType($type = null)
30+
{
31+
return parent::getInputfieldType(new ListType(new IntType()));
32+
}
33+
2734
public function resolve($value, array $args, ResolveInfo $info)
2835
{
2936
$defaultSelector = new SelectorType();

src/Schema.php

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,23 @@
99
use ProcessWire\GraphQL\Field\Auth\LoginField;
1010
use ProcessWire\GraphQL\Field\Auth\LogoutField;
1111
use ProcessWire\GraphQL\Field\User\UserField;
12-
12+
use ProcessWire\GraphQL\Field\Mutation\CreateTemplatedPage;
1313

1414

1515
class Schema extends AbstractSchema {
1616

1717
protected $fields = [];
18-
18+
1919
public function build(SchemaConfig $config)
2020
{
21+
/**
22+
* Query
23+
*/
2124
$query = $config->getQuery();
2225

2326
// $pages API
2427
$query->addField(new PagesField());
25-
28+
2629
// $templates
2730
foreach (Settings::getLegalTemplates() as $template) {
2831
$query->addField(new TemplatedPageArrayField($template));
@@ -39,11 +42,23 @@ public function build(SchemaConfig $config)
3942

4043
// User
4144
$query->addField(new UserField());
45+
46+
47+
/**
48+
* Mutation
49+
*/
50+
$mutation = $config->getMutation();
51+
52+
// CreatePage
53+
foreach (Settings::getLegalTemplates() as $template) {
54+
$mutation->addField(new CreateTemplatedPage($template));
55+
}
56+
4257
}
4358

4459
public function getName()
4560
{
4661
return 'Root';
4762
}
4863

49-
}
64+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
namespace ProcessWire\GraphQL\Type\Input;
4+
5+
use Youshido\GraphQL\Type\InputObject\AbstractInputObjectType;
6+
use Youshido\GraphQL\Type\NonNullType;
7+
use Youshido\GraphQL\Type\Scalar\StringType;;
8+
use ProcessWire\Template;
9+
10+
class TemplatedPageInputType extends AbstractInputObjectType {
11+
12+
protected $template;
13+
14+
public function __construct(Template $template)
15+
{
16+
$this->template = $template;
17+
parent::__construct([]);
18+
}
19+
20+
public Static function normalizeName($name)
21+
{
22+
return str_replace('-', '_', $name);
23+
}
24+
25+
public function getName()
26+
{
27+
return ucfirst(self::normalizeName($this->template->name)) . 'PageInputType';
28+
}
29+
30+
public function getDescription()
31+
{
32+
return "InputType for pages with template {$this->template->name}.";
33+
}
34+
35+
public function build($config)
36+
{
37+
// parent
38+
$config->addField('parent', [
39+
'type' => new NonNullType(new StringType()),
40+
'description' => 'Id or the path of the parent page.',
41+
]);
42+
43+
// name
44+
$config->addField('name', [
45+
'type' => new NonNullType(new StringType()),
46+
'description' => 'ProcessWire page name.',
47+
]);
48+
49+
$unsupportedFieldtypes = [
50+
'FieldtypeFile',
51+
'FieldtypeImage',
52+
''
53+
];
54+
55+
// the template fields
56+
foreach ($this->template->fields as $field) {
57+
$className = $field->type->className();
58+
if (in_array($className, $unsupportedFieldtypes)) continue;
59+
$Class = "\\ProcessWire\\GraphQL\\Field\\Page\\Fieldtype\\" . $className;
60+
if (!class_exists($Class)) continue;
61+
$field = new $Class($field);
62+
$config->addField($field->getName(), [
63+
'type' => $field->getInputfieldType(),
64+
'description' => $field->getDescription(),
65+
]);
66+
}
67+
}
68+
69+
}

0 commit comments

Comments
 (0)