association-1.0.0-alpha2/src/Plugin/Association/Behavior/EntityManifestBehavior.php
src/Plugin/Association/Behavior/EntityManifestBehavior.php
<?php namespace Drupal\association\Plugin\Association\Behavior; use Drupal\association\Attribute\AssociationBehavior; use Drupal\association\Entity\AssociationInterface; use Drupal\association\Entity\AssociationTypeInterface; use Drupal\association\Plugin\BehaviorBase; use Drupal\association\Plugin\BehaviorInterface; use Drupal\Core\Access\AccessResult; use Drupal\Core\Access\AccessResultInterface; use Drupal\Core\Plugin\PluginWithFormsInterface; use Drupal\Core\Plugin\PluginWithFormsTrait; use Drupal\Core\Session\AccountInterface; use Drupal\Core\StringTranslation\TranslatableMarkup; /** * Behavior for managing associations which have a prescriptive entity manifest. * * Manages Entity Associations that need to maintain the specific counts of * entities and bundles allowed. Each entity bundle can have a separate * cardinality constraint. This gives a associations a more templated content * building experience. */ #[AssociationBehavior( id: 'entity_manifest', label: new TranslatableMarkup('Entity manifest'), manager_builder: '\Drupal\association\Behavior\Manager\EntityManifestBuilder', forms: [ 'configure' => '\Drupal\association\Behavior\Form\ConfigureManifestBehaviorForm', ], )] class EntityManifestBehavior extends BehaviorBase implements PluginWithFormsInterface { use PluginWithFormsTrait; /** * {@inheritdoc} */ public function defaultConfiguration() { return [ 'manifest' => [], ]; } /** * {@inheritdoc} */ public function getEntityTypes(): array { $allowedTypes = $this->adapterManager->getEntityTypes(); $manifest = $this->getConfiguration()['manifest'] ?? []; $entityTypes = []; foreach ($manifest as $tagInfo) { foreach ($tagInfo['entity_types'] as $type => $bundles) { if (isset($allowedTypes[$type])) { $entityTypes[$type] = $type; } } } return $entityTypes; } /** * {@inheritdoc} */ public function isValidEntity($tag, $entity_type, $bundle): bool { $config = $this->getConfiguration(); return !empty($config['manifest'][$tag]['entity_types'][$entity_type][$bundle]); } /** * {@inheritdoc} */ public function getTags(): array { $manifest = $this->configuration['manifest'] ?? []; $tags = []; foreach ($manifest as $key => $definition) { $tags[$key] = $definition['label']; } return $tags; } /** * {@inheritdoc} */ public function getTagLabel($tag, $entity_type_id, $bundle) { return $this->configuration['manifest'][$tag]['label'] ?? ''; } /** * {@inheritdoc} */ public function createAccess(AssociationInterface $association, $tag, $entity_type_id, $bundle, AccountInterface $account): AccessResultInterface { if (!$this->isValidEntity($tag, $entity_type_id, $bundle)) { return AccessResult::forbidden(); } $definition = $this->getConfiguration()['manifest'][$tag]; // If not an unlimited number of items, we need to ensure that it's okay // to create another new instance of the entity type. if ($definition['limit'] !== BehaviorInterface::CARDINALITY_UNLIMITED) { $count = $this->entityTypeManager ->getStorage('association_link') ->getQuery() ->accessCheck(FALSE) ->condition('association', $association->id()) ->condition('tag', $tag) ->count() ->execute(); return $count < $definition['limit'] ? AccessResult::allowed() : AccessResult::forbidden(); } return AccessResult::allowed(); } /** * {@inheritdoc} */ public function validateConfigUpdate(AssociationTypeInterface $assocation_type, array $changes): array { $errors = []; $current = $this->getConfiguration()['manifest'] ?? []; $missing = array_diff_key($current, $changes['manifest']); if ($missing) { $errors[] = $this->t('Entities have been removed from the manifest after association type has data: @types', [ '@types' => implode(', ', array_keys($missing)), ]); } else { foreach ($current as $tag => $info) { $tagChange = $changes['manifest'][$tag]; if ($info['required'] && !$tagChange['required']) { $errors[] = $this->t('Cannot remove required flag for @tag.', [ '@tag' => $tag, ]); } foreach ($info['entity_types'] as $entityTypeId => $bundles) { if (empty($tagChange['entity_types'][$entityTypeId])) { $errors[] = $this->t('Entity type of "@entity_type" cannot be removed from @tag', [ '@entity_type' => $entityTypeId, '@tag' => $tag, ]); } elseif ($diff = array_diff($tagChange['entity_types'][$entityTypeId], $bundles)) { $errors[] = $this->t('Entity type %entity_type missing bundles "@bundles" from @tag', [ '%entity_type' => $entityTypeId, '@bundles' => implode(', ', $diff), '@tag' => $tag, ]); } } if (array_keys($tagChange['entity_types']) != array_keys($info['entity_types'])) { $errors[] = $this->t('Entity manifest bundle and required properties cannot be changed for @tag', [ '@tag' => $tag, ]); } if ($tagChange['limit'] < $info['limit']) { $errors[] = $this->t('Entity manifest limit cannot be reduced for @tag', [ '@tag' => $tag, ]); } } } return $errors; } }