619 lines
16 KiB
PHP
619 lines
16 KiB
PHP
<?php
|
|
|
|
namespace Drupal\blazy;
|
|
|
|
use Drupal\Core\Cache\Cache;
|
|
use Drupal\Core\Cache\CacheBackendInterface;
|
|
use Drupal\Core\Config\ConfigFactoryInterface;
|
|
use Drupal\Core\Entity\EntityRepositoryInterface;
|
|
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
|
use Drupal\Core\Extension\ModuleHandlerInterface;
|
|
use Drupal\Core\Render\RendererInterface;
|
|
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
|
|
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
|
use Drupal\blazy\Cache\BlazyCache;
|
|
use Drupal\blazy\Media\BlazyImage;
|
|
use Drupal\blazy\Media\BlazyResponsiveImage;
|
|
use Drupal\blazy\Utility\Check;
|
|
use Drupal\blazy\Utility\Path;
|
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
|
|
|
/**
|
|
* Provides common shared methods across Blazy ecosystem to DRY.
|
|
*
|
|
* @todo extends BlazyBase at or by 3.x, and remove most non-media methods.
|
|
*/
|
|
abstract class BlazyManagerBase implements BlazyManagerInterface {
|
|
|
|
// Fixed for EB AJAX issue: #2893029.
|
|
use DependencySerializationTrait;
|
|
use StringTranslationTrait;
|
|
|
|
/**
|
|
* The app root.
|
|
*
|
|
* @var \SplString
|
|
*/
|
|
protected $root;
|
|
|
|
/**
|
|
* The entity repository service.
|
|
*
|
|
* @var \Drupal\Core\Entity\EntityRepositoryInterface
|
|
*/
|
|
protected $entityRepository;
|
|
|
|
/**
|
|
* The entity type manager service.
|
|
*
|
|
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
|
*/
|
|
protected $entityTypeManager;
|
|
|
|
/**
|
|
* The module handler service.
|
|
*
|
|
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
|
*/
|
|
protected $moduleHandler;
|
|
|
|
/**
|
|
* The renderer.
|
|
*
|
|
* @var \Drupal\Core\Render\RendererInterface
|
|
*/
|
|
protected $renderer;
|
|
|
|
/**
|
|
* The config factory.
|
|
*
|
|
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
|
*/
|
|
protected $configFactory;
|
|
|
|
/**
|
|
* The cache backend.
|
|
*
|
|
* @var \Drupal\Core\Cache\CacheBackendInterface
|
|
*/
|
|
protected $cache;
|
|
|
|
/**
|
|
* The language manager.
|
|
*
|
|
* @var \Drupal\Core\Language\LanguageManager
|
|
*/
|
|
protected $languageManager;
|
|
|
|
/**
|
|
* The cached data.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $cachedData;
|
|
|
|
/**
|
|
* Constructs a BlazyManager object.
|
|
*/
|
|
public function __construct($root, EntityRepositoryInterface $entity_repository, EntityTypeManagerInterface $entity_type_manager, ModuleHandlerInterface $module_handler, RendererInterface $renderer, ConfigFactoryInterface $config_factory, CacheBackendInterface $cache) {
|
|
$this->root = $root;
|
|
$this->entityRepository = $entity_repository;
|
|
$this->entityTypeManager = $entity_type_manager;
|
|
$this->moduleHandler = $module_handler;
|
|
$this->renderer = $renderer;
|
|
$this->configFactory = $config_factory;
|
|
$this->cache = $cache;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public static function create(ContainerInterface $container) {
|
|
$instance = new static(
|
|
Blazy::root($container),
|
|
$container->get('entity.repository'),
|
|
$container->get('entity_type.manager'),
|
|
$container->get('module_handler'),
|
|
$container->get('renderer'),
|
|
$container->get('config.factory'),
|
|
$container->get('cache.default')
|
|
);
|
|
|
|
// @todo remove and use DI at 2.x+ post sub-classes updates.
|
|
$instance->setLanguageManager($container->get('language_manager'));
|
|
return $instance;
|
|
}
|
|
|
|
/**
|
|
* Sets the language manager service.
|
|
*
|
|
* @todo remove and use DI at 3.x+ post sub-classes updates.
|
|
*/
|
|
public function setLanguageManager($language_manager) {
|
|
$this->languageManager = $language_manager;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Returns the entity repository service.
|
|
*
|
|
* @todo deprecated for BlazyInterface::entityRepository once extended.
|
|
*/
|
|
public function getEntityRepository() {
|
|
return $this->entityRepository;
|
|
}
|
|
|
|
/**
|
|
* Returns the entity type manager.
|
|
*
|
|
* @todo deprecated for BlazyInterface::entityTypeManager once extended.
|
|
*/
|
|
public function getEntityTypeManager() {
|
|
return $this->entityTypeManager;
|
|
}
|
|
|
|
/**
|
|
* Returns the module handler.
|
|
*
|
|
* @todo deprecated for BlazyInterface::moduleHandler once extended.
|
|
*/
|
|
public function getModuleHandler() {
|
|
return $this->moduleHandler;
|
|
}
|
|
|
|
/**
|
|
* Returns the renderer.
|
|
*
|
|
* @todo deprecated for BlazyInterface::renderer once extended.
|
|
*/
|
|
public function getRenderer() {
|
|
return $this->renderer;
|
|
}
|
|
|
|
/**
|
|
* Returns the config factory.
|
|
*
|
|
* @todo deprecated for BlazyInterface::configFactory once extended.
|
|
*/
|
|
public function getConfigFactory() {
|
|
return $this->configFactory;
|
|
}
|
|
|
|
/**
|
|
* Returns the cache.
|
|
*
|
|
* @todo deprecated for BlazyInterface::cache once extended.
|
|
*/
|
|
public function getCache() {
|
|
return $this->cache;
|
|
}
|
|
|
|
/**
|
|
* Returns any config, or keyed by the $setting_name.
|
|
*
|
|
* @todo deprecated for BlazyInterface::config once extended.
|
|
*/
|
|
public function configLoad($setting_name = '', $settings = 'blazy.settings') {
|
|
$config = $this->configFactory->get($settings);
|
|
$configs = $config->get();
|
|
unset($configs['_core']);
|
|
return empty($setting_name) ? $configs : $config->get($setting_name);
|
|
}
|
|
|
|
/**
|
|
* Returns a shortcut for loading a config entity: image_style, slick, etc.
|
|
*
|
|
* @todo deprecated for BlazyInterface::load once extended.
|
|
*/
|
|
public function entityLoad($id, $type = 'image_style') {
|
|
return $this->getStorage($type)->load($id);
|
|
}
|
|
|
|
/**
|
|
* Returns a shortcut for loading multiple configuration entities.
|
|
*
|
|
* @todo deprecated for BlazyInterface::loadMultiple once extended.
|
|
*/
|
|
public function entityLoadMultiple($type = 'image_style', $ids = NULL) {
|
|
return $this->getStorage($type)->loadMultiple($ids);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function attach(array $attach = []) {
|
|
$load = [];
|
|
Check::attachments($load, $attach);
|
|
|
|
$this->moduleHandler->alter('blazy_attach', $load, $attach);
|
|
return $load;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getIoSettings(array $attach = []): object {
|
|
$io = [];
|
|
$thold = $this->configLoad('io.threshold');
|
|
$thold = str_replace(['[', ']'], '', trim($thold ?: '0'));
|
|
|
|
// @todo re-check, looks like the default 0 is broken sometimes.
|
|
if ($thold == '0') {
|
|
$thold = '0, 0.25, 0.5, 0.75, 1';
|
|
}
|
|
|
|
$thold = strpos($thold, ',') !== FALSE
|
|
? array_map('trim', explode(',', $thold)) : [$thold];
|
|
$formatted = [];
|
|
foreach ($thold as $value) {
|
|
$formatted[] = strpos($value, '.') !== FALSE ? (float) $value : (int) $value;
|
|
}
|
|
|
|
// Respects hook_blazy_attach_alter() for more fine-grained control.
|
|
foreach (['disconnect', 'rootMargin', 'threshold'] as $key) {
|
|
$default = $key == 'rootMargin' ? '0px' : FALSE;
|
|
$value = $key == 'threshold' ? $formatted : $this->configLoad('io.' . $key);
|
|
$io[$key] = $attach['io.' . $key] ?? ($value ?: $default);
|
|
}
|
|
|
|
return (object) $io;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getImageEffects(): array {
|
|
$cid = 'blazy_image_effects';
|
|
$effects[] = 'blur';
|
|
return $this->getCachedData($cid, $effects);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getLightboxes(): array {
|
|
$cid = 'blazy_lightboxes';
|
|
$data = BlazyCache::lightboxes($this->root);
|
|
return $this->getCachedData($cid, $data);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getStyles(): array {
|
|
$styles = [
|
|
'column' => 'CSS3 Columns',
|
|
'grid' => 'Grid Foundation',
|
|
'flex' => 'Flexbox Masonry',
|
|
'nativegrid' => 'Native Grid',
|
|
];
|
|
$this->moduleHandler->alter('blazy_style', $styles);
|
|
return $styles;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function getThumbnail(array $settings, $item = NULL) {
|
|
return BlazyImage::thumbnail($settings, $item);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function isBlazy(array &$settings, array $data = []): void {
|
|
Check::blazyOrNot($settings, $data);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function prepareData(array &$build, $entity = NULL): void {
|
|
// Do nothing, let extenders share data at ease as needed.
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function preSettings(array &$settings): void {
|
|
Blazy::verify($settings);
|
|
|
|
$blazies = $settings['blazies'];
|
|
$ui = array_intersect_key($this->configLoad(), BlazyDefault::uiSettings());
|
|
$iframe_domain = $this->configLoad('iframe_domain', 'media.settings');
|
|
$is_debug = !$this->configLoad('css.preprocess', 'system.performance');
|
|
$ui['fx'] = $ui['fx'] ?? '';
|
|
$ui['fx'] = empty($settings['fx']) ? $ui['fx'] : $settings['fx'];
|
|
$ui['blur_minwidth'] = (int) ($ui['blur_minwidth'] ?? 0);
|
|
$fx = $settings['_fx'] ?? $ui['fx'];
|
|
$fx = $blazies->get('fx', $fx);
|
|
$language = $this->languageManager->getCurrentLanguage()->getId();
|
|
$lightboxes = $this->getLightboxes();
|
|
$lightboxes = $blazies->get('lightbox.plugins', $lightboxes) ?: [];
|
|
$is_blur = $fx == 'blur';
|
|
$is_resimage = $this->moduleExists('responsive_image');
|
|
|
|
$blazies->set('fx', $fx)
|
|
->set('iframe_domain', $iframe_domain)
|
|
->set('is.blur', $is_blur)
|
|
->set('is.debug', $is_debug)
|
|
->set('is.resimage', $is_resimage)
|
|
->set('is.unblazy', $this->configLoad('io.unblazy'))
|
|
->set('language.current', $language)
|
|
->set('libs.animate', $fx)
|
|
->set('libs.blur', $is_blur)
|
|
->set('lightbox.plugins', $lightboxes)
|
|
->set('ui', $ui);
|
|
|
|
if ($router = Path::routeMatch()) {
|
|
$settings['route_name'] = $route_name = $router->getRouteName();
|
|
$blazies->set('route_name', $route_name);
|
|
}
|
|
|
|
// Sub-modules may need to provide their data to be consumed here.
|
|
// Basicaly needs basic UI and definitions above to supply data properly,
|
|
// such as to determine Slick/ Splide own lazy load methods based on UI.
|
|
$this->preSettingsData($settings);
|
|
|
|
// Preliminary globals when using the provided API.
|
|
Blazy::preSettings($settings);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function postSettings(array &$settings): void {
|
|
Blazy::postSettings($settings);
|
|
|
|
// Sub-modules may need to override Blazy definitions.
|
|
$this->postSettingsData($settings);
|
|
}
|
|
|
|
/**
|
|
* Overrides data massaged by [blazy|slick|splide, etc.]_settings_alter().
|
|
*/
|
|
public function postSettingsAlter(array &$settings, $entity = NULL): void {
|
|
Check::settingsAlter($settings, $entity);
|
|
}
|
|
|
|
/**
|
|
* Provides data to be consumed by Blazy::preSettings().
|
|
*
|
|
* Such as to provide lazy attribute and class for Slick or Splide, etc.
|
|
*/
|
|
protected function preSettingsData(array &$settings): void {
|
|
// Do nothing, let extenders input data at ease as needed.
|
|
}
|
|
|
|
/**
|
|
* Overrides data massaged by Blazy::postSettings().
|
|
*/
|
|
protected function postSettingsData(array &$settings): void {
|
|
// Do nothing, let extenders override data at ease as needed.
|
|
}
|
|
|
|
/**
|
|
* Provides attachments and cache common for all blazy-related modules.
|
|
*/
|
|
protected function setAttachments(
|
|
array &$element,
|
|
array $settings,
|
|
array $attachments = []
|
|
): void {
|
|
$cache = $this->getCacheMetadata($settings);
|
|
$attached = $this->attach($settings);
|
|
$attachments = Blazy::merge($attached, $attachments);
|
|
$element['#attached'] = Blazy::merge($attachments, $element, '#attached');
|
|
$element['#cache'] = Blazy::merge($cache, $element, '#cache');
|
|
}
|
|
|
|
/**
|
|
* Builds an entity query.
|
|
*/
|
|
private function buildPropertyQuery($query, array $values, $condition = 'IN'): void {
|
|
foreach ($values as $name => $value) {
|
|
// Cast scalars to array so we can consistently use an IN condition.
|
|
$query->condition($name, (array) $value, $condition);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function root() {
|
|
return $this->root;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function languageManager() {
|
|
return $this->languageManager;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function getStorage($type = 'media') {
|
|
return $this->entityTypeManager->getStorage($type);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function entityQuery($type, $conjunction = 'AND') {
|
|
return $this->getStorage($type)->getQuery($conjunction);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function loadByProperties(
|
|
array $values,
|
|
$type = 'file',
|
|
$access = TRUE,
|
|
$conjunction = 'AND',
|
|
$condition = 'IN'
|
|
): array {
|
|
$storage = $this->getStorage($type);
|
|
$query = $storage->getQuery($conjunction);
|
|
|
|
$query->accessCheck($access);
|
|
$this->buildPropertyQuery($query, $values, $condition);
|
|
|
|
$result = $query->execute();
|
|
return $result ? $storage->loadMultiple($result) : [];
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function loadByUuid($uuid, $type = 'file') {
|
|
return $this->entityRepository->loadEntityByUuid($type, $uuid);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function getCachedData(
|
|
$cid,
|
|
array $data = [],
|
|
$reset = FALSE,
|
|
$alter = NULL,
|
|
array $context = []
|
|
): array {
|
|
if (!isset($this->cachedData[$cid]) || $reset) {
|
|
$cache = $this->cache->get($cid);
|
|
if (!$reset && $cache && $result = $cache->data) {
|
|
$this->cachedData[$cid] = $result;
|
|
}
|
|
else {
|
|
// Allows empty array to trigger hook_alter.
|
|
if (is_array($data)) {
|
|
$this->moduleHandler->alter($alter ?: $cid, $data, $context);
|
|
}
|
|
|
|
// Only if we have data, cache them.
|
|
if ($data && is_array($data)) {
|
|
if (isset($data[1])) {
|
|
$data = array_unique($data);
|
|
}
|
|
|
|
ksort($data);
|
|
|
|
$count = count($data);
|
|
$tags = Cache::buildTags($cid, ['count:' . $count]);
|
|
$this->cache->set($cid, $data, Cache::PERMANENT, $tags);
|
|
}
|
|
|
|
$this->cachedData[$cid] = $data;
|
|
}
|
|
}
|
|
return $this->cachedData[$cid] ? array_filter($this->cachedData[$cid]) : [];
|
|
}
|
|
|
|
/**
|
|
* Alias for BlazyCache::metadata() to forget looking up unknown classes.
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function getCacheMetadata(array $build = []) {
|
|
return BlazyCache::metadata($build);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function getLibrariesPath($name, $base_path = FALSE): ?string {
|
|
return Blazy::getLibrariesPath($name, $base_path);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function getPath($type, $name, $absolute = FALSE): ?string {
|
|
return Blazy::getPath($type, $name, $absolute);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function moduleExists($name): bool {
|
|
return $this->moduleHandler->moduleExists($name);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* @todo remove for BlazyInterface once extended.
|
|
*/
|
|
public function toGrid(array $items, array $settings): array {
|
|
return Blazy::grid($items, $settings);
|
|
}
|
|
|
|
/**
|
|
* Collects defined skins as registered via hook_MODULE_NAME_skins_info().
|
|
*
|
|
* @todo remove for sub-modules own skins as plugins at blazy:8.x-2.1+.
|
|
* @see https://www.drupal.org/node/2233261
|
|
* @see https://www.drupal.org/node/3105670
|
|
*/
|
|
public function buildSkins($namespace, $skin_class, $methods = []) {
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* Deprecated method, not safe to remove before 3.x for being generic.
|
|
*
|
|
* @deprecated in blazy:8.x-2.5 and is removed from blazy:3.0.0. Use
|
|
* BlazyResponsiveImage::styles() instead.
|
|
* @see https://www.drupal.org/node/3103018
|
|
*/
|
|
public function getResponsiveImageStyles($responsive) {
|
|
return BlazyResponsiveImage::styles($responsive);
|
|
}
|
|
|
|
/**
|
|
* Deprecated method, safe to remove before 3.x for being too specific.
|
|
*
|
|
* @deprecated in blazy:8.x-2.9 and is removed from blazy:3.0.0. Use
|
|
* self::postSettings() instead.
|
|
* @see https://www.drupal.org/node/3103018
|
|
*/
|
|
public function getCommonSettings(array &$settings = []) {
|
|
$this->postSettings($settings);
|
|
}
|
|
|
|
/**
|
|
* Deprecated method, safe to remove before 3.x for being too specific.
|
|
*
|
|
* @deprecated in blazy:8.x-2.9 and is removed from blazy:3.0.0. Use
|
|
* BlazyEntity::settings() instead.
|
|
* @see https://www.drupal.org/node/3103018
|
|
*/
|
|
public function getEntitySettings(array &$settings, $entity) {
|
|
BlazyEntity::settings($settings, $entity);
|
|
}
|
|
|
|
}
|