Skip to content
This repository has been archived by the owner on Aug 18, 2024. It is now read-only.

Fix #417 by adding an add user route, local action and form #418

Closed
wants to merge 12 commits into from
3 changes: 3 additions & 0 deletions og.links.action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
og.local_actions:
class: \Drupal\Core\Menu\LocalActionDefault
deriver: \Drupal\og\Plugin\Derivative\OgLocalAction
20 changes: 20 additions & 0 deletions src/Controller/OgAdminMembersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\og\Entity\OgMembership;
use Drupal\og\OgMembershipInterface;
use Drupal\views\Views;

/**
Expand All @@ -32,4 +34,22 @@ public function membersList(RouteMatchInterface $route_match) {
return Views::getView('og_members_overview')->executeDisplay('default', $arguments);
}

/**
* Display subscribe form.
*
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The route match service.
*
* @return array
* The subscribe form.
*/
public function addMember(RouteMatchInterface $route_match) {
$parameter_name = $route_match->getRouteObject()->getOption('_og_entity_type_id');
/** @var \Drupal\Core\Entity\EntityInterface $group */
$group = $route_match->getParameter($parameter_name);
$membership = OgMembership::create(['type' => OgMembershipInterface::TYPE_DEFAULT]);
$membership->setGroup($group);
return $this->entityFormBuilder()->getForm($membership, 'user-subscribe');
}

}
5 changes: 5 additions & 0 deletions src/Controller/OgAdminRoutesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ public function overview(RouteMatchInterface $route_match) {
$route_name = "entity.$entity_type_id.og_admin_routes.$name";
$parameters = [$entity_type_id => $group->id()];

// Don't list items that are intentionally hidden from the overview.
if (array_intersect_assoc(['_overview' => FALSE], $info)) {
continue;
}

// We don't use Url::fromRoute() here for the access check, as it will
// prevent us from unit testing this method.
if (!$this->accessManager->checkNamedRoute($route_name, $parameters)) {
Expand Down
1 change: 1 addition & 0 deletions src/Entity/OgMembership.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
* "views_data" = "Drupal\og\OgMembershipViewsData",
* "form" = {
* "subscribe" = "Drupal\og\Form\GroupSubscribeForm",
* "user-subscribe" = "Drupal\og\Form\GroupUserSubscribeForm",
* "unsubscribe" = "Drupal\og\Form\GroupUnsubscribeConfirmForm",
* },
* }
Expand Down
10 changes: 10 additions & 0 deletions src/EventSubscriber/OgEventSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,16 @@ public function provideOgAdminRoutes(OgAdminRoutesEventInterface $event) {
'_module_dependencies' => 'views',
],
];
$routes_info['add_member'] = [
'controller' => '\Drupal\og\Controller\OgAdminMembersController::addMember',
'title' => 'Add Member',
'description' => 'Add group membership',
'path' => 'add-member',
'requirements' => [
'_og_user_access_group' => 'administer group',
],
'_overview' => FALSE,
];

$event->setRoutesInfo($routes_info);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Form/GroupSubscribeForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public function getQuestion() {

$message = $this->isStateActive()
? $this->t('Are you sure you want to join the group %label?', ['%label' => $label])
: $this->t('Are you sure you want to request subscription the group %label?', ['%label' => $label]);
: $this->t('Are you sure you want to request a subscription to the group %label?', ['%label' => $label]);

return $message;
}
Expand Down
129 changes: 129 additions & 0 deletions src/Form/GroupUserSubscribeForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php

declare(strict_types = 1);

namespace Drupal\og\Form;

use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\og\Entity\OgRole;
use Drupal\og\OgMembershipInterface;

/**
* Provides a form for subscribing a user to a group.
*/
class GroupUserSubscribeForm extends ContentEntityForm {

/**
* {@inheritdoc}
*/
public function getFormId() {
return 'og_user_subscribe_form';
}

/**
* Return the URL to redirect on cancel.
*
* @return \Drupal\Core\Url
* The URL object to redirect to.
*/
public function getCancelUrl() {
/** @var \Drupal\Core\Entity\ContentEntityInterface $group */
$group = $this->entity->getGroup();
// User have access to the group entity, direct to the member admin page.
// Otherwise back to the front page.
if ($group->access('view')) {
return new Url("entity.{$group->getEntityTypeId()}.og_admin_routes.members", [$group->getEntityTypeId() => $group->id()]);
}
return new Url('<front>');
}

/**
* {@inheritdoc}
*
* @see \Drupal\Core\Entity\EntityConfirmFormBase::buildForm
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
/** @var \Drupal\og\OgMembershipInterface $membership */
$membership = $this->entity;
$form['uid'] = [
'#type' => 'entity_autocomplete',
'#title' => $this->t('Member'),
'#target_type' => 'user',
];
$options = [];
/** @var \Drupal\og\OgRoleInterface $role */
foreach (OgRole::loadByGroupType($membership->getGroup()->getEntityTypeId(), $membership->getGroup()->bundle()) as $role) {
// Only add the role to the list if it is not a required role, these
// cannot be added. Nor should invalid roles be added.
if (!$role->isRequired() && $membership->isRoleValid($role)) {
$options[$role->id()] = $role->label();
}
}
$form['roles'] = [
'#type' => 'select',
'#title' => $this->t('Roles'),
'#multiple' => TRUE,
'#options' => $options,
];
$form[OgMembershipInterface::REQUEST_FIELD]['#access'] = FALSE;
return $form;
}

/**
* {@inheritdoc}
*/
protected function actions(array $form, FormStateInterface $form_state) {
$actions = parent::actions($form, $form_state);
$actions['submit']['#value'] = $this->t('Add');
$actions['cancel'] = [
'#type' => 'link',
'#title' => $this->t('Cancel'),
'#attributes' => ['class' => ['button']],
'#url' => $this->getCancelUrl(),
'#cache' => [
'contexts' => [
'url.query_args:destination',
],
],
];
return $actions;
}

/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
/** @var \Drupal\og\OgMembershipInterface $membership */
$membership = $this->entity;
$result = $this->entityTypeManager
->getStorage($membership->getEntityTypeId())
->getQuery()
->condition('uid', $form_state->getValue('uid'))
->condition('type', $membership->bundle())
->condition('entity_type', $membership->getGroup()->getEntityTypeId())
->condition('entity_id', $membership->getGroup()->id())
->execute();
if ($result) {
$form_state->setErrorByName('uid', $this->t('The user is already a member of the group.'));
}
}

/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
/** @var \Drupal\og\OgMembershipInterface $membership */
$membership = $this->entity;
amitaibu marked this conversation as resolved.
Show resolved Hide resolved
$this->messenger()->addStatus($this->t('%name added to %group.', [
'%name' => $membership->getOwner()->getAccountName(),
'%group' => $membership->getGroup()->label(),
]));
$form_state->setRedirectUrl($this->getCancelUrl());
}

}
86 changes: 86 additions & 0 deletions src/Plugin/Derivative/OgLocalAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

declare(strict_types = 1);

namespace Drupal\og\Plugin\Derivative;

use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Drupal\Core\Routing\RouteProvider;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\og\GroupTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Provides local action definitions for all entity bundles.
*/
class OgLocalAction extends DeriverBase implements ContainerDeriverInterface {

use StringTranslationTrait;

/**
* The group type manager.
*
* @var \Drupal\og\GroupTypeManagerInterface
*/
protected $groupTypeManager;

/**
* Route provider object.
*
* @var \Drupal\Core\Routing\RouteProvider
*/
protected $routProvider;

/**
* Creates an OgLocalTask object.
*
* @param \Drupal\og\GroupTypeManagerInterface $group_type_manager
* The group type manager.
* @param \Drupal\Core\Routing\RouteProvider $route_provider
* The route provider services.
*/
public function __construct(GroupTypeManagerInterface $group_type_manager, RouteProvider $route_provider) {
$this->groupTypeManager = $group_type_manager;
$this->routProvider = $route_provider;
}

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, $base_plugin_id) {
return new static(
$container->get('og.group_type_manager'),
$container->get('router.route_provider')
);
}

/**
* {@inheritdoc}
*/
public function getDerivativeDefinitions($base_plugin_definition) {
$derivatives = [];

foreach (array_keys($this->groupTypeManager->getGroupMap()) as $entity_type_id) {
$route_name = "entity.$entity_type_id.og_admin_routes.add_member";
$appears_route = "entity.$entity_type_id.og_admin_routes.members";
if (!$this->routProvider->getRoutesByNames([$route_name, $appears_route])) {
// Routes not found.
continue;
}

$derivatives["$entity_type_id.add_member"] = [
'route_name' => $route_name,
'title' => $this->t('Add member'),
'appears_on' => [$appears_route],
];
}

foreach ($derivatives as &$entry) {
$entry += $base_plugin_definition;
}

return $derivatives;
}

}