farm-2.x-dev/modules/core/flag/farm_flag.module
modules/core/flag/farm_flag.module
<?php
/**
* @file
* The farmOS Flags module.
*/
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\farm_flag\Form\EntityFlagActionForm;
use Drupal\farm_flag\Routing\EntityFlagActionRouteProvider;
/**
* Implements hook_entity_base_field_info().
*/
function farm_flag_entity_base_field_info(EntityTypeInterface $entity_type) {
$fields = [];
// Add flag field to farmOS entities.
if (in_array($entity_type->id(), ['asset', 'log', 'plan'])) {
$field_info = [
'type' => 'list_string',
'label' => t('Flags'),
'description' => t('Add flags to enable better sorting and filtering of records.'),
'allowed_values_function' => 'farm_flag_field_allowed_values',
'multiple' => TRUE,
'weight' => [
'form' => -75,
'view' => -75,
],
];
$fields['flag'] = \Drupal::service('farm_field.factory')->baseFieldDefinition($field_info);
}
return $fields;
}
/**
* Flag options helper.
*
* @param string|null $entity_type
* The entity type. Returns all flags if NULL.
* @param string[] $bundles
* Array of bundle ids to limit to. An empty array loads all bundles.
* @param bool $intersection
* A flag indicating to return an intersection of the allowed options.
*
* @return array
* Returns an array of flags for use in form select options.
*/
function farm_flag_options(string $entity_type = NULL, array $bundles = [], bool $intersection = FALSE) {
/** @var \Drupal\farm_flag\Entity\FarmFlagInterface[] $flags */
$flags = \Drupal::entityTypeManager()->getStorage('flag')->loadMultiple();
// If an entity type is provided, begin the filtering process...
if (!empty($entity_type)) {
// If no bundles are specified, load all bundles of the entity type.
if (empty($bundles) && $bundle_entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type)->getBundleEntityType()) {
$bundles = array_keys(\Drupal::entityTypeManager()
->getStorage($bundle_entity_type)
->loadMultiple());
}
// Find only the flags that apply to the entity type and bundles.
$flags = array_filter($flags, function ($flag) use ($entity_type, $bundles, $intersection) {
$flag_entity_types = $flag->getEntityTypes();
// The flag applies if no entity type is specified.
if (empty($flag_entity_types)) {
return TRUE;
}
// Otherwise the flag must specify the entity type.
if (!array_key_exists($entity_type, $flag_entity_types)) {
return FALSE;
}
// The flag applies to the bundle if:
// Case 1: The flag specifies 'all' bundles of the entity type.
$bundle_applies = in_array('all', $flag_entity_types[$entity_type]);
// Case 2: No intersection.
// The flag applies if any of the requested bundles are supported.
$bundle_applies |= !$intersection && !empty(array_intersect($bundles, $flag_entity_types[$entity_type]));
// Case 3: Intersection.
// The flag only applies if all the requested bundles are supported.
$bundle_applies |= $intersection && empty(array_diff($bundles, $flag_entity_types[$entity_type]));
return $bundle_applies;
});
}
// Assemble the options.
$options = [];
foreach ($flags as $id => $flag) {
$options[$id] = $flag->label();
}
return $options;
}
/**
* Allowed values callback function for the flags field.
*
* @param \Drupal\Core\Field\FieldStorageDefinitionInterface $definition
* The field storage definition.
* @param \Drupal\Core\Entity\ContentEntityInterface|null $entity
* The entity being created if applicable.
* @param bool $cacheable
* Boolean indicating if the allowed values can be cached. Defaults to TRUE.
*
* @return array
* Returns an array of allowed values for use in form select options.
*/
function farm_flag_field_allowed_values(FieldStorageDefinitionInterface $definition, ContentEntityInterface $entity = NULL, bool &$cacheable = TRUE) {
$entity_type = NULL;
$bundles = [];
if (!empty($entity)) {
$cacheable = FALSE;
$entity_type = $entity->getEntityTypeId();
$bundles = [$entity->bundle()];
}
return farm_flag_options($entity_type, $bundles);
}
/**
* Implements hook_theme().
*/
function farm_flag_theme() {
return [
'field__flag' => [
'base hook' => 'field',
],
];
}
/**
* Prepares variables for field--flag templates.
*
* Adds classes to each flag wrapper.
*
* Default template: field--flag.html.twig.
*
* @param array $variables
* An associative array containing:
* - element: An associative array containing render arrays for the list of
* flags.
*/
function template_preprocess_field__flag(array &$variables) {
// Preprocess list_string flag fields.
if ($variables['element']['#field_type'] == 'list_string') {
/** @var \Drupal\Core\Field\FieldItemListInterface $items */
$items = $variables['element']['#items'];
// Add classes to each flag.
foreach ($items as $key => $list_item) {
$classes = ['flag', 'flag--' . $list_item->getString()];
$variables['items'][$key]['attributes']->addClass($classes);
}
}
}
/**
* Implements hook_entity_type_build().
*/
function farm_flag_entity_type_build(array &$entity_types) {
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
// Enable the entity flag action on entity types with a flag field.
foreach (['asset', 'log', 'plan'] as $entity_type) {
if (!empty($entity_types[$entity_type])) {
$route_providers = $entity_types[$entity_type]->getRouteProviderClasses();
$route_providers['flag'] = EntityFlagActionRouteProvider::class;
$entity_types[$entity_type]->setHandlerClass('route_provider', $route_providers);
$entity_types[$entity_type]->setLinkTemplate('flag-action-form', '/' . $entity_type . '/flag');
$entity_types[$entity_type]->setFormClass('flag-action-form', EntityFlagActionForm::class);
}
}
}
