entity_legal-4.0.x-dev/src/Entity/EntityLegalDocument.php
src/Entity/EntityLegalDocument.php
<?php
declare(strict_types=1);
namespace Drupal\entity_legal\Entity;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\entity_legal\EntityLegalDocumentInterface;
use Drupal\entity_legal\EntityLegalDocumentVersionInterface;
use Drupal\entity_legal\Form\EntityLegalDocumentAcceptanceForm;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
/**
* Defines the entity legal document entity.
*
* @ConfigEntityType(
* id = "entity_legal_document",
* label = @Translation("Legal document"),
* handlers = {
* "access" = "Drupal\entity_legal\EntityLegalDocumentAccessControlHandler",
* "list_builder" = "Drupal\entity_legal\EntityLegalDocumentListBuilder",
* "form" = {
* "add" = "Drupal\entity_legal\Form\EntityLegalDocumentForm",
* "edit" = "Drupal\entity_legal\Form\EntityLegalDocumentForm",
* "delete" = "Drupal\Core\Entity\EntityDeleteForm"
* }
* },
* config_prefix = "document",
* admin_permission = "administer entity legal",
* bundle_of = "entity_legal_document_version",
* entity_keys = {
* "id" = "id",
* "label" = "label"
* },
* links = {
* "delete-form" = "/admin/structure/legal/manage/{entity_legal_document}/delete",
* "edit-form" = "/admin/structure/legal/manage/{entity_legal_document}",
* "collection" = "/admin/structure/legal",
* "canonical" = "/legal/document/{entity_legal_document}",
* },
* config_export = {
* "id",
* "label",
* "require_signup",
* "require_existing",
* "settings",
* },
* )
*/
class EntityLegalDocument extends ConfigEntityBundleBase implements EntityLegalDocumentInterface {
/**
* The legal document ID.
*/
protected string $id;
/**
* The human-readable label of the legal document.
*/
protected string $label;
/**
* Require new users to accept this document on signup.
*/
protected bool $require_signup = FALSE;
/**
* Require existing users to accept this document.
*/
protected bool $require_existing = FALSE;
/**
* Am array of additional data related to the legal document.
*/
protected array $settings = [];
/**
* {@inheritdoc}
*/
public static function preCreate(EntityStorageInterface $storage, array &$values): void {
parent::preCreate($storage, $values);
if (empty($values['settings']['title_pattern'])) {
$values['settings']['title_pattern'] = '[entity_legal_document:label]';
}
}
/**
* {@inheritdoc}
*/
public function delete(): void {
if (!$this->isNew()) {
// Delete all associated versions.
$versions = $this->getAllVersions();
foreach ($versions as $version) {
$version->delete();
}
}
parent::delete();
}
/**
* {@inheritdoc}
*/
public function getAcceptanceForm(): array {
/** @var \Drupal\entity_legal\Form\EntityLegalDocumentAcceptanceForm $form */
$form = \Drupal::classResolver()->getInstanceFromDefinition(EntityLegalDocumentAcceptanceForm::class);
$form->setDocument($this);
return \Drupal::formBuilder()->getForm($form);
}
/**
* {@inheritdoc}
*/
public function getAllVersions(): array {
$query = \Drupal::entityQuery(ENTITY_LEGAL_DOCUMENT_VERSION_ENTITY_NAME)
->accessCheck(FALSE)
->condition('document_name', $this->id());
$results = $query->execute();
if (!empty($results)) {
return \Drupal::entityTypeManager()
->getStorage(ENTITY_LEGAL_DOCUMENT_VERSION_ENTITY_NAME)
->loadMultiple($results);
}
return [];
}
/**
* {@inheritdoc}
*/
public function getPublishedVersion(): ?EntityLegalDocumentVersionInterface {
$storage = $this->entityTypeManager()->getStorage(ENTITY_LEGAL_DOCUMENT_VERSION_ENTITY_NAME);
$ids = $storage->getQuery()
->accessCheck(FALSE)
->condition('document_name', $this->id())
->condition('published', TRUE)
->execute();
if (!$ids) {
return NULL;
}
$id = reset($ids);
$publishedVersion = $storage->load($id);
$currentLangCode = \Drupal::languageManager()->getCurrentLanguage()->getId();
if ($publishedVersion->hasTranslation($currentLangCode)) {
$publishedVersion = $publishedVersion->getTranslation($currentLangCode);
}
return $publishedVersion;
}
/**
* {@inheritdoc}
*/
public function setPublishedVersion(EntityLegalDocumentVersionInterface $versionEntity): bool {
if (!$versionEntity->isNew()) {
/** @var \Drupal\entity_legal\EntityLegalDocumentVersionInterface $unchangedVersion */
$unchangedVersion = $this->entityTypeManager()
->getStorage(ENTITY_LEGAL_DOCUMENT_VERSION_ENTITY_NAME)
->loadUnchanged($versionEntity->id());
if ($unchangedVersion->isPublished()) {
// An existing entity is already published.
return TRUE;
}
}
// If the version entity is not of this bundle, fail.
if ($versionEntity->bundle() != $this->id()) {
return FALSE;
}
// Unpublish a published version.
if ($actualPublishedVersion = $this->getPublishedVersion()) {
$actualPublishedVersion->unpublish()->save();
}
$versionEntity->publish()->save();
return TRUE;
}
/**
* {@inheritdoc}
*/
public function getAcceptanceLabel(): string {
$label = '';
$publishedVersion = $this->getPublishedVersion();
if ($publishedVersion) {
$label = $publishedVersion->get('acceptance_label')->value;
}
$label = \Drupal::service('token')->replace($label, [ENTITY_LEGAL_DOCUMENT_ENTITY_NAME => $this]);
return Xss::filter($label);
}
/**
* {@inheritdoc}
*/
public function toUrl($rel = 'canonical', array $options = []): Url {
// Unless language was already provided, avoid setting an explicit language.
$options += ['language' => NULL];
return parent::toUrl($rel, $options);
}
/**
* {@inheritdoc}
*/
public function userMustAgree(bool $newUser = FALSE, ?AccountInterface $account = NULL): bool {
// User cannot agree unless there is a published version.
if (!$this->getPublishedVersion()) {
return FALSE;
}
if (empty($account)) {
$account = \Drupal::currentUser();
}
if ($newUser) {
return !empty($this->require_signup);
}
else {
return !empty($this->require_existing) && $account->hasPermission($this->getPermissionExistingUser());
}
}
/**
* {@inheritdoc}
*/
public function userHasAgreed(?AccountInterface $account = NULL): bool {
$account = $account ?? \Drupal::currentUser();
return count($this->getAcceptances($account)) > 0;
}
/**
* {@inheritdoc}
*/
public function getAcceptances(?AccountInterface $account = NULL, bool $published = TRUE): array {
$acceptances = [];
$versions = [];
if ($published) {
$versions[] = $this->getPublishedVersion();
}
else {
$versions = $this->getAllVersions();
}
/** @var \Drupal\entity_legal\EntityLegalDocumentVersionInterface $version */
foreach ($versions as $version) {
$acceptances += $version->getAcceptances($account);
}
return $acceptances;
}
/**
* {@inheritdoc}
*/
public function getPermissionView(): string {
return 'legal view ' . $this->id();
}
/**
* {@inheritdoc}
*/
public function getPermissionExistingUser(): string {
return 'legal re-accept ' . $this->id();
}
/**
* {@inheritdoc}
*/
public function getAcceptanceDeliveryMethod(bool $newUser = FALSE): ?string {
$settingGroup = $newUser ? 'new_users' : 'existing_users';
return $this->get('settings')[$settingGroup]['require_method'] ?? NULL;
}
/**
* {@inheritdoc}
*/
public function save() {
$status = parent::save();
if ($status == SAVED_NEW && !\Drupal::isConfigSyncing()) {
// Add or remove the body field, as needed.
$field = FieldConfig::loadByName('entity_legal_document_version', $this->id(), 'entity_legal_document_text');
if (empty($field)) {
FieldConfig::create([
'field_storage' => FieldStorageConfig::loadByName('entity_legal_document_version', 'entity_legal_document_text'),
'bundle' => $this->id(),
'label' => 'Document text',
'settings' => ['display_summary' => FALSE],
])->save();
// Assign widget settings for the 'default' form mode.
\Drupal::service('entity_display.repository')->getFormDisplay('entity_legal_document_version', $this->id(), 'default')
->setComponent('entity_legal_document_text', [
'type' => 'text_textarea_with_summary',
])
->save();
// Assign display settings for 'default' view mode.
\Drupal::service('entity_display.repository')->getViewDisplay('entity_legal_document_version', $this->id(), 'default')
->setComponent('entity_legal_document_text', [
'label' => 'hidden',
'type' => 'text_default',
])
->save();
}
}
else {
Cache::invalidateTags(["entity_legal_document:{$this->id()}"]);
}
return $status;
}
}
