Source of file Project.php
Size: 12,370 Bytes - Last Modified: 2014-09-10T12:24:21+02:00
/home/theseer/storage/php/phpdox/src/collector/project/Project.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 | <?php /** * Copyright (c) 2010-2014 Arne Blankerts <arne@blankerts.de> * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * * Neither the name of Arne Blankerts nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package phpDox * @author Arne Blankerts <arne@blankerts.de> * @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved. * @license BSD License */ namespace TheSeer\phpDox\Collector { use TheSeer\fDOM\fDOMDocument; use TheSeer\fDOM\fDOMElement; use TheSeer\phpDox\FileInfo; /** * */ class Project { /** * @var FileInfo */ private $xmlDir; /** * @var FileInfo */ private $srcDir; /** * @var SourceCollection */ private $source = NULL; /** * @var IndexCollection */ private $index = NULL; /** * @var SourceFile[] */ private $files = array(); private $saveUnits = array(); private $loadedUnits = array(); /** * @param $srcDir * @param $xmlDir */ public function __construct(FileInfo $srcDir, FileInfo $xmlDir) { $this->xmlDir = $xmlDir; $this->srcDir = $srcDir; $this->initCollections(); } /** * @return FileInfo */ public function getSourceDir() { return $this->srcDir; } /** * @return FileInfo */ public function getXmlDir() { return $this->xmlDir; } /** * @param FileInfo $file * @return bool */ public function addFile(SourceFile $file) { $isNew = $this->source->addFile($file); if ($isNew) { $this->removeFileReferences($file->getPathname()); $this->files[$file->getPathname()] = $file; } return $isNew; } /** * @param FileInfo $file */ public function removeFile(FileInfo $file) { $this->removeFileReferences($file->getPathname()); unset($this->files[$file->getPathname()]); $this->source->removeFile($file); } /** * @param ClassObject $class */ public function addClass(ClassObject $class) { $this->loadedUnits[$class->getName()] = $class; $this->registerForSaving($class); $this->index->addClass($class); } /** * */ public function addInterface(InterfaceObject $interface) { $this->loadedUnits[$interface->getName()] = $interface; $this->registerForSaving($interface); $this->index->addInterface($interface); } /** * */ public function addTrait(TraitObject $trait) { $this->loadedUnits[$trait->getName()] = $trait; $this->registerForSaving($trait); $this->index->addTrait($trait); } /** * @return fDOMDocument */ public function getIndex() { return $this->index->export(); } /** * @return fDOMDocument */ public function getSourceTree() { return $this->source->export(); } /** * @return bool */ public function hasNamespaces() { return $this->index->export()->query('count(//phpdox:namespace[not(@name="/")])') > 0; } /** * @param $namespace * @param $name * @return fDOMElement */ public function getUnitByName($name) { if (isset($this->loadedUnits[$name])) { return $this->loadedUnits[$name]; } $parts = explode('\\', $name); $local = array_pop($parts); $namespace = join('\\', $parts); $indexNode = $this->index->findUnitNodeByName($namespace, $local); if (!$indexNode) { throw new ProjectException("No unit with name '$name' found"); } switch ($indexNode->localName) { case 'interface': { $unit = new InterfaceObject(); break; } case 'trait': { $unit = new TraitObject(); break; } case 'class': { $unit = new ClassObject(); break; } default: { throw new ProjectException( sprintf('Unexpected type "%s"', $indexNode->localName), ProjectException::UnexpectedType ); } } $dom = new fDOMDocument(); $dom->load($this->xmlDir . '/' . $indexNode->getAttribute('xml')); $unit->import($dom); return $unit; } /** * @return array */ public function cleanVanishedFiles() { $files = $this->source->getVanishedFiles(); foreach ($files as $path) { $this->removeFileReferences($path); } return $files; } public function registerForSaving(AbstractUnitObject $unit) { $this->saveUnits[$unit->getName()] = $unit; } /** * @return array */ public function save() { $map = $this->initDirectories(); $indexDom = $this->index->export(); $reportUnits = $this->saveUnits; foreach($this->saveUnits as $unit) { /** @var AbstractUnitObject $unit */ $indexNode = $this->index->findUnitNodeByName($unit->getNamespace(), $unit->getLocalName()); if (!$indexNode) { throw new ProjectException( sprintf( "Internal Error: Unit '%s' not found in index (ns: %s, n: %s).", $unit->getName(), $unit->getNamespace(), $unit->getLocalName() ), ProjectException::UnitNotFoundInIndex ); } $name = str_replace('\\', '_', $unit->getName()); $dom = $unit->export(); $dom->formatOutput = TRUE; $dom->preserveWhiteSpace = FALSE; $fname = $map[$dom->documentElement->localName] . '/' . $name . '.xml'; if ($indexNode->hasAttribute('xml')) { $reportUnits = array_merge($reportUnits, $this->findAffectedUnits($fname)); } else { $indexNode->setAttribute('xml', $fname); } $dom->save($this->xmlDir . '/' . $fname); } $indexDom->formatOutput = TRUE; $indexDom->preserveWhiteSpace = FALSE; $indexDom->save($this->xmlDir . '/index.xml'); $this->saveSources(); $this->saveUnits = array(); $this->files = array(); return $reportUnits; } /** * @param $fname * * @return array */ private function findAffectedUnits($fname) { $affected = array(); $dom = new fDOMDocument(); $dom->load($this->xmlDir . '/' . $fname); $dom->registerNamespace('phpdox', 'http://xml.phpdox.net/src'); $extends = $dom->queryOne('//phpdox:extends'); if ($extends instanceof fDOMElement) { try { $affected[$extends->getAttribute('full')] = $this->getUnitByName($extends->getAttribute('full')); } catch (ProjectException $e) {} } $implements = $dom->query('//phpdox:implements'); foreach($implements as $implement) { try { $affected[$implement->getAttribute('full')] = $this->getUnitByName($implement->getAttribute('full')); } catch (ProjectException $e) {} } return $affected; } private function initDirectories() { $map = array('class' => 'classes', 'trait' => 'traits', 'interface' => 'interfaces'); foreach ($map as $col) { $path = $this->xmlDir . '/' . $col; if (!file_exists($path)) { mkdir($path, 0755, TRUE); } } return $map; } /** * @return void */ private function initCollections() { $this->source = new SourceCollection($this->srcDir); $srcFile = $this->xmlDir . '/source.xml'; if (file_exists($srcFile)) { $dom = new fDOMDocument(); $dom->load($srcFile); $this->source->import($dom); } $this->index = new IndexCollection($this->srcDir); $srcFile = $this->xmlDir . '/index.xml'; if (file_exists($srcFile)) { $dom = new fDOMDocument(); $dom->load($srcFile); $this->index->import($dom); } } /** * @param string $path */ private function removeFileReferences($path) { foreach($this->index->findUnitNodesBySrcFile($path) as $node) { /** @var $node \DOMElement */ $fname = $this->xmlDir . '/' . $node->getAttribute('xml'); if (file_exists($fname)) { unlink($fname); } $node->parentNode->removeChild($node); } } private function saveSources() { foreach($this->files as $file) { $tokenDom = $file->getTokens(); $tokenDom->formatOutput = TRUE; $tokenDom->preserveWhiteSpace = FALSE; $relName = 'tokens/' . $file->getRelative($this->srcDir, FALSE) . '.xml'; $fname = $this->xmlDir . '/' . $relName; $dir = dirname($fname); if (!file_exists($dir)) { mkdir($dir, 0755, true); } $tokenDom->save($fname); $this->source->setTokenFileReference($file, $relName); } $sourceDom = $this->source->export(); $sourceDom->formatOutput = TRUE; $sourceDom->preserveWhiteSpace = FALSE; $sourceDom->save($this->xmlDir . '/source.xml'); } } class ProjectException extends \Exception { const UnitNotFoundInIndex = 1; const UnexpectedType = 2; } } |