SHARE
TWEET

ManageEntitiesBaseForm

ivanjaros Apr 29th, 2015 (edited) 46 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?php
  2.  
  3. /**
  4.  * @file
  5.  * Contains \Drupal\mymodule\Forms\ManageEntitiesBaseForm.
  6.  */
  7.  
  8. namespace Drupal\mymodule\Form;
  9.  
  10. use Drupal\Core\Form\FormBase;
  11. use Drupal\Core\Entity\EntityInterface;
  12. use Drupal\Core\Form\FormStateInterface;
  13. use Drupal\Core\Entity\EntityManager;
  14. use Symfony\Component\DependencyInjection\ContainerInterface;
  15. use Drupal\Component\Plugin\CategorizingPluginManagerInterface;
  16.  
  17. /**
  18.  * Defines base for administering entities.
  19.  */
  20. abstract class ManageEntitiesBaseForm extends FormBase {
  21.  
  22.   /**
  23.    * The Entity Manager.
  24.    *
  25.    * @var \Drupal\Core\Entity\EntityManager
  26.    */
  27.   protected $entityManager;
  28.  
  29.   /**
  30.    * The action plugin manager.
  31.    *
  32.    * @var \Drupal\Core\Action\ActionManager
  33.    */
  34.   protected $actionManager;
  35.  
  36.   /**
  37.    * The original query used to load the entities without any filters applied.
  38.    *
  39.    * @var \Drupal\Core\Entity\Query\QueryInterface
  40.    */
  41.   private $original_query;
  42.  
  43.   /**
  44.    * The query used to load the entities with applied filters, if any.
  45.    *
  46.    * @var \Drupal\Core\Entity\Query\QueryInterface
  47.    */
  48.   private $query;
  49.  
  50.   /**
  51.    * The total amount of entities matching the current filter criteria.
  52.    *
  53.    * @var int
  54.    */
  55.   private $all_entities_count = 0;
  56.  
  57.   /**
  58.    * List of allowed actions.
  59.    *
  60.    * @var array
  61.    */
  62.   private $actions = array();
  63.  
  64.   /**
  65.    * Constructs a ManageEntitiesBaseForm object.
  66.    *
  67.    * @param \Drupal\Core\Entity\EntityManager $entity_manager
  68.    *   The entity manager.
  69.    * @param \Drupal\Component\Plugin\CategorizingPluginManagerInterface $action_manager
  70.    *   The action manager.
  71.    */
  72.   public function __construct(EntityManager $entity_manager, CategorizingPluginManagerInterface $action_manager) {
  73.     $this->entityManager = $entity_manager;
  74.     $this->actionManager = $action_manager;
  75.     $this->initializeQuery();
  76.   }
  77.  
  78.   /**
  79.    * {@inheritdoc}
  80.    */
  81.   public static function create(ContainerInterface $container) {
  82.     return new static(
  83.       $container->get('entity.manager'),
  84.       $container->get('plugin.manager.action')
  85.     );
  86.   }
  87.  
  88.   /**
  89.    * {@inheritdoc}
  90.    */
  91.   public function getFormId() {
  92.     $class = explode('\\', get_called_class());
  93.     $class = end($class);
  94.     return strtolower(preg_replace('/(?<!^)([A-Z])/', '_\\1', $class));
  95.   }
  96.  
  97.   /**
  98.    * Get the entity type id.
  99.    *
  100.    * @return string
  101.    */
  102.   abstract public function getEntityType();
  103.  
  104.   /**
  105.    * Returns renderable elements for one entity entry entry.
  106.    * Each element represents one column.
  107.    *
  108.    * @param \Drupal\Core\Entity\EntityInterface $entity
  109.    *   The entity to display the elements for.
  110.    *
  111.    * @return array
  112.    *   Returns array of renderable form elements.
  113.    */
  114.   abstract public function buildEntry(EntityInterface $entity);
  115.  
  116.   /**
  117.    * Get the table headers.
  118.    * Each field that wants to be used for sorting needs to define the
  119.    * 'field' and 'specifier' values and the 'data' is used as label.
  120.    * The field that should be used as default sorting filter has to
  121.    * define the 'sort' value which can be 'asc' or 'desc'.
  122.    *
  123.    * @see \Drupal\Core\Entity\Query\QueryInterface::tableSort
  124.    *
  125.    * @return array
  126.    *   List of headers with keys corresponding with those returned
  127.    *   by the buildEntry() method.
  128.    */
  129.   abstract public function headers();
  130.  
  131.   /**
  132.    * Returns the table headers with the 'select all' checkbox.
  133.    *
  134.    * @return array
  135.    */
  136.   final public function getHeaders() {
  137.     $headers = $this->headers();
  138.     // Make sure there are headers.
  139.     if (empty($headers)) {
  140.       return array();
  141.     }
  142.  
  143.     // Make sure at least one column has 'sort' set, otherwise the first column
  144.     // would be used for sorting, which in this case is a checkbox and it would
  145.     // thrown an error.
  146.     $has_sort = FALSE;
  147.     foreach ($headers AS $header) {
  148.       if (isset($header['sort'])) {
  149.         $has_sort = TRUE;
  150.         break;
  151.       }
  152.     }
  153.     if (!$has_sort) {
  154.       reset($headers);
  155.       $column = key($headers);
  156.       $headers[$column]['sort'] = 'desc';
  157.     }
  158.  
  159.     return array_merge(
  160.       array(
  161.         'identifier' => array(
  162.           'data' => array(
  163.             '#type' => 'checkbox'
  164.           )
  165.         )
  166.       ),
  167.       $headers
  168.     );
  169.   }
  170.  
  171.   /**
  172.    * Returns the entity query for the current entity type.
  173.    *
  174.    * In case any default filtering is need the extendeding classes
  175.    * should override this method.
  176.    *
  177.    * @return \Drupal\Core\Entity\Query\QueryInterface
  178.    */
  179.   public function getQuery() {
  180.     return $this->entityManager->getStorage($this->getEntityType())->getQuery();
  181.   }
  182.  
  183.   /**
  184.    * Sets the un-executed query object used to retrieve the entities.
  185.    * When executed the \Drupal\Core\Database\StatementInterface::fetchCol()
  186.    * method has to return a sorted list of entity IDs.
  187.    */
  188.   final protected function initializeQuery() {
  189.     // Since we do not want to load the entities right away we need
  190.     // to use the original query.
  191.     $query = $this->getQuery();
  192.  
  193.     // Apply table sort.
  194.     $headers = $this->getHeaders();
  195.     $query->tableSort($headers);
  196.  
  197.     // Apply pager.
  198.     $query->pager(15);
  199.  
  200.     // Save the query.
  201.     // Clone the query since we're about to count the number of all entities
  202.     // and that changes the whole query into a count query instead of returning
  203.     // a cloned object.
  204.     // @see \Drupal\Core\Entity\Query\QueryInterface::count().
  205.     $this->query = clone $query;
  206.  
  207.     // Save the query again, but this query cannot be altered by filters.
  208.     $this->original_query = clone $query;
  209.  
  210.     // Compute the number of all entities matching the current filter criteria.
  211.     $this->all_entities_count = $query->count()->execute();
  212.   }
  213.  
  214.   /**
  215.    * Attaches checkbox identifier to one entry.
  216.    *
  217.    * @param array $entry
  218.    *   The array with elements of one entry.
  219.    *
  220.    * @return array
  221.    *   Renderable array of element for one entry with attached identifier.
  222.    */
  223.   public function attachIdentifier(array $entry) {
  224.     return array_merge(
  225.       array(
  226.         'identifier' => array(
  227.           '#type' => 'checkbox'
  228.         )
  229.       ),
  230.       $entry
  231.     );
  232.   }
  233.  
  234.   /**
  235.    * Return the list of specifically allowed actions.
  236.    *
  237.    * @return array
  238.    */
  239.   final public function getActions() {
  240.     return $this->actions;
  241.   }
  242.  
  243.   /**
  244.    * Set a list of specifically allowed actions.
  245.    *
  246.    * @param array $actions
  247.    */
  248.   final public function setActions(array $actions) {
  249.     $this->actions = $actions;
  250.   }
  251.  
  252.   /**
  253.    * Add a specifically allowed action.
  254.    *
  255.    * @param string $action
  256.    *   The machine name of the action.
  257.    */
  258.   final public function addAction($action) {
  259.     if (!in_array($action, $this->actions)) {
  260.       $this->actions[] = $action;
  261.     }
  262.   }
  263.  
  264.   /**
  265.    * Load the action entities.
  266.    * If there are a specifically allowed actions then those will be loaded
  267.    * if they match the type of the entity.
  268.    * Otherwise all actions for the used entity type will be loaded.
  269.    *
  270.    * @return \Drupal\Core\Entity\EntityInterface[]
  271.    */
  272.   final public function loadActions() {
  273.     $actions = empty($this->actions)
  274.       ? array_keys($this->actionManager->getDefinitionsByType($this->getEntityType()))
  275.       : $this->actions;
  276.  
  277.     return $this->entityManager->getStorage('action')->loadByProperties(array(
  278.       'plugin' => $actions,
  279.       // In case actions were provided, make sure they work with proper type.
  280.       'type' => $this->getEntityType()
  281.     ));
  282.   }
  283.  
  284.   /**
  285.    * Returns the message that will be displayed in case there are no results.
  286.    *
  287.    * @return string
  288.    */
  289.   public function emptyMessage() {
  290.     return $this->t('There are no results to display.');
  291.   }
  292.  
  293.   /**
  294.    * {@inheritdoc}
  295.    */
  296.   public function buildForm(array $form, FormStateInterface $form_state) {
  297.     // Add helper class to identify these forms.
  298.     $form['#attributes']['class'][] = 'manage-entities-form';
  299.  
  300.     // Get the IDs.
  301.     $ids = $this->query->execute();
  302.  
  303.     // Add actions if there is at least one and if there are entities available.
  304.     if (!empty($ids)) {
  305.       $actions = $this->loadActions();
  306.       if (!empty($actions)) {
  307.         $form['actions_wrapper'] = array(
  308.           '#type' => 'fieldset',
  309.           '#title' => $this->t('Bulk operations')
  310.         );
  311.         $form['actions_wrapper']['action'] = array(
  312.           '#type' => 'select',
  313.           '#title' => $this->t('Action'),
  314.           '#options' => array_map(function ($action) {
  315.             return $action->label();
  316.           }, $actions)
  317.         );
  318.         // In order to avoid ajax rebuilds we will insert configuration per each
  319.         // configurable action.
  320.         $form['actions_wrapper']['configuration'] = array('#tree' => TRUE);
  321.         foreach ($actions AS $action) {
  322.           if ($action->getPlugin() instanceof \Drupal\Core\Action\ConfigurableActionBase) {
  323.             $form['actions_wrapper']['configuration'][$action->id()] =
  324.               $action->getPlugin()->buildConfigurationForm($form, $form_state);
  325.             $form['actions_wrapper']['configuration'][$action->id()]['#states'] =
  326.               array(
  327.                 'visible' => array(
  328.                   'select[name="action"]' => array('value' => $action->id())
  329.                 )
  330.               );
  331.           }
  332.         }
  333.  
  334.         $form['actions_wrapper']['buttons']['apply_to_selected'] = array(
  335.           '#type' => 'submit',
  336.           '#value' => t('Apply to selected items'),
  337.           '#states' => array(
  338.             'visible' => array(
  339.               ':input[name$="][identifier]"]' => array('checked' => TRUE)
  340.             )
  341.           )
  342.         );
  343.         $form['actions_wrapper']['buttons']['apply_to_all'] = array(
  344.           '#type' => 'submit',
  345.           '#value' => t('Apply to all @count items', array('@count' => $this->all_entities_count))
  346.         );
  347.       }
  348.     }
  349.  
  350.     // Load the entities.
  351.     $entities = $this->entityManager->getStorage($this->getEntityType())->loadMultiple($ids);
  352.  
  353.     // Transform entities into renderable arrays.
  354.     $entities = array_map(array($this, 'buildEntry'), $entities);
  355.  
  356.     // Add identifier for each entry.
  357.     $entities = array_map(array($this, 'attachIdentifier'), $entities);
  358.  
  359.     // Create table.
  360.     $form['entities'] = array(
  361.       '#type' => 'table',
  362.       '#header' => $this->getHeaders(),
  363.       '#empty' => $this->emptyMessage()
  364.     ) + $entities;
  365.  
  366.     $form['pager'] = array(
  367.       '#type' => 'pager'
  368.     );
  369.  
  370.     return $form;
  371.   }
  372.  
  373.   /**
  374.    * {@inheritdoc}
  375.    */
  376.   public function submitForm(array &$form, FormStateInterface $form_state) {
  377.     dsm($form_state->getValues());
  378.   }
  379.  
  380. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top