foldershare-8.x-1.2/src/Plugin/Field/FieldFormatter/FolderShareInternalFolderName.php
src/Plugin/Field/FieldFormatter/FolderShareInternalFolderName.php
<?php
namespace Drupal\foldershare\Plugin\Field\FieldFormatter;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Component\Utility\Html;
use Drupal\user\Entity\User;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\foldershare\Branding;
use Drupal\foldershare\Constants;
use Drupal\foldershare\Entity\FolderShare;
use Drupal\foldershare\Entity\FolderShareAccessControlHandler;
/**
* Formats a FolderShare folder entity name with a link and icon.
*
* <B>Warning:</B> This field formatter is strictly internal to the FolderShare
* module. The formatter's existance, name, and content may change from
* release to release without any promise of backwards compatability.
*
* The folder entity name may be formatted to include:
* - An anchor around the name that links to the entity's page.
* - Classes that themes use to add a file/folder MIME type icon.
*
* Hidden, disabled, and non-folder items are returned without links or
* data attributes and are marked as hidden or disabled. All other folders
* are linked and include data attributes needed by the user interface.
*
* @ingroup foldershare
*
* @FieldFormatter(
* id = "foldershare_internal_folder_name",
* label = @Translation("FolderShare (Internal) - Folder name, link, & icon"),
* weight = 920,
* field_types = {
* "string"
* }
* )
*/
class FolderShareInternalFolderName extends FormatterBase implements ContainerFactoryPluginInterface {
/*--------------------------------------------------------------------
*
* Fields - construction.
*
*------------------------------------------------------------------*/
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/*--------------------------------------------------------------------
*
* Construct.
*
*------------------------------------------------------------------*/
/**
* {@inheritdoc}
*/
public static function create(
ContainerInterface $container,
array $configuration,
$pluginId,
$pluginDefinition) {
// Construct a static plugin with the given parameters.
return new static(
$pluginId,
$pluginDefinition,
$configuration['field_definition'],
$configuration['settings'],
$configuration['label'],
$configuration['view_mode'],
$configuration['third_party_settings'],
$container->get('current_user')
);
}
/**
* Constructs an instance of the plugin.
*
* @param string $pluginId
* The ID for the plugin instance.
* @param mixed $pluginDefinition
* The plugin implementation definition.
* @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition
* The definition of the field to which the formatter is associated.
* @param array $settings
* The formatter's settings.
* @param string $label
* The formatter's label display setting.
* @param string $viewMode
* The view mode.
* @param array $thirdPartySettings
* Third party settings.
* @param \Drupal\Core\Session\AccountProxyInterface $currentUser
* The current user.
*/
public function __construct(
$pluginId,
$pluginDefinition,
FieldDefinitionInterface $fieldDefinition,
array $settings,
$label,
$viewMode,
array $thirdPartySettings,
AccountProxyInterface $currentUser) {
parent::__construct(
$pluginId,
$pluginDefinition,
$fieldDefinition,
$settings,
$label,
$viewMode,
$thirdPartySettings);
$this->currentUser = $currentUser;
}
/*---------------------------------------------------------------------
*
* Configuration.
*
*---------------------------------------------------------------------*/
/**
* {@inheritdoc}
*/
public static function isApplicable(FieldDefinitionInterface $fieldDef) {
// The entity containing the field to be formatted must be
// a FolderShare entity, and the field must be the 'name' field.
return $fieldDef->getTargetEntityTypeId() === FolderShare::ENTITY_TYPE_ID &&
$fieldDef->getName() === 'name';
}
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return [
'showIcon' => TRUE,
];
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$this->sanitizeSettings();
// Get current settings.
$showIcon = $this->getSetting('showIcon');
// Add text.
$summary = [];
$summary[] = $this->t('Folder name and link.');
$summary[] = $this->t('File name without link.');
if ($showIcon === TRUE) {
$summary[] = $this->t('Include MIME-type icon.');
}
$summary[] = $this->t('Data attributes for the UI.');
return $summary;
}
/*---------------------------------------------------------------------
*
* Settings form.
*
*---------------------------------------------------------------------*/
/**
* Returns a brief description of the formatter.
*
* @return string
* Returns a brief translated description of the formatter.
*/
protected function getDescription() {
return $this->t('<span class="foldershare-field-formatter-internal-use-only">For FolderShare module internal use only.</span> For folders only, show the name, link to the folder, and include data attributes needed by the user interface. For non-folders, just show the name, without a link or data attributes. Optionally include a MIME-type icon.');
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $formState) {
// Add branding.
$elements = [];
$elements = Branding::addFieldFormatterBranding($elements, TRUE);
$elements['#attached']['library'][] = Constants::LIBRARY_FIELD_FORMATTER;
// Add description.
//
// Use a large negative weight to insure it comes first.
$elements['description'] = [
'#type' => 'html_tag',
'#tag' => 'div',
'#value' => $this->getDescription(),
'#weight' => -1000,
'#attributes' => [
'class' => [
'foldershare-settings-description',
],
],
];
// Add a checkbox to enable/disable including an icon before the name.
$elements['showIcon'] = [
'#title' => $this->t('Show a MIME-type icon before the file/folder name'),
'#type' => 'checkbox',
'#default_value' => $this->getSetting('showIcon'),
'#weight' => 0,
'#attributes' => [
'class' => [
'foldershare-settings-name-show-icon',
],
],
];
return $elements;
}
/**
* Sanitize settings to insure that they are safe and valid.
*
* @internal
* Drupal's class hierarchy for plugins and their settings does not
* include a 'validate' function, like that for other classes with forms.
* Validation must therefore occur on use, rather than on form submission.
* @endinternal
*/
protected function sanitizeSettings() {
$this->setSetting(
'showIcon',
boolval($this->getSetting('showIcon')));
}
/*---------------------------------------------------------------------
*
* View.
*
*---------------------------------------------------------------------*/
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langCode) {
$this->sanitizeSettings();
if (empty($items) === TRUE) {
return [];
}
// Get settings.
$showIcon = $this->getSetting('showIcon');
$linkToEntity = TRUE;
// The $items array has a list of string items to format, but we
// need entities.
$entities = [];
foreach ($items as $delta => $item) {
$entities[$delta] = $item->getEntity();
}
// At this point, the $entities array has a list of items to format.
// We need to return an array with identical indexing and corresponding
// render elements for those items.
$build = [];
foreach ($entities as $delta => $entity) {
// Create a link for the entity and add it to the returned array.
$build[$delta] = $this->format(
$entity,
$langCode,
$showIcon,
$linkToEntity);
}
return $build;
}
/**
* Returns a formatted field for icon-linked values.
*
* Folders have a link and data attributes, while other kinds do not.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* A entity to return a value for.
* @param string $langCode
* The target language.
* @param bool $showIcon
* When TRUE, the entity will be marked with classes so that themes can
* add a MIME-type icon.
* @param bool $linkToEntity
* When TRUE, the entity name will be enclosed within an anchor to the
* entity's view page.
*
* @return array
* The render element to present the field.
*/
protected function format(
EntityInterface $entity,
$langCode,
$showIcon,
$linkToEntity) {
//
// Setup
// -----
// Get the entity's attributes.
$name = $entity->getName();
$kind = $entity->getKind();
$mime = $entity->getMimeType();
$url = $entity->toUrl();
$hidden = $entity->isSystemHidden();
$disabled = $entity->isSystemDisabled() || ($entity->isFolder() === FALSE);
$attr = [];
if ($disabled === FALSE) {
// So far, entity is not disabled. Get the user's access to it.
$updateFound = FALSE;
$access = [];
$summary = FolderShareAccessControlHandler::getAccessSummary($entity);
foreach ($summary as $op => $tf) {
if ($tf === TRUE) {
$access[] = $op;
if ($op === 'update') {
$updateFound = TRUE;
}
}
}
// If update access is not granted, then disable the item.
// Otherwise add attributes for use by the UI.
if ($updateFound === FALSE) {
$disabled = TRUE;
}
else {
$user = $this->currentUser;
$userId = (int) $user->id();
$anonymous = User::getAnonymousUser();
$anonId = (int) $anonymous->id();
$prefix = 'data-foldershare-';
$root = $entity->getRootItem();
// Since access grants are set on the root only, use it to determine
// the sharing states below.
$attr = [
$prefix . 'id' => $entity->id(),
$prefix . 'kind' => $kind,
$prefix . 'access' => implode(',', $access),
$prefix . 'extension' => $entity->getExtension(),
$prefix . 'ownerid' => $entity->getOwnerId(),
$prefix . 'ownedbyuser' => $entity->isOwnedBy($userId),
$prefix . 'ownedbyanonymous' => $entity->isOwnedBy($anonId),
$prefix . 'ownedbyanother' => ($entity->isOwnedBy($userId) === FALSE),
$prefix . 'sharedbyuser' => $root->isSharedBy($userId),
$prefix . 'sharedwithusertoview' => $root->isSharedWith($userId, 'view'),
$prefix . 'sharedwithusertoauthor' => $root->isSharedWith($userId, 'author'),
$prefix . 'sharedwithanonymoustoview' => $root->isSharedWith($anonId, 'view'),
$prefix . 'sharedwithanonymoustoauthor' => $root->isSharedWith($anonId, 'author'),
];
}
}
//
// Classes
// -------
// Set classes based on what is to be shown and the entity's attributes.
$classes = [];
$attached = [];
if ($hidden === TRUE) {
$classes[] = 'foldershare-hidden-entity';
}
if ($disabled === TRUE) {
$classes[] = 'foldershare-disabled-entity';
$linkToEntity = FALSE;
}
if ($showIcon === TRUE) {
// When including an icon, get the classes needed so that themes can
// mark the item with an icon.
//
// The Drupal Core File module defines conventional classes that mark
// an item as a file of varying type. While Drupal Core does not provide
// icons, some Core themes do. This module automatically includes those
// icons and adds icons for folders.
$classes[] = 'file';
switch ($kind) {
case FolderShare::FOLDER_KIND:
$classes[] = 'file--mime-folder-directory';
$classes[] = 'file--folder';
break;
default:
$classes[] = 'file--mime-' . strtr(
$mime,
[
'/' => '-',
'.' => '-',
]);
$classes[] = 'file--' . file_icon_class($mime);
break;
}
$attached = [
'library' => ['file/drupal.file'],
];
}
//
// Format
// ------
// Add link, or non-link text, along with above configured classes
// and attributes.
if ($linkToEntity === TRUE) {
$render = [
'#type' => 'link',
'#title' => $name,
'#url' => $url,
'#cache' => [
'contexts' => ['url.site'],
],
'#attached' => $attached,
'#attributes' => array_merge($attr, ['class' => $classes]),
];
}
else {
$render = [
'#type' => 'html_tag',
'#tag' => 'span',
'#value' => Html::escape($name),
'#attached' => $attached,
'#attributes' => array_merge($attr, ['class' => $classes]),
];
}
return $render;
}
}
