/** * {@inheritdoc} */ public function determine() { // Where are we? SystemStore::add('_.current', preg_replace('/\\[@([^\\]]*)\\]/', ' [@' . $this->tag->getName() . ']', SystemStore::get('_.current'))); $tag = strtolower($this->tag->getName()); $this->triggerEvent("vanity.parse.user.description.{$tag}.pre", new EventStore(array('tag' => &$tag, 'ancestry' => $this->ancestry))); switch ($tag) { case 'example': $processed = new ExampleHandler($this->tag, $this->ancestry); break; case 'inheritdoc': $processed = new InheritdocHandler($this->tag, $this->ancestry); break; case 'internal': $processed = new InternalHandler($this->tag, $this->ancestry); break; case 'link': $processed = new LinkHandler($this->tag, $this->ancestry); break; case 'see': $processed = new SeeHandler($this->tag, $this->ancestry); break; default: $processed = new DefaultHandler($this->tag, $this->ancestry); break; } $this->triggerEvent("vanity.parse.user.description.{$tag}.post", new EventStore(array('tag' => &$tag, 'ancestry' => $this->ancestry))); return $processed; }
/** * {@inheritdoc} */ public function determine() { // Where are we? SystemStore::add('_.current', preg_replace('/\\[@([^\\]]*)\\]/', ' [@' . $this->tag->getName() . ']', SystemStore::get('_.current'))); $tag = strtolower($this->tag->getName()); $this->triggerEvent("vanity.parse.user.tag.{$tag}.pre", new EventStore(array('tag' => &$tag, 'ancestry' => $this->ancestry))); switch ($tag) { case 'api': $processed = new ApiHandler($this->tag, $this->ancestry); break; case 'author': $processed = new AuthorHandler($this->tag, $this->ancestry); break; case 'copyright': $processed = new CopyrightHandler($this->tag, $this->ancestry); break; case 'deprecated': case 'depreciated': $processed = new DeprecatedHandler($this->tag, $this->ancestry); break; case 'dispatches': case 'event': $processed = new EventHandler($this->tag, $this->ancestry); break; case 'example': $processed = new ExampleHandler($this->tag, $this->ancestry); break; case 'global': $processed = new GlobalHandler($this->tag, $this->ancestry); break; case 'internal': $processed = new InternalHandler($this->tag, $this->ancestry); break; case 'license': $processed = new LicenseHandler($this->tag, $this->ancestry); break; case 'link': $processed = new LinkHandler($this->tag, $this->ancestry); break; case 'method': $processed = new MethodHandler($this->tag, $this->ancestry); break; case 'package': $processed = new PackageHandler($this->tag, $this->ancestry); break; case 'param': $processed = new ParamHandler($this->tag, $this->ancestry); break; case 'property': case 'property-read': case 'property-write': $processed = new PropertyHandler($this->tag, $this->ancestry); break; case 'return': case 'returns': $processed = new ReturnHandler($this->tag, $this->ancestry); break; case 'alias': case 'see': $processed = new SeeHandler($this->tag, $this->ancestry); break; case 'since': case 'available': $processed = new SinceHandler($this->tag, $this->ancestry); break; case 'throw': case 'throws': $processed = new ThrowHandler($this->tag, $this->ancestry); break; case 'todo': case 'fixme': $processed = new TodoHandler($this->tag, $this->ancestry); break; case 'type': case 'var': $processed = new TypeHandler($this->tag, $this->ancestry); break; case 'uses': case 'used-by': $processed = new UsesHandler($this->tag, $this->ancestry); break; case 'version': $processed = new VersionHandler($this->tag, $this->ancestry); break; default: $processed = new DefaultHandler($this->tag, $this->ancestry); break; } $this->triggerEvent("vanity.parse.user.tag.{$tag}.post", new EventStore(array('tag' => &$tag, 'ancestry' => $this->ancestry))); return $processed; }
/** * Retrieve the properties for the class. * * @return array A list of properties. */ public function getProperties() { $rproperties = $this->class->getProperties(); foreach ($rproperties as $rproperty) { if (!isset($this->properties['count'])) { $this->properties['count'] = count($rproperties); } if (!isset($this->properties['property'])) { $this->properties['property'] = array(); } $rproperty = InheritdocHandler::resolve($rproperty); $_tags = new TagHandler($rproperty->getDocComment(), $this->ancestry); $property_docblock = new DocBlock($rproperty->getDocComment()); // Property-specific data $entry = array(); $entry['name'] = $rproperty->getName(); $entry['visibility'] = $this->access($rproperty); // Where are we? SystemStore::add('_.current', $this->class->getName() . '::$' . $rproperty->getName()); if ($description = $_tags->getDescription()) { $entry['description'] = $description; } // Property inheritance if (($declaring_class = $rproperty->getDeclaringClass()->getName()) !== $this->class->getName()) { if (!isset($entry['inheritance'])) { $entry['inheritance'] = array(); } if (!isset($entry['inheritance']['class'])) { $entry['inheritance']['class'] = array(); } $declaring_class = $rproperty->getDeclaringClass(); $subentry = array(); $subentry['name'] = $declaring_class->getName(); if ($declaring_class->getFileName()) { $subentry['path'] = str_replace(VANITY_PROJECT_WORKING_DIR . '/', '', $declaring_class->getFileName()); } $entry['inheritance']['class'][] = $subentry; } // Default value, if accessible if ($rproperty->isPublic()) { $rvalue = $rproperty->getValue($this->class); $adjusted_rvalue = null; switch (strtolower(gettype($rvalue))) { case 'boolean': $adjusted_rvalue = $rvalue == 1 ? 'true' : 'false'; break; case 'null': $adjusted_rvalue = 'null'; break; case 'string': $adjusted_rvalue = $rvalue; break; case 'integer': $adjusted_rvalue = (int) $rvalue; break; case 'array': $adjusted_rvalue = ParseUtil::unwrapArray($rvalue); break; } $entry['initializer'] = array(); $entry['initializer']['type'] = gettype($rvalue); $entry['initializer']['value'] = $adjusted_rvalue; } // Property tags if ($t = $_tags->getTags()) { $entry['metadata'] = $t; } $this->properties['property'][] = $entry; } return $this->properties; }
/** * Retrieve the properties for the class. * * @return array A list of properties. */ public function getMethods() { $rclass_methods = $this->class->getMethods(); // Add methods and parameters $rclass_methods = array_values(array_filter($rclass_methods, function ($rmethod) { if ($exclusions = ConfigStore::get('source.exclude.methods')) { return !preg_match($exclusions, $rmethod->getName()); } return true; })); foreach ($rclass_methods as $rmethod) { $documentThis = true; if (!isset($this->methods['count'])) { $this->methods['count'] = count($rclass_methods); } if (!isset($this->methods['method'])) { $this->methods['method'] = array(); } $rmethod = InheritdocHandler::resolve($rmethod); $_tags = new TagHandler($rmethod->getDocComment(), $this->ancestry); $method_docblock = new DocBlock($rmethod->getDocComment()); $entry = array(); $entry['name'] = $rmethod->getName(); $entry['visibility'] = $this->methodAccess($rmethod); if ($extension = $rmethod->getExtensionName()) { $entry['extension'] = $extension; DependencyCollector::add($extension); } if ($rmethod->getFileName()) { $entry['path'] = str_replace(array(VANITY_SYSTEM . '/', VANITY_PROJECT_WORKING_DIR . '/'), '', $rmethod->getFileName()); $entry['lines'] = array('start' => $rmethod->getStartLine(), 'end' => $rmethod->getEndLine()); if ($viewsource = ConfigStore::get('source.viewsource')) { $entry['viewsource'] = str_replace(array('%PATH%', '%LINE%'), array($entry['path'], $entry['lines']['start']), $viewsource); } } if ($description = $_tags->getDescription()) { $entry['description'] = $description; } // Method inheritance if (($declaring_class = $rmethod->getDeclaringClass()->getName()) !== $this->class->getName()) { if (!isset($entry['inheritance'])) { $entry['inheritance'] = array(); } if (!isset($entry['inheritance']['class'])) { $entry['inheritance']['class'] = array(); } $declaring_class = new ReflectionClass($declaring_class); $subentry = array(); $subentry['name'] = $declaring_class->getName(); if ($declaring_class->getFileName()) { $subentry['path'] = str_replace(VANITY_PROJECT_WORKING_DIR . '/', '', $declaring_class->getFileName()); } $entry['inheritance']['class'][] = $subentry; } // Method tags if (count($method_docblock->getTags())) { if (!isset($entry['metadata'])) { $entry['metadata'] = array(); } if (!isset($entry['metadata']['tag'])) { $entry['metadata']['tag'] = array(); } foreach ($method_docblock->getTags() as $rtag) { $dtag = new Tag($rtag, $this->ancestry); $tagData = $dtag->determine()->process(ConfigStore::get('source.resolve_aliases')); if ($tagData['name'] === 'alias') { SystemStore::add('alias.' . $tagData['entity'], $this->class->getName() . '::' . $rmethod->getName()); $documentThis = false; } $entry['metadata']['tag'][] = $tagData; } } // Method parameters if ($count = count($rmethod->getParameters())) { if (!isset($entry['parameters'])) { $entry['parameters'] = array(); } if (!isset($entry['parameters']['count'])) { $entry['parameters']['count'] = $count; } if (!isset($entry['parameters']['parameter'])) { $entry['parameters']['parameter'] = array(); } foreach ($rmethod->getParameters() as $rparameter) { $tag_finder = new TagFinder($entry); $param = array(); $param['name'] = $rparameter->getName(); $param['required'] = !$rparameter->isOptional(); $param['passed_by_reference'] = $rparameter->isPassedByReference(); if ($rparameter->isDefaultValueAvailable()) { $param['default'] = $rparameter->getDefaultValue(); } // Pull-in from @tags if ($_description = $tag_finder->find('description', $param['name'])) { $param['description'] = $_description; } if ($_type = $tag_finder->find('type', $param['name'])) { $param['type'] = $this->ancestry->resolveNamespace($_type); } if ($_types = $tag_finder->find('types', $param['name'])) { $param['types'] = $_types; } // Clean-up parameter metadata tags if (isset($entry['metadata']) && isset($entry['metadata']['tag'])) { foreach ($entry['metadata']['tag'] as $index => $tag) { if ($tag['name'] === 'param' && $tag['variable'] === $param['name']) { unset($entry['metadata']['tag'][$index]); } } } // Type hinting trumps docblock if ($rparameter->getClass()) { if (isset($param['type']) && $param['type'] !== $rparameter->getClass()->getName()) { // @todo: Resolve namespace of declaring class. Inconsistency::add($this->class->getName() . '::' . $rmethod->getName() . '($' . $rparameter->getName() . ') [' . $param['type'] . ' => ' . $rparameter->getClass()->getName() . ']'); } $param['type'] = $rparameter->getClass()->getName(); if (isset($param['types'])) { unset($param['types']); } } $entry['parameters']['parameter'][] = $param; } } // Return value $entry['return'] = array('type' => 'void'); if (isset($entry['metadata']) && isset($entry['metadata']['tag'])) { foreach ($entry['metadata']['tag'] as $index => $tag) { if ($tag['name'] === 'return') { $entry['return'] = $tag; unset($entry['return']['name']); // Clean-up return metadata tags unset($entry['metadata']['tag'][$index]); } } } if ($documentThis) { $this->methods['method'][] = $entry; } } return $this->methods; }
/** * Retrieve the constants for the class. * * @return array A list of constants. */ public function getConstants() { $rclass_constants = $this->class->getConstants(); ksort($rclass_constants); // Add constants foreach ($rclass_constants as $rconstant_name => $rconstant_value) { if (!isset($this->constants['count'])) { $this->constants['count'] = count($rclass_constants); } if (!isset($this->constants['constant'])) { $this->constants['constant'] = array(); } $entry = array(); $entry['name'] = $rconstant_name; $entry['value'] = $rconstant_value; $entry['type'] = gettype($rconstant_value); // Where are we? SystemStore::add('_.current', $this->class->getName() . '::' . $rconstant_name); $this->constants['constant'][] = $entry; } return $this->constants; }
/** * Reflects over the given class and produces an associative array * containing all relevant class data. * * @event EventStore vanity.parse.user.reflect.pre * @event EventStore vanity.parse.user.reflect.post * @return array An associative array containing all relevant class data. */ public function process() { // REFLECT ALL THE THINGS! $rclass_methods = $this->rclass->getMethods(); $long_filename = $this->rclass->getFileName(); $short_filename = str_replace(array(VANITY_SYSTEM . '/', VANITY_PROJECT_WORKING_DIR . '/'), '', $long_filename); $this->triggerEvent("vanity.parse.user.reflect.pre", new EventStore(array('data' => &$this->data))); $this->data['name'] = $this->rclass->getShortName(); $this->data['namespace'] = $this->rclass->getNamespaceName(); $this->data['full_name'] = $this->class_name; $this->data['namespace_as_path'] = str_replace('\\', '/', $this->class_name); $this->data['path'] = $short_filename; if (SystemStore::get('_.php54') && $this->rclass->isTrait()) { $this->data['kind'] = 'Trait'; } elseif ($this->rclass->isInterface()) { $this->data['kind'] = 'Interface'; } elseif ($this->rclass->isSubClassOf('Exception')) { $this->data['kind'] = 'Exception'; } else { $this->data['kind'] = 'Class'; } SystemStore::add('_.current', $this->class_name); #--------------------------------------------------------------------------# // Enable GitHub lookups for author data if (ConfigStore::get('source.github.user') && ConfigStore::get('source.github.pass')) { $github = new GitHub(ConfigStore::get('source.github.user'), ConfigStore::get('source.github.pass')); $github->setRepository(ConfigStore::get('source.github.repo_owner'), ConfigStore::get('source.github.repo_name')); $this->data['github'] = $github->getAuthorsForFile($this->data['path']); } #--------------------------------------------------------------------------# // Add description if ($description = $this->class_tags->getDescription()) { $this->data['description'] = $description; } // Add inheritance chain if ($this->inheritance) { $this->data['inheritance'] = $this->inheritance; } // Add implemented interfaces if ($this->implements) { $this->data['implements'] = $this->implements; } // Add used traits if ($this->traits) { $this->data['traits'] = $this->traits; } // Add class tags if ($tags = $this->class_tags->getTags()) { $this->data['metadata'] = $tags; } // Add constants if ($constants = $this->constants->getConstants()) { $this->data['constants'] = $constants; } // Add properties if ($properties = $this->properties->getProperties()) { $this->data['properties'] = $properties; } // Add meta-properties if (isset($this->data['metadata']) && isset($this->data['properties'])) { $new = $this->formatMetaProperties($this->data['metadata']); $this->data['properties']['property'] = array_merge($this->data['properties']['property'], $new); $this->data['properties']['count'] += count($new); } elseif (isset($this->data['metadata'])) { $new = $this->formatMetaProperties($this->data['metadata']); $this->data['properties']['property'] = $new; $this->data['properties']['count'] = count($new); } // Sort the properties alphabetically if (isset($this->data['properties']) && isset($this->data['properties']['property']) && is_array($this->data['properties']['property'])) { usort($this->data['properties']['property'], function ($a, $b) { $a = $a['name']; $b = $b['name']; if ($a === $b) { return 0; } return $a < $b ? -1 : 1; }); } // Add methods if ($methods = $this->methods->getMethods()) { $this->data['methods'] = $methods; } // Add meta-methods if (isset($this->data['metadata']) && isset($this->data['methods'])) { $new = $this->formatMetaMethods($this->data['metadata']); $this->data['methods']['method'] = array_merge($this->data['methods']['method'], $new); $this->data['methods']['count'] += count($new); } elseif (isset($this->data['metadata'])) { $new = $this->formatMetaMethods($this->data['metadata']); $this->data['methods']['method'] = $new; $this->data['methods']['count'] = count($new); } // Sort the methods alphabetically if (isset($this->data['methods']) && isset($this->data['methods']['method']) && is_array($this->data['methods']['method'])) { usort($this->data['methods']['method'], function ($a, $b) { $a = $a['name']; $b = $b['name']; if ($a === $b) { return 0; } return $a < $b ? -1 : 1; }); } // Sort the metadata tags, post-edit from @method, @property and @return if (isset($this->data['metadata'])) { $this->data['metadata']['tag'] = array_values($this->data['metadata']['tag']); // Sort the tags alphabetically usort($this->data['metadata']['tag'], function ($a, $b) { $a = $a['name']; $b = $b['name']; if ($a === $b) { return 0; } return $a < $b ? -1 : 1; }); } // Handle alias tags $this->triggerEvent("vanity.parse.user.reflect.post", new EventStore(array('data' => &$this->data))); }