View source
<?php
namespace Drupal\agreement;
use Drupal\agreement\Entity\Agreement;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Path\PathMatcherInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\user\RoleInterface;
use Drupal\user\UserInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\RequestStack;
class AgreementHandler implements AgreementHandlerInterface {
const ANON_AGREEMENT_COOKIE_PREFIX = 'agreement_anon_';
protected $connection;
protected $entityTypeManager;
protected $pathMatcher;
protected $time;
protected $requestStack;
public function __construct(Connection $connection, EntityTypeManagerInterface $entityTypeManager, PathMatcherInterface $pathMatcher, TimeInterface $time, RequestStack $requestStack) {
$this->connection = $connection;
$this->entityTypeManager = $entityTypeManager;
$this->pathMatcher = $pathMatcher;
$this->time = $time;
$this->requestStack = $requestStack;
}
public function agree(Agreement $agreement, AccountProxyInterface $account, $agreed = 1) {
if ($this
->isAnonymousAgreement($agreement, $account)) {
return $this
->agreeAnonymously($account, $agreement, $agreed);
}
return $this
->agreeWhileLoggedIn($account, $agreement, $agreed);
}
public function hasAgreed(Agreement $agreement, AccountProxyInterface $account) {
if ($this
->isAnonymousAgreement($agreement, $account)) {
return $this
->hasAnonymousUserAgreed($agreement);
}
return $this
->hasAuthenticatedUserAgreed($agreement, $account);
}
public function lastAgreed(Agreement $agreement, UserInterface $account) {
$query = $this->connection
->select('agreement');
$query
->fields('agreement', [
'agreed_date',
])
->condition('uid', $account
->id())
->condition('type', $agreement
->id())
->range(0, 1);
$agreed_date = $query
->execute()
->fetchField();
return $agreed_date === FALSE || $agreed_date === NULL ? -1 : $agreed_date;
}
public function canAgree(Agreement $agreement, AccountProxyInterface $account) {
return !$account
->hasPermission('bypass agreement') && $agreement
->accountHasAgreementRole($account);
}
public function isAnonymousAgreement(Agreement $agreement, AccountProxyInterface $account) {
if ($account
->isAnonymous() && in_array(RoleInterface::ANONYMOUS_ID, $agreement
->getSettings()['roles'])) {
return TRUE;
}
return FALSE;
}
public function getAgreementByUserAndPath(AccountProxyInterface $account, $path) {
$agreement_types = $this->entityTypeManager
->getStorage('agreement')
->loadMultiple();
$default_exceptions = [
'/user/password',
'/user/register',
'/user/reset/*',
'/user/login',
'/user/logout',
'/admin/config/people/agreement',
'/admin/config/people/agreement/*',
'/admin/config/people/agreement/manage/*',
];
$exceptions = array_reduce($agreement_types, function (&$result, Agreement $item) {
$result[] = $item
->get('path');
return $result;
}, $default_exceptions);
$exception_string = implode("\n", $exceptions);
if ($this->pathMatcher
->matchPath($path, $exception_string)) {
return FALSE;
}
$agreements_with_roles = array_reduce($agreement_types, function (&$result, Agreement $item) use ($account) {
if ($item
->accountHasAgreementRole($account)) {
$result[] = $item;
}
return $result;
}, []);
$pathMatcher = $this->pathMatcher;
$self = $this;
$info = array_reduce($agreements_with_roles, function (&$result, Agreement $item) use ($account, $path, $pathMatcher, $self) {
if ($result) {
return $result;
}
$pattern = $item
->getVisibilityPages();
$has_match = $pathMatcher
->matchPath($path, $pattern);
$has_agreed = $self
->hasAgreed($item, $account);
$visibility = (int) $item
->getVisibilitySetting();
if (0 === $visibility && FALSE === $has_match && !$has_agreed) {
$result = $item;
}
elseif (1 === $visibility && $has_match && !$has_agreed) {
$result = $item;
}
return $result;
}, FALSE);
return $info;
}
public static function prefixPath($value) {
return $value ? '/' . $value : $value;
}
protected function agreeAnonymously(AccountProxyInterface $account, Agreement $agreement, $agreed) {
$agreementType = $agreement
->id();
$cookieName = static::ANON_AGREEMENT_COOKIE_PREFIX . $agreementType;
$expire = 0;
if ($agreement
->getSettings()['frequency'] == 365) {
$expire = new \DateTime('+1 year');
}
elseif ($agreement
->agreeOnce()) {
$expire = new \DateTime('+10 years');
}
return new Cookie($cookieName, $agreed, $expire, '/', NULL, NULL, 'lax');
}
protected function agreeWhileLoggedIn(AccountProxyInterface $account, Agreement $agreement, $agreed) {
try {
$transaction = $this->connection
->startTransaction();
$this->connection
->delete('agreement')
->condition('uid', $account
->id())
->condition('type', $agreement
->id())
->execute();
$id = $this->connection
->insert('agreement')
->fields([
'uid' => $account
->id(),
'type' => $agreement
->id(),
'agreed' => $agreed,
'sid' => session_id(),
'agreed_date' => $this->time
->getRequestTime(),
])
->execute();
} catch (DatabaseExceptionWrapper $e) {
$transaction
->rollback();
return FALSE;
} catch (\Exception $e) {
$transaction
->rollback();
return FALSE;
}
return isset($id);
}
protected function hasAnonymousUserAgreed(Agreement $agreement) {
$agreementType = $agreement
->id();
return $this->requestStack
->getCurrentRequest()->cookies
->has(static::ANON_AGREEMENT_COOKIE_PREFIX . $agreementType);
}
protected function hasAuthenticatedUserAgreed(Agreement $agreement, AccountProxyInterface $account) {
$settings = $agreement
->getSettings();
$frequency = $settings['frequency'];
$query = $this->connection
->select('agreement');
$query
->fields('agreement', [
'agreed',
])
->condition('uid', $account
->id())
->condition('type', $agreement
->id())
->range(0, 1);
if ($frequency == 0) {
$query
->condition('sid', session_id());
}
else {
$timestamp = $agreement
->getAgreementFrequencyTimestamp();
if ($timestamp > 0) {
$query
->condition('agreed_date', $agreement
->getAgreementFrequencyTimestamp(), '>=');
}
}
$agreed = $query
->execute()
->fetchField();
return $agreed !== NULL && $agreed > 0;
}
}