Chris@13: presenter = $presenter; Chris@13: } Chris@13: Chris@13: /** Chris@13: * {@inheritdoc} Chris@13: */ Chris@13: protected function configure() Chris@13: { Chris@13: list($grep, $insensitive, $invert) = FilterOptions::getOptions(); Chris@13: Chris@13: $this Chris@13: ->setName('ls') Chris@13: ->setAliases(['list', 'dir']) Chris@13: ->setDefinition([ Chris@13: new CodeArgument('target', CodeArgument::OPTIONAL, 'A target class or object to list.'), Chris@13: Chris@13: new InputOption('vars', '', InputOption::VALUE_NONE, 'Display variables.'), Chris@13: new InputOption('constants', 'c', InputOption::VALUE_NONE, 'Display defined constants.'), Chris@13: new InputOption('functions', 'f', InputOption::VALUE_NONE, 'Display defined functions.'), Chris@13: new InputOption('classes', 'k', InputOption::VALUE_NONE, 'Display declared classes.'), Chris@13: new InputOption('interfaces', 'I', InputOption::VALUE_NONE, 'Display declared interfaces.'), Chris@13: new InputOption('traits', 't', InputOption::VALUE_NONE, 'Display declared traits.'), Chris@13: Chris@13: new InputOption('no-inherit', '', InputOption::VALUE_NONE, 'Exclude inherited methods, properties and constants.'), Chris@13: Chris@13: new InputOption('properties', 'p', InputOption::VALUE_NONE, 'Display class or object properties (public properties by default).'), Chris@13: new InputOption('methods', 'm', InputOption::VALUE_NONE, 'Display class or object methods (public methods by default).'), Chris@13: Chris@13: $grep, Chris@13: $insensitive, Chris@13: $invert, Chris@13: Chris@13: new InputOption('globals', 'g', InputOption::VALUE_NONE, 'Include global variables.'), Chris@13: new InputOption('internal', 'n', InputOption::VALUE_NONE, 'Limit to internal functions and classes.'), Chris@13: new InputOption('user', 'u', InputOption::VALUE_NONE, 'Limit to user-defined constants, functions and classes.'), Chris@13: new InputOption('category', 'C', InputOption::VALUE_REQUIRED, 'Limit to constants in a specific category (e.g. "date").'), Chris@13: Chris@13: new InputOption('all', 'a', InputOption::VALUE_NONE, 'Include private and protected methods and properties.'), Chris@13: new InputOption('long', 'l', InputOption::VALUE_NONE, 'List in long format: includes class names and method signatures.'), Chris@13: ]) Chris@13: ->setDescription('List local, instance or class variables, methods and constants.') Chris@13: ->setHelp( Chris@13: <<<'HELP' Chris@13: List variables, constants, classes, interfaces, traits, functions, methods, Chris@13: and properties. Chris@13: Chris@13: Called without options, this will return a list of variables currently in scope. Chris@13: Chris@13: If a target object is provided, list properties, constants and methods of that Chris@13: target. If a class, interface or trait name is passed instead, list constants Chris@13: and methods on that class. Chris@13: Chris@13: e.g. Chris@13: >>> ls Chris@13: >>> ls $foo Chris@13: >>> ls -k --grep mongo -i Chris@13: >>> ls -al ReflectionClass Chris@13: >>> ls --constants --category date Chris@13: >>> ls -l --functions --grep /^array_.*/ Chris@13: >>> ls -l --properties new DateTime() Chris@13: HELP Chris@13: ); Chris@13: } Chris@13: Chris@13: /** Chris@13: * {@inheritdoc} Chris@13: */ Chris@13: protected function execute(InputInterface $input, OutputInterface $output) Chris@13: { Chris@13: $this->validateInput($input); Chris@13: $this->initEnumerators(); Chris@13: Chris@13: $method = $input->getOption('long') ? 'writeLong' : 'write'; Chris@13: Chris@13: if ($target = $input->getArgument('target')) { Chris@13: list($target, $reflector) = $this->getTargetAndReflector($target); Chris@13: } else { Chris@13: $reflector = null; Chris@13: } Chris@13: Chris@13: // @todo something cleaner than this :-/ Chris@13: if ($input->getOption('long')) { Chris@13: $output->startPaging(); Chris@13: } Chris@13: Chris@13: foreach ($this->enumerators as $enumerator) { Chris@13: $this->$method($output, $enumerator->enumerate($input, $reflector, $target)); Chris@13: } Chris@13: Chris@13: if ($input->getOption('long')) { Chris@13: $output->stopPaging(); Chris@13: } Chris@13: Chris@13: // Set some magic local variables Chris@13: if ($reflector !== null) { Chris@13: $this->setCommandScopeVariables($reflector); Chris@13: } Chris@13: } Chris@13: Chris@13: /** Chris@13: * Initialize Enumerators. Chris@13: */ Chris@13: protected function initEnumerators() Chris@13: { Chris@13: if (!isset($this->enumerators)) { Chris@13: $mgr = $this->presenter; Chris@13: Chris@13: $this->enumerators = [ Chris@13: new ClassConstantEnumerator($mgr), Chris@13: new ClassEnumerator($mgr), Chris@13: new ConstantEnumerator($mgr), Chris@13: new FunctionEnumerator($mgr), Chris@13: new GlobalVariableEnumerator($mgr), Chris@13: new PropertyEnumerator($mgr), Chris@13: new MethodEnumerator($mgr), Chris@13: new VariableEnumerator($mgr, $this->context), Chris@13: ]; Chris@13: } Chris@13: } Chris@13: Chris@13: /** Chris@13: * Write the list items to $output. Chris@13: * Chris@13: * @param OutputInterface $output Chris@13: * @param null|array $result List of enumerated items Chris@13: */ Chris@13: protected function write(OutputInterface $output, array $result = null) Chris@13: { Chris@13: if ($result === null) { Chris@13: return; Chris@13: } Chris@13: Chris@13: foreach ($result as $label => $items) { Chris@17: $names = \array_map([$this, 'formatItemName'], $items); Chris@17: $output->writeln(\sprintf('%s: %s', $label, \implode(', ', $names))); Chris@13: } Chris@13: } Chris@13: Chris@13: /** Chris@13: * Write the list items to $output. Chris@13: * Chris@13: * Items are listed one per line, and include the item signature. Chris@13: * Chris@13: * @param OutputInterface $output Chris@13: * @param null|array $result List of enumerated items Chris@13: */ Chris@13: protected function writeLong(OutputInterface $output, array $result = null) Chris@13: { Chris@13: if ($result === null) { Chris@13: return; Chris@13: } Chris@13: Chris@13: $table = $this->getTable($output); Chris@13: Chris@13: foreach ($result as $label => $items) { Chris@13: $output->writeln(''); Chris@17: $output->writeln(\sprintf('%s:', $label)); Chris@13: Chris@13: $table->setRows([]); Chris@13: foreach ($items as $item) { Chris@13: $table->addRow([$this->formatItemName($item), $item['value']]); Chris@13: } Chris@13: Chris@13: if ($table instanceof TableHelper) { Chris@13: $table->render($output); Chris@13: } else { Chris@13: $table->render(); Chris@13: } Chris@13: } Chris@13: } Chris@13: Chris@13: /** Chris@13: * Format an item name given its visibility. Chris@13: * Chris@13: * @param array $item Chris@13: * Chris@13: * @return string Chris@13: */ Chris@13: private function formatItemName($item) Chris@13: { Chris@17: return \sprintf('<%s>%s', $item['style'], OutputFormatter::escape($item['name']), $item['style']); Chris@13: } Chris@13: Chris@13: /** Chris@13: * Validate that input options make sense, provide defaults when called without options. Chris@13: * Chris@13: * @throws RuntimeException if options are inconsistent Chris@13: * Chris@13: * @param InputInterface $input Chris@13: */ Chris@13: private function validateInput(InputInterface $input) Chris@13: { Chris@13: if (!$input->getArgument('target')) { Chris@13: // if no target is passed, there can be no properties or methods Chris@13: foreach (['properties', 'methods', 'no-inherit'] as $option) { Chris@13: if ($input->getOption($option)) { Chris@13: throw new RuntimeException('--' . $option . ' does not make sense without a specified target'); Chris@13: } Chris@13: } Chris@13: Chris@13: foreach (['globals', 'vars', 'constants', 'functions', 'classes', 'interfaces', 'traits'] as $option) { Chris@13: if ($input->getOption($option)) { Chris@13: return; Chris@13: } Chris@13: } Chris@13: Chris@13: // default to --vars if no other options are passed Chris@13: $input->setOption('vars', true); Chris@13: } else { Chris@13: // if a target is passed, classes, functions, etc don't make sense Chris@13: foreach (['vars', 'globals', 'functions', 'classes', 'interfaces', 'traits'] as $option) { Chris@13: if ($input->getOption($option)) { Chris@13: throw new RuntimeException('--' . $option . ' does not make sense with a specified target'); Chris@13: } Chris@13: } Chris@13: Chris@13: foreach (['constants', 'properties', 'methods'] as $option) { Chris@13: if ($input->getOption($option)) { Chris@13: return; Chris@13: } Chris@13: } Chris@13: Chris@13: // default to --constants --properties --methods if no other options are passed Chris@13: $input->setOption('constants', true); Chris@13: $input->setOption('properties', true); Chris@13: $input->setOption('methods', true); Chris@13: } Chris@13: } Chris@13: }