99use Drupal \Core \Plugin \ContainerFactoryPluginInterface ;
1010use Drupal \Core \Render \Element \FormElementBase ;
1111use Drupal \patternkit \Entity \PatternInterface ;
12+ use Drupal \patternkit \Exception \SchemaValidationException ;
1213use Drupal \patternkit \Exception \UnknownPatternException ;
1314use Drupal \patternkit \Form \PatternLibraryJSONForm ;
1415use Drupal \patternkit \PatternLibraryPluginManager ;
2122 * Properties:
2223 * - #pattern_name: The name of the pattern to be loaded and used for the form.
2324 * - #pattern_entity: (optional) The loaded Pattern entity for the form.
24- * - #data : (optional) A serialized string of JSON values for the form.
25+ * - #default_value : (optional) A serialized string of JSON values for the form.
2526 * - #config: (optional) An associative array of configuration options for
2627 * JSONEditor behaviors.
2728 *
3334 * '#config' => [
3435 * 'disablePropertiesButtons' => FALSE,
3536 * ],
37+ * '#default_value' => '{"text": "My text value"}',
3638 * ];
3739 * @endcode
3840 *
@@ -71,18 +73,24 @@ public function getInfo(): array {
7173 '#pre_render ' => [
7274 [$ this , 'loadPattern ' ],
7375 [$ this , 'buildEditorForm ' ],
76+ [static ::class, 'preRenderGroup ' ],
7477 ],
7578 '#process ' => [
79+ [static ::class, 'processAjaxForm ' ],
80+ [static ::class, 'processGroup ' ],
7681 [static ::class, 'processEditorForm ' ],
7782 ],
7883 '#theme_wrappers ' => ['form_element ' ],
84+ '#input ' => TRUE ,
7985 '#pattern_name ' => NULL ,
8086 '#pattern_entity ' => NULL ,
8187 '#schema ' => '' ,
82- // Pattern instance configuration values.
83- '#data ' => '{} ' ,
8488 // Editor configuration options to be overridden.
8589 '#config ' => [],
90+ // Validate upon submissions.
91+ '#element_validate ' => [
92+ [static ::class, 'validatePatternConfig ' ],
93+ ],
8694 ];
8795 }
8896
@@ -204,7 +212,8 @@ public function buildEditorForm(array $element): array {
204212 $ editor_overrides = $ element ['#config ' ] ?? [];
205213
206214 // Assemble the full instance settings for the editor.
207- $ settings = $ this ->editorSettings ($ element ['#schema ' ], $ element ['#data ' ] ?? '{} ' , $ editor_overrides );
215+ $ value = $ element ['#value ' ] ?? $ element ['#default_value ' ] ?? '{} ' ;
216+ $ settings = $ this ->editorSettings ($ element ['#schema ' ], $ value , $ editor_overrides );
208217
209218 // Load the editor from the pattern's library plugin.
210219 $ pattern = $ element ['#pattern_entity ' ];
@@ -240,19 +249,75 @@ public function buildEditorForm(array $element): array {
240249 * The updated render element.
241250 */
242251 public static function processEditorForm (&$ element , FormStateInterface $ form_state , array $ form ) {
252+ // Retrieve the form-submitted value if available, otherwise, default to the
253+ // original element data.
254+ $ data = $ form_state ->getValue ($ element ['#parents ' ]);
255+
256+ // Update the element data value to persist it to the next form build.
257+ // This ensures even if it was loaded from a previous form submission, the
258+ // element initialization data is synchronized with the submitted value.
259+ $ element ['#value ' ] = $ data ;
260+
243261 // Add a hidden field to capture configuration from the JSONEditor form.
244262 $ element ['instance_config ' ] = [
245263 '#type ' => 'hidden ' ,
246264 '#attributes ' => [
247265 'id ' => 'schema_instance_config ' ,
248266 ],
249- '#default_value ' => $ element [ ' # data' ] ?? ' {} ' ,
267+ '#value ' => $ data ,
250268 '#parents ' => $ element ['#parents ' ],
251269 ];
252270
253271 return $ element ;
254272 }
255273
274+ /**
275+ * Validates the pattern configuration.
276+ *
277+ * @param array $element
278+ * The render element being processed.
279+ * @param \Drupal\Core\Form\FormStateInterface $form_state
280+ * The current form state.
281+ * @param array $form
282+ * The full form.
283+ *
284+ * @see \Drupal\patternkit\Element\JsonEditorForm::getInfo()
285+ */
286+ public static function validatePatternConfig (&$ element , FormStateInterface $ form_state , array $ form ): void {
287+ $ value = $ form_state ->getValue ($ element ['#parents ' ]);
288+ $ pattern = $ element ['#pattern_entity ' ];
289+ $ schema = $ pattern ->getSchema ();
290+ $ validationHelper = \Drupal::service ('patternkit.helper.validation ' );
291+ $ validationHelper ->validateContent ($ schema , $ value );
292+ if ($ validationHelper ->hasExceptions ()) {
293+
294+ $ message = 'Content has failed to validate. See errors below. ' ;
295+
296+ // Log additional information if debug mode is enabled.
297+ /** @var \Drupal\patternkit\PatternkitEnvironment $environment */
298+ $ environment = \Drupal::service ('patternkit.environment ' );
299+ if ($ environment ->isDebug ()) {
300+ $ exceptions = $ validationHelper ->getExceptions ();
301+ $ exception = array_shift ($ exceptions );
302+ if ($ exception instanceof SchemaValidationException && $ previous = $ exception ->getPrevious ()) {
303+ $ message .= "\n" . $ previous ->getMessage ();
304+ }
305+ else {
306+ $ message .= "\n" . $ exception ->getMessage ();
307+ }
308+ }
309+
310+ $ form_state ->setError ($ element , $ message );
311+ }
312+ }
313+
314+ /**
315+ * {@inheritdoc}
316+ */
317+ public static function valueCallback (&$ element , $ input , FormStateInterface $ form_state ) {
318+ return is_string ($ input ) ? $ input : NULL ;
319+ }
320+
256321 /**
257322 * Statically load the configured settings for default JSON Editor behaviors.
258323 *
@@ -285,22 +350,8 @@ protected function defaultEditorSettings(): array {
285350 $ config_object = $ this ->configFactory ->get (PatternLibraryJSONForm::SETTINGS );
286351 $ config_array = isset ($ config_object ) ? $ config_object ->get () : [];
287352
288- // Map config names to JS-friendly identifiers.
289353 // @todo Remove this once internal config names are renamed.
290- $ mapped_config = [];
291- $ map = PatternLibraryJSONForm::JSON_EDITOR_SETTINGS_MAP ;
292- array_walk ($ config_array , function ($ value , $ key ) use (&$ mapped_config , $ map ) {
293- if (array_key_exists ($ key , $ map )) {
294- // Relabel the value if a mapped key is found.
295- $ mapped_config [$ map [$ key ]] = $ value ;
296- }
297- else {
298- // Maintain the existing key if no mapped key is found.
299- $ mapped_config [$ key ] = $ value ;
300- }
301- });
302-
303- $ this ->config = $ mapped_config ;
354+ $ this ->config = $ this ->mapConfigNames ($ config_array );
304355 }
305356
306357 $ this ->defaults = $ this ->config + [
@@ -316,4 +367,33 @@ protected function defaultEditorSettings(): array {
316367 return $ this ->defaults ;
317368 }
318369
370+ /**
371+ * Map server-side configuration values to JS names.
372+ *
373+ * @param mixed $config_array
374+ * The server-side configuration values to be mapped to JS names.
375+ *
376+ * @return array
377+ * An array of config mapped to JS-friendly names.
378+ *
379+ * @todo Remove this once internal config names are renamed.
380+ */
381+ private function mapConfigNames (mixed $ config_array ): array {
382+ // Map config names to JS-friendly identifiers.
383+ $ mapped_config = [];
384+ $ map = PatternLibraryJSONForm::JSON_EDITOR_SETTINGS_MAP ;
385+ array_walk ($ config_array , function ($ value , $ key ) use (&$ mapped_config , $ map ) {
386+ if (array_key_exists ($ key , $ map )) {
387+ // Relabel the value if a mapped key is found.
388+ $ mapped_config [$ map [$ key ]] = $ value ;
389+ }
390+ else {
391+ // Maintain the existing key if no mapped key is found.
392+ $ mapped_config [$ key ] = $ value ;
393+ }
394+ });
395+
396+ return $ mapped_config ;
397+ }
398+
319399}
0 commit comments