diff --git a/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/entityreference/selection/SelectionBase.php b/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/entityreference/selection/SelectionBase.php
index ca81cf1..eeeb0a1 100644
--- a/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/entityreference/selection/SelectionBase.php
+++ b/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/entityreference/selection/SelectionBase.php
@@ -42,6 +42,9 @@ public static function settingsForm($field, $instance) {
$entity_info = entity_get_info($field['settings']['target_type']);
// Merge-in default values.
+ if (!isset($field['settings']['handler_settings'])) {
+ $field['settings']['handler_settings'] = array();
+ }
$field['settings']['handler_settings'] += array(
'target_bundles' => array(),
'sort' => array(
diff --git a/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/views/display/Entityreference.php b/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/views/display/Entityreference.php
new file mode 100644
index 0000000..c5d7cda
--- /dev/null
+++ b/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/views/display/Entityreference.php
@@ -0,0 +1,166 @@
+ 'entityreference');
+ $options['defaults']['default']['style'] = FALSE;
+ $options['row']['contains']['type'] = array('default' => 'entityreference');
+ $options['defaults']['default']['row'] = FALSE;
+
+ // Make sure the query is not cached.
+ $options['defaults']['default']['cache'] = FALSE;
+
+ // Set the display title to an empty string (not used in this display type).
+ $options['title']['default'] = '';
+ $options['defaults']['default']['title'] = FALSE;
+
+ return $options;
+ }
+
+ /**
+ * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::getStyleType().
+ */
+ protected function getStyleType() {
+ return 'entityreference';
+ }
+
+ /**
+ * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::execute().
+ */
+ public function execute() {
+ return $this->view->render($this->display['id']);
+ }
+
+ /**
+ * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::render().
+ */
+ public function render() {
+ if (!empty($this->view->result) || !empty($this->view->style_plugin->definition['even empty'])) {
+ return $this->view->style_plugin->render($this->view->result);
+ }
+ return '';
+ }
+
+ /**
+ * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::usesExposed().
+ */
+ public function usesExposed() {
+ return FALSE;
+ }
+
+ /**
+ * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::query().
+ */
+ public function query() {
+ $options = $this->getOption('entityreference_options');
+
+ // Play nice with Views UI 'preview' : if the view is not executed through
+ // EntityReference_SelectionHandler_Views::getReferencableEntities(),
+ // don't alter the query.
+ if (empty($options)) {
+ return;
+ }
+
+ // Make sure the id field is included in the results, and save its alias
+ // so that references_plugin_style can retrieve it.
+ $this->id_field_alias = $id_field = $this->view->query->add_field($this->view->storage->base_table, $this->view->storage->base_field);
+ if (strpos($id_field, '.') === FALSE) {
+ $id_field = $this->view->storage->base_table . '.' . $this->id_field_alias;
+ }
+
+ // Restrict the autocomplete options based on what's been typed already.
+ if (isset($options['match'])) {
+ $style_options = $this->getOption('style');
+ $value = db_like($options['match']) . '%';
+ if ($options['match_operator'] != 'STARTS_WITH') {
+ $value = '%' . $value;
+ }
+
+ // Multiple search fields are OR'd together
+ $conditions = db_or();
+
+ // Build the condition using the selected search fields
+ foreach ($style_options['options']['search_fields'] as $field_alias) {
+ if (!empty($field_alias)) {
+ // Get the table and field names for the checked field
+ $field = $this->view->query->fields[$this->view->field[$field_alias]->field_alias];
+ // Add an OR condition for the field
+ $conditions->condition($field['table'] . '.' . $field['field'], $value, 'LIKE');
+ }
+ }
+
+ $this->view->query->add_where(0, $conditions);
+ }
+
+ // Add an IN condition for validation.
+ if (!empty($options['ids'])) {
+ $this->view->query->add_where(0, $id_field, $options['ids']);
+ }
+
+ $this->view->setItemsPerPage($options['limit']);
+ }
+
+ /**
+ * Overrides Drupal\views\Plugin\views\display\DisplayPluginBase::validate().
+ */
+ public function validate() {
+ $errors = parent::validate();
+ // Verify that search fields are set up.
+ $style = $this->getOption('style');
+ if (!isset($style['options']['search_fields'])) {
+ $errors[] = t('Display "@display" needs a selected search fields to work properly. See the settings for the Entity Reference list format.', array('@display' => $this->display['display_title']));
+ }
+ else {
+ // Verify that the search fields used actually exist.
+ //$fields = array_keys($this->view->get_items('field'));
+ $fields = array_keys($this->handlers['field']);
+ foreach ($style['options']['search_fields'] as $field_alias => $enabled) {
+ if ($enabled && !in_array($field_alias, $fields)) {
+ $errors[] = t('Display "@display" uses field %field as search field, but the field is no longer present. See the settings for the Entity Reference list format.', array('@display' => $this->display['display_title'], '%field' => $field_alias));
+ }
+ }
+ }
+ return $errors;
+ }
+}
diff --git a/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/views/row/Entityreference.php b/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/views/row/Entityreference.php
new file mode 100644
index 0000000..655cdc7
--- /dev/null
+++ b/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/views/row/Entityreference.php
@@ -0,0 +1,61 @@
+ '-');
+
+ return $options;
+ }
+
+ /**
+ * Overrides Drupal\views\Plugin\views\row\Fields::buildOptionsForm().
+ */
+ public function buildOptionsForm(&$form, &$form_state) {
+ parent::buildOptionsForm($form, $form_state);
+
+ // Expand the description of the 'Inline field' checkboxes.
+ $form['inline']['#description'] .= '
' . t("Note: In 'Entity Reference' displays, all fields will be displayed inline unless an explicit selection of inline fields is made here." );
+ }
+
+ /**
+ * Overrides Drupal\views\Plugin\views\row\Fields::pre_render().
+ */
+ public function pre_render($row) {
+ // Force all fields to be inline by default.
+ if (empty($this->options['inline'])) {
+ $fields = $this->view->getItems('field', $this->displayHandler->display['id']);
+ $this->options['inline'] = drupal_map_assoc(array_keys($fields));
+ }
+
+ return parent::pre_render($row);
+ }
+}
diff --git a/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/views/style/Entityreference.php b/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/views/style/Entityreference.php
new file mode 100644
index 0000000..6ee9476
--- /dev/null
+++ b/core/modules/field/modules/entityreference/lib/Drupal/entityreference/Plugin/views/style/Entityreference.php
@@ -0,0 +1,105 @@
+ NULL);
+
+ return $options;
+ }
+
+ /**
+ * Overrides Drupal\views\Plugin\views\style\StylePluginBase\StylePluginBase::buildOptionsForm().
+ */
+ public function buildOptionsForm(&$form, &$form_state) {
+ parent::buildOptionsForm($form, $form_state);
+ $options = array();
+
+ if (isset($form['grouping'])) {
+ $options = $form['grouping'][0]['field']['#options'];
+ unset($options['']);
+ $form['search_fields'] = array(
+ '#type' => 'checkboxes',
+ '#title' => t('Search fields'),
+ '#options' => $options,
+ '#required' => TRUE,
+ '#default_value' => $this->options['search_fields'],
+ '#description' => t('Select the field(s) that will be searched when using the autocomplete widget.'),
+ '#weight' => -3,
+ );
+ }
+ }
+
+ /**
+ * Overrides Drupal\views\Plugin\views\style\StylePluginBase\StylePluginBase::render().
+ */
+ public function render() {
+ $options = $this->displayHandler->getOption('entityreference_options');
+
+ // Play nice with Views UI 'preview': if the view is not executed through
+ // Drupal\views\Plugin\entityreference\selection\Views::getReferencableEntities(),
+ // just display the HTML.
+ if (empty($options)) {
+ return parent::render();
+ }
+
+ // Group the rows according to the grouping field, if specified.
+ $sets = $this->render_grouping($this->view->result, $this->options['grouping']);
+
+ // Grab the alias of the 'id' field added by entityreference_plugin_display.
+ $id_field_alias = $this->displayHandler->id_field_alias;
+
+ // @todo We don't display grouping info for now. Could be useful for select
+ // widget, though.
+ $results = array();
+ $this->view->row_index = 0;
+ foreach ($sets as $records) {
+ foreach ($records as $values) {
+ // Sanitize html, remove line breaks and extra whitespace.
+ $results[$values->{$id_field_alias}] = filter_xss_admin(preg_replace('/\s\s+/', ' ', str_replace("\n", '', $this->row_plugin->render($values))));
+ $this->view->row_index++;
+ }
+ }
+ unset($this->view->row_index);
+ return $results;
+ }
+
+ /**
+ * Overrides Drupal\views\Plugin\views\style\StylePluginBase\StylePluginBase::even_empty().
+ */
+ function even_empty() {
+ return TRUE;
+ }
+}
diff --git a/core/modules/field/modules/options/options.module b/core/modules/field/modules/options/options.module
index 31652e3..4436089 100644
--- a/core/modules/field/modules/options/options.module
+++ b/core/modules/field/modules/options/options.module
@@ -437,14 +437,14 @@ function options_field_widget_info() {
return array(
'options_select' => array(
'label' => t('Select list'),
- 'field types' => array('list_integer', 'list_float', 'list_text'),
+ 'field types' => array('list_integer', 'list_float', 'list_text', 'entityreference'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
),
),
'options_buttons' => array(
'label' => t('Check boxes/radio buttons'),
- 'field types' => array('list_integer', 'list_float', 'list_text', 'list_boolean'),
+ 'field types' => array('list_integer', 'list_float', 'list_text', 'list_boolean', 'entityreference'),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
),
diff --git a/core/modules/views/lib/Drupal/views/Plugin/entityreference/selection/Views.php b/core/modules/views/lib/Drupal/views/Plugin/entityreference/selection/Views.php
new file mode 100644
index 0000000..815cbeb
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Plugin/entityreference/selection/Views.php
@@ -0,0 +1,218 @@
+field = $field;
+ $this->instance = $instance;
+ $this->entity = $entity;
+ }
+
+ /**
+ * Implements Drupal\entityreference\Plugin\Type\Selection\SelectionInterface::settingsForm().
+ */
+ public static function settingsForm($field, $instance) {
+ $view_settings = empty($field['settings']['handler_settings']['view']) ? '' : $field['settings']['handler_settings']['view'];
+ $displays = views_get_applicable_views('entityreference_display');
+ // Filter views that list the entity type we want, and group the separate
+ // displays by view.
+ $entity_info = entity_get_info($field['settings']['target_type']);
+ $options = array();
+ foreach ($displays as $data) {
+ list($view, $display_id) = $data;
+ if ($view->storage->base_table == $entity_info['base table']) {
+ $options[$view->storage->name . ':' . $display_id] = $view->storage->name . ' - ' . $view->storage->display[$display_id]['display_title'];
+ }
+ }
+
+ // The value of the 'view_and_display' select below will need to be split
+ // into 'view_name' and 'view_display' in the final submitted values, so
+ // we massage the data at validate time on the wrapping element (not
+ // ideal).
+ $plugin = new static($field, $instance);
+ $form['view']['#element_validate'] = array(array($plugin, 'settingsFormValidate'));
+
+ if ($options) {
+ $default = !empty($view_settings['view_name']) ? $view_settings['view_name'] . ':' . $view_settings['display_name'] : NULL;
+ $form['view']['view_and_display'] = array(
+ '#type' => 'select',
+ '#title' => t('View used to select the entities'),
+ '#required' => TRUE,
+ '#options' => $options,
+ '#default_value' => $default,
+ '#description' => '
' . t('Choose the view and display that select the entities that can be referenced.
Only views with a display of type "Entity Reference" are eligible.') . '
' . t('No eligible views were found. Create a view with an Entity Reference display, or add such a display to an existing view.', array( + '@create' => url('admin/structure/views/add'), + '@existing' => url('admin/structure/views'), + )) . '
', + ); + } + return $form; + } + + /** + * Initializes a view. + * + * @param string $match + * @param string $match_operator + * @param int $limit + * @param array $ids + * + * @return bool + * Return TRUE if the views was initialized, FALSE otherwise. + */ + protected function initializeView($match = NULL, $match_operator = 'CONTAINS', $limit = 0, $ids = NULL) { + $view_name = $this->field['settings']['handler_settings']['view']['view_name']; + $display_name = $this->field['settings']['handler_settings']['view']['display_name']; + $args = $this->field['settings']['handler_settings']['view']['args']; + $entity_type = $this->field['settings']['target_type']; + + // Check that the view is valid and the display still exists. + $this->view = views_get_view($view_name); + if (!$this->view || !isset($this->view->storage->display[$display_name]) || !$this->view->access($display_name)) { + watchdog('entityreference', 'The view %view_name is no longer eligible for the %field_name field.', array('%view_name' => $view_name, '%field_name' => $this->instance['label']), WATCHDOG_WARNING); + return FALSE; + } + $this->view->setDisplay($display_name); + + // Pass options to the display handler to make them available later. + $entityreference_options = array( + 'match' => $match, + 'match_operator' => $match_operator, + 'limit' => $limit, + 'ids' => $ids, + ); + $this->view->displayHandlers[$display_name]->setOption('entityreference_options', $entityreference_options); + return TRUE; + } + + /** + * Implements Drupal\entityreference\Plugin\Type\Selection\SelectionInterface::getReferencableEntities(). + */ + public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) { + $display_name = $this->field['settings']['handler_settings']['view']['display_name']; + $args = $this->field['settings']['handler_settings']['view']['args']; + $result = array(); + if ($this->initializeView($match, $match_operator, $limit)) { + // Get the results. + $result = $this->view->executeDisplay($display_name, $args); + } + + $return = array(); + if ($result) { + $target_type = $this->field['settings']['target_type']; + $entity_info = entity_get_info($target_type); + $entities = entity_load_multiple($target_type, array_keys($result)); + foreach($entities as $entity) { + $return[$entity->bundle()][$entity->id()] = $result[$entity->id()]; + } + } + return $return; + } + + /** + * Implements Drupal\entityreference\Plugin\Type\Selection\SelectionInterface::countReferencableEntities(). + */ + public function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS') { + $this->getReferencableEntities($match, $match_operator); + return $this->view->total_items; + } + + /** + * Implements Drupal\entityreference\Plugin\Type\Selection\SelectionInterface::validateReferencableEntities(). + */ + public function validateReferencableEntities(array $ids) { + $display_name = $this->field['settings']['handler_settings']['view']['display_name']; + $args = $this->field['settings']['handler_settings']['view']['args']; + $result = array(); + if ($this->initializeView(NULL, 'CONTAINS', 0, $ids)) { + // Get the results. + $entities = $this->view->executeDisplay($display_name, $args); + $result = array_keys($entities); + } + return $result; + } + + /** + * Implements Drupal\entityreference\Plugin\Type\Selection\SelectionInterface::validateAutocompleteInput(). + */ + public function validateAutocompleteInput($input, &$element, &$form_state, $form) { + return NULL; + } + + /** + * Implements Drupal\entityreference\Plugin\Type\Selection\SelectionInterface::entityFieldQueryAlter(). + */ + public function entityFieldQueryAlter(SelectInterface $query) { } + + /** + * Element validate; Check View is valid. + */ + public function settingsFormValidate($element, &$form_state, $form) { + // Split view name and display name from the 'view_and_display' value. + if (!empty($element['view_and_display']['#value'])) { + list($view, $display) = explode(':', $element['view_and_display']['#value']); + } + else { + form_error($element, t('The views entity selection mode requires a view.')); + return; + } + + // Explode the 'args' string into an actual array. Beware, explode() turns an + // empty string into an array with one empty string. We'll need an empty array + // instead. + $args_string = trim($element['args']['#value']); + if ($args_string === '') { + $args = array(); + } + else { + // array_map is called to trim whitespaces from the arguments. + $args = array_map('trim', explode(',', $args_string)); + } + + $value = array('view_name' => $view, 'display_name' => $display, 'args' => $args); + form_set_value($element, $value, $form_state); + } +}