This repository has been archived on 2025-01-19. You can view files and clone it, but cannot push or open issues or pull requests.
drupalcampbristol/web/modules/contrib/webform/includes/webform.editor.inc
2018-11-23 12:29:20 +00:00

268 lines
8.6 KiB
PHP

<?php
/**
* @file
* Webform module editor file upload hooks.
*
* Because Webforms are config entities the editor.module's file uploading
* is not supported.
*
* The below code adds file upload support to Webform config entities and
* 'webform.settings' config.
*
* Below functions are copied from editor.module.
*/
use Drupal\Core\Config\Config;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Serialization\Yaml;
use Drupal\webform\WebformInterface;
use Drupal\Component\Utility\Html;
/******************************************************************************/
// Webform entity hooks.
/******************************************************************************/
/**
* Implements hook_webform_insert().
*
* @see editor_entity_insert()
*/
function webform_webform_insert(WebformInterface $webform) {
$uuids = _webform_get_config_entity_file_uuids($webform);
_webform_record_file_usage($uuids, $webform->getEntityTypeId(), $webform->id());
}
/**
* Implements hook_webform_update().
*
* @see editor_entity_update()
*/
function webform_webform_update(WebformInterface $webform) {
$original_uuids = _webform_get_config_entity_file_uuids($webform->original);
$uuids = _webform_get_config_entity_file_uuids($webform);
// Detect file usages that should be incremented.
$added_files = array_diff($uuids, $original_uuids);
_webform_record_file_usage($added_files, $webform->getEntityTypeId(), $webform->id());
// Detect file usages that should be decremented.
$removed_files = array_diff($original_uuids, $uuids);
_webform_delete_file_usage($removed_files, $webform->getEntityTypeId(), $webform->id(), 1);
}
/**
* Implements hook_webform_delete().
*
* @see editor_entity_delete()
*/
function webform_webform_delete(WebformInterface $webform) {
$uuids = _webform_get_config_entity_file_uuids($webform);
_webform_delete_file_usage($uuids, $webform->getEntityTypeId(), $webform->id(), 0);
}
/******************************************************************************/
// Webform config (settings) hooks.
// @see \Drupal\webform\Form\AdminConfig\WebformAdminConfigBaseForm::loadConfig
// @see \Drupal\webform\Form\AdminConfig\WebformAdminConfigBaseForm::saveConfig
/******************************************************************************/
/**
* Update config editor file references.
*
* @param \Drupal\Core\Config\Config $config
* An editable configuration object.
*/
function _webform_config_update(Config $config) {
$original_uuids = _webform_get_array_file_uuids($config->getOriginal());
$uuids = _webform_get_array_file_uuids($config->getRawData());
// Detect file usages that should be incremented.
$added_files = array_diff($uuids, $original_uuids);
_webform_record_file_usage($added_files, 'config', $config->getName());
// Detect file usages that should be decremented.
$removed_files = array_diff($original_uuids, $uuids);
_webform_delete_file_usage($removed_files, 'config', $config->getName(), 1);
}
/**
* Delete config editor file references.
*
* @param \Drupal\Core\Config\Config $config
* An editable configuration object.
*
* @see webform_uninstall()
*/
function _webform_config_delete(Config $config) {
$uuids = _webform_get_array_file_uuids($config->getRawData());
_webform_delete_file_usage($uuids, 'config', $config->getName(), 0);
}
/******************************************************************************/
// Config entity functions.
/******************************************************************************/
/**
* Finds all files referenced (data-entity-uuid) by config entity.
*
* @param \Drupal\Core\Config\Entity\ConfigEntityInterface $entity
* An entity whose fields to analyze.
*
* @return array
* An array of file entity UUIDs.
*
* @see _editor_get_file_uuids_by_field()
*/
function _webform_get_config_entity_file_uuids(ConfigEntityInterface $entity) {
return _webform_get_array_file_uuids($entity->toArray());
}
/******************************************************************************/
// Config settings functions.
/******************************************************************************/
/**
* Finds all files referenced (data-entity-uuid) in an associatve array.
*
* @param array $data
* An associative array.
*
* @return array
* An array of file entity UUIDs.
*
* @see _editor_get_file_uuids_by_field()
*/
function _webform_get_array_file_uuids(array $data) {
$text = Yaml::encode($data);
return _webform_parse_file_uuids($text);
}
/******************************************************************************/
// File usage functions.
/******************************************************************************/
/**
* Records file usage of files referenced by formatted text fields.
*
* Every referenced file that does not yet have the FILE_STATUS_PERMANENT state,
* will be given that state.
*
* @param array $uuids
* An array of file entity UUIDs.
* @param string $type
* The type of the object that contains the referenced file.
* @param string $id
* The unique ID of the object containing the referenced file.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*
* @see _editor_record_file_usage()
*/
function _webform_record_file_usage(array $uuids, $type, $id) {
if (empty($uuids) || !\Drupal::moduleHandler()->moduleExists('file')) {
return;
}
/** @var \Drupal\file\FileUsage\FileUsageInterface $file_usage */
$file_usage = \Drupal::service('file.usage');
foreach ($uuids as $uuid) {
if ($file = \Drupal::entityManager()->loadEntityByUuid('file', $uuid)) {
if ($file->status !== FILE_STATUS_PERMANENT) {
$file->status = FILE_STATUS_PERMANENT;
$file->save();
}
$file_usage->add($file, 'editor', $type, $id);
}
}
}
/**
* Deletes file usage of files referenced by formatted text fields.
*
* @param array $uuids
* An array of file entity UUIDs.
* @param string $type
* The type of the object that contains the referenced file.
* @param string $id
* The unique ID of the object containing the referenced file.
* @param int $count
* The number of references to delete. Should be 1 when deleting a single
* revision and 0 when deleting an entity entirely.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*
* @see \Drupal\file\FileUsage\FileUsageInterface::delete()
* @see _editor_delete_file_usage()
*/
function _webform_delete_file_usage(array $uuids, $type, $id, $count) {
if (empty($uuids) || !\Drupal::moduleHandler()->moduleExists('file')) {
return;
}
/** @var \Drupal\file\FileUsage\FileUsageInterface $file_usage */
$file_usage = \Drupal::service('file.usage');
$make_unused_managed_files_temporary = \Drupal::config('webform.settings')->get('html_editor.make_unused_managed_files_temporary');
foreach ($uuids as $uuid) {
if ($file = \Drupal::entityManager()->loadEntityByUuid('file', $uuid)) {
$file_usage->delete($file, 'editor', $type, $id, $count);
// Make unused files temporary.
if ($make_unused_managed_files_temporary && empty($file_usage->listUsage($file)) && !$file->isTemporary()) {
$file->setTemporary();
$file->save();
}
}
}
}
/******************************************************************************/
// File parsing functions.
/******************************************************************************/
/**
* Parse an HTML snippet for any linked file with data-entity-uuid attributes.
*
* @param string $text
* The partial (X)HTML snippet to load. Invalid markup will be corrected on
* import.
*
* @return array
* An array of all found UUIDs.
*
* @see _editor_parse_file_uuids()
*/
function _webform_parse_file_uuids($text) {
if (strpos($text, 'data-entity-uuid') === FALSE) {
return [];
}
$uuids = [];
// Get all images using a regex.
if (preg_match_all('/<img[^>]+>/', $text, $matches)) {
foreach ($matches[0] as $img) {
// Cleanup quotes escaped via YAML.
// Please note, calling stripslashes() twice because elements are
// double escaped.
$img = stripslashes(stripslashes($img));
// Create a DomElement so that we can parse the image's attributes.
$dom_node = Html::load($img)->getElementsByTagName('img')->item(0);
// Get the entity type and uuid.
$type = $dom_node->getAttribute('data-entity-type');
$uuid = $dom_node->getAttribute('data-entity-uuid');
// Check the image is a file entity with a uuid.
if ($type === 'file' && $uuid) {
$uuids[] = $uuid;
}
}
}
// Use array_unique() to collect one uuid per uploaded file.
// This prevents cut-n-pasted uploaded files from having multiple usages.
return array_unique($uuids);
}