turnstile

Drupal paywall plugin
Log | Files | Refs | README | LICENSE

SubscriptionPricesForm.php (6903B)


      1 <?php
      2 
      3 namespace Drupal\taler_turnstile\Form;
      4 
      5 use Drupal\Core\Form\ConfigFormBase;
      6 use Drupal\Core\Form\FormStateInterface;
      7 use Drupal\Core\Config\ConfigFactoryInterface;
      8 use Drupal\Core\Url;
      9 use Drupal\taler_turnstile\TalerMerchantApiService;
     10 use Symfony\Component\DependencyInjection\ContainerInterface;
     11 
     12 /**
     13  * Configure subscription prices.
     14  */
     15 class SubscriptionPricesForm extends ConfigFormBase {
     16 
     17   /**
     18    * The Taler Merchant API service.
     19    *
     20    * @var \Drupal\taler_turnstile\TalerMerchantApiService
     21    */
     22   protected $apiService;
     23 
     24   /**
     25    * Constructs a SubscriptionPricesForm object.
     26    *
     27    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
     28    *   The factory for configuration objects.
     29    * @param \Drupal\taler_turnstile\TalerMerchantApiService $api_service
     30    *   The API service.
     31    */
     32   public function __construct(ConfigFactoryInterface $config_factory, TalerMerchantApiService $api_service) {
     33     parent::__construct($config_factory);
     34     $this->apiService = $api_service;
     35   }
     36 
     37   /**
     38    * {@inheritdoc}
     39    */
     40   public static function create(ContainerInterface $container) {
     41     return new static(
     42       $container->get('config.factory'),
     43       $container->get('taler_turnstile.api_service')
     44     );
     45   }
     46 
     47   /**
     48    * {@inheritdoc}
     49    */
     50   protected function getEditableConfigNames() {
     51     return ['taler_turnstile.settings'];
     52   }
     53 
     54   /**
     55    * {@inheritdoc}
     56    */
     57   public function getFormId() {
     58     return 'taler_turnstile_subscription_prices_form';
     59   }
     60 
     61   /**
     62    * {@inheritdoc}
     63    */
     64   public function buildForm(array $form, FormStateInterface $form_state) {
     65     $config = $this->config('taler_turnstile.settings');
     66 
     67     // Check if backend is configured
     68     $backend_url = $config->get('payment_backend_url');
     69     $access_token = $config->get('access_token');
     70 
     71     if (empty($backend_url) || empty($access_token)) {
     72       $this->messenger()->addError(
     73         $this->t('Turnstile payment backend is not configured. Please <a href="@url">configure the backend</a> first.', [
     74           '@url' => Url::fromRoute('taler_turnstile.settings')->toString(),
     75         ])
     76       );
     77       return parent::buildForm($form, $form_state);
     78     }
     79 
     80     $form['description'] = [
     81       '#type' => 'item',
     82       '#markup' => $this->t('<p>Set the price for buying each subscription type in different currencies. Leave a field empty to prevent users from buying that subscription with that currency.</p>'),
     83     ];
     84 
     85     // Get subscriptions and currencies from API. Show the specific
     86     // backend error (timeout / 401 / 502 / ...) so the admin doesn't
     87     // have to dig through the logs to figure out what's wrong.
     88     $subs_result = $this->apiService->getSubscriptions();
     89     $cur_result  = $this->apiService->getCurrencies();
     90 
     91     if (!$cur_result->isOk()) {
     92       $this->messenger()->addError($cur_result->toUserMessage($backend_url));
     93       return parent::buildForm($form, $form_state);
     94     }
     95     $currencies = is_array($cur_result->data) ? $cur_result->data : [];
     96     if (empty($currencies)) {
     97       $this->messenger()->addError($this->t('The merchant backend returned no currencies.'));
     98       return parent::buildForm($form, $form_state);
     99     }
    100 
    101     if (!$subs_result->isOk()) {
    102       $this->messenger()->addError($subs_result->toUserMessage($backend_url));
    103       return parent::buildForm($form, $form_state);
    104     }
    105     // %none% is always present; strip it to count "real" subscriptions.
    106     $subscriptions = is_array($subs_result->data) ? $subs_result->data : [];
    107     $real = $subscriptions;
    108     unset($real['%none%']);
    109     if (empty($real)) {
    110       $this->messenger()->addWarning($this->t('No subscriptions configured in Taler merchant backend.'));
    111       return parent::buildForm($form, $form_state);
    112     }
    113 
    114     $form['subscription_prices'] = [
    115       '#type' => 'fieldset',
    116       '#title' => $this->t('Subscription Prices'),
    117       '#description' => $this->t('Set the price for buying each subscription type in different currencies.'),
    118       '#tree' => TRUE,
    119     ];
    120 
    121     $existing_prices = $config->get('subscription_prices') ?: [];
    122 
    123     foreach ($subscriptions as $subscription_id => $subscription) {
    124       $subscription_label = $subscription['label'] ?? $subscription['name'];
    125 
    126       // Skip the %none% case as you can't buy "no subscription"
    127       if ($subscription_id === '%none%') {
    128         continue;
    129       }
    130 
    131       $form['subscription_prices'][$subscription_id] = [
    132         '#type' => 'details',
    133         '#title' => $subscription_label,
    134         '#description' => $subscription['description'] ?? '',
    135         '#open' => TRUE,
    136       ];
    137 
    138       foreach ($currencies as $currency) {
    139         $currency_code = $currency['code'];
    140         $currency_label = $currency['label'] ?? $currency['code'];
    141 
    142         $form['subscription_prices'][$subscription_id][$currency_code] = [
    143           '#type' => 'number',
    144           '#title' => $currency_label,
    145           '#default_value' => $existing_prices[$subscription_id][$currency_code] ?? '',
    146           '#min' => 0,
    147           // HTML's step attribute wants a bare decimal ("0.01"),
    148           // not a Taler amount ("EUR:0.01").
    149           '#step' => isset($currency['step'])
    150             ? $currency['step']->numericString()
    151             : '0.01',
    152           '#size' => 20,
    153           '#description' => $this->t('Leave empty to prevent buying this subscription with @currency.', [
    154             '@currency' => $currency_code,
    155           ]),
    156         ];
    157       } // for all currencies
    158     } // for all subscriptions
    159 
    160     return parent::buildForm($form, $form_state);
    161   }
    162 
    163   /**
    164    * {@inheritdoc}
    165    */
    166   public function validateForm(array &$form, FormStateInterface $form_state) {
    167     parent::validateForm($form, $form_state);
    168 
    169     // Validate subscription prices
    170     $subscription_prices = $form_state->getValue('subscription_prices');
    171     if (is_array($subscription_prices)) {
    172       foreach ($subscription_prices as $subscription_id => $currencies) {
    173         if (is_array($currencies)) {
    174           foreach ($currencies as $currency_code => $price) {
    175             // Skip empty values as they are allowed
    176             if ($price === '' || $price === NULL) {
    177               continue;
    178             }
    179 
    180             // Validate that the price is a valid non-negative number
    181             if (!is_numeric($price) || $price < 0) {
    182               $form_state->setErrorByName(
    183                 "subscription_prices][{$subscription_id}][{$currency_code}",
    184                 $this->t('Subscription prices cannot be negative.')
    185               );
    186             }
    187           }
    188         }
    189       }
    190     }
    191   }
    192 
    193 
    194   /**
    195    * {@inheritdoc}
    196    */
    197   public function submitForm(array &$form, FormStateInterface $form_state) {
    198     $config = $this->config('taler_turnstile.settings');
    199     $subscription_prices = $form_state->getValue('subscription_prices');
    200 
    201     $config->set('subscription_prices', $subscription_prices);
    202     $config->save();
    203 
    204     parent::submitForm($form, $form_state);
    205   }
    206 
    207 }