Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions sms.api.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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'];
Expand Down
7 changes: 6 additions & 1 deletion sms.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand All @@ -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']
Expand Down
98 changes: 98 additions & 0 deletions src/Event/SmsEntityPhoneNumber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php

namespace Drupal\sms\Event;

use Drupal\Core\Entity\EntityInterface;
use Symfony\Component\EventDispatcher\Event;

/**
* Event fired when resolving phone numbers for an entity.
*
* @see \Drupal\sms\Event\SmsEvents
*/
class SmsEntityPhoneNumber extends Event {

/**
* The entity to find phone numbers.
*
* @var \Drupal\Core\Entity\EntityInterface
*/
protected $entity;

/**
* Whether the returned phone numbers must be verified, or NULL to get all
* phone numbers regardless of status.
*
* @var boolean|NULL
*/
protected $verified;

/**
* An array of phone numbers.
*
* @var string[]
*/
protected $phoneNumbers = [];

/**
* Constructs the object.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to find phone numbers.
* @param boolean|NULL $verified
* Whether the returned phone numbers must be verified, or NULL to get all
* phone numbers regardless of status.
*/
public function __construct(EntityInterface $entity, $verified = TRUE) {
$this->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;
}

}
9 changes: 9 additions & 0 deletions src/Event/SmsEvents.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';

}
84 changes: 84 additions & 0 deletions src/EventSubscriber/SmsEntityPhoneNumberProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

namespace Drupal\sms\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Drupal\sms\Event\SmsEvents;
use Drupal\sms\Event\SmsEntityPhoneNumber;
use Drupal\sms\Exception\PhoneNumberSettingsException;
use Drupal\sms\Provider\PhoneNumberVerificationInterface;

/**
* Resolve phone numbers for an entity using phone verification system.
*/
class SmsEntityPhoneNumberProcessor implements EventSubscriberInterface {

/**
* The phone number verification service.
*
* @var \Drupal\sms\Provider\PhoneNumberVerificationInterface
*/
protected $phoneNumberVerification;

/**
* Constructs a new SmsEntityPhoneNumberProcessor object.
*
* @param \Drupal\sms\Provider\PhoneNumberVerificationInterface $phone_number_verification
* The phone number verification service.
*/
public function __construct(PhoneNumberVerificationInterface $phone_number_verification) {
$this->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;
}

}
55 changes: 18 additions & 37 deletions src/Provider/PhoneNumberProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -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();
}

/**
Expand Down
5 changes: 1 addition & 4 deletions src/Provider/PhoneNumberProviderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
11 changes: 6 additions & 5 deletions tests/src/Kernel/SmsFrameworkPhoneNumberProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down