* Jordi Boggiano * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Composer\Installer; use Composer\IO\IOInterface; use Composer\Package\PackageInterface; use Composer\Repository\RepositoryInterface; use Symfony\Component\Console\Formatter\OutputFormatter; /** * Add suggested packages from different places to output them in the end. * * @author Haralan Dobrev */ class SuggestedPackagesReporter { const MODE_LIST = 1; const MODE_BY_PACKAGE = 2; const MODE_BY_SUGGESTION = 4; /** * @var array */ protected $suggestedPackages = array(); /** * @var IOInterface */ private $io; public function __construct(IOInterface $io) { $this->io = $io; } /** * @return array Suggested packages with source, target and reason keys. */ public function getPackages() { return $this->suggestedPackages; } /** * Add suggested packages to be listed after install * * Could be used to add suggested packages both from the installer * or from CreateProjectCommand. * * @param string $source Source package which made the suggestion * @param string $target Target package to be suggested * @param string $reason Reason the target package to be suggested * @return SuggestedPackagesReporter */ public function addPackage($source, $target, $reason) { $this->suggestedPackages[] = array( 'source' => $source, 'target' => $target, 'reason' => $reason, ); return $this; } /** * Add all suggestions from a package. * * @param PackageInterface $package * @return SuggestedPackagesReporter */ public function addSuggestionsFromPackage(PackageInterface $package) { $source = $package->getPrettyName(); foreach ($package->getSuggests() as $target => $reason) { $this->addPackage( $source, $target, $reason ); } return $this; } /** * Output suggested packages. * * Do not list the ones already installed if installed repository provided. * * @param int $mode One of the MODE_* constants from this class * @return SuggestedPackagesReporter */ public function output($mode, RepositoryInterface $installedRepo = null) { $suggestedPackages = $this->getFilteredSuggestions($installedRepo); $suggesters = array(); $suggested = array(); foreach ($suggestedPackages as $suggestion) { $suggesters[$suggestion['source']][$suggestion['target']] = $suggestion['reason']; $suggested[$suggestion['target']][$suggestion['source']] = $suggestion['reason']; } ksort($suggesters); ksort($suggested); // Simple mode if ($mode & self::MODE_LIST) { foreach (array_keys($suggested) as $name) { $this->io->write(sprintf('%s', $name)); } return 0; } // Grouped by package if ($mode & self::MODE_BY_PACKAGE) { foreach ($suggesters as $suggester => $suggestions) { $this->io->write(sprintf('%s suggests:', $suggester)); foreach ($suggestions as $suggestion => $reason) { $this->io->write(sprintf(' - %s' . ($reason ? ': %s' : ''), $suggestion, $this->escapeOutput($reason))); } $this->io->write(''); } } // Grouped by suggestion if ($mode & self::MODE_BY_SUGGESTION) { // Improve readability in full mode if ($mode & self::MODE_BY_PACKAGE) { $this->io->write(str_repeat('-', 78)); } foreach ($suggested as $suggestion => $suggesters) { $this->io->write(sprintf('%s is suggested by:', $suggestion)); foreach ($suggesters as $suggester => $reason) { $this->io->write(sprintf(' - %s' . ($reason ? ': %s' : ''), $suggester, $this->escapeOutput($reason))); } $this->io->write(''); } } return $this; } /** * Output number of new suggested packages and a hint to use suggest command. ** * Do not list the ones already installed if installed repository provided. * * @return SuggestedPackagesReporter */ public function outputMinimalistic(RepositoryInterface $installedRepo = null) { $suggestedPackages = $this->getFilteredSuggestions($installedRepo); if ($suggestedPackages) { $this->io->writeError(''.count($suggestedPackages).' package suggestions were added by new dependencies, use `composer suggest` to see details.'); } return $this; } private function getFilteredSuggestions(RepositoryInterface $installedRepo = null) { $suggestedPackages = $this->getPackages(); $installedNames = array(); if (null !== $installedRepo && !empty($suggestedPackages)) { foreach ($installedRepo->getPackages() as $package) { $installedNames = array_merge( $installedNames, $package->getNames() ); } } $suggestions = array(); foreach ($suggestedPackages as $suggestion) { if (in_array($suggestion['target'], $installedNames)) { continue; } $suggestions[] = $suggestion; } return $suggestions; } /** * @param string $string * @return string */ private function escapeOutput($string) { return OutputFormatter::escape( $this->removeControlCharacters($string) ); } /** * @param string $string * @return string */ private function removeControlCharacters($string) { return preg_replace( '/[[:cntrl:]]/', '', str_replace("\n", ' ', $string) ); } }