diff --git a/modules/crm_case_external_id/config/optional/field.storage.crm_case.external_id.yml b/modules/crm_case_external_id/config/optional/field.storage.crm_case.external_id.yml new file mode 100644 index 0000000000000000000000000000000000000000..a11a19a87df74927f22498a4e8177ab52395f449 --- /dev/null +++ b/modules/crm_case_external_id/config/optional/field.storage.crm_case.external_id.yml @@ -0,0 +1,24 @@ +langcode: en +status: true +dependencies: + module: + - crm_case + enforced: + module: + - crm_case_external_id +id: crm_case.external_id +field_name: external_id +entity_type: crm_case +type: integer +settings: + unsigned: true + size: normal +module: core +locked: false +cardinality: 1 +translatable: true +indexes: + value: + - value +persist_with_no_fields: true +custom_storage: false diff --git a/modules/crm_case_external_id/crm_case_external_id.info.yml b/modules/crm_case_external_id/crm_case_external_id.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..c8bbd06f65d79d0220356eae0975bbb5a0557b54 --- /dev/null +++ b/modules/crm_case_external_id/crm_case_external_id.info.yml @@ -0,0 +1,5 @@ +name: 'External Case Id' +type: module +description: 'An external Id for CRM Case entity.' +package: CRM +core_version_requirement: ^10 || ^11 diff --git a/modules/crm_case_external_id/crm_case_external_id.module b/modules/crm_case_external_id/crm_case_external_id.module new file mode 100644 index 0000000000000000000000000000000000000000..282ad42e602694980efae82658bd75742accc313 --- /dev/null +++ b/modules/crm_case_external_id/crm_case_external_id.module @@ -0,0 +1,90 @@ +<?php + +/** + * @file + * Contains crm_case_external_id.module. + */ + +use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Form\FormStateInterface; + +/** + * Implements hook_entity_bundle_field_info_alter(). + */ +function crm_case_external_id_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) { + + if ($entity_type->id() === 'crm_case') { + if (isset($fields['external_id'])) { + // Use the ID as defined in the annotation of the constraint definition. + $fields['external_id']->addConstraint('CrmCaseExternalId', []); + } + } +} + +/** + * Implements hook_form_FORM_ID_alter() for 'field_config_edit_form'. + */ +function crm_case_external_id_form_field_config_form_alter(&$form, FormStateInterface $form_state, $form_id) { + $field = $form_state->getFormObject()->getEntity(); + if ($field->getName() !== 'external_id' || $field->getTargetEntityTypeId() !== 'crm_case') { + return; + + } + $crm_case_bundles = \Drupal::entityTypeManager()->getStorage('crm_case_type')->loadMultiple(); + $options = []; + foreach ($crm_case_bundles as $crm_case_bundle) { + $options[$crm_case_bundle->id()] = $crm_case_bundle->label(); + } + + $form['third_party_settings']['external_id'] = [ + '#type' => 'details', + '#title' => t('External Id settings'), + '#open' => TRUE, + '#group' => 'advanced', + '#weight' => 100, + ]; + + $form['third_party_settings']['external_id']['bundles'] = [ + '#type' => 'checkboxes', + '#title' => t('Bundles'), + '#options' => $options, + '#default_value' => $field->getThirdPartySetting('external_id', 'bundles', []), + ]; + $form['third_party_settings']['external_id']['negate'] = [ + '#type' => 'radios', + '#title' => t('Negate'), + '#options' => [ + 0 => t('Include'), + 1 => t('Exclude'), + ], + '#default_value' => $field->getThirdPartySetting('external_id', 'negate', 0), + ]; + + $form['#validate'][] = 'crm_case_external_id_form_field_config_form_validate'; +} + +/** + * Validation for 'field_config_edit_form'. + */ +function crm_case_external_id_form_field_config_form_validate(&$form, FormStateInterface $form_state) { + + $third_party_settings = $form_state->getValue('third_party_settings'); + $bundles = $third_party_settings['external_id']['bundles']; + $bundles = array_filter($bundles); + if (empty($bundles)) { + return; + } + + $field = $form_state->getFormObject()->getEntity(); + $bundle = $field->getTargetBundle(); + $in_array = in_array($bundle, $bundles); + $negate = $third_party_settings['external_id']['negate']; + + if ($negate && $in_array) { + $form_state->setErrorByName('third_party_settings][external_id][bundles', t('The bundle %bundle is selected and negate is enabled.', ['%bundle' => $bundle])); + } + elseif (!$negate && !$in_array) { + $form_state->setErrorByName('third_party_settings][external_id][bundles', t('The bundle %bundle is not selected and negate is disabled.', ['%bundle' => $bundle])); + } + +} diff --git a/modules/crm_case_external_id/src/Plugin/Validation/Constraint/ExternalIdConstraint.php b/modules/crm_case_external_id/src/Plugin/Validation/Constraint/ExternalIdConstraint.php new file mode 100644 index 0000000000000000000000000000000000000000..2140a0f4d4ca784e61375758636426b640a541fc --- /dev/null +++ b/modules/crm_case_external_id/src/Plugin/Validation/Constraint/ExternalIdConstraint.php @@ -0,0 +1,32 @@ +<?php + +namespace Drupal\crm_case_external_id\Plugin\Validation\Constraint; + +use Symfony\Component\Validator\Constraint; + +/** + * Checks that the submitted value is a unique integer. + * + * @Constraint( + * id = "CrmCaseExternalId", + * label = @Translation("External Crm Case Id", context = "Validation"), + * type = "integer" + * ) + */ +class ExternalIdConstraint extends Constraint { + + /** + * The message that will be shown if the value is not an integer. + * + * @var string + */ + public $notInteger = '%value is not an integer'; + + /** + * The message that will be shown if the value is not unique. + * + * @var string + */ + public $notUnique = '%value is not unique'; + +} diff --git a/modules/crm_case_external_id/src/Plugin/Validation/Constraint/ExternalIdConstraintValidator.php b/modules/crm_case_external_id/src/Plugin/Validation/Constraint/ExternalIdConstraintValidator.php new file mode 100644 index 0000000000000000000000000000000000000000..8b4b29ae3666602329e488449fb106fe05afee79 --- /dev/null +++ b/modules/crm_case_external_id/src/Plugin/Validation/Constraint/ExternalIdConstraintValidator.php @@ -0,0 +1,103 @@ +<?php + +namespace Drupal\crm_case_external_id\Plugin\Validation\Constraint; + +use Drupal\Core\DependencyInjection\ContainerInjectionInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; + +/** + * Validates the UniqueInteger constraint. + */ +class ExternalIdConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface { + + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + private $entityTypeManager; + + /** + * Creates a new TaxonomyTermHierarchyConstraintValidator instance. + * + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + */ + public function __construct(EntityTypeManagerInterface $entity_type_manager) { + $this->entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('entity_type.manager') + ); + } + + /** + * {@inheritdoc} + */ + public function validate($value, Constraint $constraint) { + $entity = $value->getEntity(); + $field_definition = $value->getFieldDefinition(); + + // dpm($field_definition->get('entity_type')); + // dpm($field_definition->get('field_name')); + // dpm($field_definition->get('bundle'));. + foreach ($value as $item) { + // First check if the value is an integer. + if (!is_int((int) $item->value)) { + // The value is not an integer, so a violation, aka error, is applied. + // The type of violation applied comes from the constraint description + // in step 1. + $this->context->addViolation($constraint->notInteger, ['%value' => $item->value]); + } + + // Next check if the value is unique. + if (!$this->isUnique($item->value, $entity, $field_definition)) { + $this->context->addViolation($constraint->notUnique, ['%value' => $item->value]); + } + } + } + + /** + * Is unique? + * + * @param string $value + * The value to check. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition + * The field definition. + */ + private function isUnique($value, $entity, $field_definition) { + + $entity_type = $field_definition->get('entity_type'); + $field_name = $field_definition->get('field_name'); + $bundle = $field_definition->get('bundle'); + $bundles = $field_definition->getThirdPartySetting('external_id', 'bundles', []); + $bundles = array_filter($bundles); + $negate = $field_definition->getThirdPartySetting('external_id', 'negate', FALSE); + // Here is where the check for a unique value would happen. + $query = $this->entityTypeManager->getStorage($entity_type)->getQuery(); + $query->condition($field_name, $value); + if (!$entity->isNew()) { + $entity_id = $entity->id(); + $query->condition('id', $entity_id, '<>'); + } + if (!empty($bundles)) { + $operator = $negate ? 'NOT IN' : 'IN'; + $query->condition('bundle', $bundles, $operator); + } + + $results = $query->accessCheck(FALSE)->count()->execute(); + + return $results === 0; + } + +}