TurnstileConfigSubscriber.php (6232B)
1 <?php 2 3 /** 4 * @file 5 * Location: src/EventSubscriber/TurnstileConfigSubscriber.php 6 * 7 * Subscriber for turnstile config changes. 8 */ 9 10 namespace Drupal\taler_turnstile\EventSubscriber; 11 12 use Symfony\Component\EventDispatcher\EventSubscriberInterface; 13 use Drupal\Core\StringTranslation\StringTranslationTrait; 14 use Drupal\Core\StringTranslation\TranslationInterface; 15 use Drupal\Core\Config\ConfigCrudEvent; 16 use Drupal\Core\Config\ConfigEvents; 17 use Drupal\Core\Entity\EntityTypeManagerInterface; 18 use Drupal\taler_turnstile\TurnstileFieldManager; 19 use Drupal\taler_turnstile\TalerMerchantApiService; 20 use Drupal\Core\Messenger\MessengerInterface; 21 22 class TurnstileConfigSubscriber implements EventSubscriberInterface { 23 24 // This provides the $this->t() method. 25 use StringTranslationTrait; 26 27 /** 28 * The entity type manager. 29 * 30 * @var \Drupal\Core\Entity\EntityTypeManagerInterface 31 */ 32 protected $entityTypeManager; 33 34 /** 35 * The Turnstile field manager. 36 * 37 * @var \Drupal\taler_turnstile\TurnstileFieldManager 38 */ 39 protected $fieldManager; 40 41 42 /** 43 * The messenger service. 44 * 45 * @var \Drupal\Core\Messenger\MessengerInterface 46 */ 47 protected $messenger; 48 49 /** 50 * The Turnstile API service. 51 * 52 * @var \Drupal\taler_turnstile\TalerMerchantApiService 53 */ 54 protected $apiService; 55 56 /** 57 * Constructs a TurnstileSettingsForm object. 58 * 59 * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation 60 * The translation interface. 61 * @param \Drupal\Core\Messenger\MessengerInterface 62 * The messenger interface. 63 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager 64 * The entity type manager. 65 * @param \Drupal\taler_turnstile\TurnstileFieldManager $field_manager 66 * The field manager. 67 * @param \Drupal\taler_turnstile\TalerMerchantApiService $api_service 68 * The Turnstile API service. 69 */ 70 public function __construct(TranslationInterface $string_translation, 71 MessengerInterface $messenger, 72 EntityTypeManagerInterface $entity_type_manager, 73 TurnstileFieldManager $field_manager, 74 TalerMerchantApiService $api_service) { 75 $this->stringTranslation = $string_translation; 76 $this->messenger = $messenger; 77 $this->entityTypeManager = $entity_type_manager; 78 $this->fieldManager = $field_manager; 79 $this->apiService = $api_service; 80 } 81 82 /** 83 * {@inheritdoc} 84 */ 85 public static function getSubscribedEvents() { 86 // Listen for the configuration save event. 87 $events[ConfigEvents::SAVE][] = ['onConfigSave']; 88 return $events; 89 } 90 91 /** 92 * React to configuration changes. 93 * 94 * @param \Drupal\Core\Config\ConfigCrudEvent $event 95 * The configuration event. 96 */ 97 public function onConfigSave(ConfigCrudEvent $event) { 98 $config = $event->getConfig(); 99 if ($config->getName() !== 'taler_turnstile.settings') { 100 return; 101 } 102 if ($event->isChanged('enabled_content_types')) { 103 $old_enabled_types = $config->getOriginal('enabled_content_types') ?? []; 104 $new_enabled_types = $config->get('enabled_content_types'); 105 106 // FIXME: Consider validating new_enabled_types. 107 108 // Find content types to add and remove. 109 $types_to_add = array_diff($new_enabled_types, $old_enabled_types); 110 $types_to_remove = array_diff($old_enabled_types, $new_enabled_types); 111 112 // Add fields to newly enabled content types. 113 if (!empty($types_to_add)) { 114 $this->fieldManager->addFieldsToContentTypes($types_to_add); 115 } 116 117 // Remove fields from disabled content types. 118 if (!empty($types_to_remove)) { 119 $this->fieldManager->removeFieldsFromContentTypes($types_to_remove); 120 } 121 if (empty($new_enabled_types)) { 122 $this->fieldManager->cleanupFieldStorage(); 123 } 124 // Display summary of changes. 125 if (!empty($types_to_add) || !empty($types_to_remove)) { 126 $this->displayFieldChanges($types_to_add, $types_to_remove); 127 } 128 \Drupal::logger('taler_turnstile')->info('Turnstile content types changed from @old to @new.', [ 129 '@old' => json_encode($old_enabled_types), 130 '@new' => json_encode($new_enabled_types), 131 ]); 132 } 133 // Subscription prices feed every category's "buy subscription" 134 // choices, so keep all merchant templates in sync when they change. 135 if ($event->isChanged('subscription_prices')) { 136 $this->apiService->syncAllTemplates(); 137 } 138 // When the operator (re)configures the merchant backend or 139 // rotates the access token, the new instance will not yet have 140 // any of our templates — push them all so the paywall keeps 141 // working without manual intervention. 142 if ($event->isChanged('payment_backend_url') || 143 $event->isChanged('access_token')) { 144 $this->apiService->syncAllTemplates(); 145 } 146 } 147 148 /** 149 * Display messages about field changes. 150 * 151 * @param array $types_added 152 * Content types that had fields added. 153 * @param array $types_removed 154 * Content types that had fields removed. 155 */ 156 protected function displayFieldChanges(array $types_added, array $types_removed) { 157 $content_types = $this->entityTypeManager->getStorage('node_type')->loadMultiple(); 158 159 if (!empty($types_added)) { 160 $added_labels = []; 161 foreach ($types_added as $type) { 162 if (isset($content_types[$type])) { 163 $added_labels[] = $content_types[$type]->label(); 164 } 165 } 166 if (!empty($added_labels)) { 167 $this->messenger->addStatus( 168 $this->t('Price category fields added to: @types', [ 169 '@types' => implode(', ', $added_labels), 170 ]) 171 ); 172 } 173 } 174 175 if (!empty($types_removed)) { 176 $removed_labels = []; 177 foreach ($types_removed as $type) { 178 if (isset($content_types[$type])) { 179 $removed_labels[] = $content_types[$type]->label(); 180 } 181 } 182 if (!empty($removed_labels)) { 183 $this->messenger->addStatus( 184 $this->t('Price category fields removed from: @types', [ 185 '@types' => implode(', ', $removed_labels), 186 ]) 187 ); 188 } 189 } 190 } 191 }