/** * Triggers an event and logs it to the INFO log. * * @param string $event The string identifier for the event. * @param Event $eventObject An object that extends the {@see Symfony\Component\EventDispatcher\Event} object. * @return void */ public function triggerEvent($event, Event $eventObject = null) { Logger::get()->{ConfigStore::get('log.events')}('Triggering event:', array($event)); Dispatcher::get()->dispatch($event, $eventObject); }
public static function resolve($reflected) { $is_method = false; $is_property = false; // Are we working with a property or a method? if ($reflected instanceof ReflectionMethod) { $is_method = true; } elseif ($reflected instanceof ReflectionProperty) { $is_property = true; } else { throw new Exception('Only methods and properties can be reflected with ' . get_called_class()); } // Parse the docblock $docblock = new DocBlock($reflected->getDocComment()); $found_description = false; $return = $reflected; // Save these for messaging $__class = $reflected->getDeclaringClass()->getName(); $__kind = $reflected->getName(); // Can we just do a straight-up inherit? // @todo: Do a better job of handling {@inheritdoc} according to the spec. try { while (!$found_description && strpos($docblock->getShortDescription(), '{@inheritdoc}') !== false) { // Start over... $found_description = false; // Log that we're starting... Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Starting resolution:', array(sprintf("{$__class}%s{$__kind}%s", $is_method ? '::' : '::$', $is_method ? '()' : ''))); // Grab a reference to the class containing the entity with the {@inheritdoc} tag $klass = $reflected->getDeclaringClass(); // Is this an Interface? if ($klass->isInterface()) { throw new InheritdocInInterfaceException('The {@inheritdoc} tag is not resolvable from within Interfaces. Methods and properties should ' . 'be fully-documented.'); } elseif (SystemStore::get('_.php54') && $klass->isTrait()) { throw new InheritdocInTraitException('The {@inheritdoc} tag is not resolvable from within Traits. Methods and properties should ' . 'be fully-documented.'); } // Are we using Interfaces? if (!$found_description && ($interface_count = count($klass->getInterfaces())) > 0) { $count = 1; foreach ($klass->getInterfaces() as $rinterface) { Logger::get()->{ConfigStore::get('log.info')}("{@inheritdoc} Checking Interface {$count}/{$interface_count}:", array($rinterface->getName())); try { $return = $rinterface->getMethod($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($rinterface->getName(), $reflected->getName(), 'Method')); $found_description = true; break 2; } catch (Exception $e) { try { $return = $rinterface->getProperty($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($rinterface->getName(), $reflected->getName(), 'Property')); $found_description = true; break 2; } catch (Exception $e) { Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} No match. Will keep looking...', array($rinterface->getName(), $reflected->getName())); } } $count++; } } // Are we using Traits? if (!$found_description && SystemStore::get('_.php54') && ($trait_count = count($klass->getTraits())) > 0) { $count = 1; foreach ($klass->getTraits() as $rtrait) { Logger::get()->{ConfigStore::get('log.info')}("{@inheritdoc} Checking Trait {$count}/{$trait_count}:", array($rtrait->getName())); try { $return = $rtrait->getMethod($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($rtrait->getName(), $reflected->getName(), 'Method')); $found_description = true; break 2; } catch (Exception $e) { try { $return = $rtrait->getProperty($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($rtrait->getName(), $reflected->getName(), 'Property')); $found_description = true; break 2; } catch (Exception $e) { Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} No match. Will keep looking...', array($rtrait->getName(), $reflected->getName())); } } $count++; } } // Are we extending a class? if ($klass->getParentClass()) { // Continue climbing up the ancestry as necessary while (!$found_description && $klass->getParentClass()) { // Rewrite the reference to $klass $klass = $klass->getParentClass(); Logger::get()->{ConfigStore::get('log.info')}("{@inheritdoc} Checking the parent class:", array($klass->getName())); try { $return = $klass->getMethod($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($klass->getName(), $reflected->getName(), 'Method')); $found_description = true; break 2; } catch (Exception $e) { try { $return = $klass->getProperty($reflected->getName()); Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} Match!', array($klass->getName(), $reflected->getName(), 'Property')); $found_description = true; break 2; } catch (Exception $e) { Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} No match. Will keep looking...', array($klass->getName(), $reflected->getName())); } } } } // We couldn't find anything throw new CouldNotResolveInheritdocException('Leaving as-is. The tag will be viewable in the ' . 'resulting documentation.'); } } catch (InheritdocInInterfaceException $e) { $message = sprintf("{$__class}%s{$__kind}%s", $is_method ? '::' : '::$', $is_method ? '()' : ''); // Log that we're starting... Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} ' . $e->getMessage(), array($message)); $formatter = ConsoleUtil::formatters(); Inconsistency::add($message . $formatter->gold->apply(' => Could not resolve {@inheritdoc}. ' . $e->getMessage())); } catch (InheritdocInTraitException $e) { $message = sprintf("{$__class}%s{$__kind}%s", $is_method ? '::' : '::$', $is_method ? '()' : ''); // Log that we're starting... Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} ' . $e->getMessage(), array($message)); $formatter = ConsoleUtil::formatters(); Inconsistency::add($message . $formatter->gold->apply(' => Could not resolve {@inheritdoc}. ' . $e->getMessage())); } catch (CouldNotResolveInheritdocException $e) { $message = sprintf("{$__class}%s{$__kind}%s", $is_method ? '::' : '::$', $is_method ? '()' : ''); // Log that we're starting... Logger::get()->{ConfigStore::get('log.info')}('{@inheritdoc} ' . $e->getMessage(), array($message)); $formatter = ConsoleUtil::formatters(); Inconsistency::add($message . $formatter->gold->apply(' => Could not resolve {@inheritdoc}. ' . $e->getMessage())); } catch (VanityException $e) { } catch (Exception $e) { } return $return; }
/** * Resolves a namespace alias into a fully-qualified namespace. * * @param string $short A shortened namespace alias. * @return string The fully-qualified namespace, if available. */ public function resolveNamespace($short) { if (isset($this->aliases[$short])) { Logger::get()->{ConfigStore::get('log.aliases')}('Aliases: Matched in the list of known aliases.', array($short, $this->aliases[$short])); return $this->aliases[$short]; } else { // Handle implicit aliases in the same namespace. try { $namespace = $this->class->getNamespaceName() . '\\' . $short; new ReflectionClass($namespace); Logger::get()->{ConfigStore::get('log.aliases')}('Aliases: Matched in the current namespace.', array($short, $namespace)); // If we didn't throw an exception, we're good. return $namespace; } catch (ReflectionException $e) { // Handle implicit namespaces in an extended/implemented namespace. try { foreach ($this->namespaces as $ns) { try { $namespace = $ns . '\\' . $short; new ReflectionClass($namespace); Logger::get()->{ConfigStore::get('log.aliases')}('Aliases: Matched in an extended/implemented namespace.', array($short, $namespace)); // If we didn't throw an exception, we're good. return $namespace; } catch (ReflectionException $e) { } } throw new ReflectionException(); } catch (ReflectionException $e) { // Try removing the beginning '\' to see if we find a match. try { $class = preg_replace('/^\\\\/', '', $short); new ReflectionClass($class); Logger::get()->{ConfigStore::get('log.aliases')}('Aliases: Matched by stripping the \\ prefix.', array($short, $class)); // If we didn't throw an exception, we're good. return $class; } catch (ReflectionException $e) { $formatter = ConsoleUtil::formatters(); Inconsistency::add($class . $formatter->gold->apply(' => No match found for ' . $short . ' (' . SystemStore::get('_.current') . ')')); Logger::get()->{ConfigStore::get('log.aliases')}('Aliases: No match found.', array($short)); // No match. Return it as-is (without any starting backslash). return $class; } } } } }
/** * Execute the logic for the command. * * @param InputInterface $input The command-line input. * @param OutputInterface $output The command-line output. * @return void */ protected function execute(InputInterface $input, OutputInterface $output) { echo PHP_EOL; // Resolve the configuration and display it $config = new ConfigResolve($input, __DIR__ . '/fetch_configs.php'); $config->read(); $this->displayConfig($output); Logger::get()->{ConfigStore::get('log.commands')}('Running command:', array($this->getName())); echo PHP_EOL; // Instantiate $filesystem = new Filesystem(); // Handle a fresh checkout if (!$filesystem->exists(VANITY_CACHE_DIR)) { Logger::get()->{ConfigStore::get('log.info')}('Cache directory does not exist.'); Logger::get()->{ConfigStore::get('log.info')}('Attempting to create:', array(VANITY_CACHE_DIR)); try { $filesystem->mkdir(VANITY_CACHE_DIR, 0777); $this->triggerEvent('vanity.command.php.fetch.checkout.pre', new EventStore(array('cache_dir' => VANITY_CACHE_DIR, 'type' => 'checkout'))); $output->writeln($this->formatter->yellow->apply('PHP DOCUMENTATION CHECKOUT')); $output->writeln('Downloading the PHP documentation for the first time. This may take a few minutes.'); echo PHP_EOL; foreach ($this->repositories as $write_to => $repository) { $url = $repository[0]; $append = isset($repository[1]) ? $repository[1] : ''; $output->writeln($this->formatter->green->apply($url)); $svn = "svn co {$url} {$write_to}{$append}"; Logger::get()->{ConfigStore::get('log.commands')}($svn); $process = new Process($svn); $process->run(function ($type, $buffer) use($output) { if ($type === 'err') { $output->writeln('ERR > ' . $buffer); } else { $output->writeln(TAB . trim($buffer)); } }); unset($process); echo PHP_EOL; } $this->triggerEvent('vanity.command.php.fetch.checkout.post', new EventStore(array('cache_dir' => VANITY_CACHE_DIR, 'type' => 'update'))); } catch (IOException $e) { Logger::get()->{ConfigStore::get('log.error')}('Failed to create user cache directory. Halting.', array(VANITY_CACHE_DIR)); throw new IOException('Vanity was unable to create the user cache directory at ' . VANITY_CACHE_DIR . ', or was unable to set the permissions to 0777.'); } } else { Logger::get()->{ConfigStore::get('log.info')}('Cache directory already exists.', array(VANITY_CACHE_DIR)); $this->triggerEvent('vanity.command.php.fetch.update.pre', new EventStore(array('cache_dir' => VANITY_CACHE_DIR, 'type' => 'update'))); $output->writeln($this->formatter->yellow->apply('PHP DOCUMENTATION UPDATE')); $output->writeln('Updating the PHP documentation.'); echo PHP_EOL; foreach ($this->repositories as $write_to => $repository) { $url = $repository[0]; $append = isset($repository[1]) ? $repository[1] : ''; $output->writeln($this->formatter->green->apply($url)); $svn = "svn up {$write_to}{$append}"; Logger::get()->{ConfigStore::get('log.commands')}($svn); $process = new Process($svn); $process->run(function ($type, $buffer) use($output) { if ($type === 'err') { $output->writeln('ERR > ' . $buffer); } else { $output->writeln(TAB . trim($buffer)); } }); unset($process); echo PHP_EOL; } $this->triggerEvent('vanity.command.php.fetch.update.post', new EventStore(array('cache_dir' => VANITY_CACHE_DIR, 'type' => 'update'))); } $this->triggerLogMessageEvent(); $this->triggerEvent('vanity.command.complete'); echo PHP_EOL; }
/** * Execute the logic for the command. * * @event EventStore vanity.command.parse.files.pre * @event EventStore vanity.command.parse.files.post * @event EventStore vanity.command.parse.classlist.pre * @event EventStore vanity.command.parse.classlist.post * @event EventStore vanity.command.parse.reflection.pre * @event EventStore vanity.command.parse.reflection.post * @event Event vanity.command.parse.warn.dependencies * @event Event vanity.command.parse.warn.inconsistencies * @event Event vanity.command.parse.report.dependencies * @event Event vanity.command.parse.report.inconsistencies * @event Event vanity.command.log_path * @event Event vanity.command.complete * @param InputInterface $input The command-line input. * @param OutputInterface $output The command-line output. * @return void */ protected function execute(InputInterface $input, OutputInterface $output) { echo PHP_EOL; // Resolve the configuration and display it $config = new ConfigResolve($input, __DIR__ . '/parse_configs.php'); $config->read(); $this->displayConfig($output); Logger::get()->{ConfigStore::get('log.commands')}('Running command:', array($this->getName())); if ($input->getOption('vanity.view_config')) { exit; } // Load the bootstrap, if any if (file_exists($bootstrap = ConfigStore::get('vanity.bootstrap'))) { include_once $bootstrap; } #--------------------------------------------------------------------------# $output->writeln($this->formatter->yellow->apply('MATCHED FILES:')); // Parse the pattern to determine the files to match $path = pathinfo(ConfigStore::get('source.input'), PATHINFO_DIRNAME); $pattern = pathinfo(ConfigStore::get('source.input'), PATHINFO_BASENAME); $files = Find::files($path, $pattern); $this->triggerEvent('vanity.command.parse.files.pre', new EventStore(array('files' => &$files))); // Display the list of matches foreach ($files['relative'] as $file) { $output->writeln(TAB . $this->formatter->green->apply('-> ') . $file); } // Count the matches echo PHP_EOL; $count = count($files['relative']); $output->writeln('Matched ' . $this->formatter->info->apply(" {$count} ") . ' ' . ConsoleUtil::pluralize($count, 'file', 'files') . '.'); echo PHP_EOL; // Trigger events $this->triggerEvent('vanity.command.parse.files.post', new EventStore(array('files' => &$files))); #--------------------------------------------------------------------------# // Find the classes $output->writeln($this->formatter->yellow->apply('MATCHED CLASSES:')); $classes = array_filter(Find::classes($files['absolute']), function ($class) { if ($regex = ConfigStore::get('source.exclude.classes')) { return !preg_match($regex, $class); } return true; }); $this->triggerEvent('vanity.command.parse.classlist.pre', new EventStore(array('classes' => &$classes))); // Display the classes foreach ($classes as $class) { $output->writeln(TAB . $this->formatter->green->apply('-> ') . $class); } // Count the classes echo PHP_EOL; $count = count($classes); $output->writeln('Found ' . $this->formatter->info->apply(" {$count} ") . ' ' . ConsoleUtil::pluralize($count, 'class', 'classes') . ' to document.'); echo PHP_EOL; $this->triggerEvent('vanity.command.parse.classlist.post', new EventStore(array('classes' => &$classes))); #--------------------------------------------------------------------------# $reflector = new ReflectAll($classes, ConfigStore::get('source.output')); $this->triggerEvent('vanity.command.parse.reflection.pre', new EventStore(array('reflector' => &$reflector))); $reflector->process($output); $this->triggerEvent('vanity.command.parse.reflection.post', new EventStore(array('reflector' => &$reflector))); #--------------------------------------------------------------------------# // Warnings if (ConfigStore::get('warn.dependencies')) { $this->triggerEvent('vanity.command.parse.warn.dependencies'); } if (ConfigStore::get('warn.inconsistencies')) { $this->triggerEvent('vanity.command.parse.warn.inconsistencies'); } // Reports if (ConfigStore::get('report.dependencies')) { $this->triggerEvent('vanity.command.parse.report.dependencies'); } if (ConfigStore::get('report.inconsistencies')) { $this->triggerEvent('vanity.command.parse.report.inconsistencies'); } $this->triggerLogMessageEvent(); $this->triggerEvent('vanity.command.complete'); echo PHP_EOL; }
/** * Execute the logic for the command. * * @event Event vanity.command.generate.files.pre * @event Event vanity.command.generate.files.post * @event Event vanity.command.complete * @param InputInterface $input The command-line input. * @param OutputInterface $output The command-line output. * @return void */ protected function execute(InputInterface $input, OutputInterface $output) { echo PHP_EOL; // Resolve the configuration and display it $config = new ConfigResolve($input, __DIR__ . '/generate_configs.php'); $config->read(); $this->displayConfig($output); Logger::get()->{ConfigStore::get('log.commands')}('Running command:', array($this->getName())); if ($input->getOption('vanity.view_config')) { exit; } // Load the bootstrap, if any if (file_exists($bootstrap = ConfigStore::get('vanity.bootstrap'))) { include_once $bootstrap; } $output->writeln($this->formatter->yellow->apply('SOURCE DEFINITIONS TO DOCUMENT:')); // Parse the pattern to determine the files to match $path = pathinfo(ConfigStore::get('generator.input'), PATHINFO_DIRNAME); $pattern = pathinfo(ConfigStore::get('generator.input'), PATHINFO_BASENAME); $path = str_replace('%STAGE%', ConsoleUtil::asciify(ConfigStore::get('vanity.stage')), $path); $path = str_replace('%VERSION%', ConsoleUtil::asciify(ConfigStore::get('vanity.version')), $path); $files = Find::files($path, $pattern); $this->triggerEvent('vanity.command.generate.files.pre', new EventStore(array('files' => &$files))); // Display the list of matches foreach ($files['relative'] as $file) { $output->writeln(TAB . $this->formatter->green->apply('-> ') . $file); } // Count the matches echo PHP_EOL; $count = count($files['relative']); $output->writeln('Matched ' . $this->formatter->info->apply(" {$count} ") . ' ' . ConsoleUtil::pluralize($count, 'file', 'files') . '.'); echo PHP_EOL; // Trigger events $this->triggerEvent('vanity.command.generate.files.post', new EventStore(array('files' => &$files))); #--------------------------------------------------------------------------# foreach (ConfigStore::get('generator.formats') as $format) { $this->triggerEvent("vanity.generate.format.{$format}.pre", new EventStore(array('files' => &$files, 'input' => ConfigStore::get('generator.input'), 'output' => ConfigStore::get('generator.output')))); $this->triggerEvent("vanity.generate.format.{$format}", new EventStore(array('files' => &$files, 'input' => ConfigStore::get('generator.input'), 'output' => ConfigStore::get('generator.output')))); $this->triggerEvent("vanity.generate.format.{$format}.post", new EventStore(array('files' => &$files, 'input' => ConfigStore::get('generator.input'), 'output' => ConfigStore::get('generator.output')))); } #--------------------------------------------------------------------------# $this->triggerLogMessageEvent(); $this->triggerEvent('vanity.command.complete'); echo PHP_EOL; }