contacts_subscriptions-1.x-dev/src/Form/SubscriptionFormTrait.php
src/Form/SubscriptionFormTrait.php
<?php
namespace Drupal\contacts_subscriptions\Form;
use Drupal\commerce_product\Entity\ProductVariationInterface;
use Drupal\contacts_subscriptions\Entity\SubscriptionInterface;
use Drupal\Core\Access\CsrfTokenGenerator;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\EnforcedResponseException;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\user\UserInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Trait for tracking and validating subscription related arguments in forms.
*/
trait SubscriptionFormTrait {
/**
* The CSRF token generator.
*
* @var \Drupal\Core\Access\CsrfTokenGenerator
*/
protected CsrfTokenGenerator $csrf;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected EntityTypeManagerInterface $entityTypeManager;
/**
* The organisation user entity.
*
* @var \Drupal\user\UserInterface
*/
protected UserInterface $user;
/**
* The subscription.
*
* @var \Drupal\contacts_subscriptions\Entity\SubscriptionInterface
*/
protected SubscriptionInterface $subscription;
/**
* The product variation.
*
* @var \Drupal\commerce_product\Entity\ProductVariationInterface
*/
protected ProductVariationInterface $productVariation;
/**
* The logger channel.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected LoggerChannelInterface $logger;
/**
* Whether we are dealing with a new product.
*
* @var bool
*/
protected bool $isNewProduct = FALSE;
/**
* Initialise and validate the user and subscription properties.
*
* @param \Drupal\user\UserInterface|null $user
* The organisation user entity, if any.
* @param bool $check_active
* Whether to check that the subscription is active.
* @param \Drupal\commerce_product\Entity\ProductVariationInterface $productVariation
* (Optional) The subscription type to initialise.
*/
protected function initSubscription(?UserInterface $user, bool $check_active, ProductVariationInterface $productVariation = NULL): void {
if (!$user) {
throw new \InvalidArgumentException('User is required.');
}
$subscription_type = $productVariation ? $productVariation->getProduct()->subscription_type->target_id : NULL;
$subscriptions = $this->entityTypeManager
->getStorage('contacts_subscription')
->loadByUser($user, $subscription_type);
if (count($subscriptions)) {
$this->subscription = reset($subscriptions);
}
else {
$values = [
'user' => $user->id(),
'bundle' => $productVariation->getProduct()->subscription_type->target_id,
];
$this->subscription = $this->entityTypeManager
->getStorage('contacts_subscription')
->create($values);
}
$this->user = $user;
// Validate they have an active subscription, if required.
if ($check_active && !$this->subscription->isActive()) {
throw new NotFoundHttpException('Membership is not active.');
}
}
/**
* Initialise and validate the product variation property.
*
* @param \Drupal\commerce_product\Entity\ProductVariationInterface|null $product_variation
* The product variation, if any.
* @param string|null $token
* The token, if any.
* @param bool $fallback_to_current
* Whether to fall back to the currently active product.
*
* @throws \Drupal\Core\Form\EnforcedResponseException
*/
protected function initVariation(?ProductVariationInterface $product_variation, ?string $token, bool $fallback_to_current): void {
// If we have received a variation, validate the token.
if ($product_variation) {
if (!$this->csrf->validate($token ?? '', $this->subscription->getCsrfValue($product_variation))) {
$this->messenger()->addWarning($this->t('Sorry, there was a problem validating your request. Please try selection your preferred membership again.'));
$this->logger->warning('Invalid CSRF token for variation.');
throw new EnforcedResponseException(new RedirectResponse('/user/' . $this->user->id() . '/subscription'), 'Invalid CSRF');
}
$this->productVariation = $product_variation;
$this->isNewProduct = $product_variation->getProductId() != $this->subscription->getProductId();
}
// Otherwise, fall back if requested.
elseif ($fallback_to_current) {
$this->productVariation = $this->subscription->getProduct(FALSE)->getDefaultVariation();
}
// If we have no variation, throw a not found.
if (!$this->productVariation) {
throw new NotFoundHttpException('No valid product variation.');
}
}
/**
* Get the subscription.
*
* @return \Drupal\contacts_subscriptions\Entity\SubscriptionInterface
* The subscription.
*/
public function getSubscription(): SubscriptionInterface {
return $this->subscription;
}
/**
* Get the product variation.
*
* @return \Drupal\commerce_product\Entity\ProductVariationInterface
* The product variation.
*/
public function getVariation(): ProductVariationInterface {
return $this->productVariation;
}
}
