diff --git a/src/Controller/JSONFieldProcessorConfigListBuilder.php b/src/Controller/JSONFieldProcessorConfigListBuilder.php index 7e88329..9809181 100644 --- a/src/Controller/JSONFieldProcessorConfigListBuilder.php +++ b/src/Controller/JSONFieldProcessorConfigListBuilder.php @@ -18,62 +18,67 @@ * * @ingroup json_field_processor */ -class JSONFieldProcessorConfigListBuilder extends ConfigEntityListBuilder { +class JSONFieldProcessorConfigListBuilder extends ConfigEntityListBuilder +{ - /** - * {@inheritdoc} - */ - protected function getModuleName() { - return 'json_field_processor'; - } + /** + * {@inheritdoc} + */ + protected function getModuleName() + { + return 'json_field_processor'; + } - /** - * Builds the header row for the entity listing. - * - * @return array - * A render array structure of header strings. - */ - public function buildHeader() { - $header['label'] = $this->t('JSON Field Processor Configuration'); - $header['field_name'] = $this->t('Field Name'); - $header['json_path'] = $this->t('JSON Path'); - $header['json_field_name'] = $this->t('JSON Field Name'); - return $header + parent::buildHeader(); - } + /** + * Builds the header row for the entity listing. + * + * @return array + * A render array structure of header strings. + */ + public function buildHeader() + { + $header['label'] = $this->t('JSON Field Processor Configuration'); + $header['field_name'] = $this->t('Field Name'); + $header['json_path'] = $this->t('JSON Path'); + $header['json_field_name'] = $this->t('JSON Field Name'); + return $header + parent::buildHeader(); + } - /** - * Builds a row for an entity in the entity listing. - * - * @param \Drupal\Core\Entity\EntityInterface $entity - * The entity for which to build the row. - * - * @return array - * A render array of the table row for displaying the entity. - */ - public function buildRow(EntityInterface $entity) { - $row['label'] = $entity->label(); - $row['field_name'] = $entity->get('field_name'); - $row['json_path'] = $entity->get('json_path'); - $row['json_field_name'] = $entity->get('label'); + /** + * Builds a row for an entity in the entity listing. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity for which to build the row. + * + * @return array + * A render array of the table row for displaying the entity. + */ + public function buildRow(EntityInterface $entity) + { + $row['label'] = $entity->label(); + $row['field_name'] = $entity->get('field_name'); + $row['json_path'] = $entity->get('json_path'); + $row['json_field_name'] = $entity->get('label'); - return $row + parent::buildRow($entity); - } + return $row + parent::buildRow($entity); + } - /** - * Adds a descriptive message above the entity list. - * - * Typically, there's no need to override render(). We override here - * to add introductory markup before the table listing. - * - * @return array - * Renderable array including description and table listing. - */ - public function render() { - $build = [ - '#markup' => $this->t('Manage and view JSON Field Processor Configurations.'), - ]; - $build[] = parent::render(); - return $build; - } + /** + * Adds a descriptive message above the entity list. + * + * Typically, there's no need to override render(). We override here + * to add introductory markup before the table listing. + * + * @return array + * Renderable array including description and table listing. + */ + public function render() + { + $build = [ + '#markup' => $this->t('Manage and view JSON Field Processor Configurations.'), + ]; + $build[] = parent::render(); + return $build; + } } diff --git a/src/Entity/JSONFieldProcessorConfig.php b/src/Entity/JSONFieldProcessorConfig.php index 4fbb67e..ed1ac1f 100644 --- a/src/Entity/JSONFieldProcessorConfig.php +++ b/src/Entity/JSONFieldProcessorConfig.php @@ -40,63 +40,65 @@ * } * ) */ -class JSONFieldProcessorConfig extends ConfigEntityBase { +class JSONFieldProcessorConfig extends ConfigEntityBase +{ - /** - * The json_field_processor_config ID. - * - * @var string - */ - public $id; + /** + * The json_field_processor_config ID. + * + * @var string + */ + public $id; - /** - * The json_field_processor_config UUID. - * - * @var string - */ - public $uuid; + /** + * The json_field_processor_config UUID. + * + * @var string + */ + public $uuid; - /** - * The json_field_processor_config label. - * - * @var string - */ - public $label; + /** + * The json_field_processor_config label. + * + * @var string + */ + public $label; - /** - * The name of the field submitted. - * - * @var string - */ - public $field_name; + /** + * The name of the field submitted. + * + * @var string + */ + public $field_name; - /** - * The JSON path associated with the json_field_processor_config. - * - * @var string - */ - public $json_path; + /** + * The JSON path associated with the json_field_processor_config. + * + * @var string + */ + public $json_path; - /** - * {@inheritdoc} - */ - public function delete() { - // Custom logic before deletion. - $field_name = 'json_field_processor_' . $this->get('field_name'); + /** + * {@inheritdoc} + */ + public function delete() + { + // Custom logic before deletion. + $field_name = 'json_field_processor_' . $this->get('id'); - // Load the search index. - $indexes = Index::loadMultiple(); - foreach ($indexes as $index) { - $fields = $index->getFields(); - if (isset($fields[$field_name])) { - // Remove the field from the index. - $index->removeField($field_name); - $index->save(); - } - } + // Load the search index. + $indexes = Index::loadMultiple(); + foreach ($indexes as $index) { + $fields = $index->getFields(); + if (isset($fields[$field_name])) { + // Remove the field from the index. + $index->removeField($field_name); + $index->save(); + } + } - // Call parent delete to perform the actual deletion. - parent::delete(); - } + // Call parent delete to perform the actual deletion. + parent::delete(); + } } diff --git a/src/Form/JSONFieldProcessorConfigAddForm.php b/src/Form/JSONFieldProcessorConfigAddForm.php index c631cc2..e115f78 100644 --- a/src/Form/JSONFieldProcessorConfigAddForm.php +++ b/src/Form/JSONFieldProcessorConfigAddForm.php @@ -11,25 +11,27 @@ * * @ingroup json_field_processor */ -class JSONFieldProcessorConfigAddForm extends JSONFieldProcessorConfigFormBase { +class JSONFieldProcessorConfigAddForm extends JSONFieldProcessorConfigFormBase +{ - /** - * Returns the actions provided by this form. - * - * For our add form, we only need to change the text of the submit button. - * - * @param array $form - * An associative array containing the structure of the form. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * An associative array containing the current state of the form. - * - * @return array - * An array of supported actions for the current entity form. - */ - protected function actions(array $form, FormStateInterface $form_state) { - $actions = parent::actions($form, $form_state); - $actions['submit']['#value'] = $this->t('Create JSON Field Processor Configuration'); - return $actions; - } + /** + * Returns the actions provided by this form. + * + * For our add form, we only need to change the text of the submit button. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return array + * An array of supported actions for the current entity form. + */ + protected function actions(array $form, FormStateInterface $form_state) + { + $actions = parent::actions($form, $form_state); + $actions['submit']['#value'] = $this->t('Create JSON Field Processor Configuration'); + return $actions; + } } diff --git a/src/Form/JSONFieldProcessorConfigDeleteForm.php b/src/Form/JSONFieldProcessorConfigDeleteForm.php index 66c044b..8c2dd37 100644 --- a/src/Form/JSONFieldProcessorConfigDeleteForm.php +++ b/src/Form/JSONFieldProcessorConfigDeleteForm.php @@ -14,73 +14,84 @@ * * @ingroup config_entity_example */ -class JSONFieldProcessorConfigDeleteForm extends EntityConfirmFormBase { +class JSONFieldProcessorConfigDeleteForm extends EntityConfirmFormBase +{ - /** - * Gathers a confirmation question. - * - * The question is used as a title in our confirm form. For delete confirm - * forms, this typically takes the form of "Are you sure you want to - * delete...", including the entity label. - * - * @return string - * Translated string. - */ - public function getQuestion() { - return $this->t('Are you sure you want to delete configuration %label? This will remove the corresponding field from your index.', [ - '%label' => $this->entity->label(), - ]); - } + /** + * Gathers a confirmation question. + * + * The question is used as a title in our confirm form. For delete confirm + * forms, this typically takes the form of "Are you sure you want to + * delete...", including the entity label. + * + * @return string + * Translated string. + */ + public function getQuestion() + { + return $this->t( + 'Are you sure you want to delete configuration %label? This will remove the corresponding field from your index.', [ + '%label' => $this->entity->label(), + ] + ); + } - /** - * Gather the confirmation text. - * - * The confirm text is used as the text in the button that confirms the - * question posed by getQuestion(). - * - * @return string - * Translated string. - */ - public function getConfirmText() { - return $this->t('Delete Configuration'); - } + /** + * Gather the confirmation text. + * + * The confirm text is used as the text in the button that confirms the + * question posed by getQuestion(). + * + * @return string + * Translated string. + */ + public function getConfirmText() + { + return $this->t('Delete Configuration'); + } - /** - * Gets the cancel URL. - * - * Provides the URL to go to if the user cancels the action. For entity - * delete forms, this is typically the route that points at the list - * controller. - * - * @return \Drupal\Core\Url - * The URL to go to if the user cancels the deletion. - */ - public function getCancelUrl() { - return new Url('entity.json_field_processor_config.list'); - } + /** + * Gets the cancel URL. + * + * Provides the URL to go to if the user cancels the action. For entity + * delete forms, this is typically the route that points at the list + * controller. + * + * @return \Drupal\Core\Url + * The URL to go to if the user cancels the deletion. + */ + public function getCancelUrl() + { + return new Url('entity.json_field_processor_config.list'); + } - /** - * The submit handler for the confirm form. - * - * For entity delete forms, you use this to delete the entity in - * $this->entity. - * - * @param array $form - * An associative array containing the structure of the form. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * An associative array containing the current state of the form. - */ - public function submitForm(array &$form, FormStateInterface $form_state) { - // Delete the entity. - $this->entity->delete(); + /** + * The submit handler for the confirm form. + * + * For entity delete forms, you use this to delete the entity in + * $this->entity. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + */ + public function submitForm(array &$form, FormStateInterface $form_state) + { + // Delete the entity. + $this->entity->delete(); - // Set a message that the entity was deleted. - $this->messenger()->addMessage($this->t('Configuration %label was deleted.', [ - '%label' => $this->entity->label(), - ])); + // Set a message that the entity was deleted. + $this->messenger()->addMessage( + $this->t( + 'Configuration %label was deleted.', [ + '%label' => $this->entity->label(), + ] + ) + ); - // Redirect the user to the list controller when complete. - $form_state->setRedirectUrl($this->getCancelUrl()); - } + // Redirect the user to the list controller when complete. + $form_state->setRedirectUrl($this->getCancelUrl()); + } } diff --git a/src/Form/JSONFieldProcessorConfigEditForm.php b/src/Form/JSONFieldProcessorConfigEditForm.php index 36a06d4..42a6e80 100644 --- a/src/Form/JSONFieldProcessorConfigEditForm.php +++ b/src/Form/JSONFieldProcessorConfigEditForm.php @@ -11,30 +11,32 @@ * * @ingroup json_field_processor */ -class JSONFieldProcessorConfigEditForm extends JSONFieldProcessorConfigFormBase { +class JSONFieldProcessorConfigEditForm extends JSONFieldProcessorConfigFormBase +{ - /** - * Returns the actions provided by this form. - * - * For the edit form, we only need to change the text of the submit button. - * - * @param array $form - * An associative array containing the structure of the form. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * An associative array containing the current state of the form. - * - * @return array - * An array of supported actions for the current entity form. - */ - protected function actions(array $form, FormStateInterface $form_state) { - // Get the default actions from the base class. - $actions = parent::actions($form, $form_state); + /** + * Returns the actions provided by this form. + * + * For the edit form, we only need to change the text of the submit button. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return array + * An array of supported actions for the current entity form. + */ + protected function actions(array $form, FormStateInterface $form_state) + { + // Get the default actions from the base class. + $actions = parent::actions($form, $form_state); - // Change the submit button text to reflect the "Update Configuration" action. - $actions['submit']['#value'] = $this->t('Update Configuration'); + // Change the submit button text to reflect the "Update Configuration" action. + $actions['submit']['#value'] = $this->t('Update Configuration'); - // Return the modified actions array. - return $actions; - } + // Return the modified actions array. + return $actions; + } } diff --git a/src/Form/JSONFieldProcessorConfigFormBase.php b/src/Form/JSONFieldProcessorConfigFormBase.php index 54f383c..503bcfc 100644 --- a/src/Form/JSONFieldProcessorConfigFormBase.php +++ b/src/Form/JSONFieldProcessorConfigFormBase.php @@ -18,210 +18,240 @@ * * @ingroup json_field_processor */ -class JSONFieldProcessorConfigFormBase extends EntityForm { - - /** - * An entity query factory for the json_field_processor_config entity type. - * - * @var \Drupal\Core\Entity\EntityStorageInterface - */ - protected $entityStorage; - - /** - * Construct the JSONFieldProcessorConfigFormBase. - * - * @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage - * An entity query factory for the json_field_processor_config entity type. - */ - public function __construct(EntityStorageInterface $entity_storage) { - $this->entityStorage = $entity_storage; - } - - /** - * Factory method for JSONFieldProcessorConfigFormBase. - * - * @param \Symfony\Component\DependencyInjection\ContainerInterface $container - * The container. - * - * @return \Drupal\json_field_processor\Form\JSONFieldProcessorConfigFormBase - * The form object. - */ - public static function create(ContainerInterface $container) { - $form = new static($container->get('entity_type.manager')->getStorage('json_field_processor_config')); - $form->setMessenger($container->get('messenger')); - return $form; - } - - /** - * Overrides Drupal\Core\Entity\EntityFormController::form(). - * - * Builds the entity add/edit form. - * - * @param array $form - * An associative array containing the structure of the form. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * An associative array containing the current state of the form. - * - * @return array - * An associative array containing the json_field_processor_config add/edit form. - */ - public function buildForm(array $form, FormStateInterface $form_state) { - // Get anything we need from the base class. - $form = parent::buildForm($form, $form_state); - - // Drupal provides the entity to us as a class variable. If this is an - // existing entity, it will be populated with existing values as class - // variables. If this is a new entity, it will be a new object with the - // class of our entity. Drupal knows which class to call from the - // annotation on our JSONFieldProcessorConfig class. - $json_field_processor_config = $this->entity; - - // Build the form. - $form['field_name'] = [ - '#type' => 'textfield', - '#title' => $this->t('Field Name'), - '#maxlength' => 255, - '#default_value' => $json_field_processor_config->field_name, - '#required' => TRUE, - ]; - // Ensure the machine name depends on the field name. - $form['id'] = [ - '#type' => 'machine_name', - '#title' => $this->t('Machine name'), - '#maxlength' => 128, - '#default_value' => $json_field_processor_config->id(), - '#machine_name' => [ +class JSONFieldProcessorConfigFormBase extends EntityForm +{ + + /** + * An entity query factory for the json_field_processor_config entity type. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $entityStorage; + + /** + * Construct the JSONFieldProcessorConfigFormBase. + * + * @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage + * An entity query factory for the json_field_processor_config entity type. + */ + public function __construct(EntityStorageInterface $entity_storage) + { + $this->entityStorage = $entity_storage; + } + + /** + * Factory method for JSONFieldProcessorConfigFormBase. + * + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container + * The container. + * + * @return \Drupal\json_field_processor\Form\JSONFieldProcessorConfigFormBase + * The form object. + */ + public static function create(ContainerInterface $container) + { + $form = new static($container->get('entity_type.manager')->getStorage('json_field_processor_config')); + $form->setMessenger($container->get('messenger')); + return $form; + } + + /** + * Overrides Drupal\Core\Entity\EntityFormController::form(). + * + * Builds the entity add/edit form. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return array + * An associative array containing the json_field_processor_config add/edit form. + */ + public function buildForm(array $form, FormStateInterface $form_state) + { + // Get anything we need from the base class. + $form = parent::buildForm($form, $form_state); + + // Drupal provides the entity to us as a class variable. If this is an + // existing entity, it will be populated with existing values as class + // variables. If this is a new entity, it will be a new object with the + // class of our entity. Drupal knows which class to call from the + // annotation on our JSONFieldProcessorConfig class. + $json_field_processor_config = $this->entity; + + // Build the form. + $form['field_name'] = [ + '#type' => 'textfield', + '#title' => $this->t('Field Name'), + '#maxlength' => 255, + '#default_value' => $json_field_processor_config->field_name, + '#required' => true, + ]; + // Ensure the machine name depends on the field name. + $form['id'] = [ + '#type' => 'machine_name', + '#title' => $this->t('Machine name'), + '#maxlength' => 128, + '#default_value' => $json_field_processor_config->id(), + '#machine_name' => [ // Use 'field_name' as the source for the machine name. 'source' => ['field_name'], // Uniqueness check. 'exists' => [$this, 'exists'], 'error' => 'The machine-readable name must be unique, and can only contain lowercase letters, numbers, and underscores.', - ], - // Disable editing for existing configurations. - '#disabled' => !$json_field_processor_config->isNew(), - ]; - $form['json_path'] = [ - '#type' => 'textfield', - '#title' => $this->t('JSON Path'), - '#maxlength' => 255, - '#default_value' => $json_field_processor_config->json_path, - '#required' => TRUE, - ]; - $form['label'] = [ - '#type' => 'textfield', - '#title' => $this->t('Json Field Machine Name'), - '#maxlength' => 255, - '#default_value' => $json_field_processor_config->label(), - '#required' => TRUE, - ]; - - // Return the form. - return $form; - } - - /** - * Checks for an existing json_field_processor_config. - * - * @param string|int $entity_id - * The entity ID. - * @param array $element - * The form element. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * The form state. - * - * @return bool - * TRUE if this format already exists, FALSE otherwise. - */ - public function exists($entity_id, array $element, FormStateInterface $form_state) { - // Use the query factory to build a new json_field_processor_config entity query. - $query = $this->entityStorage->getQuery(); - - // Query the entity ID to see if it's in use. - $result = $query->condition('id', $element['#field_prefix'] . $entity_id) - ->accessCheck() - ->execute(); - - // We don't need to return the ID, only if it exists or not. - return (bool) $result; - } - - /** - * Overrides Drupal\Core\Entity\EntityFormController::actions(). - * - * To set the submit button text, we need to override actions(). - * - * @param array $form - * An associative array containing the structure of the form. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * An associative array containing the current state of the form. - * - * @return array - * An array of supported actions for the current entity form. - */ - protected function actions(array $form, FormStateInterface $form_state) { - // Get the basic actions from the base class. - $actions = parent::actions($form, $form_state); - - // Change the submit button text. - $actions['submit']['#value'] = $this->t('Save'); - - // Return the result. - return $actions; - } - - /** - * {@inheritdoc} - */ - public function validateForm(array &$form, FormStateInterface $form_state) { - parent::validateForm($form, $form_state); - - // Add code here to validate your config entity's form elements. - // Nothing to do here. - } - - /** - * Overrides Drupal\Core\Entity\EntityFormController::save(). - * - * Saves the entity. This is called after submit() has built the entity from - * the form values. Do not override submit() as save() is the preferred - * method for entity form controllers. - * - * @param array $form - * An associative array containing the structure of the form. - * @param \Drupal\Core\Form\FormStateInterface $form_state - * An associative array containing the current state of the form. - */ - public function save(array $form, FormStateInterface $form_state) { - // EntityForm provides us with the entity we're working on. - $json_field_processor_config = $this->getEntity(); - - // Drupal already populated the form values in the entity object. Each - // form field was saved as a public variable in the entity class. PHP - // allows Drupal to do this even if the method is not defined ahead of - // time. - $status = $json_field_processor_config->save(); - - // Grab the URL of the new entity. We'll use it in the message. - $url = $json_field_processor_config->toUrl(); - - // Create an edit link. - $edit_link = Link::fromTextAndUrl($this->t('Edit'), $url)->toString(); - - if ($status == SAVED_UPDATED) { - // If we edited an existing entity... - $this->messenger()->addMessage($this->t('JSON Field Processor Configuration %label has been updated.', ['%label' => $json_field_processor_config->label()])); - $this->logger('contact')->notice('JSON Field Processor Configuration %label has been updated.', ['%label' => $json_field_processor_config->label(), 'link' => $edit_link]); + ], + // Disable editing for existing configurations. + '#disabled' => !$json_field_processor_config->isNew(), + ]; + $form['json_path'] = [ + '#type' => 'textfield', + '#title' => $this->t('JSON Path'), + '#maxlength' => 255, + '#default_value' => $json_field_processor_config->json_path, + '#required' => true, + ]; + $form['label'] = [ + '#type' => 'textfield', + '#title' => $this->t('Json Field Machine Name'), + '#maxlength' => 255, + '#default_value' => $json_field_processor_config->label(), + '#required' => true, + ]; + + $form['#validate'][] = '::validateForm'; + // Return the form. + return $form; + } + + /** + * Checks for an existing json_field_processor_config. + * + * @param string|int $entity_id + * The entity ID. + * @param array $element + * The form element. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return bool + * TRUE if this format already exists, FALSE otherwise. + */ + public function exists($entity_id, array $element, FormStateInterface $form_state) + { + // Use the query factory to build a new json_field_processor_config entity query. + $query = $this->entityStorage->getQuery(); + + // Query the entity ID to see if it's in use. + $result = $query->condition('id', $element['#field_prefix'] . $entity_id) + ->accessCheck() + ->execute(); + + // We don't need to return the ID, only if it exists or not. + return (bool) $result; } - else { - // If we created a new entity... - $this->messenger()->addMessage($this->t('JSON Field Processor Configuration %label has been added.', ['%label' => $json_field_processor_config->label()])); - $this->logger('contact')->notice('JSON Field Processor Configuration %label has been added.', ['%label' => $json_field_processor_config->label(), 'link' => $edit_link]); + + /** + * Overrides Drupal\Core\Entity\EntityFormController::actions(). + * + * To set the submit button text, we need to override actions(). + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + * + * @return array + * An array of supported actions for the current entity form. + */ + protected function actions(array $form, FormStateInterface $form_state) + { + // Get the basic actions from the base class. + $actions = parent::actions($form, $form_state); + + // Change the submit button text. + $actions['submit']['#value'] = $this->t('Save'); + + // Return the result. + return $actions; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state) + { + parent::validateForm($form, $form_state); + // Get entered machine name for json field + $entered_name = $form_state->getValue('label'); + + // Load field definitions for both 'node' and 'media' entity types. + $node_bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('node'); + $media_bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('media'); + + $node_fields = []; + foreach (array_keys($node_bundles) as $bundle) { + $node_fields += \Drupal::service('entity_field.manager')->getFieldDefinitions('node', $bundle); + } + + $media_fields = []; + foreach (array_keys($media_bundles) as $bundle) { + $media_fields += \Drupal::service('entity_field.manager')->getFieldDefinitions('media', $bundle); + } + + + // Check if the field with the given machine name exists. + if (!isset($node_fields[$entered_name]) && !isset($media_fields[$entered_name])) { + // Set an error if the field does not exist. + $form_state->setErrorByName('label', $this->t('The field with machine name "%name" does not exist on the node or media entities.', ['%name' => $entered_name])); + } + // Add code here to validate your config entity's form elements. } - // Redirect the user back to the listing route after the save operation. - $form_state->setRedirect('entity.json_field_processor_config.list'); + /** + * Overrides Drupal\Core\Entity\EntityFormController::save(). + * + * Saves the entity. This is called after submit() has built the entity from + * the form values. Do not override submit() as save() is the preferred + * method for entity form controllers. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * An associative array containing the current state of the form. + */ + public function save(array $form, FormStateInterface $form_state) + { + // EntityForm provides us with the entity we're working on. + $json_field_processor_config = $this->getEntity(); - return $status; - } + // Drupal already populated the form values in the entity object. Each + // form field was saved as a public variable in the entity class. PHP + // allows Drupal to do this even if the method is not defined ahead of + // time. + $status = $json_field_processor_config->save(); + + // Grab the URL of the new entity. We'll use it in the message. + $url = $json_field_processor_config->toUrl(); + + // Create an edit link. + $edit_link = Link::fromTextAndUrl($this->t('Edit'), $url)->toString(); + + if ($status == SAVED_UPDATED) { + // If we edited an existing entity... + $this->messenger()->addMessage($this->t('JSON Field Processor Configuration %label has been updated.', ['%label' => $json_field_processor_config->label()])); + $this->logger('contact')->notice('JSON Field Processor Configuration %label has been updated.', ['%label' => $json_field_processor_config->label(), 'link' => $edit_link]); + } + else { + // If we created a new entity... + $this->messenger()->addMessage($this->t('JSON Field Processor Configuration %label has been added.', ['%label' => $json_field_processor_config->label()])); + $this->logger('contact')->notice('JSON Field Processor Configuration %label has been added.', ['%label' => $json_field_processor_config->label(), 'link' => $edit_link]); + } + + // Redirect the user back to the listing route after the save operation. + $form_state->setRedirect('entity.json_field_processor_config.list'); + + return $status; + } } diff --git a/src/JSONFieldProcessorConfigAccessController.php b/src/JSONFieldProcessorConfigAccessController.php index 21ff225..b8b411e 100644 --- a/src/JSONFieldProcessorConfigAccessController.php +++ b/src/JSONFieldProcessorConfigAccessController.php @@ -16,45 +16,48 @@ * * @ingroup json_field_processor */ -class JSONFieldProcessorConfigAccessController extends EntityAccessControlHandler { - - /** - * {@inheritdoc} - */ - public function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) { - // If the user has the overarching permission, allow all operations. - if ($account->hasPermission('administer json field processor')) { - return AccessResult::allowed(); +class JSONFieldProcessorConfigAccessController extends EntityAccessControlHandler +{ + + /** + * {@inheritdoc} + */ + public function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) + { + // If the user has the overarching permission, allow all operations. + if ($account->hasPermission('administer json field processor')) { + return AccessResult::allowed(); + } + + // Otherwise, check operation-specific permissions. + switch ($operation) { + case 'view': + // Allow access for view operation (or customize this further if needed). + return AccessResult::allowedIfHasPermission($account, 'view json field processor configurations'); + + case 'edit': + return AccessResult::allowedIfHasPermission($account, 'edit json field processor configurations'); + + case 'delete': + return AccessResult::allowedIfHasPermission($account, 'delete json field processor configurations'); + } + + // Default to the parent's access logic for unknown operations. + return parent::checkAccess($entity, $operation, $account); } - // Otherwise, check operation-specific permissions. - switch ($operation) { - case 'view': - // Allow access for view operation (or customize this further if needed). - return AccessResult::allowedIfHasPermission($account, 'view json field processor configurations'); - - case 'edit': - return AccessResult::allowedIfHasPermission($account, 'edit json field processor configurations'); - - case 'delete': - return AccessResult::allowedIfHasPermission($account, 'delete json field processor configurations'); + /** + * {@inheritdoc} + */ + protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = null) + { + // If the user has the overarching permission, allow create access. + if ($account->hasPermission('administer json field processor')) { + return AccessResult::allowed(); + } + + // Otherwise, forbid creation unless additional permissions are defined. + return AccessResult::allowedIfHasPermission($account, 'create json_field_processor_config'); } - // Default to the parent's access logic for unknown operations. - return parent::checkAccess($entity, $operation, $account); - } - - /** - * {@inheritdoc} - */ - protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) { - // If the user has the overarching permission, allow create access. - if ($account->hasPermission('administer json field processor')) { - return AccessResult::allowed(); - } - - // Otherwise, forbid creation unless additional permissions are defined. - return AccessResult::allowedIfHasPermission($account, 'create json_field_processor_config'); - } - } diff --git a/src/Plugin/search_api/processor/JSONFieldProcessor.php b/src/Plugin/search_api/processor/JSONFieldProcessor.php index f67b836..253bf50 100644 --- a/src/Plugin/search_api/processor/JSONFieldProcessor.php +++ b/src/Plugin/search_api/processor/JSONFieldProcessor.php @@ -24,123 +24,173 @@ * hidden = false, * ) */ -class JSONFieldProcessor extends ProcessorPluginBase { - - /** - * The HTTP client to fetch the feed data with. - * - * @var \GuzzleHttp\ClientInterface - */ - protected $httpClient; - - /** - * Theme settings config. - * - * @var \Drupal\Core\Config\ConfigFactoryInterface - */ - protected $configFactory; - /** - * {@inheritdoc} - */ - - /** - * Class property to store the results in a key-value array. - */ - protected $json_field_configurations = []; - - protected $json_field_name = []; - - /** - * Load the relationship types from the database. - * Populates $json_field_configurations with field_name => json_path pairs. - */ - protected function loadJSONFieldConfigurations() { - // Fetch the results from the database. - $json_field_processor_config = \Drupal::entityTypeManager()->getStorage('json_field_processor_config')->loadMultiple(); - foreach ($json_field_processor_config as $submission) { - $label = $submission->label(); - $field_name = $submission->field_name; - $json_path = $submission->json_path; - // Process each submission as needed. - $this->json_field_configurations[$field_name] = $json_path; - $this->json_field_name[$field_name] = $label; +class JSONFieldProcessor extends ProcessorPluginBase +{ + + /** + * The HTTP client to fetch the feed data with. + * + * @var \GuzzleHttp\ClientInterface + */ + protected $httpClient; + + /** + * Theme settings config. + * + * @var \Drupal\Core\Config\ConfigFactoryInterface + */ + protected $configFactory; + /** + * {@inheritdoc} + */ + + /** + * Class property to store the results in a key-value array. + */ + protected $json_field_configurations = []; + + protected $json_field_name = []; + + /** + * Load the relationship types from the database. + * Populates $json_field_configurations with field_name => json_path pairs. + */ + protected function loadJSONFieldConfigurations() + { + // Fetch the results from the database. + $json_field_processor_config = \Drupal::entityTypeManager()->getStorage('json_field_processor_config')->loadMultiple(); + foreach ($json_field_processor_config as $submission) { + $label = $submission->label(); + $field_name = $submission->id(); + $json_path = $submission->json_path; + // Process each submission as needed. + $this->json_field_configurations[$field_name] = $json_path; + $this->json_field_name[$field_name] = $label; + } + } + + /** + * + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) + { + /** + * @var static $processor +*/ + $processor = parent::create($container, $configuration, $plugin_id, $plugin_definition); + $processor->httpClient = $container->get('http_client'); + $processor->configFactory = $container->get('config.factory'); + return $processor; + } + + /** + * {@inheritdoc} + */ + public function getPropertyDefinitions(DatasourceInterface $datasource = null) + { + $properties = []; + $this->loadJSONFieldConfigurations(); + + if (!$datasource) { + foreach ($this->json_field_configurations as $field_name => $json_path) { + $definition = [ + 'label' => $this->t('Field: @label', ['@label' => $json_path]), + 'description' => $this->t('Json Data of Islandora Site to be indexed to Solr'), + 'type' => 'string', + 'processor_id' => $this->getPluginId(), + 'is_list' => true, + ]; + $properties['json_field_processor_' . $field_name] = new ProcessorProperty($definition); + } + } + + return $properties; } - } - - /** - * - */ - public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { - /** @var static $processor */ - $processor = parent::create($container, $configuration, $plugin_id, $plugin_definition); - $processor->httpClient = $container->get('http_client'); - $processor->configFactory = $container->get('config.factory'); - return $processor; - } - - /** - * {@inheritdoc} - */ - public function getPropertyDefinitions(DatasourceInterface $datasource = NULL) { - $properties = []; - $this->loadJSONFieldConfigurations(); - - if (!$datasource) { - foreach ($this->json_field_configurations as $field_name => $json_path) { - $definition = [ - 'label' => $this->t('Field: @label', ['@label' => $json_path]), - 'description' => $this->t('Json Data of Islandora Site to be indexed to Solr'), - 'type' => 'string', - 'processor_id' => $this->getPluginId(), - 'is_list' => TRUE, - ]; - $properties['json_field_processor_' . $field_name] = new ProcessorProperty($definition); - } + + /** + * {@inheritdoc} + */ + public function addFieldValues(ItemInterface $item) + { + $datasourceId = $item->getDatasourceId(); + $entity = $item->getOriginalObject()->getValue(); + + // Process JSON fields for supported entity types. + if (in_array($datasourceId, ['entity:node', 'entity:media'])) { + foreach ($this->json_field_configurations as $field_name => $json_path) { + $this->processJsonField($entity, $item, $field_name, $json_path); + } + } } - return $properties; - } - - /** - * {@inheritdoc} - */ - public function addFieldValues(ItemInterface $item) { - $datasourceId = $item->getDatasourceId(); - - // Handle node entities. - foreach ($this->json_field_configurations as $field_name => $json_path) { - $json_field = $this->json_field_name[$field_name]; - if ($datasourceId == 'entity:node') { - $node = $item->getOriginalObject()->getValue(); - if ($node instanceof Node && $node->hasField($json_field)) { - $json_data = $node->get($json_field)->value; - $data = json_decode($json_data, TRUE); - $result = JmesPath::search($json_path, $data); - if ($result !== NULL) { - $fields = $this->getFieldsHelper()->filterForPropertyPath($item->getFields(), NULL, 'json_field_processor_' . $field_name); - foreach ($fields as $field) { - $field->addValue($result); + /** + * Process JSON field for the given entity and field configuration. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity being processed. + * @param \Drupal\search_api\Item\ItemInterface $item + * The search API item. + * @param string $field_name + * The machine name of the field configuration. + * @param string $json_path + * The JSON path to process. + */ + private function processJsonField($entity, ItemInterface $item, $field_name, $json_path) + { + $json_field = $this->json_field_name[$field_name]; + + if ($entity->hasField($json_field)) { + $json_data = $entity->get($json_field)->value; + $data = json_decode($json_data, true); + $result = JmesPath::search($json_path, $data); + + if (is_array($result)) { + $result = $this->flattenJson($result); + } + + if ($result !== null) { + $fields = $this->getFieldsHelper()->filterForPropertyPath($item->getFields(), null, 'json_field_processor_' . $field_name); + foreach ($fields as $field) { + $field->addValue($result); + } } - } } - } - // Handle media entities. - elseif ($datasourceId == 'entity:media') { - \Drupal::logger('json_field_processor')->notice('Media entity detected'); - $media = $item->getOriginalObject()->getValue(); - if ($media instanceof Media && $media->hasField($json_field)) { - $json_data = $media->get($json_field)->value; - $data = json_decode($json_data, TRUE); - $result = JmesPath::search($json_path, $data); - if ($result !== NULL) { - $fields = $this->getFieldsHelper()->filterForPropertyPath($item->getFields(), NULL, 'json_field_processor_' . $field_name); - foreach ($fields as $field) { - $field->addValue($result); + } + + /** + * Flattens a JSON structure into a "key:value, key:value" string. + * + * @param mixed $data The JSON data to flatten. + * @param string $parentKey The parent key for nested elements (used recursively). + * @return string The flattened key:value pairs. + */ + private function flattenJson($data, $parentKey = '') + { + $result = []; + + foreach ($data as $key => $value) { + // Build the full key for nested elements. + $fullKey = $parentKey ? $parentKey . '.' . $key : $key; + + if (is_array($value)) { + // Recursively process arrays and convert to string. + $result[] = $fullKey . ': [' . $this->flattenJson($value, '') . ']'; + } elseif (is_object($value)) { + // Recursively process nested objects. + $result[] = $this->flattenJson($value, $fullKey); + } else { + // Handle scalar values (strings, numbers, etc.) and avoid extra escaping. + if (is_string($value)) { + // Ensure no extra escaping by directly adding the value. + $result[] = $fullKey . ': "' . addslashes($value) . '"'; + } else { + $result[] = $fullKey . ': ' . $value; + } } - } } - } + + return implode(', ', $result); } - } + } diff --git a/tests/src/Functional/JSONFieldProcessorConfigEntityTest.php b/tests/src/Functional/JSONFieldProcessorConfigEntityTest.php index 5a5d454..11ab53d 100644 --- a/tests/src/Functional/JSONFieldProcessorConfigEntityTest.php +++ b/tests/src/Functional/JSONFieldProcessorConfigEntityTest.php @@ -13,169 +13,171 @@ * * @ingroup config_entity_example */ -class JSONFieldProcessorConfigEntityTest extends BrowserTestBase { - - /** - * {@inheritdoc} - */ - protected $defaultTheme = 'stark'; - - /** - * Modules to enable. - * - * @var array - */ - protected static $modules = ['json_field_processor']; - - /** - * The installation profile to use with this test. - * - * We need the 'minimal' profile in order to make sure the Tool block is - * available. - * - * @var string - */ - protected $profile = 'minimal'; - - /** - * Various functional tests of the Config Entity Example module. - * - * 1) Verify that the default json_field_processor_config entity was created when the module was installed. - * - * 2) Verify that permissions are applied to the various defined paths. - * - * 3) Verify that we can manage entities through the user interface. - * - * 4) Verify that the entity we add can be re-edited. - * - * 5) Verify that the label is shown in the list. - */ - public function testConfigEntityExample() { - $assert = $this->assertSession(); - - // 2) Verify that permissions are applied to the various defined paths. - // Define some paths. Since the default json_field_processor_config entity is defined, we can use it - // in our management paths. - $forbidden_paths = [ - '/admin/json-field-processor/json_field_processor_config', - '/admin/json-field-processor/json_field_processor_config/add', - ]; - // Check each of the paths to make sure we don't have access. At this point - // we haven't logged in any users, so the client is anonymous. - foreach ($forbidden_paths as $path) { - $this->drupalGet($path); - $assert->statusCodeEquals(403); +class JSONFieldProcessorConfigEntityTest extends BrowserTestBase +{ + + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * Modules to enable. + * + * @var array + */ + protected static $modules = ['json_field_processor']; + + /** + * The installation profile to use with this test. + * + * We need the 'minimal' profile in order to make sure the Tool block is + * available. + * + * @var string + */ + protected $profile = 'minimal'; + + /** + * Various functional tests of the Config Entity Example module. + * + * 1) Verify that the default json_field_processor_config entity was created when the module was installed. + * + * 2) Verify that permissions are applied to the various defined paths. + * + * 3) Verify that we can manage entities through the user interface. + * + * 4) Verify that the entity we add can be re-edited. + * + * 5) Verify that the label is shown in the list. + */ + public function testConfigEntityExample() + { + $assert = $this->assertSession(); + + // 2) Verify that permissions are applied to the various defined paths. + // Define some paths. Since the default json_field_processor_config entity is defined, we can use it + // in our management paths. + $forbidden_paths = [ + '/admin/json-field-processor/json_field_processor_config', + '/admin/json-field-processor/json_field_processor_config/add', + ]; + // Check each of the paths to make sure we don't have access. At this point + // we haven't logged in any users, so the client is anonymous. + foreach ($forbidden_paths as $path) { + $this->drupalGet($path); + $assert->statusCodeEquals(403); + } + + // Create a user with no permissions. + $without_perms_user = $this->drupalCreateUser(); + $this->drupalLogin($without_perms_user); + // Should be the same result for forbidden paths, since the user needs + // special permissions for these paths. + foreach ($forbidden_paths as $path) { + $this->drupalGet($path); + // Again 404? + $assert->statusCodeEquals(403); + } + + // Create a user who can administer json_field_processor_configs. + $admin_user = $this->drupalCreateUser(['administer json field processor']); + $this->drupalLogin($admin_user); + // Forbidden paths are no longer forbidden. + foreach ($forbidden_paths as $path) { + $this->drupalGet($path); + $assert->statusCodeEquals(200); + } + + // Now that we have the admin user logged in, check the menu links. + // $this->drupalGet('/admin/config'); + // $assert->linkByHrefExists('/admin/json-field-processor/json_field_processor_config');. + // 3) Verify that we can manage entities through the user interface. + // We still have the admin user logged in, so we'll create, update, and + // delete an entity. + // Go to the list page. + $this->drupalGet('/admin/json-field-processor/json_field_processor_config'); + $this->clickLink('Add JSON Field Processor Configuration'); + $json_field_processor_config_machine_name = 'json_field_processor_config_01'; + $form_values = [ + 'field_name' => 'Test Field Name', + 'id' => $json_field_processor_config_machine_name, + 'json_path' => 'data.test', + 'label' => 'Test Label', + ]; + + // Submit the form with the required values. + $this->submitForm($form_values, 'Create JSON Field Processor Configuration'); + // 4) Verify that our json_field_processor_config appears when we edit it. + // Step 4: Verify that the config entity appears when we edit it. + $this->drupalGet('/admin/json-field-processor/json_field_processor_config/' . $json_field_processor_config_machine_name . '/edit'); + // Ensure label is pre-filled correctly. + $assert->fieldValueEquals('label', 'Test Label'); + // Verify field_name value. + $assert->fieldValueEquals('field_name', 'Test Field Name'); + // Verify JSON path value. + $assert->fieldValueEquals('json_path', 'data.test'); + // Check that the edit button exists. + $assert->buttonExists('Update Configuration'); + + // Step 5: Verify that the label and machine name appear in the list. + $this->drupalGet('/admin/json-field-processor/json_field_processor_config'); + // Ensure label is shown. + $assert->pageTextContains('Test Label'); + // Ensure json path is shown. + $assert->pageTextContains('data.test'); + // Ensure field name is shown. + $assert->pageTextContains('Test Field Name'); + + // Add another configuration. + $this->clickLink('Add JSON Field Processor Configuration'); + $robby_machine_name = 'robby_json_field_processor_config'; + $robby_label = 'Robby JSON Field Processor Configuration Label'; + $form_values = [ + 'field_name' => 'Robby Field Name', + 'id' => $robby_machine_name, + 'json_path' => 'data.robby', + 'label' => $robby_label, + ]; + $this->submitForm($form_values, 'Create JSON Field Processor Configuration'); + $this->drupalGet('/admin/json-field-processor/json_field_processor_config'); + $assert->pageTextContains('Robby Field Name'); + $assert->pageTextContains('data.robby'); + $assert->pageTextContains($robby_label); + + // Step 6: Verify links on the listing page. + $this->drupalGet(Url::fromRoute('entity.json_field_processor_config.list')); + $assert->linkByHrefExists('/admin/json-field-processor/json_field_processor_config/add'); + $assert->linkByHrefExists('/admin/json-field-processor/json_field_processor_config/' . $robby_machine_name); + $assert->linkByHrefExists('/admin/json-field-processor/json_field_processor_config/' . $robby_machine_name . '/delete'); + + // Verify links on the Add JSON Field Processor Configuration page. + $this->drupalGet('/admin/json-field-processor/json_field_processor_config/add'); + // Verify links on the Edit JSON Field Processor Configuration page. + $this->drupalGet('/admin/json-field-processor/json_field_processor_config/' . $robby_machine_name . '/edit'); + $assert->linkByHrefExists('/admin/json-field-processor/json_field_processor_config/' . $robby_machine_name . '/delete'); + + // Step 7: Verify deletion workflow. + $this->drupalGet('/admin/json-field-processor/json_field_processor_config/' . $robby_machine_name . '/delete'); + // Verify the delete button exists. + $assert->buttonExists('Delete'); + + // Step 8: Verify the cancel button on the delete page redirects to the list page. + $cancel_button = $this->xpath( + '//a[@id="edit-cancel" and contains(@href, :path)]', + [':path' => '/admin/json-field-processor/json_field_processor_config'] + ); + $this->assertEquals(count($cancel_button), 1, 'Found cancel button linking to list page.'); + + // Step 9: Reserved keyword test. + // $this->drupalGet(Url::fromRoute('entity.json_field_processor_config.add_form')); + // $this->submitForm([ + // 'field_name' => 'Custom Field Name', + // 'id' => 'custom', + // 'json_path' => 'data.custom', + // 'label' => 'Custom', + // ], 'Create JSON Field Processor Configuration'); + // $assert->pageTextContains('Additionally, it cannot be the reserved word "custom".');. } - // Create a user with no permissions. - $without_perms_user = $this->drupalCreateUser(); - $this->drupalLogin($without_perms_user); - // Should be the same result for forbidden paths, since the user needs - // special permissions for these paths. - foreach ($forbidden_paths as $path) { - $this->drupalGet($path); - // Again 404? - $assert->statusCodeEquals(403); - } - - // Create a user who can administer json_field_processor_configs. - $admin_user = $this->drupalCreateUser(['administer json field processor']); - $this->drupalLogin($admin_user); - // Forbidden paths are no longer forbidden. - foreach ($forbidden_paths as $path) { - $this->drupalGet($path); - $assert->statusCodeEquals(200); - } - - // Now that we have the admin user logged in, check the menu links. - // $this->drupalGet('/admin/config'); - // $assert->linkByHrefExists('/admin/json-field-processor/json_field_processor_config');. - // 3) Verify that we can manage entities through the user interface. - // We still have the admin user logged in, so we'll create, update, and - // delete an entity. - // Go to the list page. - $this->drupalGet('/admin/json-field-processor/json_field_processor_config'); - $this->clickLink('Add JSON Field Processor Configuration'); - $json_field_processor_config_machine_name = 'json_field_processor_config_01'; - $form_values = [ - 'field_name' => 'Test Field Name', - 'id' => $json_field_processor_config_machine_name, - 'json_path' => 'data.test', - 'label' => 'Test Label', - ]; - - // Submit the form with the required values. - $this->submitForm($form_values, 'Create JSON Field Processor Configuration'); - // 4) Verify that our json_field_processor_config appears when we edit it. - // Step 4: Verify that the config entity appears when we edit it. - $this->drupalGet('/admin/json-field-processor/json_field_processor_config/' . $json_field_processor_config_machine_name . '/edit'); - // Ensure label is pre-filled correctly. - $assert->fieldValueEquals('label', 'Test Label'); - // Verify field_name value. - $assert->fieldValueEquals('field_name', 'Test Field Name'); - // Verify JSON path value. - $assert->fieldValueEquals('json_path', 'data.test'); - // Check that the edit button exists. - $assert->buttonExists('Update Configuration'); - - // Step 5: Verify that the label and machine name appear in the list. - $this->drupalGet('/admin/json-field-processor/json_field_processor_config'); - // Ensure label is shown. - $assert->pageTextContains('Test Label'); - // Ensure json path is shown. - $assert->pageTextContains('data.test'); - // Ensure field name is shown. - $assert->pageTextContains('Test Field Name'); - - // Add another configuration. - $this->clickLink('Add JSON Field Processor Configuration'); - $robby_machine_name = 'robby_json_field_processor_config'; - $robby_label = 'Robby JSON Field Processor Configuration Label'; - $form_values = [ - 'field_name' => 'Robby Field Name', - 'id' => $robby_machine_name, - 'json_path' => 'data.robby', - 'label' => $robby_label, - ]; - $this->submitForm($form_values, 'Create JSON Field Processor Configuration'); - $this->drupalGet('/admin/json-field-processor/json_field_processor_config'); - $assert->pageTextContains('Robby Field Name'); - $assert->pageTextContains('data.robby'); - $assert->pageTextContains($robby_label); - - // Step 6: Verify links on the listing page. - $this->drupalGet(Url::fromRoute('entity.json_field_processor_config.list')); - $assert->linkByHrefExists('/admin/json-field-processor/json_field_processor_config/add'); - $assert->linkByHrefExists('/admin/json-field-processor/json_field_processor_config/' . $robby_machine_name); - $assert->linkByHrefExists('/admin/json-field-processor/json_field_processor_config/' . $robby_machine_name . '/delete'); - - // Verify links on the Add JSON Field Processor Configuration page. - $this->drupalGet('/admin/json-field-processor/json_field_processor_config/add'); - // Verify links on the Edit JSON Field Processor Configuration page. - $this->drupalGet('/admin/json-field-processor/json_field_processor_config/' . $robby_machine_name . '/edit'); - $assert->linkByHrefExists('/admin/json-field-processor/json_field_processor_config/' . $robby_machine_name . '/delete'); - - // Step 7: Verify deletion workflow. - $this->drupalGet('/admin/json-field-processor/json_field_processor_config/' . $robby_machine_name . '/delete'); - // Verify the delete button exists. - $assert->buttonExists('Delete'); - - // Step 8: Verify the cancel button on the delete page redirects to the list page. - $cancel_button = $this->xpath( - '//a[@id="edit-cancel" and contains(@href, :path)]', - [':path' => '/admin/json-field-processor/json_field_processor_config'] - ); - $this->assertEquals(count($cancel_button), 1, 'Found cancel button linking to list page.'); - - // Step 9: Reserved keyword test. - // $this->drupalGet(Url::fromRoute('entity.json_field_processor_config.add_form')); - // $this->submitForm([ - // 'field_name' => 'Custom Field Name', - // 'id' => 'custom', - // 'json_path' => 'data.custom', - // 'label' => 'Custom', - // ], 'Create JSON Field Processor Configuration'); - // $assert->pageTextContains('Additionally, it cannot be the reserved word "custom".');. - } - }