devel_wizard-2.x-dev/src/Plugin/DevelWizard/Spell/BlockContentTypeBehatSpell.php
src/Plugin/DevelWizard/Spell/BlockContentTypeBehatSpell.php
<?php
declare(strict_types=1);
namespace Drupal\devel_wizard\Plugin\DevelWizard\Spell;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\devel_wizard\Attribute\DevelWizardSpell;
use Symfony\Component\Filesystem\Path;
#[DevelWizardSpell(
id: 'devel_wizard_block_content_type_behat',
category: new TranslatableMarkup('Block type'),
label: new TranslatableMarkup('Block type - Behat tests'),
description: new TranslatableMarkup('Generates Behat tests for an existing Block type.'),
tags: [
'bundle' => new TranslatableMarkup('Bundle'),
'config_entity' => new TranslatableMarkup('Config entity'),
'block_content_type' => new TranslatableMarkup('Block type'),
'quality_assurance' => new TranslatableMarkup('QA'),
'behat' => new TranslatableMarkup('Behat'),
],
)]
class BlockContentTypeBehatSpell extends ConfigEntityBehatSpellBase {
protected string $id = 'devel_wizard_block_content_type_behat';
protected string $provider = 'block_content';
protected string $contentEntityTypeId = 'block_content';
protected string $configEntityTypeId = 'block_content_type';
protected EntityTypeBundleInfoInterface $bundleInfo;
/**
* @throws \Drupal\Core\Entity\EntityMalformedException
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
protected function doItGenerateTests(): static {
$configuration = $this->getConfiguration();
$machineName = $configuration['machine_name'];
$configStorage = $this->getConfigStorage();
/** @var \Drupal\Core\Config\Entity\ConfigEntityInterface $bundle */
$bundle = $configStorage->load($machineName);
if (!$bundle) {
throw new \InvalidArgumentException("{$this->configEntityTypeId}:$machineName not exists");
}
$args = [
'@spell' => $this->getPluginDefinition()->id(),
'@machine_name' => $machineName,
'@bundle.url.canonical' => $bundle->toUrl()->toString(),
'@bundle.label' => $bundle->label(),
];
/* @noinspection HtmlUnknownTarget */
$this->batchContext['sandbox']['messages'][] = [
'type' => MessengerInterface::TYPE_STATUS,
'message' => $this->t(
'@spell - Create behat test for <a href="@bundle.url.canonical">@bundle.label</a>',
$args,
),
];
$tests = [
'access' => [
'create',
'edit',
'delete',
],
'form' => [
'create',
'edit',
],
];
foreach ($tests as $testType => $operations) {
foreach ($operations as $operation) {
$this->doItGenerateTest(
$testType,
$operation,
$bundle->getEntityTypeId(),
$machineName,
$bundle->label(),
);
}
}
return $this;
}
/**
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\SyntaxError
*/
protected function doItGenerateTest(
string $testType,
string $operation,
string $entityTypeId,
string $bundleMachineName,
string $bundleLabel,
): static {
$conf = $this->getConfiguration();
$filePath = Path::join(
$conf['features_dir'],
$bundleMachineName,
"{$bundleMachineName}.{$this->contentEntityTypeId}.{$testType}.{$operation}.feature",
);
$templatePath = "@devel_wizard/behat/{$entityTypeId}/devel_wizard.behat_{$testType}_{$operation}.feature.twig";
$values = [
'machine_name' => $bundleMachineName,
'label' => $bundleLabel,
'roles' => $this->getRolesWithStatusCode($bundleMachineName),
];
$rendered = $this->twig->render($templatePath, $values);
$this->fs->mkdir(Path::getDirectory($filePath));
$this->fs->dumpFile($filePath, $rendered);
$this->messageFilesystemEntryCreate($filePath);
return $this;
}
/**
* Loads all roles in the system with status codes.
*
* Helper method to load all roles in the system with status codes
* determining if the role has access to various operations, also provides
* the number of spaces needed between TableNode keys.
*
* @param string $bundleMachineName
* The bundle machine-name we are creating the Behat tests for.
*
* @return array
* Returns an array with the roles and status codes.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function getRolesWithStatusCode(string $bundleMachineName): array {
$roles = [];
$userRoleStorage = $this
->entityTypeManager
->getStorage('user_role');
$adminRoles = $userRoleStorage
->getQuery()
->condition('is_admin', TRUE)
->execute();
$adminRoles[] = "{$this->configEntityTypeId}_{$bundleMachineName}_admin";
$allRoles = $userRoleStorage->loadMultiple();
$roleNames = array_keys($allRoles);
$longestRoleLength = (int) max(array_map('strlen', $roleNames));
foreach ($roleNames as $role) {
// Determine how many spaces we need in each row of TableNode.
$roles[$role]['spaces'] = $longestRoleLength - strlen($role) + 1;
if (!in_array($role, $adminRoles)) {
$roles[$role]['code'] = 403;
continue;
}
$roles[$role]['code'] = 200;
}
// Sort the array by code.
array_multisort(array_column($roles, 'code'), SORT_ASC, $roles);
// Determine how many spaces we need in TableNode header after 'role'.
$roles['headerSpaces'] = $longestRoleLength - 4 + 1;
return $roles;
}
}
