/** * Creates a Descriptor from the provided data. * * @param FileReflector $data * * @return FileDescriptor */ public function create($data) { $fileDescriptor = new FileDescriptor($data->getHash()); $fileDescriptor->setPackage($this->extractPackageFromDocBlock($data->getDocBlock()) ?: $data->getDefaultPackageName()); $packages = new Collection(); $package = $this->extractPackageFromDocBlock($data->getDocBlock()); if (!$package) { $package = $data->getDefaultPackageName(); } $tag = new TagDescriptor('package'); $tag->setDescription($package); $packages->add($tag); $fileDescriptor->getTags()->set('package', $packages); $fileDescriptor->setName(basename($data->getFilename())); $fileDescriptor->setPath($data->getFilename()); $fileDescriptor->setSource($data->getContents()); $fileDescriptor->setIncludes(new Collection($data->getIncludes())); $fileDescriptor->setNamespaceAliases(new Collection($data->getNamespaceAliases())); $this->assembleDocBlock($data->getDocBlock(), $fileDescriptor); $this->addMarkers($data->getMarkers(), $fileDescriptor); $this->addConstants($data->getConstants(), $fileDescriptor); $this->addFunctions($data->getFunctions(), $fileDescriptor); $this->addClasses($data->getClasses(), $fileDescriptor); $this->addInterfaces($data->getInterfaces(), $fileDescriptor); $this->addTraits($data->getTraits(), $fileDescriptor); return $fileDescriptor; }
/** * Creates a new FileReflector for the given filename or null if the file contains no modifications. * * @param ProjectDescriptorBuilder $builder * @param string $filename * * @return FileReflector|null Returns a new FileReflector or null if no modifications were detected for the given * filename. */ protected function createFileReflector(ProjectDescriptorBuilder $builder, $filename) { $file = new FileReflector($filename, $this->parser->doValidation(), $this->parser->getEncoding()); $file->setDefaultPackageName($this->parser->getDefaultPackageName()); $file->setMarkers($this->parser->getMarkers()); $file->setFilename($this->getRelativeFilename($filename)); $cachedFiles = $builder->getProjectDescriptor()->getFiles(); $hash = $cachedFiles->get($file->getFilename()) ? $cachedFiles->get($file->getFilename())->getHash() : null; return $hash === $file->getHash() && !$this->parser->isForced() ? null : $file; }
/** * Creates a Descriptor from the provided data. * * @param FileReflector $data * * @return FileDescriptor */ public function create($data) { $fileDescriptor = new FileDescriptor($data->getHash()); $fileDescriptor->setPackage($this->extractPackageFromDocBlock($data->getDocBlock()) ?: $data->getDefaultPackageName()); $fileDescriptor->setName(basename($data->getFilename())); $fileDescriptor->setPath($data->getFilename()); $fileDescriptor->setSource($data->getContents()); $fileDescriptor->setIncludes(new Collection($data->getIncludes())); $fileDescriptor->setNamespaceAliases(new Collection($data->getNamespaceAliases())); $this->assembleDocBlock($data->getDocBlock(), $fileDescriptor); $this->overridePackageTag($data, $fileDescriptor); $this->addMarkers($data->getMarkers(), $fileDescriptor); $this->addConstants($data->getConstants(), $fileDescriptor); $this->addFunctions($data->getFunctions(), $fileDescriptor); $this->addClasses($data->getClasses(), $fileDescriptor); $this->addInterfaces($data->getInterfaces(), $fileDescriptor); $this->addTraits($data->getTraits(), $fileDescriptor); return $fileDescriptor; }
/** * Export the given file to the provided parent element. * * @param \DOMElement $parent Element to augment. * @param \phpDocumentor\Reflection\FileReflector $file Element to export. * * @return void */ public function export(\DOMElement $parent, $file) { $child = new \DOMElement('file'); $parent->appendChild($child); $child->setAttribute('path', ltrim($file->getFilename(), './')); $child->setAttribute('hash', $file->getHash()); $object = new DocBlockExporter(); $object->export($child, $file); // add namespace aliases foreach ($file->getNamespaceAliases() as $alias => $namespace) { $alias_obj = new \DOMElement('namespace-alias', $namespace); $child->appendChild($alias_obj); $alias_obj->setAttribute('name', $alias); } /** @var \phpDocumentor\Reflection\IncludeReflector $include */ foreach ($file->getIncludes() as $include) { $include->setDefaultPackageName($file->getDefaultPackageName()); $object = new IncludeExporter(); $object->export($child, $include); } /** @var \phpDocumentor\Reflection\ConstantReflector $constant */ foreach ($file->getConstants() as $constant) { $constant->setDefaultPackageName($file->getDefaultPackageName()); $object = new ConstantExporter(); $object->export($child, $constant); } /** @var \phpDocumentor\Reflection\FunctionReflector $function */ foreach ($file->getFunctions() as $function) { $function->setDefaultPackageName($file->getDefaultPackageName()); $object = new FunctionExporter(); $object->export($child, $function); } /** @var \phpDocumentor\Reflection\InterfaceReflector $interface */ foreach ($file->getInterfaces() as $interface) { $interface->setDefaultPackageName($file->getDefaultPackageName()); $object = new InterfaceExporter(); $object->export($child, $interface); } /** @var \phpDocumentor\Reflection\ClassReflector $class */ foreach ($file->getClasses() as $class) { $class->setDefaultPackageName($file->getDefaultPackageName()); $object = new ClassExporter(); $object->export($child, $class); } // add markers if (count($file->getMarkers()) > 0) { $markers = new \DOMElement('markers'); $child->appendChild($markers); foreach ($file->getMarkers() as $marker) { $marker_obj = new \DOMElement(strtolower($marker[0]), htmlspecialchars(trim($marker[1]))); $markers->appendChild($marker_obj); $marker_obj->setAttribute('line', $marker[2]); } } if (count($file->getParseErrors()) > 0) { $parse_errors = new \DOMElement('parse_markers'); $child->appendChild($parse_errors); foreach ($file->getParseErrors() as $error) { $marker_obj = new \DOMElement(strtolower($error[0]), htmlspecialchars(trim($error[1]))); $parse_errors->appendChild($marker_obj); $marker_obj->setAttribute('line', $error[2]); $marker_obj->setAttribute('code', $error[3]); } } // if we want to include the source for each file; append a new // element 'source' which contains a compressed, encoded version // of the source if ($this->include_source) { $child->appendChild(new \DOMElement('source', base64_encode(gzcompress($file->getContents())))); } }
/** * Iterates through the given files feeds them to the builder. * * @param ProjectDescriptorBuilder $builder * @param Collection $files A files container to parse. * * @api * * @throws Exception if no files were found. * * @return bool|string */ public function parse(ProjectDescriptorBuilder $builder, Collection $files) { $timer = microtime(true); $paths = $this->getFilenames($files); $this->log(' Project root is: ' . $files->getProjectRoot()); $this->log(' Ignore paths are: ' . implode(', ', $files->getIgnorePatterns()->getArrayCopy())); if ($builder->getProjectDescriptor()->getSettings()->isModified()) { $this->setForced(true); $this->log('One of the project\'s settings have changed, forcing a complete rebuild'); } foreach ($paths as $filename) { if (class_exists('phpDocumentor\\Event\\Dispatcher')) { Dispatcher::getInstance()->dispatch('parser.file.pre', PreFileEvent::createInstance($this)->setFile($filename)); } $this->log('Starting to parse file: ' . $filename); $memory = memory_get_usage(); try { $file = new FileReflector($filename, $this->doValidation(), $this->getEncoding()); $file->setDefaultPackageName($this->getDefaultPackageName()); $file->setMarkers($this->getMarkers()); $file->setFilename($this->getRelativeFilename($filename)); // if the hash is unchanged; continue to the next file $cachedFiles = $builder->getProjectDescriptor()->getFiles(); $hash = $cachedFiles->get($file->getFilename()) ? $cachedFiles->get($file->getFilename())->getHash() : null; if ($hash === $file->getHash() && !$this->isForced()) { $this->log('>> Skipped file ' . $file->getFilename() . ' as no modifications were detected'); continue; } $file->process(); $builder->buildFileUsingSourceData($file); $fileDescriptor = $builder->getProjectDescriptor()->getFiles()->get($file->getFilename()); $errors = $fileDescriptor->getAllErrors(); foreach ($errors as $error) { $this->log($error->getCode(), $error->getSeverity(), $error->getContext()); } } catch (Exception $e) { $this->log(' Unable to parse file "' . $filename . '", an error was detected: ' . $e->getMessage(), LogLevel::ALERT); } $memoryDelta = memory_get_usage() - $memory; $this->log('>> Memory after processing of file: ' . number_format(memory_get_usage() / 1024 / 1024, 2) . ' megabytes (' . ($memoryDelta > -0 ? '+' : '') . number_format($memoryDelta / 1024) . ' kilobytes)', LogLevel::DEBUG); } $this->log('Elapsed time to parse all files: ' . round(microtime(true) - $timer, 2) . 's'); $this->log('Peak memory usage: ' . round(memory_get_peak_usage() / 1024 / 1024, 2) . 'M'); return $builder->getProjectDescriptor(); }
/** * Runs a file through the static reflectors, generates an XML file element * and returns it. * * @param string $filename The filename to parse. * @param bool $include_source whether to include the source in the * generated output. * * @api * * @return void */ public function parseFile($filename, $include_source = false) { $this->log('Starting to parse file: ' . $filename); $this->log('Starting to parse file: ' . $filename, \phpDocumentor\Plugin\Core\Log::DEBUG); $dispatched = false; try { $file = new FileReflector($filename, $this->doValidation()); $file->setDefaultPackageName($this->getDefaultPackageName()); if (class_exists('phpDocumentor\\Event\\Dispatcher')) { \phpDocumentor\Event\Dispatcher::getInstance()->addListener('parser.log', array($file, 'addParserMarker')); } $dispatched = true; $file->setMarkers($this->getMarkers()); $file->setFilename($this->getRelativeFilename($filename)); // if an existing structure exists; and we do not force re-generation; // re-use the old definition if the hash differs if ($this->getExistingXml() !== null && !$this->isForced()) { $xpath = new \DOMXPath($this->getExistingXml()); // try to find the file with it's hash /** @var \DOMNodeList $qry */ $qry = $xpath->query('/project/file[@path=\'' . ltrim($file->getFilename(), './') . '\' and @hash=\'' . $file->getHash() . '\']'); // if an existing entry who matches the file, then re-use if ($qry->length > 0) { $this->exporter->getDomDocument()->documentElement->appendChild($this->exporter->getDomDocument()->importNode($qry->item(0), true)); $this->log('>> File has not changed since last build, re-using the ' . 'old definition'); } else { $this->log('Exporting file: ' . $filename); $file->process(); $this->exporter->setIncludeSource($include_source); $this->exporter->export($file); } } else { $this->log('Exporting file: ' . $filename); $file->process(); $this->exporter->setIncludeSource($include_source); $this->exporter->export($file); } } catch (Exception $e) { $this->log(' Unable to parse file "' . $filename . '", an error was detected: ' . $e->getMessage(), \phpDocumentor\Plugin\Core\Log::ALERT); $this->log('Unable to parse file "' . $filename . '", an error was detected: ' . $e->getMessage(), \phpDocumentor\Plugin\Core\Log::DEBUG); } //disconnects the dispatcher here so if any error occured, it still // removes the event if ($dispatched && class_exists('phpDocumentor\\Event\\Dispatcher')) { \phpDocumentor\Event\Dispatcher::getInstance()->removeListener('parser.log', array($file, 'addParserMarker')); } $this->log('>> Memory after processing of file: ' . number_format(memory_get_usage()) . ' bytes', \phpDocumentor\Plugin\Core\Log::DEBUG); $this->log('>> Parsed file', \phpDocumentor\Plugin\Core\Log::DEBUG); }