class PhoneNumberVerification in SMS Framework 8
Same name in this branch
- 8 src/Provider/PhoneNumberVerification.php \Drupal\sms\Provider\PhoneNumberVerification
- 8 src/Entity/PhoneNumberVerification.php \Drupal\sms\Entity\PhoneNumberVerification
Same name and namespace in other branches
- 2.x src/Provider/PhoneNumberVerification.php \Drupal\sms\Provider\PhoneNumberVerification
- 2.1.x src/Provider/PhoneNumberVerification.php \Drupal\sms\Provider\PhoneNumberVerification
Phone number verification provider.
Hierarchy
- class \Drupal\sms\Provider\PhoneNumberVerification implements PhoneNumberVerificationInterface
Expanded class hierarchy of PhoneNumberVerification
1 string reference to 'PhoneNumberVerification'
1 service uses PhoneNumberVerification
File
- src/
Provider/ PhoneNumberVerification.php, line 19
Namespace
Drupal\sms\ProviderView source
class PhoneNumberVerification implements PhoneNumberVerificationInterface {
/**
* The SMS provider.
*
* @var \Drupal\sms\Provider\SmsProviderInterface
*/
protected $smsProvider;
/**
* Storage for phone number settings.
*
* @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface
*/
protected $phoneNumberSettings;
/**
* Storage for Phone Number Verification entities.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $phoneNumberVerificationStorage;
/**
* The token service.
*
* @var \Drupal\Core\Utility\Token
*/
protected $token;
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* Constructs a new PhoneNumberProvider object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\Utility\Token $token
* The token replacement system.
* @param \Drupal\sms\Provider\SmsProviderInterface $sms_provider
* The SMS provider.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config_factory, Token $token, SmsProviderInterface $sms_provider) {
$this->smsProvider = $sms_provider;
$this->phoneNumberSettings = $entity_type_manager
->getStorage('phone_number_settings');
$this->phoneNumberVerificationStorage = $entity_type_manager
->getStorage('sms_phone_number_verification');
$this->token = $token;
$this->configFactory = $config_factory;
}
/**
* {@inheritdoc}
*/
public function getPhoneNumberSettings($entity_type_id, $bundle) {
return $this->phoneNumberSettings
->load($entity_type_id . '.' . $bundle);
}
/**
* {@inheritdoc}
*/
public function getPhoneNumberSettingsForEntity(EntityInterface $entity) {
if (!($phone_number_settings = $this
->getPhoneNumberSettings($entity
->getEntityTypeId(), $entity
->bundle()))) {
throw new PhoneNumberSettingsException(sprintf('Entity phone number config does not exist for bundle %s:%s', $entity
->getEntityTypeId(), $entity
->bundle()));
}
return $phone_number_settings;
}
/**
* {@inheritdoc}
*/
public function getPhoneVerificationByCode($code) {
$entities = $this->phoneNumberVerificationStorage
->loadByProperties([
'code' => $code,
]);
return reset($entities);
}
/**
* {@inheritdoc}
*/
public function getPhoneVerificationByPhoneNumber($phone_number, $verified = TRUE, $entity_type = NULL) {
$properties['phone'] = $phone_number;
if (isset($entity_type)) {
$properties['entity__target_type'] = $entity_type;
}
if (isset($verified)) {
$properties['status'] = (int) $verified;
}
return $this->phoneNumberVerificationStorage
->loadByProperties($properties);
}
/**
* {@inheritdoc}
*/
public function getPhoneVerificationByEntity(EntityInterface $entity, $phone_number) {
$entities = $this->phoneNumberVerificationStorage
->loadByProperties([
'entity__target_id' => $entity
->id(),
'entity__target_type' => $entity
->getEntityTypeId(),
'phone' => $phone_number,
]);
return reset($entities);
}
/**
* {@inheritdoc}
*/
public function newPhoneVerification(EntityInterface $entity, $phone_number) {
$config = $this
->getPhoneNumberSettingsForEntity($entity);
$message = $config
->getVerificationMessage() ?: '';
// @todo Replace with code generator.
$random = new Random();
$code = strtoupper($random
->name(6));
/** @var \Drupal\sms\Entity\PhoneNumberVerificationInterface $phone_verification */
$phone_verification = $this->phoneNumberVerificationStorage
->create();
$phone_verification
->setCode($code)
->setStatus(FALSE)
->setPhoneNumber($phone_number)
->setEntity($entity)
->save();
if ($phone_verification) {
$sms_message = new SmsMessage();
$sms_message
->addRecipient($phone_number)
->setOption('_is_verification_message', TRUE)
->setMessage($message)
->setDirection(Direction::OUTGOING);
$data['sms-message'] = $sms_message;
$data['sms_verification_code'] = $phone_verification
->getCode();
$sms_message
->setMessage($this->token
->replace($message, $data))
->setAutomated(FALSE);
$this->smsProvider
->queue($sms_message);
}
return $phone_verification;
}
/**
* {@inheritdoc}
*/
public function updatePhoneVerificationByEntity(EntityInterface $entity) {
try {
$phone_number_settings = $this
->getPhoneNumberSettingsForEntity($entity);
$field_name = $phone_number_settings
->getFieldName('phone_number');
if (!empty($field_name)) {
$items_original = isset($entity->original) ? $entity->original->{$field_name} : NULL;
$items = $entity->{$field_name};
}
} catch (PhoneNumberSettingsException $e) {
// Missing phone number configuration for this entity.
}
// $items can be unassigned because field_name is not configured, or is NULL
// because there is no items.
if (!isset($items)) {
return;
}
$numbers = [];
assert($items instanceof FieldItemListInterface);
foreach ($items as $item) {
$phone_number = $item->value;
$numbers[] = $phone_number;
if (!$this
->getPhoneVerificationByEntity($entity, $phone_number)) {
$this
->newPhoneVerification($entity, $phone_number);
}
}
if (isset($items_original) && !$items
->equals($items_original)) {
foreach ($items_original as $item) {
$phone_number = $item->value;
// A phone number was deleted.
if (!in_array($phone_number, $numbers)) {
if ($phone_verification = $this
->getPhoneVerificationByEntity($entity, $phone_number)) {
$phone_verification
->delete();
}
}
}
}
}
/**
* {@inheritdoc}
*/
public function deletePhoneVerificationByEntity(EntityInterface $entity) {
// Check the entity uses phone numbers. To save on a SQL call, and to
// prevent having to install phone number verification for SMS Framework
// tests which delete entities. Which would otherwise error on non-existent
// tables.
try {
$this
->getPhoneNumberSettingsForEntity($entity);
$verification_entities = $this->phoneNumberVerificationStorage
->loadByProperties([
'entity__target_id' => $entity
->id(),
'entity__target_type' => $entity
->getEntityTypeId(),
]);
$this->phoneNumberVerificationStorage
->delete($verification_entities);
} catch (PhoneNumberSettingsException $e) {
}
}
/**
* {@inheritdoc}
*/
public function purgeExpiredVerifications() {
$current_time = \Drupal::request()->server
->get('REQUEST_TIME');
$verification_ids = [];
foreach ($this->configFactory
->listAll('sms.phone.') as $config_id) {
$config = $this->configFactory
->get($config_id);
$lifetime = $config
->get('verification_code_lifetime');
if (!empty($lifetime)) {
$verification_ids += $this->phoneNumberVerificationStorage
->getQuery()
->condition('entity__target_type', $config
->get('entity_type'))
->condition('bundle', $config
->get('bundle'))
->condition('status', 0)
->condition('created', $current_time - $lifetime, '<')
->execute();
}
}
/** @var \Drupal\sms\Entity\PhoneNumberVerificationInterface $phone_number_verification */
foreach ($this->phoneNumberVerificationStorage
->loadMultiple($verification_ids) as $phone_number_verification) {
if ($entity = $phone_number_verification
->getEntity()) {
try {
$config = $this
->getPhoneNumberSettingsForEntity($entity);
$purge = $config
->getPurgeVerificationPhoneNumber();
$field_name = $config
->getFieldName('phone_number');
if (!empty($purge) && isset($entity->{$field_name})) {
$entity->{$field_name}
->filter(function ($item) use ($phone_number_verification) {
return $item->value != $phone_number_verification
->getPhoneNumber();
});
$entity
->save();
}
} catch (EntityStorageException $e) {
// Failed to save entity.
}
}
$this->phoneNumberVerificationStorage
->delete([
$phone_number_verification,
]);
}
}
}