digital_signage_framework-2.3.x-dev/src/ContentEvent.php
src/ContentEvent.php
<?php
namespace Drupal\digital_signage_framework;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Url;
use Drupal\digital_signage_framework\Entity\ContentSetting;
use Drupal\digital_signage_framework\Entity\Device;
/**
* Content event service.
*/
class ContentEvent {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManager
*/
protected EntityTypeManager $entityTypeManager;
/**
* The messenger service.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected MessengerInterface $messenger;
/**
* Constructs an Entity update service.
*
* @param \Drupal\Core\Entity\EntityTypeManager $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger service.
*/
public function __construct(EntityTypeManager $entity_type_manager, MessengerInterface $messenger) {
$this->entityTypeManager = $entity_type_manager;
$this->messenger = $messenger;
}
/**
* Load the settings for an entity.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity.
*
* @return \Drupal\digital_signage_framework\ContentSettingInterface|false|null
* The settings of this entity, if they exist, NULL otherwise. Returns
* FALSE, if either the entity is not relevant for digital signage.
*/
private function loadSettings(EntityInterface $entity): ContentSettingInterface|bool|null {
if (!($entity instanceof ContentEntityInterface)) {
// Only deal with content entities.
return FALSE;
}
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
if (!$entity->hasField('digital_signage')) {
// Only deal with entities that have the digital_signage field.
return FALSE;
}
// Load the settings entity.
$settingsTarget = $entity->get('digital_signage')->getValue();
if (!isset($settingsTarget[0]['target_id'])) {
// Might be missing in some circumstances.
return FALSE;
}
/** @var \Drupal\digital_signage_framework\ContentSettingInterface|null $settings */
$settings = ContentSetting::load($settingsTarget[0]['target_id']);
return $settings;
}
/**
* Called when an entity gets pre-saved.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function presave(EntityInterface $entity): void {
$settings = $this->loadSettings($entity);
if ($settings === NULL) {
$settings = ContentSetting::create();
$settings->save();
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity->set('digital_signage', $settings->id());
}
}
/**
* Called when an entity gets updated.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function update(EntityInterface $entity): void {
$settings = $this->loadSettings($entity);
if ($settings === FALSE) {
return;
}
if ($settings === NULL) {
// This shouldn't ever happen as the presave hook should have made sure,
// that we always have a settings entity.
// @todo Write an exception to watchdog/logger.
return;
}
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entityIsPublished = $entity->hasField('status') && $entity->get('status')->value;
$needsUpdate = FALSE;
// Store reverse reference.
if (!$settings->getReverseEntity()) {
$settings
->setReverseEntity($entity)
->setReverseEntityStatus($entityIsPublished)
->save();
// New content entity, schedule updates required.
$needsUpdate = TRUE;
}
elseif ($settings->isReverseEntityEnabled() !== $entityIsPublished) {
$settings
->setReverseEntityStatus($entityIsPublished)
->save();
// Publishing status got changed, schedule updates required.
$needsUpdate = TRUE;
}
elseif ($settings->hasChanged()) {
$needsUpdate = TRUE;
}
if ($settings->isEnabled() && (empty($settings->getLabel()) || $settings->isAutoLabel()) && $settings->getLabel() !== $entity->label()) {
$settings->setLabel($entity->label());
$settings->save();
}
if (!$needsUpdate) {
// No schedule update required.
return;
}
$this->messenger
->addMessage(t('Click <a href="@url">here</a> for the Digital Signage preview.', [
'@url' => Url::fromRoute('entity.digital_signage_device.collection')->toString(),
]));
$deviceIds = $settings->getDeviceIds();
$segmentIds = $settings->getSegmentIds();
// It's time to find out on which devices the content should be published.
// @phpstan-ignore-next-line
$query = $this->entityTypeManager
->getStorage('digital_signage_device')
->getQuery()
->accessCheck(FALSE)
->condition('status', 1);
if ($deviceIds || $segmentIds) {
$subGroup = $query->orConditionGroup();
if ($deviceIds) {
$subGroup->condition('id', $deviceIds, 'IN');
}
if ($segmentIds) {
$subGroup->condition('segments.target_id', $segmentIds, 'IN');
}
$query->condition($subGroup);
}
// @todo Remember devices, this content has been published before on and
// update schedules for those too, where the content no longer gets
// published at.
// Retrieve and update all devices.
foreach ($query->execute() as $id) {
/** @var \Drupal\digital_signage_framework\DeviceInterface $device */
$device = Device::load($id);
$device->scheduleUpdate();
}
}
}
