Skip to content

Commit

Permalink
feat(SLB-218): generalize the create webform submission service
Browse files Browse the repository at this point in the history
  • Loading branch information
chindris committed Mar 27, 2024
1 parent 0e93d84 commit 68c3745
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 229 deletions.
2 changes: 1 addition & 1 deletion apps/website/src/templates/contact.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Contact } from '@custom/ui/routes/Contact';
import React from 'react';

export default function ContentHubPage() {
export default function ContactPage() {
return <Contact />;
}
1 change: 1 addition & 0 deletions packages/drupal/custom/custom.info.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ dependencies:
- silverback_gatsby:silverback_gatsby
- simple_oauth:simple_oauth
- consumers:consumers
- drupal:serialization
6 changes: 1 addition & 5 deletions packages/drupal/custom/custom.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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']
118 changes: 0 additions & 118 deletions packages/drupal/custom/src/Contact.php

This file was deleted.

131 changes: 105 additions & 26 deletions packages/drupal/custom/src/Webform.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -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;
}

}
1 change: 1 addition & 0 deletions packages/schema/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const scalars = {
Markup: '@amazeelabs/scalars#Markup',
Url: '@amazeelabs/scalars#Url',
ImageSource: '@amazeelabs/scalars#ImageSource',
JSONString: 'string',
};

const common = {
Expand Down
11 changes: 3 additions & 8 deletions packages/schema/src/operations/ContactRequest.gql
Original file line number Diff line number Diff line change
@@ -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
}
}
28 changes: 7 additions & 21 deletions packages/schema/src/schema.graphql
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit 68c3745

Please sign in to comment.