From 4d2d699ce4b1a537e37fcd1697cbb4d07f721ff9 Mon Sep 17 00:00:00 2001 From: Vincent Gao Date: Mon, 3 Apr 2023 17:57:55 +1000 Subject: [PATCH] [SDPAP-7155] webform validation --- .../src/Resource/AddWebform.php | 223 ++++++++++++++++++ .../tide_webform_jsonapi.info.yml | 6 + .../tide_webform_jsonapi.module | 21 ++ .../tide_webform_jsonapi.routing.yml | 11 + 4 files changed, 261 insertions(+) create mode 100644 modules/tide_webform_jsonapi/src/Resource/AddWebform.php create mode 100644 modules/tide_webform_jsonapi/tide_webform_jsonapi.info.yml create mode 100644 modules/tide_webform_jsonapi/tide_webform_jsonapi.module create mode 100644 modules/tide_webform_jsonapi/tide_webform_jsonapi.routing.yml diff --git a/modules/tide_webform_jsonapi/src/Resource/AddWebform.php b/modules/tide_webform_jsonapi/src/Resource/AddWebform.php new file mode 100644 index 0000000..2e2b67c --- /dev/null +++ b/modules/tide_webform_jsonapi/src/Resource/AddWebform.php @@ -0,0 +1,223 @@ +currentUser = $current_user; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('current_user') + ); + } + + /** + * Process the resource request. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The request. + * @param \Drupal\jsonapi\JsonApiResource\JsonApiDocumentTopLevel $document + * The deserialized request document. + * + * @return \Drupal\jsonapi\ResourceResponse + * The response. + * + * @throws \Symfony\Component\HttpKernel\Exception\ConflictHttpException + * Thrown when the entity to be created already exists. + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * Thrown if the storage handler couldn't be loaded. + * @throws \Drupal\Core\Entity\EntityStorageException + * Thrown if the entity could not be saved. + */ + public function process(Request $request, Webform $webform): ResourceResponse { + /** @var \Drupal\jsonapi\ResourceType\ResourceTypeRepository $resource_type_repo */ + $resource_type_repo = \Drupal::service('jsonapi.resource_type.repository'); + $resource_type = $resource_type_repo->get( + 'webform_submission', + 'tide_webform_content_rating' + ); + /** @var \Drupal\jsonapi\Controller\EntityResource $entity_resource_controller */ + $entity_resource_controller = \Drupal::service('jsonapi.entity_resource'); + $reflectedMethod = new \ReflectionMethod( + $entity_resource_controller, + 'deserialize' + ); + $reflectedMethod->setAccessible(TRUE); + /** @var \Drupal\webform\Entity\WebformSubmission $entity */ + $entity = $reflectedMethod->invoke( + $entity_resource_controller, + $resource_type, + $request, + JsonApiDocumentTopLevel::class + ); + + static::validate($entity); + $entity->save(); + +// $data = $this->createIndividualDataFromEntity($entity); +// $resource_object = $data->getIterator()->current(); +// assert($resource_object instanceof ResourceObject); +// $response = $this->createJsonapiResponse($data, $request, 201); + +// $webform = \Drupal\webform\Entity\Webform::load('tide_webform_content_rating'); + $original_elements = $webform->getElementsDecodedAndFlattened(); + $supported_validations = $this->getSupportedValidateElements(); + $results = $this->webformValidateSettingsExtractor($supported_validations,$original_elements); + $new_array = []; + foreach ($results as $key => $r){ + $new_array[$key] = $this->attachValidateSettingsToPayload($r); + } + $errors = $this->validatePayload($entity->getData(),$new_array); + // check internal errors + $internal_errors = WebformSubmissionForm::validateWebformSubmission($entity); + if (!empty($internal_errors)){ + foreach ($internal_errors as $key => $message){ + $errors[$key][] = $message->__toString(); + } + } + $errors_collection = []; + if (!empty($errors)){ + foreach ($errors as $field_id => $details){ + foreach ($details as $item){ + $errors_collection[] = new HttpException(422,$field_id . '|' . $item); + } + } + $errs = new ErrorCollection($errors_collection); + $document = new JsonApiDocumentTopLevel($errs, new NullIncludedData(), new LinkCollection([])); + $response = new ResourceResponse($document, 422); + return $response; + } + + $resource_object = ResourceObject::createFromEntity($resource_type, $entity); + $primary_data = new ResourceObjectData([$resource_object], 1); + $response = $this->createJsonapiResponse($primary_data, $request, 201); + // Normal data +// $resource_object = ResourceObject::createFromEntity($resource_type, $entity); +// $primary_data = new ResourceObjectData([$resource_object], 1); +// $response = $this->createJsonapiResponse($primary_data, $request, 201); + // Normal data + +// $err = new HttpException(422,'hello'); +// $errs = new ErrorCollection([$err,$err,$err]); +// $errs = new ErrorCollection($errors_collection); +// +// $document = new JsonApiDocumentTopLevel($errs, new NullIncludedData(), new LinkCollection([])); +// $response = new ResourceResponse($document, 422); + return $response; + } + + public function getRouteResourceTypes(Route $route, string $route_name): array { + return $this->getResourceTypesByEntityTypeId('webform_submission'); + } + + public function webformValidateSettingsExtractor(array $supported_validation,array $original_elements): array { + $res = []; + // Iterate through webform values. + foreach ($original_elements as $w_key => $items) { + // Iterate through supported validation keys and their values. + foreach ($supported_validation as $key => $value) { + // If the current value is an array, check for a match with the key. + if (is_array($value)) { + if (array_key_exists($key, $items)) { + $res[$w_key][$key] = $items[$key]; + } + } + else { + // If the value exists in the items and is not an array, store it in the result. + if (array_key_exists($value, $items)) { + $res[$w_key][$value] = $items[$value]; + } + } + } + } + return $res; + } + + public function getSupportedValidateElements(){ + return [ + '#required', + '#required_error', + '#pattern', + '#pattern_error', + ]; + } + + public function attachValidateSettingsToPayload(array $payload){ + $output = []; + $mapping = [ + '#required' => 'required', + '#required_error' => 'required', + '#pattern' => 'pattern', + '#pattern_error' => 'pattern', + ]; + foreach ($payload as $key => $value) { + if (isset($mapping[$key])) { + $output[$mapping[$key]][] = $value; + } + } + return $output; + } + + public function validatePayload(array $payload, array $massaged_validates_array){ + $results = []; + foreach ($payload as $id => $value){ + if (array_key_exists($id,$massaged_validates_array)){ + if (!empty($this->generateErrorString($value, $massaged_validates_array[$id]))){ + $results[$id] = $this->generateErrorString($value, $massaged_validates_array[$id]); + } + } + } + return $results; + } + + public function generateErrorString($value, array $arr){ + $res = []; + foreach ($arr as $k => $v) { + if (call_user_func('tide_webform_' . $k . '_validate',$value,$v) !== TRUE){ + $res[] = call_user_func('tide_webform_' . $k . '_validate',$value,$v); + } + } + return $res; + } +} diff --git a/modules/tide_webform_jsonapi/tide_webform_jsonapi.info.yml b/modules/tide_webform_jsonapi/tide_webform_jsonapi.info.yml new file mode 100644 index 0000000..b256ceb --- /dev/null +++ b/modules/tide_webform_jsonapi/tide_webform_jsonapi.info.yml @@ -0,0 +1,6 @@ +name: 'JSON:API Tide_webform' +description: "This module let's you validate payload for webform." +core_version_requirement: ^9 || ^10 +type: module +dependencies: + - drupal:jsonapi_resources diff --git a/modules/tide_webform_jsonapi/tide_webform_jsonapi.module b/modules/tide_webform_jsonapi/tide_webform_jsonapi.module new file mode 100644 index 0000000..3bd0160 --- /dev/null +++ b/modules/tide_webform_jsonapi/tide_webform_jsonapi.module @@ -0,0 +1,21 @@ + 1){ + return $arr[1]; + } + return 'The field is required'; + } + return TRUE; +} + +function tide_webform_pattern_validate($value, $arr) { + if (preg_match($arr[0],$value) != 1){ + if (count($arr) > 1) { + return $arr[1]; + } + return 'The field does not match defined format.'; + } + return TRUE; +} \ No newline at end of file diff --git a/modules/tide_webform_jsonapi/tide_webform_jsonapi.routing.yml b/modules/tide_webform_jsonapi/tide_webform_jsonapi.routing.yml new file mode 100644 index 0000000..c972f9e --- /dev/null +++ b/modules/tide_webform_jsonapi/tide_webform_jsonapi.routing.yml @@ -0,0 +1,11 @@ +tide_webform_jsonapi.add_webform: + path: '/%jsonapi%/webform/{webform}/add' + methods: ['POST'] + defaults: + _jsonapi_resource: Drupal\tide_webform_jsonapi\Resource\AddWebform + requirements: + _permission: 'access content' + options: + parameters: + webform: + type: 'entity:webform' \ No newline at end of file