og-8.x-1.x-dev/src/Plugin/Validation/Constraint/ValidOgMembershipReferenceConstraintValidator.php
src/Plugin/Validation/Constraint/ValidOgMembershipReferenceConstraintValidator.php
<?php
declare(strict_types=1);
namespace Drupal\og\Plugin\Validation\Constraint;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\og\GroupTypeManagerInterface;
use Drupal\og\OgAccessInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Checks if referenced entities are valid.
*/
class ValidOgMembershipReferenceConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
public function __construct(
protected EntityTypeManagerInterface $entityTypeManager,
protected GroupTypeManagerInterface $groupTypeManager,
protected AccountInterface $currentUser,
protected OgAccessInterface $ogAccess,
) {}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container): self {
return new static(
$container->get('entity_type.manager'),
$container->get('og.group_type_manager'),
$container->get('current_user'),
$container->get('og.access')
);
}
/**
* {@inheritdoc}
*/
public function validate(mixed $value, Constraint $constraint) {
if (!$value instanceof FieldItemListInterface) {
return;
}
// Pull the raw field values instead of relying on referencedEntities(),
// which may be filtered for unauthorized viewers.
$raw_items = $value->getValue();
if (empty($raw_items)) {
return;
}
$groups = [];
$target_ids = [];
foreach ($raw_items as $item) {
$group = $item['entity'] ?? NULL;
if ($group instanceof ContentEntityInterface) {
$groups[$group->id()] = $group;
continue;
}
if (isset($item['target_id'])) {
$target_ids[$item['target_id']] = $item['target_id'];
}
}
if ($target_ids) {
$target_type = $value->getFieldDefinition()->getSetting('target_type');
$loaded = $this->entityTypeManager->getStorage($target_type)->loadMultiple($target_ids);
foreach ($loaded as $group) {
if ($group instanceof ContentEntityInterface) {
$groups[$group->id()] = $group;
}
}
}
if (!$groups) {
// Nothing to validate.
return;
}
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = $this->context->getRoot()->getValue();
$user = $this->currentUser->getAccount();
foreach ($groups as $group) {
$params = ['%label' => $group->label()];
// Ensure the referenced entity is actually a group.
if (!$this->groupTypeManager->isGroup($group->getEntityTypeId(), $group->bundle())) {
$this->context->addViolation($constraint->notValidGroup, $params);
// No access check needed if it's not a group.
continue;
}
// Check if the user has permission to create content in this group.
// We use 'create' operation for both new and existing entities because
// in OG, the 'create' permission represents the ability to post content
// within a group, regardless of entity state.
$access = $this->ogAccess->userAccessGroupContentEntityOperation('create', $group, $entity, $user);
if (!$access->isAllowed()) {
$this->context->addViolation($constraint->notAllowedToPostInGroup, $params);
}
}
}
}
