wse-1.0.x-dev/modules/wse_menu/src/Drush/Commands/WseMenuCommands.php

modules/wse_menu/src/Drush/Commands/WseMenuCommands.php
<?php

namespace Drupal\wse_menu\Drush\Commands;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\File\FileExists;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\workspaces\Entity\Workspace;
use Drupal\workspaces\WorkspaceManagerInterface;
use Drupal\wse_menu\MenuIterator;
use Drupal\wse_menu\WseMenuTreeStorageInterface;
use Drush\Commands\DrushCommands;
use Graphp\Graph\Graph;
use Graphp\GraphViz\GraphViz;

/**
 * Drush commands for the wse_menu module.
 */
class WseMenuCommands extends DrushCommands {

  public function __construct(
    protected string $appRoot,
    protected EntityTypeManagerInterface $entityTypeManager,
    protected WorkspaceManagerInterface $workspaceManager,
    protected WseMenuTreeStorageInterface $menuTreeStorage,
    protected MenuLinkTreeInterface $menuLinkTree,
    protected FileSystemInterface $fileSystem,
  ) {
    parent::__construct();
  }

  /**
   * Rebuilds the menu tree for a workspace.
   *
   * @param string|null $workspace_id
   *   The workspace ID.
   * @param array $options
   *   (optional) An array of options.
   *
   * @usage wse-menu:rebuild-tree workspace_id
   *   Rebuilds the menu tree for a given workspace.
   * @usage wse-menu:rebuild-tree --all
   *   Rebuilds the menu tree for all open workspaces.
   *
   * @command wse-menu:rebuild-tree
   * @aliases wsm:rt
   *
   * @option all
   *   Rebuilds the menu tree for all open workspaces.
   */
  public function rebuildTree(?string $workspace_id = NULL, array $options = ['all' => FALSE]): void {
    if ($options['all']) {
      $workspaces = $this->entityTypeManager->getStorage('workspace')
        ->loadByProperties(['status' => WSE_STATUS_OPEN]);

      if (empty($workspaces)) {
        $this->logger()->notice(dt('There are no open workspaces.'));
        return;
      }
    }
    else {
      if (empty($workspace_id)) {
        $this->logger()->error(dt('No workspace specified. Did you intend to use the --all option?'));
        return;
      }

      $workspace = Workspace::load($workspace_id);
      if (!$workspace || wse_workspace_get_status($workspace) == WSE_STATUS_CLOSED) {
        $this->logger()->error(dt('The @id workspace does not exist or is closed.', ['@id' => $workspace_id]));
        return;
      }

      $workspaces = [$workspace_id => $workspace];
    }

    foreach ($workspaces as $workspace) {
      $this->menuTreeStorage->rebuildWorkspaceMenuTree($workspace);
      $this->logger()->success(dt('The menu tree has been rebuilt for the @label workspace.', ['@label' => $workspace->label()]));
    }
  }

  /**
   * Generates the ASCII representation of menu trees.
   *
   * @param string $menu_name
   *   The name of the menu for which to generate the text representation.
   * @param array $options
   *   (optional) An array of options.
   *
   * @usage wse-menu:dump-tree main
   *   Generates the ASCII representation of the Main menu.
   *
   * @command wse-menu:dump-tree
   * @aliases wsm:dt
   *
   * @option all
   *   Generates data for all menus.
   * @option exclude
   *   List of menus to exclude when the '--all' option is used.
   * @option workspace
   *   Generate the data in the context of a workspace.
   * @option status
   *   Appends the menu item's status to the title.
   * @option id
   *   Appends the ID to the title if the item is a custom menu link entity.
   * @option file
   *   Whether to dump the menu tree in a text file. The default location is
   *   '../menu_tree', which places the file outside the web root.
   * @option dir
   *   Saves the file in the given directory, relative to Drupal's app root.
   */
  public function generateMenuTreeAsText(
    string $menu_name = 'main',
    array $options = [
      'all' => FALSE,
      'exclude' => [
        'account',
        'admin',
        'tools',
      ],
      'workspace' => NULL,
      'status' => FALSE,
      'id' => FALSE,
      'file' => FALSE,
      'dir' => '../menu_tree',
    ],
  ): void {
    $this->generateTreeCommand('doGenerateMenuTreeAsText', $menu_name, $options);
  }

  /**
   * Generates a PNG image for a menu tree using GraphViz.
   *
   * @param string $menu_name
   *   The name of the menu for which to generate the image.
   * @param array $options
   *   (optional) An associative array of options.
   *
   * @usage wse-menu:dump-tree-image main
   *   Generates a PNG image for the Main menu.
   *
   * @command wse-menu:dump-tree-image
   * @aliases wsm:dti
   *
   * @option all
   *   Generates data for all menus.
   * @option exclude
   *   List of menus to exclude when the '--all' option is used.
   * @option workspace
   *   Generate the data in the context of a workspace.
   * @option dir
   *   Saves the file in the given directory, relative to Drupal's app root.
   */
  public function generateMenuTreeAsImage(
    string $menu_name,
    array $options = [
      'all' => FALSE,
      'exclude' => [
        'account',
        'admin',
        'tools',
      ],
      'workspace' => NULL,
      'dir' => '../menu_tree',
    ],
  ): void {
    if (!class_exists('Graphp\Graph\Graph') || !class_exists('Graphp\GraphViz\GraphViz')) {
      throw new \RuntimeException("The 'graphp/graph' and 'graphp/graphviz' packages are required to run this command.");
    }

    $this->generateTreeCommand('doGenerateMenuTreeAsImage', $menu_name, $options);
  }

  /**
   * Helper for the tree generation commands.
   *
   * @param string $function_name
   *   The function name for the output type, either 'doGenerateMenuTreeAsText'
   *   or 'doGenerateMenuTreeAsImage'.
   * @param string $menu_name
   *   The name of the menu for which to generate the tree.
   * @param array $options
   *   (optional) An array of options.
   */
  protected function generateTreeCommand(string $function_name, string $menu_name, array $options): void {
    if ($options['all']) {
      $menu_names = $this->menuTreeStorage->getMenuNames();
      $menu_names = array_diff_key($menu_names, array_flip($options['exclude']));
    }
    else {
      $menu_names = [$menu_name];
    }

    $callable = function () use ($function_name, $menu_names, $options): void {
      foreach ($menu_names as $menu_name) {
        $this->$function_name($menu_name, $options);
      }
    };

    if ($options['workspace']) {
      if ($workspace = Workspace::load($options['workspace'])) {
        $this->workspaceManager->executeInWorkspace($workspace->id(), $callable);
      }
      else {
        $this->logger()->error(dt('The @id workspace does not exist.', ['@id' => $options['workspace']]));
      }
    }
    else {
      $callable();
    }
  }

  /**
   * Generates the ASCII representation for a given menu.
   *
   * @param string $menu_name
   *   The name of the menu for which to generate the text representation.
   * @param array $options
   *   (optional) An array of options.
   */
  protected function doGenerateMenuTreeAsText(string $menu_name, array $options): void {
    $tree = $this->menuLinkTree->load($menu_name, new MenuTreeParameters());
    $manipulators = [
      ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
    ];
    $tree = $this->menuLinkTree->transform($tree, $manipulators);

    $tree_iterator = new \RecursiveTreeIterator(new MenuIterator($tree, $options['status'], $options['id']));
    $file_data = implode(PHP_EOL, iterator_to_array($tree_iterator)) . PHP_EOL;

    if (!$options['file']) {
      $this->io()->section($menu_name);
      $this->io()->write($file_data);
    }
    else {
      // Store the files in a directory outside the web root.
      $target_dir = $this->appRoot . '/' . $options['dir'];
      $this->fileSystem->prepareDirectory($target_dir, FileSystemInterface:: CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
      $this->fileSystem->saveData($file_data, $target_dir . '/' . $menu_name . '.txt', FileExists::Replace);
    }
  }

  /**
   * Generates a PNG image for a menu tree using GraphViz.
   *
   * @param string $menu_name
   *   The name of the menu for which to generate the image.
   * @param array $options
   *   (optional) An array of options.
   */
  protected function doGenerateMenuTreeAsImage(string $menu_name, array $options) {
    $tree = $this->menuLinkTree->load($menu_name, new MenuTreeParameters());
    $manipulators = [
      ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
      ['callable' => 'menu.default_tree_manipulators:flatten'],
    ];
    $tree = $this->menuLinkTree->transform($tree, $manipulators);

    $graph = new Graph();
    $graph->setAttribute('graphviz.graph.rankdir', 'LR');
    foreach ($tree as $item) {
      $key = $item->link->getPluginId();
      $$key = $graph->createVertex([
        'graphviz.label' => $item->link->getTitle(),
      ]);
      if ($parent = $item->link->getParent()) {
        $graph->createEdgeDirected($$parent, $$key);
      }
    }

    $graphviz = new GraphViz();
    $tmp_file = $graphviz->createImageFile($graph);

    // Store the files in a directory outside the web root.
    $target_dir = $this->appRoot . '/' . $options['dir'];
    $this->fileSystem->prepareDirectory($target_dir, FileSystemInterface:: CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS);
    $this->fileSystem->move($tmp_file, $target_dir . '/' . $menu_name . '.png', FileExists::Replace);
  }

}

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

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