diff --git a/apps/website/src/templates/contact.tsx b/apps/website/src/templates/contact.tsx
index 09dbe50e5..5889f02d9 100644
--- a/apps/website/src/templates/contact.tsx
+++ b/apps/website/src/templates/contact.tsx
@@ -1,6 +1,6 @@
import { Contact } from '@custom/ui/routes/Contact';
import React from 'react';
-export default function ContentHubPage() {
+export default function ContactPage() {
return ;
}
diff --git a/packages/drupal/custom/custom.info.yml b/packages/drupal/custom/custom.info.yml
index e0d6338fd..732a2f809 100644
--- a/packages/drupal/custom/custom.info.yml
+++ b/packages/drupal/custom/custom.info.yml
@@ -6,3 +6,4 @@ dependencies:
- silverback_gatsby:silverback_gatsby
- simple_oauth:simple_oauth
- consumers:consumers
+ - drupal:serialization
diff --git a/packages/drupal/custom/custom.services.yml b/packages/drupal/custom/custom.services.yml
index 2f01322df..0ad082aad 100644
--- a/packages/drupal/custom/custom.services.yml
+++ b/packages/drupal/custom/custom.services.yml
@@ -9,8 +9,4 @@ services:
custom.webform:
class: Drupal\custom\Webform
- arguments: ['@renderer', '@entity_type.manager']
-
- custom.contact:
- class: Drupal\custom\Contact
- arguments: ['@custom.webform']
+ arguments: ['@renderer', '@entity_type.manager', '@serializer']
diff --git a/packages/drupal/custom/src/Contact.php b/packages/drupal/custom/src/Contact.php
deleted file mode 100644
index c0a4d7b26..000000000
--- a/packages/drupal/custom/src/Contact.php
+++ /dev/null
@@ -1,118 +0,0 @@
-webformService = $webformService;
- }
-
- /**
- * Creates a contact webform entry.
- */
- public function create(DirectiveArguments $args): array {
- try {
- $submissionData = [
- 'name' => $args->args['contact']['name'],
- 'email' => $args->args['contact']['email'],
- 'subject' => $args->args['contact']['subject'],
- 'message' => $args->args['contact']['message'],
- ];
- $webformSubmission = $this->webformService->createSubmission('contact', $submissionData);
-
- // If we get an array from the createSubmission call, then it means there
- // were errors during the insert / validate operation, so we just return
- // them.
- if (is_array($webformSubmission)) {
- return [
- 'errors' => $this->formatErrors($webformSubmission),
- 'contact' => NULL,
- ];
- }
-
- // We successfully submitted the data.
- if (is_object($webformSubmission) && $webformSubmission instanceof WebformSubmissionInterface) {
- $submittedData = $webformSubmission->getData();
- return [
- 'errors' => NULL,
- 'contact' => [
- 'id' => $webformSubmission->id(),
- 'name' => $submittedData['name'],
- 'email' => $submittedData['email'],
- 'subject' => $submittedData['subject'],
- 'message' => $submittedData['message'],
- ],
- ];
- }
- } catch (\InvalidArgumentException $e) {
- return [
- 'contact' => NULL,
- 'errors' => [
- [
- 'message' => $e->getMessage(),
- 'key' => 'invalid_webform'
- ]
- ]
- ];
- } catch (\Exception $e) {
- return [
- 'contact' => NULL,
- 'errors' => [
- [
- 'message' => $e->getMessage(),
- 'key' => 'invalid_input'
- ]
- ]
- ];
- }
-
- // We should actually never get here... if we do, we don't know what
- // happened.
- return [
- 'contact' => NULL,
- 'errors' => [
- [
- 'message' => 'Unknown error',
- 'key' => 'unknown_error',
- ]
- ]
- ];
- }
-
- /**
- * Helper method to arrange a set of webform submission errors in a way that
- * can be used by the MutationError graphl type.
- */
- protected function formatErrors(array $webformSubmissionErrors) {
- $formattedErrors = [];
- foreach ($webformSubmissionErrors as $fieldName => $error) {
- $formattedErrors[] = [
- 'message' => $error->__toString(),
- 'key' => 'invalid_field_' . $fieldName,
- 'field' => $fieldName,
- ];
- }
- return $formattedErrors;
- }
-}
diff --git a/packages/drupal/custom/src/Webform.php b/packages/drupal/custom/src/Webform.php
index 3cc44c7fa..541f367ae 100644
--- a/packages/drupal/custom/src/Webform.php
+++ b/packages/drupal/custom/src/Webform.php
@@ -8,6 +8,8 @@
use Drupal\graphql_directives\DirectiveArguments;
use Drupal\webform\WebformSubmissionForm;
use Drupal\webform\WebformSubmissionInterface;
+use Symfony\Component\Serializer\Serializer;
+use Symfony\Component\Serializer\SerializerInterface;
/**
* Helper service for managing webforms with graphql.
@@ -26,15 +28,24 @@ class Webform {
*/
protected EntityTypeManagerInterface $entityTypeManager;
+ /**
+ * The serializer serice.
+ *
+ * @var \Symfony\Component\Serializer\SerializerInterface
+ */
+ protected Serializer $serializer;
+
/**
* Webform constructor.
*/
public function __construct(
RendererInterface $renderer,
- EntityTypeManagerInterface $entityTypeManager
+ EntityTypeManagerInterface $entityTypeManager,
+ SerializerInterface $serializer
) {
$this->entityTypeManager = $entityTypeManager;
$this->renderer = $renderer;
+ $this->serializer = $serializer;
}
/**
@@ -71,34 +82,102 @@ function () use ($args, $webformId, $webFormStorage) {
}
/**
- * Creates a webform submission.
- *
- * @param string $webformId
- * @param array $submissionData
- *
- * @return \Drupal\webform\WebformSubmissionInterface|array|null
- * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
- * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
+ * Directive to create a webform submission.
*/
- public function createSubmission(string $webformId, array $submissionData) : WebformSubmissionInterface | array | null {
- $webform = $this->entityTypeManager->getStorage('webform')->load($webformId);
- if (!$webform) {
- throw new \InvalidArgumentException('The webform could no be loaded.');
- }
- $isOpen = WebformSubmissionForm::isOpen($webform);
- if ($isOpen !== TRUE) {
- throw new \Exception($isOpen);
+ public function createSubmission(DirectiveArguments $args) : array {
+ try {
+ $webformId = $args->args['webformId'];
+ $webform = $this->entityTypeManager->getStorage('webform')
+ ->load($webformId);
+ if (!$webform) {
+ throw new \InvalidArgumentException('The webform could no be loaded.');
+ }
+ $isOpen = WebformSubmissionForm::isOpen($webform);
+ if ($isOpen !== TRUE) {
+ throw new \Exception($isOpen);
+ }
+ $submittedData = $args->args['submittedData'];
+ $values = [
+ 'webform_id' => $webformId,
+ 'entity_type' => NULL,
+ 'entity_id' => NULL,
+ 'data' => $this->serializer->decode($submittedData, 'json'),
+ ];
+ // The WebformSubmissionForm::submitFormValues() will return an array with
+ // errors, if there are validation errors, otherwise it will return a
+ // webform submission entity.
+ $webformSubmission = WebformSubmissionForm::submitFormValues($values);
+
+ // If we get an array from the createSubmission call, then it means there
+ // were errors during the insert / validate operation, so we just return
+ // them.
+ if (is_array($webformSubmission)) {
+ return [
+ 'errors' => $this->formatErrors($webformSubmission),
+ 'submission' => NULL,
+ ];
+ }
+
+ // We successfully submitted the data.
+ if (is_object($webformSubmission) && $webformSubmission instanceof WebformSubmissionInterface) {
+ $webformSubmissionData = $webformSubmission->getData();
+ return [
+ 'errors' => NULL,
+ 'submission' => $this->serializer->encode(array_merge([
+ 'submissionId' => $webformSubmission->id(),
+ ], $webformSubmissionData), 'json'),
+ ];
+ }
+ } catch (\InvalidArgumentException $e) {
+ return [
+ 'submission' => NULL,
+ 'errors' => [
+ [
+ 'message' => $e->getMessage(),
+ 'key' => 'invalid_webform'
+ ]
+ ]
+ ];
+ } catch (\Exception $e) {
+ return [
+ 'submission' => NULL,
+ 'errors' => [
+ [
+ 'message' => $e->getMessage(),
+ 'key' => 'invalid_input'
+ ]
+ ]
+ ];
}
- $values = [
- 'webform_id' => 'contact',
- 'entity_type' => NULL,
- 'entity_id' => NULL,
- 'data' => $submissionData,
+
+ // We should actually never get here... if we do, we don't know what
+ // happened.
+ return [
+ 'submission' => NULL,
+ 'errors' => [
+ [
+ 'message' => 'Unknown error',
+ 'key' => 'unknown_error',
+ ]
+ ]
];
- // The WebformSubmissionForm::submitFormValues() will return an array with
- // errors, if there are validation errors, otherwise it will return a
- // webform submission entity.
- return WebformSubmissionForm::submitFormValues($values);
+
+ }
+
+ /**
+ * Helper method to arrange a set of webform submission errors in a way that
+ * can be used by the MutationError graphl type.
+ */
+ protected function formatErrors(array $webformSubmissionErrors) {
+ $formattedErrors = [];
+ foreach ($webformSubmissionErrors as $fieldName => $error) {
+ $formattedErrors[] = [
+ 'message' => $error->__toString(),
+ 'key' => 'invalid_field_' . $fieldName,
+ 'field' => $fieldName,
+ ];
+ }
+ return $formattedErrors;
}
}
diff --git a/packages/schema/codegen.ts b/packages/schema/codegen.ts
index 44f75b652..de805092a 100644
--- a/packages/schema/codegen.ts
+++ b/packages/schema/codegen.ts
@@ -8,6 +8,7 @@ const scalars = {
Markup: '@amazeelabs/scalars#Markup',
Url: '@amazeelabs/scalars#Url',
ImageSource: '@amazeelabs/scalars#ImageSource',
+ JSONString: 'string',
};
const common = {
diff --git a/packages/schema/src/operations/ContactRequest.gql b/packages/schema/src/operations/ContactRequest.gql
index 878063452..08c3d89f4 100644
--- a/packages/schema/src/operations/ContactRequest.gql
+++ b/packages/schema/src/operations/ContactRequest.gql
@@ -1,15 +1,10 @@
-mutation ContactRequest($contact: ContactInput) {
- createContact(contact: $contact) {
+mutation CreateSubmission($webformId: String!, $submittedData: JSONString!) {
+ createWebformSubmission(webformId: $webformId, submittedData: $submittedData) {
errors {
key
field
message
}
- contact {
- name
- email
- message
- subject
- }
+ submission
}
}
diff --git a/packages/schema/src/schema.graphql b/packages/schema/src/schema.graphql
index cea80f342..7574b26a6 100644
--- a/packages/schema/src/schema.graphql
+++ b/packages/schema/src/schema.graphql
@@ -1,6 +1,7 @@
scalar Url @default @value(string: "")
scalar Markup @default @value(string: "")
scalar ImageSource @default @value(string: "")
+scalar JSONString @default @value(string: "{}")
"""
implementation(drupal): custom.content_hub::query
@@ -17,9 +18,9 @@ implementation(drupal): custom.webform::url
directive @webformIdToUrl(id: String!) on FIELD_DEFINITION
"""
-implementation(drupal): custom.contact::create
+implementation(drupal): custom.webform::createSubmission
"""
-directive @createContact(contact: ContactInput) on FIELD_DEFINITION
+directive @createWebformSubmission(webformId: String!, submittedData: JSONString!) on FIELD_DEFINITION
"""
Retrieve the properties of an image.
@@ -237,28 +238,13 @@ type Query {
}
type Mutation {
- createContact(contact: ContactInput): ContactCreateResponse
- @createContact(contact: "$contact")
+ createWebformSubmission(webformId: String!, submittedData: JSONString!): WebformSubmissionCreateResponse
+ @createWebformSubmission(webformId: "$webformId", submittedData: "$submittedData")
}
-type Contact {
- id: String!
- name: String
- email: String
- subject: String
- message: String
-}
-
-input ContactInput {
- name: String
- email: String
- subject: String
- message: String
-}
-
-type ContactCreateResponse {
+type WebformSubmissionCreateResponse {
errors: [MutationError]
- contact: Contact
+ submission: JSONString
}
type MutationError {
diff --git a/packages/ui/src/components/Molecules/ContactForm.tsx b/packages/ui/src/components/Molecules/ContactForm.tsx
index be4c3eeda..ce09588b0 100644
--- a/packages/ui/src/components/Molecules/ContactForm.tsx
+++ b/packages/ui/src/components/Molecules/ContactForm.tsx
@@ -1,4 +1,4 @@
-import { ContactRequestMutation } from '@custom/schema';
+import { CreateSubmissionMutation } from '@custom/schema';
import React from 'react';
import { useForm } from 'react-hook-form';
import { useIntl } from 'react-intl';
@@ -19,18 +19,18 @@ export function ContactForm() {
type FormValue = z.infer;
const { register, handleSubmit } = useForm();
- const { data, trigger, isMutating } = useMutation(ContactRequestMutation);
+ const { data, trigger, isMutating } = useMutation(CreateSubmissionMutation);
const errorMessages =
!isMutating &&
data &&
- data.createContact?.errors &&
- data.createContact.errors.length > 0
- ? data.createContact.errors.map((error) => {
+ data.createWebformSubmission?.errors &&
+ data.createWebformSubmission.errors.length > 0
+ ? data.createWebformSubmission.errors.map((error) => {
return error?.message || '';
})
: null;
const successMessages =
- !isMutating && data && data.createContact?.contact
+ !isMutating && data && data.createWebformSubmission?.submission
? [
intl.formatMessage({
defaultMessage: 'The contact has been submitted.',
@@ -48,7 +48,8 @@ export function ContactForm() {
className="mt-5 sm:items-center"
onSubmit={handleSubmit((values) => {
trigger({
- contact: values,
+ webformId: 'contact',
+ submittedData: JSON.stringify(values),
});
})}
>
diff --git a/tests/schema/specs/contact.spec.ts b/tests/schema/specs/contact.spec.ts
index 4d4a91c30..d83d3569e 100644
--- a/tests/schema/specs/contact.spec.ts
+++ b/tests/schema/specs/contact.spec.ts
@@ -7,75 +7,47 @@ describe('create contact', () => {
it('creates a new contact using a graphql mutation', async () => {
const result = await fetch(gql`
mutation {
- createContact(
- contact: {
- name: "John Doe"
- email: "john@doe.com"
- message: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In pretium aliquam magna."
- subject: "Lorem ipsum"
- }
+ createWebformSubmission(
+ webformId: "contact",
+ submittedData: "{\\"name\\": \\"John Doe\\", \\"email\\": \\"john@doe.com\\", \\"message\\": \\"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In pretium aliquam magna.\\", \\"subject\\": \\"Lorem ipsum\\"}"
) {
errors {
key
field
message
}
- contact {
- name
- email
- message
- subject
- }
+ submission
}
}
`);
- expect(result).toMatchInlineSnapshot(`
- {
- "data": {
- "createContact": {
- "contact": {
- "email": "john@doe.com",
- "message": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In pretium aliquam magna.",
- "name": "John Doe",
- "subject": "Lorem ipsum",
- },
- "errors": null,
- },
- },
- }
- `);
+ const submission = JSON.parse(result.data.createWebformSubmission.submission);
+ expect(submission.email).toEqual('john@doe.com');
+ expect(submission.message).toEqual('Lorem ipsum dolor sit amet, consectetur adipiscing elit. In pretium aliquam magna.');
+ expect(submission.name).toEqual('John Doe');
+ expect(submission.subject).toEqual('Lorem ipsum');
+ expect(result.data.createWebformSubmission.errors).toBeNull();
});
it('tries to create a new contact with an invalid e-mail address', async () => {
const result = await fetch(gql`
mutation {
- createContact(
- contact: {
- name: "Jane"
- email: "invalid_email"
- message: "Test message."
- subject: "Test subject"
- }
+ createWebformSubmission(
+ webformId: "contact",
+ submittedData: "{\\"name\\": \\"Jane\\",\\"email\\": \\"invalid_email\\",\\"message\\": \\"Test message.\\",\\"subject\\": \\"Test subject\\"}"
) {
errors {
key
field
message
}
- contact {
- name
- email
- message
- subject
- }
+ submission
}
}
`);
expect(result).toMatchInlineSnapshot(`
{
"data": {
- "createContact": {
- "contact": null,
+ "createWebformSubmission": {
"errors": [
{
"field": "email",
@@ -83,6 +55,7 @@ describe('create contact', () => {
"message": "The email address invalid_email is not valid. Use the format user@example.com.",
},
],
+ "submission": null,
},
},
}