diff --git a/og.module b/og.module index 8a8cfa72d..4653e200f 100755 --- a/og.module +++ b/og.module @@ -156,7 +156,7 @@ function og_entity_create_access(AccountInterface $account, array $context, $bun // We can't check if user has create permissions, as there is no group // context. However, we can check if there are any groups the user will be // able to select, and if not, we don't allow access. - // @see \Drupal\og\Plugin\EntityReferenceSelection\OgSelection::buildEntityQuery() + // @see \Drupal\og\Plugin\EntityReferenceSelection\OgDefaultSelection::buildEntityQuery() $required = FALSE; $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type_id, $bundle); diff --git a/src/Og.php b/src/Og.php index 7d697f62a..465c055cc 100644 --- a/src/Og.php +++ b/src/Og.php @@ -7,14 +7,15 @@ namespace Drupal\og; -use Drupal\Component\Render\FormattableMarkup; use Drupal\Component\Utility\NestedArray; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\FieldableEntityInterface; +use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection; use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; -use Drupal\og\Plugin\EntityReferenceSelection\OgSelection; +use Drupal\Component\Plugin\Exception\PluginException; +use Drupal\views\Plugin\EntityReferenceSelection\ViewsSelection; /** * A static helper class for OG. @@ -444,7 +445,7 @@ protected static function getFieldBaseDefinition($plugin_id) { * @param array $options * Overriding the default options of the selection handler. * - * @return OgSelection + * @return \Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface * @throws \Exception */ public static function getSelectionHandler(FieldDefinitionInterface $field_definition, array $options = []) { @@ -464,7 +465,26 @@ public static function getSelectionHandler(FieldDefinitionInterface $field_defin // Deep merge the handler settings. $options['handler_settings'] = NestedArray::mergeDeep($field_definition->getSetting('handler_settings'), $options['handler_settings']); - return \Drupal::service('plugin.manager.entity_reference_selection')->createInstance('og:default', $options); + // Find our which class we should use. + /* @var \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface $selection_plugin_manager */ + $selection_plugin_manager = \Drupal::service('plugin.manager.entity_reference_selection'); + $original_handler = $selection_plugin_manager->getInstance($options); + + // See if we have a suitable class for this. + // @todo: Find a better way to do this? + if ($original_handler instanceof DefaultSelection) { + $plugin_id = 'og:default'; + } + elseif ($original_handler instanceof ViewsSelection) { + $plugin_id = 'og:views'; + } + else { + // @todo: Create our own exception for this? + throw new PluginException(sprintf("OG proxy plugin for plugin ID '%s' was not found.", $original_handler->getPluginId())); + } + + // Create and return our proxy selection handler. + return $selection_plugin_manager->createInstance($plugin_id, $options); } } diff --git a/src/OgSelectionTrait.php b/src/OgSelectionTrait.php new file mode 100644 index 000000000..aa284288c --- /dev/null +++ b/src/OgSelectionTrait.php @@ -0,0 +1,53 @@ +selectionHandler)) { + $options = [ + 'target_type' => $this->configuration['target_type'], + 'handler_settings' => $this->configuration['handler_settings'], + ]; + if (isset($this->configuration['handler_settings']['original_handler'])) { + $options['handler'] = $this->configuration['handler_settings']['original_handler']; + } + $this->selectionHandler = \Drupal::service('plugin.manager.entity_reference_selection')->getInstance($options); + } + return $this->selectionHandler; + } + + /** + * Get hold of the groups this user is part of. + * + * @return \Drupal\Core\Entity\ContentEntityInterface[] + */ + protected function getUserGroups() { + $other_groups = Og::getEntityGroups(User::load($this->currentUser->id())); + return isset($other_groups[$this->configuration['target_type']]) ? $other_groups[$this->configuration['target_type']] : []; + } + +} diff --git a/src/Plugin/EntityReferenceSelection/OgSelection.php b/src/Plugin/EntityReferenceSelection/OgDefaultSelection.php similarity index 68% rename from src/Plugin/EntityReferenceSelection/OgSelection.php rename to src/Plugin/EntityReferenceSelection/OgDefaultSelection.php index 5eb5e6c03..65610a47e 100644 --- a/src/Plugin/EntityReferenceSelection/OgSelection.php +++ b/src/Plugin/EntityReferenceSelection/OgDefaultSelection.php @@ -2,18 +2,18 @@ /** * @file - * Contains \Drupal\og\Plugin\EntityReferenceSelection\OgSelection. + * Contains \Drupal\og\Plugin\EntityReferenceSelection\OgDefaultSelection. */ namespace Drupal\og\Plugin\EntityReferenceSelection; -use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection; -use Drupal\user\Entity\User; +use Drupal\og\OgSelectionTrait; use Drupal\og\Og; /** - * Provide default OG selection handler. + * Provide a proxy OG selection handler for + * \Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection. * * Note that the id is correctly defined as "og:default" and not the other way * around, as seen in most other default selection handler (e.g. "default:node") @@ -29,23 +29,9 @@ * weight = 1 * ) */ -class OgSelection extends DefaultSelection { +class OgDefaultSelection extends DefaultSelection { - /** - * Get the selection handler of the field. - * - * @return DefaultSelection - */ - public function getSelectionHandler() { - $options = [ - 'target_type' => $this->configuration['target_type'], - // 'handler' key intentionally absent as we want the selection manager to - // choose the best option. - // @see \Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManager::getInstance() - 'handler_settings' => $this->configuration['handler_settings'], - ]; - return \Drupal::service('plugin.manager.entity_reference_selection')->getInstance($options); - } + use OgSelectionTrait; /** * Overrides the basic entity query object. Return only group in the matching @@ -67,7 +53,7 @@ protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') // the default selection handler of the entity, which the field reference // to, and add another logic to the query object i.e. check if the entities // bundle defined as group. - + $query = $this->getSelectionHandler()->buildEntityQuery($match, $match_operator); $target_type = $this->configuration['target_type']; $entityDefinition = \Drupal::entityTypeManager()->getDefinition($target_type); @@ -85,21 +71,18 @@ protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') $identifier_key = $entityDefinition->getKey('id'); $ids = []; + foreach ($user_groups as $delta => $group) { + $ids[] = $group->id(); + } + if ($this->configuration['handler_settings']['field_mode'] == 'admin') { // Don't include the groups, the user doesn't have create permission. - foreach ($user_groups as $delta => $group) { - $ids[] = $group->id(); - } - if ($ids) { $query->condition($identifier_key, $ids, 'NOT IN'); } } else { // Determine which groups should be selectable. - foreach ($user_groups as $group) { - $ids[] = $group->id(); - } if ($ids) { $query->condition($identifier_key, $ids, 'IN'); } @@ -113,13 +96,4 @@ protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') return $query; } - /** - * - * @return ContentEntityInterface[] - */ - protected function getUserGroups() { - $other_groups = Og::getEntityGroups(User::load($this->currentUser->id())); - return isset($other_groups[$this->configuration['target_type']]) ? $other_groups[$this->configuration['target_type']] : []; - } - } diff --git a/src/Plugin/EntityReferenceSelection/OgViewsSelection.php b/src/Plugin/EntityReferenceSelection/OgViewsSelection.php new file mode 100644 index 000000000..e34923f29 --- /dev/null +++ b/src/Plugin/EntityReferenceSelection/OgViewsSelection.php @@ -0,0 +1,79 @@ +getSelectionHandler()->initializeView($match, $match_operator, $limit, $ids); + $this->view = $this->getSelectionHandler()->view; + if ($return) { + $display = $this->view->getDisplay(); + + // @todo: Find a way to ensure only group entities are returned. + + $user_groups = $this->getUserGroups(); + $group_ids = []; + foreach ($user_groups as $delta => $group) { + $group_ids[] = $group->id(); + } + + if ($user_groups) { + if ($this->configuration['handler_settings']['field_mode'] == 'admin') { + // @todo: Ideally find a way to exclude certain IDs at a query level. + } + else { + // Determine which groups should be selectable. + if ($group_ids) { + $entity_reference_options = $display->getOption('entity_reference_options'); + if (isset($entity_reference_options['ids'])) { + $entity_reference_options['ids'] = array_intersect($entity_reference_options['ids'], $group_ids); + } + else { + $entity_reference_options['ids'] = $group_ids; + } + $display->setOption('entity_reference_options', $entity_reference_options); + } + else { + // User doesn't have permission to select any group simply return + // FALSE. + return FALSE; + } + } + } + } + return $return; + } + +} diff --git a/src/Plugin/Field/FieldWidget/OgComplex.php b/src/Plugin/Field/FieldWidget/OgComplex.php index 5667f70ee..22961ff92 100644 --- a/src/Plugin/Field/FieldWidget/OgComplex.php +++ b/src/Plugin/Field/FieldWidget/OgComplex.php @@ -37,8 +37,13 @@ class OgComplex extends EntityReferenceAutocompleteWidget { */ public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { $parent = parent::formElement($items, $delta, $element, $form, $form_state); - // todo: fix the definition in th UI level. - $parent['target_id']['#selection_handler'] = 'og:default'; + $options = array( + 'target_type' => $parent['target_id']['#target_type'], + 'handler' => $parent['target_id']['#selection_handler'], + 'handler_settings' => $parent['target_id']['#selection_settings'], + ); + $parent['target_id']['#selection_settings']['original_handler'] = $parent['target_id']['#selection_handler']; + $parent['target_id']['#selection_handler'] = Og::getSelectionHandler($this->fieldDefinition, $options)->getPluginId(); $parent['target_id']['#selection_settings']['field_mode'] = 'default'; return $parent; diff --git a/tests/src/Kernel/Entity/SelectionHandlerTest.php b/tests/src/Kernel/Entity/SelectionHandlerTest.php index 53454f09c..f0e149e33 100644 --- a/tests/src/Kernel/Entity/SelectionHandlerTest.php +++ b/tests/src/Kernel/Entity/SelectionHandlerTest.php @@ -27,7 +27,7 @@ class SelectionHandlerTest extends KernelTestBase { /** * The selection handler. * - * @var \Drupal\og\Plugin\EntityReferenceSelection\OgSelection. + * @var \Drupal\og\Plugin\EntityReferenceSelection\OgDefaultSelection. */ protected $selectionHandler;