You are here

class Target in Drupal 7 to 8/9 Module Upgrader 8

Default implementation of TargetInterface.

Hierarchy

Expanded class hierarchy of Target

4 files declare their use of Target
drupalmoduleupgrader.drush.inc in ./drupalmoduleupgrader.drush.inc
Declarations for Drush.
DrupalmoduleupgraderCommands.php in src/Commands/DrupalmoduleupgraderCommands.php
TargetTest.php in tests/src/Unit/TargetTest.php
TestBase.php in tests/src/Unit/TestBase.php

File

src/Target.php, line 16

Namespace

Drupal\drupalmoduleupgrader
View source
class Target implements TargetInterface {

  /**
   * The target module's machine name.
   *
   * @var string
   */
  protected $id;

  /**
   * @var \Drupal\Component\Plugin\PluginManagerInterface
   */
  protected $indexerManager;

  /**
   * The target module's base path.
   *
   * @var string
   */
  protected $basePath;

  /**
   * @var IndexerInterface[]
   */
  protected $indexers = [];

  /**
   * @var \Doctrine\Common\Collections\ArrayCollection
   */
  protected $services;

  /**
   * All open documents.
   *
   * @var \Pharborist\RootNode[]
   */
  protected $documents = [];

  /**
   * Constructs a Target.
   *
   * @param string $path
   *   The base path of the target module.
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   *   The current container, to pull any dependencies out of.
   */
  public function __construct($path, ContainerInterface $container) {
    $this->indexerManager = $container
      ->get('plugin.manager.drupalmoduleupgrader.indexer');
    if (is_dir($path)) {
      $this->basePath = $path;
    }
    else {
      throw new \RuntimeException((new FormattableMarkup('Invalid base path: @path', [
        '@path' => $path,
      ]))
        ->__toString());
    }
  }

  /**
   * {@inheritdoc}
   */
  public function id() {
    if (empty($this->id)) {
      $dir = $this
        ->getBasePath();
      $info = (new Finder())
        ->in($dir)
        ->depth('== 0')
        ->name('*.info')
        ->getIterator();
      $info
        ->rewind();
      if ($info_file = $info
        ->current()) {
        $this->id = substr($info_file
          ->getFilename(), 0, -5);
      }
      else {
        throw new \RuntimeException((new FormattableMarkup('Could not find info file in @dir', [
          '@dir' => $dir,
        ]))
          ->__toString());
      }
    }
    return $this->id;
  }

  /**
   * {@inheritdoc}
   */
  public function getBasePath() {
    return $this->basePath;
  }

  /**
   * {@inheritdoc}
   */
  public function getPath($file) {
    if ($file[0] == '.') {
      $file = $this
        ->id() . $file;
    }
    return $this
      ->getBasePath() . '/' . ltrim($file, '/');
  }

  /**
   * {@inheritdoc}
   */
  public function getFinder() {

    // We do NOT want to include submodules. We can detect one by the presence
    // of an info file -- if there is one, its directory is a submodule.
    $directories = (new Finder())
      ->directories()
      ->in($this
      ->getBasePath())
      ->filter(function (\SplFileInfo $dir) {
      return (new Finder())
        ->files()
        ->in($dir
        ->getPathname())
        ->depth('== 0')
        ->name('*.info')
        ->count() === 0;
    });
    $directories = array_keys(iterator_to_array($directories));
    $directories[] = $this
      ->getBasePath();
    return (new Finder())
      ->files()
      ->in($directories)
      ->depth('== 0')
      ->name('*.module')
      ->name('*.install')
      ->name('*.inc')
      ->name('*.php')
      ->name('*.test');
  }

  /**
   * {@inheritdoc}
   */
  public function getIndexer($which) {
    if (empty($this->indexers[$which])) {

      /** @var IndexerInterface $indexer */
      $indexer = $this->indexerManager
        ->createInstance($which);
      $indexer
        ->bind($this);
      $this->indexers[$which] = $indexer;
    }
    return $this->indexers[$which];
  }

  /**
   * {@inheritdoc}
   */
  public function getServices() {
    if (empty($this->services)) {
      $this->services = new ArrayCollection();
    }
    return $this->services;
  }

  /**
   * Runs all available indexers on this target.
   */
  public function buildIndex() {
    $indexers = array_keys($this->indexerManager
      ->getDefinitions());
    foreach ($indexers as $id) {
      $this
        ->getIndexer($id)
        ->build();
    }

    // Release syntax trees that were opened during indexing.
    $this
      ->flush();
  }

  /**
   * Destroys all index data for this target.
   */
  public function destroyIndex() {
    $indexers = array_keys($this->indexerManager
      ->getDefinitions());
    foreach ($indexers as $id) {
      $this
        ->getIndexer($id)
        ->destroy();
    }
  }

  /**
   * {@inheritdoc}
   */
  public function implementsHook($hook) {
    return $this
      ->getIndexer('function')
      ->has('hook_' . $hook);
  }

  /**
   * {@inheritdoc}
   */
  public function executeHook($hook, array $arguments = []) {
    if ($this
      ->implementsHook($hook)) {
      return $this
        ->getIndexer('function')
        ->execute('hook_' . $hook, $arguments);
    }
    else {
      $variables = [
        '@module' => $this
          ->id(),
        '@hook' => $hook,
      ];
      throw new \InvalidArgumentException((new FormattableMarkup('@module does not implement hook_@hook.', $variables))
        ->__toString());
    }
  }

  /**
   * {@inheritdoc}
   */
  public function open($file) {
    if (empty($this->documents[$file])) {
      $this->documents[$file] = Parser::parseFile($file);
    }
    return $this->documents[$file];
  }

  /**
   * {@inheritdoc}
   */
  public function save(Node $node = NULL) {
    if ($node) {
      $file = $this
        ->getFileOf($node);
      if ($file) {
        $doc = $node instanceof RootNode ? $node : $node
          ->parents()
          ->get(0);
        $victory = file_put_contents($file, $doc
          ->getText());
        if ($victory === FALSE) {
          throw new IOException((new FormattableMarkup('Failed to save @file.', [
            '@file' => $file,
          ]))
            ->__toString());
        }
      }
      else {
        throw new IOException('Cannot save a node that is not attached to an open document.');
      }
    }
    else {
      array_walk($this->documents, [
        $this,
        'save',
      ]);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function create($file, $ns = NULL) {
    $this->documents[$file] = RootNode::create($ns);
    return $this->documents[$file];
  }

  /**
   * {@inheritdoc}
   */
  public function flush() {
    $this->documents = [];
  }

  /**
   * Determines which currently-open file a node belongs to, if any. Nodes
   * which are not part of any open syntax tree will return NULL.
   *
   * @return string|null
   */
  public function getFileOf(Node $node) {
    if ($node instanceof RootNode) {
      $root = $node;
    }
    else {
      $parents = $node
        ->parents();
      if ($parents
        ->isEmpty()) {
        return NULL;
      }
      $root = $parents
        ->get(0);
    }
    foreach ($this->documents as $file => $doc) {
      if ($root === $doc) {
        return $file;
      }
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Target::$basePath protected property The target module's base path.
Target::$documents protected property All open documents.
Target::$id protected property The target module's machine name.
Target::$indexerManager protected property
Target::$indexers protected property
Target::$services protected property
Target::buildIndex public function Runs all available indexers on this target.
Target::create public function Creates a new, empty document. Overrides TargetInterface::create
Target::destroyIndex public function Destroys all index data for this target.
Target::executeHook public function Executes a hook implementation and returns the result. Overrides TargetInterface::executeHook
Target::flush public function Clears internal references to all open documents, discarding changes. Overrides TargetInterface::flush
Target::getBasePath public function Returns the base path of the target module. Overrides TargetInterface::getBasePath
Target::getFileOf public function Determines which currently-open file a node belongs to, if any. Nodes which are not part of any open syntax tree will return NULL.
Target::getFinder public function Returns a fully configured Finder which can iterate over the target module's code files. Any file type which doesn't contain PHP code should be ignored. Overrides TargetInterface::getFinder
Target::getIndexer public function Returns an indexer for this target. Overrides TargetInterface::getIndexer
Target::getPath public function Returns the path to a particular file, relative to the CWD. Overrides TargetInterface::getPath
Target::getServices public function Returns services defined by the target module. Overrides TargetInterface::getServices
Target::id public function Returns the machine name of the target module. Overrides TargetInterface::id
Target::implementsHook public function Returns if the target module implements a particular hook. Overrides TargetInterface::implementsHook
Target::open public function Parses a file into a syntax tree, keeping a reference to it, and returns it. Overrides TargetInterface::open
Target::save public function Saves the file in which a particular node appears. Overrides TargetInterface::save
Target::__construct public function Constructs a Target.