From 74f2a9b1b77fbc9f24f224b96b8b6ed08d55e9b1 Mon Sep 17 00:00:00 2001 From: Erik Seifert Date: Fri, 23 Sep 2016 16:08:16 +0200 Subject: [PATCH 1/6] Add exposed filter support --- .../ViewfieldDefaultFormatter.php | 6 + src/Plugin/Field/FieldType/ViewfieldItem.php | 12 +- .../Field/FieldWidget/ViewfieldWidget.php | 154 +++++++++++++++++- viewfield.module | 15 +- 4 files changed, 170 insertions(+), 17 deletions(-) diff --git a/src/Plugin/Field/FieldFormatter/ViewfieldDefaultFormatter.php b/src/Plugin/Field/FieldFormatter/ViewfieldDefaultFormatter.php index c4b2b14..817efd2 100644 --- a/src/Plugin/Field/FieldFormatter/ViewfieldDefaultFormatter.php +++ b/src/Plugin/Field/FieldFormatter/ViewfieldDefaultFormatter.php @@ -11,6 +11,7 @@ use Drupal\Core\Field\FormatterBase; use Drupal\Core\Field\FieldItemListInterface; use Drupal\views\Views; +use Drupal\Component\Serialization\Json; /** * Plugin implementation of the 'viewfield_default' formatter. @@ -35,6 +36,9 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $entity = $item->getEntity(); list($view_name, $view_display) = explode('|', $item->vname, 2); $view = Views::getView($view_name); + if (!empty($item->settings)) { + $settings = Json::decode($item->settings); + } $elements[$delta] = array( '#type' => 'viewfield', '#view' => $view, @@ -45,9 +49,11 @@ public function viewElements(FieldItemListInterface $items, $langcode) { '#entity_type' => $entity->getEntityTypeId(), '#entity_id' => $entity->id(), '#entity' => $entity, + '#exposed_settings' => $settings, '#theme' => 'viewfield_formatter_default', ); } return $elements; } + } diff --git a/src/Plugin/Field/FieldType/ViewfieldItem.php b/src/Plugin/Field/FieldType/ViewfieldItem.php index 5a2977d..361dc2a 100644 --- a/src/Plugin/Field/FieldType/ViewfieldItem.php +++ b/src/Plugin/Field/FieldType/ViewfieldItem.php @@ -13,7 +13,6 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\views\Views; - /** * Plugin implementation of the 'viewfield' field type. * @@ -58,14 +57,16 @@ public static function schema(FieldStorageDefinitionInterface $field_definition) 'vname' => array( 'type' => 'varchar', 'not null' => FALSE, - // Views requires at least 96 chars for the view name and display, plus - // we need 1 for our delimiter. Round up to a common value of 128. 'length' => 128, ), 'vargs' => array( 'type' => 'varchar', 'not null' => FALSE, - 'length' => 255, //viewfield_field_instance_settings_form_validate + 'length' => 255, + ), + 'settings' => array( + 'type' => 'text', + 'size' => 'big', ), ), ); @@ -79,6 +80,8 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel ->setLabel(t('View name')); $properties['vargs'] = DataDefinition::create('string') ->setLabel(t('View args')); + $properties['settings'] = DataDefinition::create('string') + ->setLabel(t('View settings')); return $properties; } @@ -127,4 +130,5 @@ public static function fieldSettingsFormValidate(array $form, FormStateInterface } } } + } diff --git a/src/Plugin/Field/FieldWidget/ViewfieldWidget.php b/src/Plugin/Field/FieldWidget/ViewfieldWidget.php index ddc3d60..7ff5321 100644 --- a/src/Plugin/Field/FieldWidget/ViewfieldWidget.php +++ b/src/Plugin/Field/FieldWidget/ViewfieldWidget.php @@ -10,7 +10,11 @@ use Drupal\Core\Field\WidgetBase; use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Render\Element; +use Drupal\Core\Form\FormState; +use Drupal\Component\Utility\Html; +use Drupal\Component\Serialization\Json; +use Drupal\Component\Utility\NestedArray; +use Drupal\Component\Utility\SortArray; use Drupal\views\Views; /** @@ -34,31 +38,133 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $field_settings = $this->getFieldSettings(); $options = $this->getPotentialReferences($field_settings); + $id = Html::getUniqueId('state-wrapper-' .$items->getName() . '-' . $delta); + $element['#field_name'] = $items->getName(); $element['vname'] = array( '#type' => 'select', '#title' => t('Views Field'), '#options' => $options, '#empty_value' => 0, + '#ajax' => array( + 'callback' => array($this, 'viewsSettings'), + 'event' => 'change', + 'progress' => array( + 'type' => 'throbber', + 'message' => NULL, + ), + 'wrapper' => $id, + ), '#access' => !$field_settings['force_default'], '#default_value' => isset($items[$delta]->vname) ? $items[$delta]->vname : NULL, ); + + $element['settings_wrapper'] = array( + '#type' => 'fieldset', + ); + + $element['settings_wrapper']['settings_wrapper_form'] = array( + '#type' => 'html_tag', + '#tag' => 'div', + ); + + $element['settings_wrapper']['settings_wrapper_form']['settings'] = array( + '#type' => 'html_tag', + '#tag' => 'div', + '#attributes' => array( + 'id' => $id, + ), + ); + + if (isset($items[$delta]->vname)) { + $view = explode('|', $items[$delta]->vname); + $viewInstance = $this->getView($view[0], $view[1]); + $itemSettings = []; + if (!empty($items[$delta]->settings)) { + $itemSettings = Json::decode($items[$delta]->settings); + } + if ($viewInstance) { + $element['settings_wrapper']['settings_wrapper_form']['settings'] = $this->getViewSettings($viewInstance, $view[1], $itemSettings); + $element['settings_wrapper']['settings_wrapper_form']['settings']['#attributes']['id'] = $id; + } + } + $element['vargs'] = array( '#type' => 'textfield', '#title' => t('Arguments'), '#default_value' => isset($items[$delta]->vargs) ? $items[$delta]->vargs : NULL, '#access' => !$field_settings['force_default'], - '#description' => t('A comma separated list of arguments to pass to the selected view. '), + '#description' => t('A comma separated list of arguments to pass to the selected view.'), ); return $element; } + /** + * Helper function for get exposed filter. + */ + public function getViewSettings($view, $display, $settings) { + $form_state = new FormState(); + $form_state->setUserInput($settings); + $view->initHandlers(); + $form = []; + // Let form plugins know this is for exposed widgets. + $form_state->set('exposed', TRUE); + $form['settings'] = []; + + // Go through each handler and let it generate its exposed widget. + foreach ($view->display_handler->handlers as $type => $value) { + /** @var \Drupal\views\Plugin\views\ViewsHandlerInterface $handler */ + foreach ($view->$type as $id => $handler) { + if ($handler->canExpose() && $handler->isExposed()) { + if ($handler->isAGroup()) { + $handler->groupForm($form, $form_state); + $id = $handler->options['group_info']['identifier']; + } + else { + $handler->buildExposedForm($form, $form_state); + } + if ($info = $handler->exposedInfo()) { + $form['#info']["$type-$id"] = $info; + } + } + } + } + + foreach ($settings as $name => $set) { + if ($form[$name]) { + $form[$name]['#default_value'] = $set; + } + } + + foreach ($form['#info'] as $info) { + if (isset($form[$info['value']])) { + $form[$info['value']]['#title'] = $info['label']; + } + } + + $exposed_form_plugin = $view->display_handler->getPlugin('exposed_form'); + $exposed_form_plugin->exposedFormAlter($form, $form_state); + + unset($form['actions']); + return $form; + } + + public function viewsSettings(array $form, FormStateInterface $form_state) { + $view = $form_state->getTriggeringElement()['#value']; + $view = explode('|', $view); + $viewInstance = $this->getView($view[0], $view[1]); + if ($viewInstance) { + return $this->getViewSettings($viewInstance, $view[1]); + } + return []; + } + /** * Returns a select options list of views displays of enabled and allowed views. * - * @param array @settings - * The field settings + * @param array $settings + * The field settings. * * @return array * An array with the allowed and enabled views and displays. @@ -75,7 +181,7 @@ protected function getPotentialReferences($settings) { } } $options = array(); - foreach ($views as $view_name => $view) { + foreach ($views as $view) { $displays = $view->get('display'); foreach ($displays as $display) { $options[$view->id() . '|' . $display['id']] = $view->id() . ' - ' . $display['display_title']; @@ -84,4 +190,42 @@ protected function getPotentialReferences($settings) { return $options; } + public function getView($view_id, $display) { + $view = Views::getView($view_id); + $view->setDisplay($display); + return $view; + } + + public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) { + // dsm($form_state->getValues()); + // dsm($form_state->getValues(),'Settings'); + parent::extractFormValues($items, $form, $form_state); + $field_name = $this->fieldDefinition->getName(); + $path = array_merge($form['#parents'], array($field_name)); + $key_exists = NULL; + $values = NestedArray::getValue($form_state->getValues(), $path, $key_exists); + if ($key_exists) { + if (!$this->handlesMultipleValues()) { + // Remove the 'value' of the 'add more' button. + unset($values['add_more']); + // The original delta, before drag-and-drop reordering, is needed to + // route errors to the correct form element. + foreach ($values as $delta => &$value) { + $value['_original_delta'] = $delta; + } + usort($values, function($a, $b) { + return SortArray::sortByKeyInt($a, $b, '_weight'); + }); + } + // Let the widget massage the submitted values. + $values = $this->massageFormValues($values, $form, $form_state); + foreach ($values as $delta => $value) { + if ($value['settings_wrapper']['settings_wrapper_form']['settings']) { + $values[$delta]['settings'] = Json::encode($value['settings_wrapper']['settings_wrapper_form']['settings']); + } + } + $items->setValue($values); + } + } + } diff --git a/viewfield.module b/viewfield.module index 56d3c68..6c82ac9 100644 --- a/viewfield.module +++ b/viewfield.module @@ -1,13 +1,12 @@ setExposedInput($element['#exposed_settings']); $view_el = $element['#view']->preview($element['#view_display'], array($element['#view_arguments'])); - $output = render ($view_el); + $output = render($view_el); $variables['output'] = $output; } @@ -42,7 +42,7 @@ function viewfield_element_info() { } /** - * #pre_render callback for a viewfield field. + * pre_render callback for a viewfield field. * * @see viewfield_post_render() */ @@ -75,7 +75,7 @@ function viewfield_pre_render($element) { } /** - * #post_render callback for a viewfield field. + * post_render callback for a viewfield field. * * @see viewfield_pre_render() */ @@ -85,9 +85,8 @@ function viewfield_post_render($content, $element) { return $content; } - /** - * Perform argument replacement + * Perform argument replacement. */ function _viewfield_get_view_args($vargs, $entity_type, $entity) { $args = array(); From 4d8db7e92d055c85566cbdd4a02659374d1cb28e Mon Sep 17 00:00:00 2001 From: Erik Seifert Date: Fri, 23 Sep 2016 16:08:40 +0200 Subject: [PATCH 2/6] Add exposed filter support --- src/Plugin/views/display/ViewFieldDisplay.php | 29 ++++++++++ .../exposed_form/ViewFieldExposedForm.php | 54 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/Plugin/views/display/ViewFieldDisplay.php create mode 100644 src/Plugin/views/exposed_form/ViewFieldExposedForm.php diff --git a/src/Plugin/views/display/ViewFieldDisplay.php b/src/Plugin/views/display/ViewFieldDisplay.php new file mode 100644 index 0000000..968b638 --- /dev/null +++ b/src/Plugin/views/display/ViewFieldDisplay.php @@ -0,0 +1,29 @@ + !\Drupal::config('views.settings')->get('ui.show.display_embed'), + * + * @ViewsDisplay( + * id = "viewfield", + * title = @Translation("Viewfield"), + * help = @Translation("Provide a display which can be embedded using the views api."), + * theme = "views_view", + * uses_menu_links = FALSE + * ) + */ +class ViewFieldDisplay extends DisplayPluginBase { + + public function displaysExposed() { + return FALSE; + } + +} diff --git a/src/Plugin/views/exposed_form/ViewFieldExposedForm.php b/src/Plugin/views/exposed_form/ViewFieldExposedForm.php new file mode 100644 index 0000000..1514d91 --- /dev/null +++ b/src/Plugin/views/exposed_form/ViewFieldExposedForm.php @@ -0,0 +1,54 @@ +setStorage([ + 'view' => $this->view, + 'display' => &$this->view->display_handler->display, + 'rerender' => TRUE, + ]) + ->setMethod('get') + ->setAlwaysProcess() + ->disableRedirect(); + + // Some types of displays (eg. attachments) may wish to use the exposed + // filters of their parent displays instead of showing an additional + // exposed filter form for the attachment as well as that for the parent. + if (!$this->view->display_handler->displaysExposed() || ($this->view->display_handler->getOption('exposed_block'))) { + $form_state->set('rerender', NULL); + } + + $form = \Drupal::formBuilder()->buildForm('\Drupal\views\Form\ViewsExposedForm', $form_state); + return []; + } + + +} From 3b2756f7b52659c09b132b4bbf7ddb0315cd3c54 Mon Sep 17 00:00:00 2001 From: Erik Seifert Date: Fri, 23 Sep 2016 17:32:28 +0200 Subject: [PATCH 3/6] Add check if view is really loaded --- src/Plugin/Field/FieldWidget/ViewfieldWidget.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Plugin/Field/FieldWidget/ViewfieldWidget.php b/src/Plugin/Field/FieldWidget/ViewfieldWidget.php index 7ff5321..87f552c 100644 --- a/src/Plugin/Field/FieldWidget/ViewfieldWidget.php +++ b/src/Plugin/Field/FieldWidget/ViewfieldWidget.php @@ -105,13 +105,17 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen */ public function getViewSettings($view, $display, $settings) { $form_state = new FormState(); - $form_state->setUserInput($settings); + if ($settings) { + $form_state->setUserInput($settings); + } $view->initHandlers(); $form = []; // Let form plugins know this is for exposed widgets. $form_state->set('exposed', TRUE); $form['settings'] = []; + + // Go through each handler and let it generate its exposed widget. foreach ($view->display_handler->handlers as $type => $value) { /** @var \Drupal\views\Plugin\views\ViewsHandlerInterface $handler */ @@ -146,6 +150,7 @@ public function getViewSettings($view, $display, $settings) { $exposed_form_plugin = $view->display_handler->getPlugin('exposed_form'); $exposed_form_plugin->exposedFormAlter($form, $form_state); + unset($form['actions']); return $form; } @@ -192,8 +197,11 @@ protected function getPotentialReferences($settings) { public function getView($view_id, $display) { $view = Views::getView($view_id); - $view->setDisplay($display); - return $view; + if ($view) { + $view->setDisplay($display); + return $view; + } + return false; } public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) { From 775c27c930ee0d078405e8e905f80258547242bd Mon Sep 17 00:00:00 2001 From: Erik Seifert Date: Fri, 23 Sep 2016 18:00:37 +0200 Subject: [PATCH 4/6] Better form values handling --- .../Field/FieldWidget/ViewfieldWidget.php | 55 +++++++------------ 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/src/Plugin/Field/FieldWidget/ViewfieldWidget.php b/src/Plugin/Field/FieldWidget/ViewfieldWidget.php index 87f552c..8cf6e0b 100644 --- a/src/Plugin/Field/FieldWidget/ViewfieldWidget.php +++ b/src/Plugin/Field/FieldWidget/ViewfieldWidget.php @@ -114,8 +114,6 @@ public function getViewSettings($view, $display, $settings) { $form_state->set('exposed', TRUE); $form['settings'] = []; - - // Go through each handler and let it generate its exposed widget. foreach ($view->display_handler->handlers as $type => $value) { /** @var \Drupal\views\Plugin\views\ViewsHandlerInterface $handler */ @@ -150,7 +148,6 @@ public function getViewSettings($view, $display, $settings) { $exposed_form_plugin = $view->display_handler->getPlugin('exposed_form'); $exposed_form_plugin->exposedFormAlter($form, $form_state); - unset($form['actions']); return $form; } @@ -159,7 +156,7 @@ public function viewsSettings(array $form, FormStateInterface $form_state) { $view = $form_state->getTriggeringElement()['#value']; $view = explode('|', $view); $viewInstance = $this->getView($view[0], $view[1]); - if ($viewInstance) { + if ($viewInstance && is_a($viewInstance->getDisplay(), 'Drupal\viewfield\Plugin\views\display\ViewFieldDisplay')) { return $this->getViewSettings($viewInstance, $view[1]); } return []; @@ -195,45 +192,31 @@ protected function getPotentialReferences($settings) { return $options; } - public function getView($view_id, $display) { - $view = Views::getView($view_id); + /** + * Helper function for retrieve view. + * + * @param string $viewId + * View machinable name to load. + * @param string $display + * Display plugin to load. + */ + public function getView($viewId, $display) { + $view = Views::getView($viewId); if ($view) { $view->setDisplay($display); return $view; } - return false; + return FALSE; } - public function extractFormValues(FieldItemListInterface $items, array $form, FormStateInterface $form_state) { - // dsm($form_state->getValues()); - // dsm($form_state->getValues(),'Settings'); - parent::extractFormValues($items, $form, $form_state); - $field_name = $this->fieldDefinition->getName(); - $path = array_merge($form['#parents'], array($field_name)); - $key_exists = NULL; - $values = NestedArray::getValue($form_state->getValues(), $path, $key_exists); - if ($key_exists) { - if (!$this->handlesMultipleValues()) { - // Remove the 'value' of the 'add more' button. - unset($values['add_more']); - // The original delta, before drag-and-drop reordering, is needed to - // route errors to the correct form element. - foreach ($values as $delta => &$value) { - $value['_original_delta'] = $delta; - } - usort($values, function($a, $b) { - return SortArray::sortByKeyInt($a, $b, '_weight'); - }); - } - // Let the widget massage the submitted values. - $values = $this->massageFormValues($values, $form, $form_state); - foreach ($values as $delta => $value) { - if ($value['settings_wrapper']['settings_wrapper_form']['settings']) { - $values[$delta]['settings'] = Json::encode($value['settings_wrapper']['settings_wrapper_form']['settings']); - } - } - $items->setValue($values); + /** + * {@inheritdoc} + */ + public function massageFormValues(array $values, array $form, FormStateInterface $formState) { + foreach ($values as $key => $value) { + $values[$key]['settings'] = Json::encode($value['settings_wrapper']['settings_wrapper_form']['settings']); } + return $values; } } From fa7d86a89e27b4d6a29a2956cc37ba85707dd04a Mon Sep 17 00:00:00 2001 From: Erik Seifert Date: Fri, 23 Sep 2016 18:42:00 +0200 Subject: [PATCH 5/6] Remove ViewFieldExposedForm --- .../exposed_form/ViewFieldExposedForm.php | 54 ------------------- 1 file changed, 54 deletions(-) delete mode 100644 src/Plugin/views/exposed_form/ViewFieldExposedForm.php diff --git a/src/Plugin/views/exposed_form/ViewFieldExposedForm.php b/src/Plugin/views/exposed_form/ViewFieldExposedForm.php deleted file mode 100644 index 1514d91..0000000 --- a/src/Plugin/views/exposed_form/ViewFieldExposedForm.php +++ /dev/null @@ -1,54 +0,0 @@ -setStorage([ - 'view' => $this->view, - 'display' => &$this->view->display_handler->display, - 'rerender' => TRUE, - ]) - ->setMethod('get') - ->setAlwaysProcess() - ->disableRedirect(); - - // Some types of displays (eg. attachments) may wish to use the exposed - // filters of their parent displays instead of showing an additional - // exposed filter form for the attachment as well as that for the parent. - if (!$this->view->display_handler->displaysExposed() || ($this->view->display_handler->getOption('exposed_block'))) { - $form_state->set('rerender', NULL); - } - - $form = \Drupal::formBuilder()->buildForm('\Drupal\views\Form\ViewsExposedForm', $form_state); - return []; - } - - -} From d4382e8e794227f1db711f73a1105ac148137c64 Mon Sep 17 00:00:00 2001 From: Erik Seifert Date: Fri, 23 Sep 2016 18:42:49 +0200 Subject: [PATCH 6/6] Some small changes --- src/Plugin/Field/FieldWidget/ViewfieldWidget.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugin/Field/FieldWidget/ViewfieldWidget.php b/src/Plugin/Field/FieldWidget/ViewfieldWidget.php index 8cf6e0b..abd9415 100644 --- a/src/Plugin/Field/FieldWidget/ViewfieldWidget.php +++ b/src/Plugin/Field/FieldWidget/ViewfieldWidget.php @@ -38,7 +38,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $field_settings = $this->getFieldSettings(); $options = $this->getPotentialReferences($field_settings); - $id = Html::getUniqueId('state-wrapper-' .$items->getName() . '-' . $delta); + $id = Html::getUniqueId('state-wrapper-' . $items->getName() . '-' . $delta); $element['#field_name'] = $items->getName(); $element['vname'] = array(