public static function find($commandName, CommandCollection $commands)
{
$threshold = 1000.0;
$distancesByName = array();
// Include aliases in the search
$actualNames = $commands->getNames(true);
foreach ($actualNames as $actualName) {
// Get Levenshtein distance between the input and each command name
$distance = levenshtein($commandName, $actualName);
$isSimilar = $distance <= strlen($commandName) / 3;
$isSubString = false !== strpos($actualName, $commandName);
if ($isSimilar || $isSubString) {
$distancesByName[$actualName] = $distance;
}
}
// Only keep results with a distance below the threshold
$distancesByName = array_filter($distancesByName, function ($distance) use($threshold) {
return $distance < 2 * $threshold;
});
// Display results with shortest distance first
asort($distancesByName);
$suggestedNames = array_keys($distancesByName);
return self::filterDuplicates($suggestedNames, $commands);
}
/** * Creates an exception for the code {@link NAME_NOT_FOUND}. * * Suggested alternatives are searched in the passed commands. * * @param string $commandName The command name that was not found. * @param CommandCollection $commands A list of available commands that * is searched for similar names. * @param Exception $cause The exception that caused this * exception. * * @return static The created exception. */ public static function nameNotFound($commandName, CommandCollection $commands, Exception $cause = null) { $message = sprintf('The command "%s" is not defined.', $commandName); $suggestedNames = SimilarCommandName::find($commandName, $commands); if (count($suggestedNames) > 0) { if (1 === count($suggestedNames)) { $message .= "\n\nDid you mean this?\n "; } else { $message .= "\n\nDid you mean one of these?\n "; } $message .= implode("\n ", $suggestedNames); } return new static($message, self::NAME_NOT_FOUND, $cause); }