View source
<?php
namespace Drupal\background_image;
use Drupal\Component\Utility\Color;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\File\Exception\FileException;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Image\ImageFactory;
use Drupal\Core\Image\ImageInterface;
use Drupal\Core\Routing\ResettableStackedRouteMatchInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\file\FileInterface;
use Drupal\imagemagick\Plugin\ImageToolkit\ImagemagickToolkit;
use Drupal\system\Plugin\ImageToolkit\GDToolkit;
use Drupal\views\ViewEntityInterface;
use Drupal\views\Views;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
class BackgroundImageManager implements BackgroundImageManagerInterface {
use ContainerAwareTrait;
use DependencySerializationTrait;
use StringTranslationTrait;
protected $backgroundImages;
protected $config;
protected $entityRepository;
protected $entityTypeBundleInfo;
protected $entityTypeManager;
protected $fileSystem;
protected $imageFactory;
protected $moduleHandler;
protected $responsiveImageStyle;
protected $routeMatch;
protected $state;
protected $storage;
protected $urlGenerator;
protected $viewBuilder;
public function __construct(ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityTypeManagerInterface $entity_type_manager, FileSystemInterface $file_system, ImageFactory $image_factory, ModuleHandlerInterface $module_handler, ResettableStackedRouteMatchInterface $route_match, StateInterface $state, UrlGeneratorInterface $url_generator) {
$this->config = $config_factory
->get('background_image.settings');
$this->entityRepository = $entity_repository;
$this->entityTypeBundleInfo = $entity_type_bundle_info;
$this->entityTypeManager = $entity_type_manager;
$this->fileSystem = $file_system;
$this->imageFactory = $image_factory;
$this->moduleHandler = $module_handler;
$this->routeMatch = $route_match;
$this->state = $state;
$this->urlGenerator = $url_generator;
$this->storage = $this->entityTypeManager
->getStorage('background_image');
$this->viewBuilder = $this->entityTypeManager
->getViewBuilder('background_image');
}
public static function create(ContainerInterface $container) {
return new self($container
->get('config.factory'), $container
->get('entity.repository'), $container
->get('entity_type.bundle.info'), $container
->get('entity_type.manager'), $container
->get('file_system'), $container
->get('image.factory'), $container
->get('module_handler'), $container
->get('current_route_match'), $container
->get('state'), $container
->get('url_generator.non_bubbling'));
}
public function alterEntityForm(array &$form, FormStateInterface $form_state) {
$inline_entity_form = $this->moduleHandler
->moduleExists('inline_entity_form');
$entity = $form_state
->get('inline_entity_form_entity');
if (!$inline_entity_form || !$entity) {
return;
}
$group = $this
->getEntityConfig($entity, 'group');
$require = $this
->getEntityConfig($entity, 'require');
$background_image = $this
->getEntityBackgroundImage($entity);
$form['background_image'] = [
'#type' => 'details',
'#theme_wrappers' => [
'details__background_image',
],
'#title' => $this
->t('Background Image'),
'#open' => !$require && $group ? FALSE : TRUE,
'#group' => $group,
'#weight' => $group ? NULL : 100,
'#tree' => TRUE,
];
$form['background_image']['inline_entity_form'] = [
'#theme_wrappers' => NULL,
'#type' => 'inline_entity_form',
'#entity_type' => 'background_image',
'#langcode' => $entity
->language()
->getId(),
'#default_value' => $background_image,
];
}
public function cacheFlush() {
$this->fileSystem
->scanDirectory('public://background_image/css', '/.*/', [
'callback' => function ($uri) {
try {
@$this->fileSystem
->deleteRecursive($uri);
} catch (FileException $e) {
}
},
]);
}
public function colorIsDark($hex = NULL) {
if (!isset($hex)) {
return FALSE;
}
$rgb = array_values(Color::hexToRgb($hex));
return 0.213 * $rgb[0] + 0.715 * $rgb[1] + 0.07199999999999999 * $rgb[2] < 255 / 2;
}
public function colorSampleFile(FileInterface $file = NULL, $default = NULL) {
return isset($file) ? $this
->colorSampleImage($this->imageFactory
->get($file
->getFileUri()), $default) : $default;
}
public function colorSampleImage(ImageInterface $image, $default = NULL) {
if (!$image
->isValid()) {
return $default;
}
$toolkit = $image
->getToolkit();
if ($toolkit instanceof GDToolkit) {
return $this
->colorSampleGdImage($toolkit, $default);
}
else {
if ($toolkit instanceof ImagemagickToolkit) {
return $this
->colorSampleImagemagickImage($toolkit, $default);
}
}
return $default;
}
protected function colorSampleGdImage(GDToolkit $image, $default = NULL) {
if ($image
->apply('resize', [
'width' => 1,
'height' => 1,
]) && ($resource = $image
->getResource())) {
return @Color::rgbToHex(array_slice(@imagecolorsforindex($resource, @imagecolorat($resource, 0, 0)), 0, 3)) ?: $default;
}
return $default;
}
protected function colorSampleImagemagickImage(ImagemagickToolkit $image, $default = NULL) {
$exec_manager = \Drupal::service('imagemagick.exec_manager');
$arguments = (new \ReflectionClass('\\Drupal\\imagemagick\\ImagemagickExecArguments'))
->newInstance($exec_manager)
->setSourceLocalPath($this->fileSystem
->realpath($image
->getSource()));
$arguments
->add('-resize 1x1\\!')
->add('-format "%[fx:int(255*r+.5)],%[fx:int(255*g+.5)],%[fx:int(255*b+.5)]"')
->add('info:-');
if ($exec_manager
->execute('convert', $arguments, $output, $error)) {
return @Color::rgbToHex(explode(',', $output)) ?: $default;
}
return $default;
}
public function getBackgroundImage($langcode = NULL, array $context = []) {
$hash = Crypt::hashBase64(serialize(func_get_args()));
if (!isset($this->backgroundImages[$hash])) {
if ($entity = $this
->getEntityFromCurrentRoute()) {
if ($entity instanceof EntityInterface && ($this->backgroundImages[$hash] = $this
->getEntityBackgroundImage($entity, $langcode, $context))) {
return $this->backgroundImages[$hash];
}
else {
if ($entity instanceof EntityInterface && ($this->backgroundImages[$hash] = $this
->getEntityBundleBackgroundImage($entity, $langcode, $context))) {
return $this->backgroundImages[$hash];
}
else {
if ($entity instanceof ViewEntityInterface && ($this->backgroundImages[$hash] = $this
->getViewBackgroundImage($entity, $langcode, $context))) {
return $this->backgroundImages[$hash];
}
}
}
}
$this->backgroundImages[$hash] = $this
->getGlobalBackgroundImage($langcode, $context) ?: FALSE;
}
return $this->backgroundImages[$hash];
}
public function getBaseClass() {
return Html::cleanCssIdentifier(preg_replace('/^(\\.|#)/', '', $this->config
->get('css.base_class') ?: 'background-image'));
}
public function getCssMinifier() {
return \Drupal::getContainer()
->get('advagg.css_minifier', ContainerInterface::NULL_ON_INVALID_REFERENCE);
}
public function getDefaultSettings() {
return NestedArray::mergeDeep([
'blur' => [
'type' => 2,
'radius' => 50,
'speed' => 1,
],
'dark' => FALSE,
'full_viewport' => FALSE,
'preload' => [
'background_color' => '#ffffff',
],
'text' => [
'format' => 'full_html',
'value' => '',
],
], $this->config
->get('defaults') ?: []);
}
public function getEnabledEntityTypes() {
$supported = $this
->getSupportedEntityTypes();
$enabled = [];
foreach ($supported as $entity_type) {
if (array_filter($this
->getEnabledEntityTypeBundles($entity_type))) {
$enabled[$entity_type
->id()] = TRUE;
}
}
return array_intersect_key($supported, $enabled);
}
public function getEnabledEntityTypeBundles(EntityTypeInterface $entity_type) {
$enabled = $this
->getEntityConfigArray($entity_type, NULL, 'enable');
$bundles = $this
->getEntityTypeBundles($entity_type);
if (empty($enabled[$entity_type
->id()]) || !$bundles) {
return [];
}
return array_intersect_key($bundles, $enabled[$entity_type
->id()]);
}
public function getEntityBackgroundImage(EntityInterface $entity, $langcode = NULL, array $context = []) {
if ($this
->validEntity($entity)) {
$entity_type = $entity
->getEntityType();
$result = $this->storage
->loadByProperties([
'type' => BackgroundImageInterface::TYPE_ENTITY,
'target' => $entity_type
->id() . ':' . $entity
->uuid(),
]);
if ($backgroundImage = reset($result)) {
return $this->entityRepository
->getTranslationFromContext($backgroundImage, $langcode, $context);
}
}
return NULL;
}
public function getEntityBundleBackgroundImage(EntityInterface $entity, $langcode = NULL, array $context = []) {
if ($bundle_entity_type = $entity
->getEntityType()
->getBundleEntityType()) {
$result = $this->storage
->loadByProperties([
'type' => BackgroundImageInterface::TYPE_ENTITY_BUNDLE,
'target' => $entity
->getEntityTypeId() . ':' . $entity
->bundle(),
]);
if ($backgroundImage = reset($result)) {
return $this->entityRepository
->getTranslationFromContext($backgroundImage, $langcode, $context);
}
}
return NULL;
}
public function getEntityBundleLabel(EntityInterface $entity) {
$bundles = $info = $this
->getEnabledEntityTypeBundles($entity
->getEntityType());
if (isset($bundles[$entity
->bundle()]['label'])) {
return $bundles[$entity
->bundle()]['label'];
}
}
public function getEntityConfig(EntityInterface $entity, $property) {
$entity_type = $entity
->getEntityTypeId();
$bundle = $entity
->bundle();
$config = $this
->getEntityConfigArray($entity_type, $bundle, $property);
return isset($config[$entity_type][$bundle]) ? $config[$entity_type][$bundle] : NULL;
}
public function getEntityConfigArray($entity_type = NULL, $bundle = NULL, $property = NULL, $filter = TRUE) {
if ($entity_type instanceof EntityInterface) {
$entity_type = $entity_type
->getEntityTypeId();
}
else {
if ($entity_type instanceof EntityTypeInterface) {
$entity_type = $entity_type
->id();
}
}
$entity_type = (string) $entity_type;
if (!$property) {
$keys = [
'entities',
];
if ($entity_type) {
$keys[] = $entity_type;
if ($bundle) {
$keys[] = (string) $bundle;
}
}
$config = $this->config
->get(implode('.', $keys)) ?: [];
return $filter ? array_filter($config) : $config;
}
$properties = [];
foreach ($this->config
->get('entities') as $t => $bundles) {
if ($entity_type && $entity_type !== $t) {
continue;
}
foreach ($bundles as $b => $data) {
if ($bundle && $bundle !== $b) {
continue;
}
foreach ($data as $key => $value) {
if ($key === $property) {
$properties[$t][$b] = $value;
}
}
if ($filter) {
$properties[$t] = array_filter($properties[$t]);
}
}
if ($filter) {
$properties = array_filter($properties);
}
}
return $properties;
}
public function getEntityFromCurrentRoute($entity_type = NULL, $bundle = NULL) {
$entity = NULL;
$parameters = $this->routeMatch
->getParameters();
if ($entity_type && $entity_type !== 'view' && ($parameter = $parameters
->get($entity_type)) && $this
->validEntity($parameter)) {
$entity = $parameter;
}
else {
if (($view_id = $parameters
->get('view_id')) && ($display_id = $parameters
->get('display_id')) && ($view = $this->entityTypeManager
->getStorage('view')
->load($view_id))) {
$executable = $view
->getExecutable();
$executable
->setDisplay($display_id);
$entity = $view;
}
else {
foreach ($parameters
->all() as $parameter) {
if ($parameter instanceof EntityInterface && $this
->validEntity($parameter)) {
$entity = $parameter;
break;
}
}
}
}
if (!isset($bundle)) {
return $entity;
}
return $entity
->bundle() === $bundle ? $entity : NULL;
}
public function getEntityTypeBundleEntityType(EntityTypeInterface $entity_type) {
if ($bundle_entity_type = $entity_type
->getBundleEntityType()) {
return $this->entityTypeManager
->getDefinition($bundle_entity_type);
}
return NULL;
}
public function getEntityTypeBundles(EntityTypeInterface $entity_type) {
return $this->entityTypeBundleInfo
->getBundleInfo($entity_type
->id());
}
public function getFallbackImageStyle() {
$image_style = $this->config
->get('image_style.fallback') ?: 'background_image_lg';
if ($responsive_image_style = $this
->getResponsiveImageStyle()) {
return $responsive_image_style
->getFallbackImageStyle() ?: $image_style;
}
return $image_style;
}
public function getGlobalBackgroundImage($langcode = NULL, array $context = []) {
$result = $this->storage
->loadByProperties([
'type' => BackgroundImageInterface::TYPE_GLOBAL,
]);
if ($backgroundImage = reset($result)) {
return $this->entityRepository
->getTranslationFromContext($backgroundImage, $langcode, $context);
}
return NULL;
}
public function getPreloadImageStyle() {
return $this->config
->get('image_style.preload') ?: 'background_image_preload';
}
public function getResponsiveImageStyle() {
if (!isset($this->responsiveImageStyle)) {
$this->responsiveImageStyle = $this->moduleHandler
->moduleExists('responsive_image') ? $this->entityTypeManager
->getStorage('responsive_image_style')
->load($this->config
->get('image_style.responsive') ?: 'background_image') : NULL;
}
return $this->responsiveImageStyle;
}
public function getRetinaRules() {
return $this->config
->get('css.retina_rules') ?: [];
}
public function getSupportedEntityTypes() {
static $entity_types;
if (!isset($entity_types)) {
$allowed_entity_types = [
'view',
];
foreach ($this->entityTypeManager
->getDefinitions() as $entity_type) {
$full_page = $entity_type
->hasViewBuilderClass() && $entity_type
->hasLinkTemplate('canonical') && $entity_type
->getLinkTemplate('canonical') !== $entity_type
->getLinkTemplate('edit-form');
if (in_array($entity_type
->id(), $allowed_entity_types) || $full_page) {
$entity_types[$entity_type
->id()] = $entity_type;
}
}
}
return $entity_types;
}
public function getViewBackgroundImage(ViewEntityInterface $view, $langcode = NULL, array $context = []) {
if ($this
->validView($view)) {
$result = $this->storage
->loadByProperties([
'type' => BackgroundImageInterface::TYPE_VIEW,
'target' => "{$view->id()}:{$view->getExecutable()->current_display}",
]);
if ($backgroundImage = reset($result)) {
return $this->entityRepository
->getTranslationFromContext($backgroundImage, $langcode, $context);
}
}
return NULL;
}
public function getViewsPages() {
static $views;
if (!isset($views)) {
$views = [];
if (!$this->moduleHandler
->moduleExists('views')) {
return $views;
}
foreach (Views::getEnabledViews() as $view_id => $view) {
$displays = $view
->get('display');
foreach ($displays as $display_id => $display) {
if ($display['display_plugin'] === 'page') {
$id = "{$view_id}:{$display_id}";
if (isset($display['display_options']['menu']['title'])) {
$views[$id] = $display['display_options']['menu']['title'] . " ({$id})";
}
else {
$label = $view
->label();
if (isset($display['display_title']) && $display['display_title'] !== 'Page') {
$label .= ' - ' . $display['display_title'];
}
$views[$id] = $label . " ({$id})";
}
}
}
}
ksort($views, SORT_NATURAL);
}
return $views;
}
public function prepareEntityForm(EntityInterface $entity, $operation, FormStateInterface $form_state) {
if ($entity
->bundle() === 'view' || !$this
->validEntity($entity) || !($operation === 'default' || $operation === 'add' || $operation === 'edit')) {
return;
}
$form_state
->set('inline_entity_form_entity', $entity);
}
public static function service() {
return \Drupal::service('background_image.manager');
}
public function useMinifiedCssUri() {
return \Drupal::config('system.performance')
->get('css.preprocess') && $this
->getCssMinifier();
}
public function validEntity(EntityInterface $entity) {
if (!in_array($entity
->bundle(), array_keys($this
->getEnabledEntityTypeBundles($entity
->getEntityType())))) {
return FALSE;
}
if (!in_array($entity
->getEntityTypeId(), array_keys($this
->getEnabledEntityTypes()))) {
return FALSE;
}
return TRUE;
}
public function validView(ViewEntityInterface $view) {
if (!in_array("{$view->id()}:{$view->getExecutable()->current_display}", array_keys($this
->getViewsPages()))) {
return FALSE;
}
return TRUE;
}
public function view($background_image, $view_mode = 'full', $langcode = NULL) {
return $this->viewBuilder
->view($background_image, $view_mode, $langcode);
}
}