layout_builder_ipe-1.0.x-dev/src/LayoutBuilderIpeLock.php
src/LayoutBuilderIpeLock.php
<?php
namespace Drupal\layout_builder_ipe;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TempStore\Lock;
use Drupal\Core\TempStore\SharedTempStoreFactory;
use Drupal\Core\Url;
use Drupal\layout_builder\SectionStorageInterface;
use Drupal\layout_builder\TempStoreIdentifierInterface;
/**
* Service class for layout builder ipe locks.
*/
class LayoutBuilderIpeLock {
/**
* The layout builder config.
*
* @var \Drupal\layout_builder_ipe\LayoutBuilderIpeConfig
*/
protected $config;
/**
* The shared tempstore factory.
*
* @var \Drupal\Core\TempStore\SharedTempStoreFactory
*/
protected $tempstoreFactory;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountInterface
*/
protected $currentUser;
/**
* The date formatter service.
*
* @var \Drupal\Core\Datetime\DateFormatterInterface
*/
protected $dateFormatter;
/**
* Creates an LayoutBuilderIpeLock object.
*/
public function __construct(LayoutBuilderIpeConfig $config, SharedTempStoreFactory $tempstore_factory, EntityTypeManagerInterface $entity_type_manager, AccountInterface $current_user, DateFormatterInterface $date_formatter) {
$this->config = $config;
$this->tempstoreFactory = $tempstore_factory;
$this->entityTypeManager = $entity_type_manager;
$this->currentUser = $current_user;
$this->dateFormatter = $date_formatter;
}
/**
* Checks if locks can be used.
*
* @return bool
* TRUE if locks can be used, FALSE otherwise.
*/
public function canLock() {
$non_concurrent_editing = $this->config->get('non_concurrent_editing');
$lock_layout = $this->config->get('lock_layout');
return !$non_concurrent_editing && $lock_layout;
}
/**
* Checks if the given section storage is currently locked.
*
* @param \Drupal\layout_builder\SectionStorageInterface $section_storage
* The section storage object to check.
*
* @return bool
* TRUE if locked, FALSE otherwise.
*/
public function isLocked(SectionStorageInterface $section_storage) {
$tempstore_metadata = $this->getTempstoreMetadata($section_storage);
return $tempstore_metadata && $tempstore_metadata->getOwnerId() != $this->currentUser->id();
}
/**
* Get the reason for the lock.
*
* @param \Drupal\layout_builder\SectionStorageInterface $section_storage
* The section storage object.
*
* @return object|null
* An object explaining the lock, or NULL if not locked or no lock metadata
* can be found.
*/
public function getLockReason(SectionStorageInterface $section_storage) {
if (!$this->isLocked($section_storage)) {
return NULL;
}
$tempstore_metadata = $this->getTempstoreMetadata($section_storage);
if (!$tempstore_metadata) {
return NULL;
}
$lock_message = trim($this->config->get('lock_message'));
$lock_message = !empty($lock_message) ? $lock_message : 'This page is currently being edited by @user and is therefore locked from editing by others. The lock is @age old.';
$break_lock_url = $this->getBreakLockUrl($section_storage)?->toString();
if ($break_lock_url) {
$lock_message .= '<br />You can break the look to start editing this page. Breaking the lock will discard any changes that @user has already made. There is no confirmation and this cannot be undone.';
}
/** @var \Drupal\user\Entity\User $owner */
$owner = $this->entityTypeManager->getStorage('user')->load($tempstore_metadata->getOwnerId());
$reason = (object) [
'reason' => 'locked',
'message' => (string) new FormattableMarkup($lock_message, [
'@user' => $owner->getDisplayName(),
'@age' => $this->dateFormatter->formatTimeDiffSince($tempstore_metadata->getUpdated()),
]),
'break_lock_url' => $break_lock_url,
];
return $reason;
}
/**
* Get the metadata from the tempstore.
*
* @param \Drupal\layout_builder\SectionStorageInterface $section_storage
* The section storage object.
*
* @return \Drupal\Core\TempStore\Lock|null
* The tempstore metadata.
*/
private function getTempstoreMetadata(SectionStorageInterface $section_storage) {
$collection = 'layout_builder.section_storage.' . $section_storage->getStorageType();
$tempstore_key = $section_storage instanceof TempStoreIdentifierInterface ? $section_storage->getTempstoreKey() : $section_storage->getStorageId();
$tempstore_metadata = $this->tempstoreFactory->get($collection)->getMetadata($tempstore_key);
return $tempstore_metadata instanceof Lock ? $tempstore_metadata : NULL;
}
/**
* Get the url for breaking a lock on the given section storage.
*
* @param \Drupal\layout_builder\SectionStorageInterface $section_storage
* The section storage object.
*
* @return \Drupal\Core\Url|null
* The url object, or NULL if the current user has no permissions to break
* locks.
*/
private function getBreakLockUrl(SectionStorageInterface $section_storage) {
if (!$this->currentUser->hasPermission('layout builder ipe break locks')) {
return NULL;
}
return Url::fromRoute('layout_builder_ipe.break_lock', [
'section_storage_type' => $section_storage->getStorageType(),
'section_storage' => $section_storage->getStorageId(),
]);
}
}
