og-8.x-1.x-dev/tests/src/Kernel/Entity/OgSelectionTest.php

tests/src/Kernel/Entity/OgSelectionTest.php
<?php

declare(strict_types=1);

namespace Drupal\Tests\og\Kernel\Entity;

use Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Entity\EntityReferenceSelection\SelectionInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\og\Entity\OgRole;
use Drupal\og\Og;
use Drupal\og\OgGroupAudienceHelperInterface;
use Drupal\og\OgRoleInterface;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Drupal\user\UserInterface;

/**
 * Tests entity reference selection plugins.
 *
 * @group og
 */
class OgSelectionTest extends KernelTestBase {

  /**
   * The selection handler.
   */
  protected SelectionInterface $selectionHandler;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'system',
    'user',
    'field',
    'node',
    'og',
    'options',
  ];

  /**
   * A site-wide group administrator.
   */
  protected UserInterface $groupAdmin;

  /**
   * A group manager.
   */
  protected UserInterface $groupManager;

  /**
   * A regular group member.
   */
  protected UserInterface $groupMember;

  /**
   * A user with 'bypass node access' permission.
   */
  protected UserInterface $nodeBypassUser;

  /**
   * The machine name of the group node type.
   */
  protected string $groupBundle;

  /**
   * The machine name of the group content node type.
   */
  protected string $groupContentBundle;

  /**
   * The field definition used in this test.
   */
  protected FieldDefinitionInterface $fieldDefinition;

  /**
   * Selection plugin manager.
   */
  protected SelectionPluginManagerInterface $selectionPluginManager;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();

    // Add membership and config schema.
    $this->installConfig(['og']);
    $this->installEntitySchema('og_membership');
    $this->installEntitySchema('user');
    $this->installEntitySchema('node');
    $this->installSchema('system', 'sequences');
    $this->installSchema('node', 'node_access');

    // Setting up variables.
    $this->groupBundle = mb_strtolower($this->randomMachineName());
    $this->groupContentBundle = mb_strtolower($this->randomMachineName());
    $this->selectionPluginManager = $this->container->get('plugin.manager.entity_reference_selection');

    // Create a group.
    NodeType::create([
      'type' => $this->groupBundle,
      'name' => $this->randomString(),
    ])->save();

    // Create a group content type.
    NodeType::create([
      'type' => $this->groupContentBundle,
      'name' => $this->randomString(),
    ])->save();

    // Define bundle as group.
    Og::groupTypeManager()->addGroup('node', $this->groupBundle);

    // Add og audience field to group content.
    $this->fieldDefinition = Og::createField(OgGroupAudienceHelperInterface::DEFAULT_FIELD, 'node', $this->groupContentBundle);

    // The selection handler for the field.
    // Get the storage of the field.
    $options = [
      'target_type' => $this->fieldDefinition->getFieldStorageDefinition()->getSetting('target_type'),
      'handler' => $this->fieldDefinition->getSetting('handler'),
    ];
    $this->selectionPluginManager->getInstance($options);
    $this->selectionHandler = $this->selectionPluginManager->getSelectionHandler($this->fieldDefinition);

    // Create users.
    $this->groupAdmin = User::create(['name' => $this->randomString()]);
    $this->groupAdmin->save();

    $this->groupManager = User::create(['name' => $this->randomString()]);
    $this->groupManager->save();

    $this->groupMember = User::create(['name' => $this->randomString()]);
    $this->groupMember->save();

    $this->nodeBypassUser = User::create(['name' => $this->randomString()]);
    $this->nodeBypassUser->save();

    // Assign administer-group permission to admin.
    $role = Role::create([
      'id' => $this->randomMachineName(),
      'label' => $this->randomMachineName(),
    ]);

    $role
      ->grantPermission('administer organic groups')
      ->save();

    $this
      ->groupAdmin
      ->addRole($role->id());

    $node_bypass_role = Role::create([
      'id' => $this->randomMachineName(),
      'label' => $this->randomMachineName(),
    ]);
    $node_bypass_role
      ->grantPermission('bypass node access')
      ->save();
    $this->nodeBypassUser->addRole($node_bypass_role->id());

    // Set the group content entity stub on the selection handler's config.
    $group_content = Node::create([
      'type' => $this->groupContentBundle,
      'title' => $this->randomString(),
    ]);

    $this->selectionHandler->setConfiguration([
      'target_type' => 'node',
      'entity' => $group_content,
    ]);
  }

  /**
   * Testing the OG manager selection handler.
   *
   * We need to verify that the manager selection handler will use the default
   * selection manager of the entity which the audience field referencing to.
   *
   * i.e: When the field referencing to node, we need verify we got the default
   * node selection handler.
   */
  public function testSelectionHandler(): void {
    $this->assertEquals(get_class($this->selectionHandler->getSelectionHandler()), 'Drupal\node\Plugin\EntityReferenceSelection\NodeSelection');
  }

  /**
   * Testing OG selection handler results.
   *
   * We need to verify that each user gets the groups they own in the normal
   * widget and the other users' groups in the other groups widget and vice
   * versa.
   */
  public function testSelectionHandlerResults(): void {
    $user1_groups = $this->createGroups(5, $this->groupAdmin);
    $user2_groups = $this->createGroups(5, $this->groupManager);

    $all_groups_ids = array_merge($user1_groups, $user2_groups);

    // Admin user can create content on all groups.
    $this->setCurrentAccount($this->groupAdmin);
    $groups = $this->selectionHandler->getReferenceableEntities();
    $this->assertEquals($all_groups_ids, array_keys($groups[$this->groupBundle]));

    // Group manager can create content in their groups.
    $this->setCurrentAccount($this->groupManager);
    $groups = $this->selectionHandler->getReferenceableEntities();
    $this->assertEquals($user2_groups, array_keys($groups[$this->groupBundle]));

    // Non-group member.
    $this->setCurrentAccount($this->groupMember);
    $groups = $this->selectionHandler->getReferenceableEntities();
    $this->assertArrayNotHasKey($this->groupBundle, $groups);

    // Add group member to first group from group admin's groups to
    // create content.
    $group_id = $user1_groups[0];
    $group = Node::load($group_id);
    $membership = Og::createMembership($group, $this->groupMember);
    $membership->save();

    // Group member cannot create content in their groups when they don't have
    // access to.
    $groups = $this->selectionHandler->getReferenceableEntities();
    $this->assertArrayNotHasKey($this->groupBundle, $groups);

    // Grant OG permission.
    $og_role = OgRole::getRole('node', $this->groupBundle, OgRoleInterface::AUTHENTICATED);
    $og_role
      ->grantPermission("create {$this->groupContentBundle} content")
      ->save();

    $groups = $this->selectionHandler->getReferenceableEntities();
    $this->assertEquals([$group_id], array_keys($groups[$this->groupBundle]));
  }

  /**
   * Tests saving multi-group content with limited visibility.
   */
  public function testMultiGroupContentSaveWithHiddenGroup(): void {
    // Create 3 groups owned by the OG group admin.
    $groups = [];
    for ($i = 0; $i < 3; $i++) {
      $group = Node::create([
        'title' => $this->randomString(),
        'uid' => $this->groupAdmin->id(),
        'type' => $this->groupBundle,
      ]);
      $group->save();
      $groups[$group->id()] = $group;
    }
    $expected_group_ids = array_keys($groups);
    $limited_group_ids = array_slice($expected_group_ids, 0, 2);

    // Create authors: one limited user and reuse the OG group admin.
    $limited_user = User::create(['name' => $this->randomString()]);
    $limited_user->save();

    $permissions = [
      "create {$this->groupContentBundle} content",
      "edit own {$this->groupContentBundle} content",
    ];

    // Grant memberships so the limited user can post in only two groups.
    $limited_role = OgRole::create()
      ->setName($this->randomMachineName())
      ->setLabel($this->randomString())
      ->setGroupType('node')
      ->setGroupBundle($this->groupBundle);
    foreach ($permissions as $permission) {
      $limited_role->grantPermission($permission);
    }
    $limited_role->save();

    // Only grant membership to 2 of the 3 groups.
    $limited_membership_one = Og::createMembership($groups[$limited_group_ids[0]], $limited_user);
    $limited_membership_one->addRole($limited_role)->save();

    $limited_membership_two = Og::createMembership($groups[$limited_group_ids[1]], $limited_user);
    $limited_membership_two->addRole($limited_role)->save();

    // Seed group content node that references all three groups.
    $audience_values = [];
    foreach ($groups as $group) {
      $audience_values[] = ['target_id' => $group->id()];
    }

    // Create and save the group content an OG group admin user.
    $this->setCurrentAccount($this->groupAdmin);
    $group_content = Node::create([
      'type' => $this->groupContentBundle,
      'title' => $this->randomString(),
      OgGroupAudienceHelperInterface::DEFAULT_FIELD => $audience_values,
      'uid' => $this->groupAdmin->id(),
    ]);
    $group_content->save();

    $group_content_id = (int) $group_content->id();
    $group_content = Node::load($group_content_id);

    // With the limited visibility user, we should only see permitted groups
    // yet still be able to save the content as members of the other groups.
    $this->setCurrentAccount($limited_user);
    $initial_save_status = $group_content->save();
    $this->assertSame(SAVED_UPDATED, $initial_save_status);
    $post_save_groups = $group_content->get(OgGroupAudienceHelperInterface::DEFAULT_FIELD)->referencedEntities();
    $post_save_group_ids = [];
    foreach ($post_save_groups as $group_entity) {
      $post_save_group_ids[] = (int) $group_entity->id();
    }
    $this->assertSame($limited_group_ids, $post_save_group_ids, 'Limited editor only sees groups they can post in.');

    // Users bypassing node access should always see every referenced group even
    // if they are not OG administrators.
    $this->setCurrentAccount($this->nodeBypassUser);
    $node_bypass_groups = $group_content->get(OgGroupAudienceHelperInterface::DEFAULT_FIELD)->referencedEntities();
    $node_bypass_group_ids = [];
    foreach ($node_bypass_groups as $group_entity) {
      $node_bypass_group_ids[] = (int) $group_entity->id();
    }
    $this->assertSame($expected_group_ids, $node_bypass_group_ids);

    // Switch back to the limited account for the remaining assertions.
    $this->setCurrentAccount($limited_user);

    // Administrators still see every referenced group, confirming hidden
    // memberships remain attached to the entity.
    $this->setCurrentAccount($this->groupAdmin);
    $admin_visible_groups = $group_content->get(OgGroupAudienceHelperInterface::DEFAULT_FIELD)->referencedEntities();
    $admin_group_ids = [];
    foreach ($admin_visible_groups as $group_entity) {
      $admin_group_ids[] = (int) $group_entity->id();
    }
    $this->assertSame($expected_group_ids, $admin_group_ids);

    // Switch back to the limited account for the remaining assertions.
    $this->setCurrentAccount($limited_user);

    // Check the selection handler only shows 2.
    $limited_selection_handler = $this->selectionPluginManager->getSelectionHandler($this->fieldDefinition);
    $limited_configuration = $limited_selection_handler->getConfiguration();
    $limited_configuration['entity'] = $group_content;
    $limited_selection_handler->setConfiguration($limited_configuration);

    $limited_referenceable = $limited_selection_handler->getReferenceableEntities();
    $this->assertArrayHasKey($this->groupBundle, $limited_referenceable);
    $visible_group_ids = [];
    foreach ($limited_referenceable[$this->groupBundle] as $group_id => $label) {
      $visible_group_ids[] = (int) $group_id;
    }
    $this->assertSame($limited_group_ids, $visible_group_ids);

    $group_content->setTitle($this->randomString());
    $this->assertSame(SAVED_UPDATED, $group_content->save());

    // Reload via entity storage to ensure all group references persisted. Use
    // the administrator account so hidden groups remain visible.
    $this->setCurrentAccount($this->groupAdmin);
    /** @var \Drupal\node\NodeInterface $reloaded */
    $reloaded = Node::load($group_content_id);
    $this->assertNotNull($reloaded);
    $actual_group_ids = [];
    foreach ($reloaded->get(OgGroupAudienceHelperInterface::DEFAULT_FIELD)->referencedEntities() as $group_entity) {
      $actual_group_ids[] = (int) $group_entity->id();
    }
    $this->assertSame($expected_group_ids, $actual_group_ids);

    // Full-access administrator should see every group when editing.
    $full_selection_handler = $this->selectionPluginManager->getSelectionHandler($this->fieldDefinition);
    $full_configuration = $full_selection_handler->getConfiguration();
    $full_configuration['entity'] = $reloaded;
    $full_selection_handler->setConfiguration($full_configuration);

    $full_referenceable = $full_selection_handler->getReferenceableEntities();
    $this->assertArrayHasKey($this->groupBundle, $full_referenceable);
    $full_visible_group_ids = [];
    foreach ($full_referenceable[$this->groupBundle] as $group_id => $label) {
      $full_visible_group_ids[] = (int) $group_id;
    }
    $this->assertSame($expected_group_ids, $full_visible_group_ids);

    $reloaded->setTitle($this->randomString());
    $this->assertSame(SAVED_UPDATED, $reloaded->save());

    // Final save should still reference each original group.
    /** @var \Drupal\node\NodeInterface $final */
    $final = Node::load($group_content_id);
    $this->assertNotNull($final);
    $final_group_ids = [];
    foreach ($final->get(OgGroupAudienceHelperInterface::DEFAULT_FIELD)->referencedEntities() as $group_entity) {
      $final_group_ids[] = (int) $group_entity->id();
    }
    $this->assertSame($expected_group_ids, $final_group_ids);
  }

  /**
   * Creating groups for a given user.
   *
   * @param int $amount
   *   The number of groups to create.
   * @param \Drupal\user\Entity\User $user
   *   The user object which owns the groups.
   *
   * @return \Drupal\Core\Entity\ContentEntityBase[]
   *   An array of group entities.
   */
  protected function createGroups(int $amount, User $user): array {
    $groups = [];

    for ($i = 0; $i <= $amount; $i++) {
      $group = Node::create([
        'title' => $this->randomString(),
        'uid' => $user->id(),
        'type' => $this->groupBundle,
      ]);
      $group->save();

      $groups[] = $group->id();
    }

    return $groups;
  }

  /**
   * Sets the current account.
   *
   * @param \Drupal\Core\Session\AccountInterface $account
   *   The account to switch to.
   */
  protected function setCurrentAccount(AccountInterface $account): void {
    $this->container->get('account_switcher')->switchTo($account);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc