diff --git a/sms.api.php b/sms.api.php index e503af2..a3af2e4 100644 --- a/sms.api.php +++ b/sms.api.php @@ -41,6 +41,18 @@ function hook_sms_gateway_info_alter(&$gateways) { */ class MySmsEventSubscriber implements \Symfony\Component\EventDispatcher\EventSubscriberInterface { + /** + * An example event subscriber. + * + * @see \Drupal\sms\Event\SmsEvents::ENTITY_PHONE_NUMBERS + */ + public function myEntityPhoneNumbers(\Drupal\sms\Event\SmsEntityPhoneNumber $event) { + // Entity to get phone numbers for. + $entity = $event->getEntity(); + // Add a phone number for above entity. + $event->addPhoneNumber('+123456879'); + } + /** * An example event subscriber. * @@ -97,6 +109,7 @@ public function myDeliveryReportPostProcessor(\Drupal\sms\Event\SmsDeliveryRepor * {@inheritdoc} */ public static function getSubscribedEvents() { + $events[\Drupal\sms\Event\SmsEvents::ENTITY_PHONE_NUMBERS][] = ['myEntityPhoneNumbers']; $events[\Drupal\sms\Event\SmsEvents::MESSAGE_PRE_PROCESS][] = ['mySmsMessagePreprocess']; $events[\Drupal\sms\Event\SmsEvents::MESSAGE_POST_PROCESS][] = ['mySmsMessagePostprocess']; $events[\Drupal\sms\Event\SmsEvents::MESSAGE_GATEWAY][] = ['mySmsMessageGateway']; diff --git a/sms.services.yml b/sms.services.yml index e4f4c08..288d000 100644 --- a/sms.services.yml +++ b/sms.services.yml @@ -13,7 +13,7 @@ services: arguments: ['@container.namespaces', '@cache.discovery', '@module_handler'] sms.phone_number: class: Drupal\sms\Provider\PhoneNumberProvider - arguments: ['@sms.provider', '@sms.phone_number.verification'] + arguments: ['@event_dispatcher', '@sms.provider'] sms.phone_number.verification: class: Drupal\sms\Provider\PhoneNumberVerification arguments: ['@entity_type.manager', '@config.factory', '@token', '@sms.provider'] @@ -25,6 +25,11 @@ services: arguments: ['@event_dispatcher', '@config.factory'] tags: - { name: event_subscriber } + sms.entity_phone_number: + class: Drupal\sms\EventSubscriber\SmsEntityPhoneNumberProcessor + arguments: ['@sms.phone_number.verification'] + tags: + - { name: event_subscriber } sms.delivery_reports_processor: class: Drupal\sms\EventSubscriber\SmsDeliveryReportsProcessor arguments: ['@entity_type.manager'] diff --git a/src/Event/SmsEntityPhoneNumber.php b/src/Event/SmsEntityPhoneNumber.php new file mode 100644 index 0000000..3911ce6 --- /dev/null +++ b/src/Event/SmsEntityPhoneNumber.php @@ -0,0 +1,98 @@ +entity = $entity; + $this->verified = $verified; + } + + /** + * Get entity to find phone numbers. + * + * @return \Drupal\Core\Entity\EntityInterface + * The entity to find phone numbers. + */ + public function getEntity() { + return $this->entity; + } + + /** + * Get phone numbers with this verification state. + * + * @return boolean|NULL + * Whether the returned phone numbers must be verified, or NULL to get all + * phone numbers regardless of status. + */ + public function getRequiresVerification() { + return $this->verified; + } + + /** + * Get phone number on this event. + * + * @return string[] + * The phone number on this event. + */ + public function getPhoneNumbers() { + return $this->phoneNumbers; + } + + /** + * Add phone number to this event. + * + * @param string $phone_number + * A phone number to add to this event. + * + * @return $this + * Return this event for chaining. + */ + public function addPhoneNumber($phone_number) { + if (!in_array($phone_number, $this->phoneNumbers)) { + $this->phoneNumbers[] = $phone_number; + } + return $this; + } + +} diff --git a/src/Event/SmsEvents.php b/src/Event/SmsEvents.php index 01c4fd9..5c74ea9 100644 --- a/src/Event/SmsEvents.php +++ b/src/Event/SmsEvents.php @@ -113,4 +113,13 @@ final class SmsEvents { */ const DELIVERY_REPORT_POST_PROCESS = 'sms.report.post_process'; + /** + * Resolve phone numbers for an entity. + * + * @Event + * + * @see \Drupal\sms\Event\SmsEntityPhoneNumber + */ + const ENTITY_PHONE_NUMBERS = 'sms.entity_phone_numbers'; + } diff --git a/src/EventSubscriber/SmsEntityPhoneNumberProcessor.php b/src/EventSubscriber/SmsEntityPhoneNumberProcessor.php new file mode 100644 index 0000000..0e127a1 --- /dev/null +++ b/src/EventSubscriber/SmsEntityPhoneNumberProcessor.php @@ -0,0 +1,84 @@ +phoneNumberVerification = $phone_number_verification; + } + + /** + * Get phone numbers for an entity using phone verification system. + * + * @param \Drupal\sms\Event\SmsEntityPhoneNumber $event + * The entity phone number event. + */ + public function entityPhoneNumbers(SmsEntityPhoneNumber $event) { + $entity = $event->getEntity(); + + try { + $phone_number_settings = $this->phoneNumberVerification + ->getPhoneNumberSettingsForEntity($entity); + $field_name = $phone_number_settings->getFieldName('phone_number'); + if (!$field_name) { + return; + } + } + catch (PhoneNumberSettingsException $e) { + return; + } + + $phone_numbers = []; + if (isset($entity->{$field_name})) { + foreach ($entity->{$field_name} as $item) { + $phone_numbers[] = $item->value; + } + } + + $verified = $event->getRequiresVerification(); + foreach ($phone_numbers as $phone_number) { + if (!isset($verified)) { + $event->addPhoneNumber($phone_number); + } + else { + $verification = $this->phoneNumberVerification + ->getPhoneVerificationByEntity($entity, $phone_number); + if (($verification->getStatus() == $verified)) { + $event->addPhoneNumber($phone_number); + } + } + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + $events[SmsEvents::ENTITY_PHONE_NUMBERS][] = ['entityPhoneNumbers', 1024]; + return $events; + } + +} diff --git a/src/Provider/PhoneNumberProvider.php b/src/Provider/PhoneNumberProvider.php index da970f7..50fa8a4 100644 --- a/src/Provider/PhoneNumberProvider.php +++ b/src/Provider/PhoneNumberProvider.php @@ -2,11 +2,13 @@ namespace Drupal\sms\Provider; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\sms\Direction; use Drupal\sms\Entity\SmsMessage as SmsMessageEntity; +use Drupal\sms\Event\SmsEvents; +use Drupal\sms\Event\SmsEntityPhoneNumber; use Drupal\sms\Exception\NoPhoneNumberException; -use Drupal\sms\Exception\PhoneNumberSettingsException; use Drupal\sms\Message\SmsMessageInterface; /** @@ -15,62 +17,41 @@ class PhoneNumberProvider implements PhoneNumberProviderInterface { /** - * The SMS provider. + * The event dispatcher. * - * @var \Drupal\sms\Provider\SmsProviderInterface + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface */ - protected $smsProvider; + protected $eventDispatcher; /** - * The phone number verification service. + * The SMS provider. * - * @var \Drupal\sms\Provider\PhoneNumberVerificationInterface + * @var \Drupal\sms\Provider\SmsProviderInterface */ - protected $phoneNumberVerification; + protected $smsProvider; /** * Constructs a new PhoneNumberProvider object. * + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher + * The event dispatcher. * @param \Drupal\sms\Provider\SmsProviderInterface $sms_provider * The SMS provider. - * @param \Drupal\sms\Provider\PhoneNumberVerificationInterface $phone_number_verification - * The phone number verification service. */ - public function __construct(SmsProviderInterface $sms_provider, PhoneNumberVerificationInterface $phone_number_verification) { + public function __construct(EventDispatcherInterface $event_dispatcher, SmsProviderInterface $sms_provider) { + $this->eventDispatcher = $event_dispatcher; $this->smsProvider = $sms_provider; - // Temporarily inject service until an event is created. - // See: https://www.drupal.org/node/2797121 - $this->phoneNumberVerification = $phone_number_verification; } /** * {@inheritdoc} */ public function getPhoneNumbers(EntityInterface $entity, $verified = TRUE) { - $phone_number_settings = $this->phoneNumberVerification - ->getPhoneNumberSettingsForEntity($entity); - $field_name = $phone_number_settings->getFieldName('phone_number'); - - if (!$field_name) { - throw new PhoneNumberSettingsException(sprintf('Entity phone number config field mapping not set for bundle %s:%s', $entity->getEntityTypeId(), $entity->bundle())); - } - - $phone_numbers = []; - if (isset($entity->{$field_name})) { - foreach ($entity->{$field_name} as $index => &$item) { - $phone_numbers[$index] = $item->value; - } - } - - if (isset($verified)) { - return array_filter($phone_numbers, function ($phone_number) use (&$entity, $verified) { - $verification = $this->phoneNumberVerification - ->getPhoneVerificationByEntity($entity, $phone_number); - return $verification && ($verification->getStatus() == $verified); - }); - } - - return $phone_numbers; + $event = new SmsEntityPhoneNumber($entity, $verified); + /** @var \Drupal\sms\Event\SmsEntityPhoneNumber $event */ + $event = $this->eventDispatcher + ->dispatch(SmsEvents::ENTITY_PHONE_NUMBERS, $event); + return $event->getPhoneNumbers(); } /** diff --git a/src/Provider/PhoneNumberProviderInterface.php b/src/Provider/PhoneNumberProviderInterface.php index 48ed1f9..ed360ae 100644 --- a/src/Provider/PhoneNumberProviderInterface.php +++ b/src/Provider/PhoneNumberProviderInterface.php @@ -20,10 +20,7 @@ interface PhoneNumberProviderInterface { * phone numbers regardless of status. * * @return string[] - * An array of phone numbers, keyed by original field item index. - * - * @throws \Drupal\sms\Exception\PhoneNumberSettingsException - * Thrown if entity is not configured for phone numbers. + * An array of phone numbers. */ public function getPhoneNumbers(EntityInterface $entity, $verified = TRUE); diff --git a/tests/src/Kernel/SmsFrameworkPhoneNumberProviderTest.php b/tests/src/Kernel/SmsFrameworkPhoneNumberProviderTest.php index 56582d7..eaf8e12 100644 --- a/tests/src/Kernel/SmsFrameworkPhoneNumberProviderTest.php +++ b/tests/src/Kernel/SmsFrameworkPhoneNumberProviderTest.php @@ -133,12 +133,13 @@ public function testGetPhoneNumbersVerified() { $phone_numbers = array_slice($phone_numbers_all, 0, $i); $entity = $this->createEntityWithPhoneNumber($this->phoneNumberSettings, $phone_numbers); - // Verify first phone number. - // Ensures test verifications don't leak between entities. - // array_slice()' $preserve_keys ensures original field index is retained. - $phone_number_verified = array_slice($phone_numbers, 0, 1, TRUE); - $phone_number_unverified = array_slice($phone_numbers, 1, $i, TRUE); + // Ensures test verifications don't leak between entities. array_values() + // resets array keys since they are not important, assertEquals() normally + // asserts keys. + $phone_number_verified = array_values(array_slice($phone_numbers, 0, 1, TRUE)); + $phone_number_unverified = array_values(array_slice($phone_numbers, 1, $i, TRUE)); + // Verify first phone number. if (!empty($phone_number_verified)) { $this->verifyPhoneNumber($entity, reset($phone_number_verified)); }