├── tests ├── PHPToolsTest │ └── Namespacer │ │ ├── _files │ │ ├── Foo │ │ │ ├── Bar │ │ │ │ ├── Bar1.php │ │ │ │ └── Bar2.php │ │ │ └── Foo.php │ │ └── Zend │ │ │ ├── Filter │ │ │ ├── Alpha.php │ │ │ └── Alnum.php │ │ │ └── Filter.php │ │ ├── DocblockContentProcessorTest.php │ │ └── FileNameProcessorTest.php ├── phpunit.xml └── bootstrap.php ├── README ├── bin └── php-namespacer.php └── library └── PHPTools ├── Namespacer ├── RecursiveFilterIterator.php ├── DocblockContentProcessor.php ├── FileRegistry.php ├── FileNameProcessor.php ├── CLIRunner.php ├── Namespacer.php └── FileContentProcessor.php └── SPL └── SplClassLoader.php /tests/PHPToolsTest/Namespacer/_files/Foo/Bar/Bar1.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ./ 5 | 6 | 7 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | PHPTools 2 | ======== 3 | 4 | Namespacer 5 | ---------- 6 | 7 | This tool is to help facilitate the conversion of PHP5 Prefixed code 8 | (ZF or PEAR standards code) to PHP 5.3 Namespaced code. 9 | 10 | .. more info .. 11 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | register(); -------------------------------------------------------------------------------- /tests/PHPToolsTest/Namespacer/_files/Foo/Foo.php: -------------------------------------------------------------------------------- 1 | register(); 16 | \PHPTools\Namespacer\CLIRunner::main(); 17 | -------------------------------------------------------------------------------- /tests/PHPToolsTest/Namespacer/DocblockContentProcessorTest.php: -------------------------------------------------------------------------------- 1 | _fileRegistry = new \PHPTools\Namespacer\FileRegistry; 12 | 13 | $libraryDirectory = realpath(dirname(__FILE__) . '/_files/'); 14 | 15 | foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($libraryDirectory)) as $realFilePath => $fileInfo) { 16 | $relativeFilePath = substr($realFilePath, strlen($libraryDirectory)+1); 17 | $fileNameProcessor = new \PHPTools\Namespacer\FileNameProcessor($relativeFilePath, $libraryDirectory); 18 | $this->_fileRegistry->registerFileNameProcessor($fileNameProcessor); 19 | } 20 | 21 | } 22 | 23 | public function teardown() 24 | { 25 | $this->_fileRegistry = null; 26 | } 27 | 28 | public function testTrue() 29 | { 30 | $docblock = <<_fileRegistry); 61 | $this->assertEquals($expected, $dcp->getContents()); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /tests/PHPToolsTest/Namespacer/FileNameProcessorTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('./foo/bar/Zend/Validate/Alpha.php', $fnc->getOriginalFilePath(), 'Original file path not preserved.'); 14 | $this->assertEquals('Zend/Validate/Alpha.php', $fnc->getOriginalRelativeFilePath(), 'Original file path not preserved.'); 15 | $this->assertEquals('Zend_Validate_Alpha', $fnc->getOriginalClassName(), 'Original class not computed or preserved.'); 16 | } 17 | 18 | public function testAbstractNamingWorks() 19 | { 20 | $fnc = new FileNameProcessor('Zend/Validate/Abstract.php', './foo/bar'); 21 | 22 | $this->assertEquals('Zend\Validate', $fnc->getNewNamespace(), 'New namespace not computed correctly.'); 23 | $this->assertEquals('AbstractValidate', $fnc->getNewClassName(), 'New class name not computed correctly.'); 24 | $this->assertEquals('Zend\Validate\AbstractValidate', $fnc->getNewFullyQualifiedName(), 'New FQN not computed correctly.'); 25 | $this->assertEquals('Zend/Validate/AbstractValidate.php', $fnc->getNewRelativeFilePath(), 'New file path not computed correctly.'); 26 | } 27 | 28 | public function testClassMovedIntoNamespaceWorks() 29 | { 30 | $fnc = new FileNameProcessor('Zend/Filter.php', realpath(dirname(__FILE__) . '/_files/')); 31 | 32 | $this->assertEquals('Zend\Filter', $fnc->getNewNamespace(), 'New namespace not computed correctly.'); 33 | $this->assertEquals('Filter', $fnc->getNewClassName(), 'New class name not computed correctly.'); 34 | $this->assertEquals('Zend\Filter\Filter', $fnc->getNewFullyQualifiedName(), 'New FQN not computed correctly.'); 35 | $this->assertEquals('Zend/Filter/Filter.php', $fnc->getNewRelativeFilePath(), 'New file path not computed correctly.'); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /library/PHPTools/Namespacer/RecursiveFilterIterator.php: -------------------------------------------------------------------------------- 1 | _filter = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $filter); 20 | if ($topDirectory == null) { 21 | $iterator->rewind(); 22 | $this->_topDirectory = (string) $iterator->current()->getPath(); 23 | } else { 24 | $this->_topDirectory = $topDirectory; 25 | } 26 | parent::__construct($iterator); 27 | } 28 | 29 | 30 | public function accept() 31 | { 32 | $relativeFileName = substr($this->current()->getRealPath(), strlen($this->_topDirectory)+1); 33 | 34 | if ($this->isDot() || preg_match('#(\.svn|_svn|\.git)#', $relativeFileName)) { 35 | return false; 36 | } 37 | 38 | if ($this->isDir()) { 39 | return true; 40 | } 41 | 42 | if (preg_match('#^' . preg_quote($this->_filter) . '#', $relativeFileName)) { 43 | return true; 44 | } else { 45 | return false; 46 | } 47 | } 48 | 49 | /** 50 | * getChildren() - overridden from RecursiveFilterIterator to allow the persistence of 51 | * the $_denyDirectoryPattern and the $_acceptFilePattern when sub iterators of this filter 52 | * are needed to be created. 53 | * 54 | * @return Zend_Tool_Framework_Loader_IncludePathLoader_RecursiveFilterIterator 55 | */ 56 | public function getChildren() 57 | { 58 | if (empty($this->ref)) { 59 | $this->ref = new \ReflectionClass($this); 60 | } 61 | 62 | return $this->ref->newInstance( 63 | $this->getInnerIterator()->getChildren(), 64 | $this->_filter, 65 | $this->_topDirectory 66 | ); 67 | } 68 | 69 | 70 | } -------------------------------------------------------------------------------- /library/PHPTools/Namespacer/DocblockContentProcessor.php: -------------------------------------------------------------------------------- 1 | _content = $docblockContent; 20 | $this->_prefixes = $prefixes; 21 | $this->_fileRegistry = $fileRegistry; 22 | $this->_generate(); 23 | } 24 | 25 | public function getContents() 26 | { 27 | $content = ''; 28 | foreach ($this->_newTokens as $newToken) { 29 | $content .= $newToken[1]; 30 | } 31 | return $content; 32 | } 33 | 34 | protected function _generate() 35 | { 36 | $tokens = docblock_tokenize($this->_content); 37 | $context = null; 38 | 39 | $this->_newTokens = array(); 40 | 41 | foreach ($tokens as $token) { 42 | $newToken = array(); 43 | $tokenName = docblock_token_name($token[0]); 44 | switch ($tokenName) { 45 | case 'DOCBLOCK_TAG': 46 | switch ($token[1]) { 47 | case '@var': 48 | case '@uses': 49 | case '@param': 50 | case '@return': 51 | case '@throws': 52 | $context = 'INSIDE_TYPE_TAG'; 53 | break; 54 | } 55 | $this->_newTokens[] = $token; 56 | break; 57 | case 'DOCBLOCK_TEXT': 58 | if ($context == 'INSIDE_TYPE_TAG') { 59 | $matches = array(); 60 | $prefixRegex = implode('|', $this->_prefixes); 61 | if (preg_match('#.*(' . $prefixRegex . '_[\\w_]*).*#', $token[1], $matches)) { 62 | $className = $matches[1]; 63 | $fileNameProc = $this->_fileRegistry->findByOriginalClassName($className); 64 | if ($fileNameProc) { 65 | $newClassName = '\\' . $fileNameProc->getNewFullyQualifiedName(); 66 | $tokenContent = preg_replace('#' . $className . '#', $newClassName, $matches[0]); 67 | $newToken[1] = $tokenContent; 68 | $this->_newTokens[] = $newToken; 69 | } else { 70 | $this->_newTokens[] = $token; 71 | } 72 | 73 | } else { 74 | $this->_newTokens[] = $token; 75 | } 76 | $context = null; 77 | } else { 78 | $this->_newTokens[] = $token; 79 | } 80 | break; 81 | default: 82 | $this->_newTokens[] = $token; 83 | break; 84 | } 85 | } 86 | 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /tests/PHPToolsTest/Namespacer/_files/Zend/Filter/Alpha.php: -------------------------------------------------------------------------------- 1 | toArray(); 71 | } else if (is_array($allowWhiteSpace)) { 72 | if (array_key_exists('allowwhitespace', $allowWhiteSpace)) { 73 | $allowWhiteSpace = $allowWhiteSpace['allowwhitespace']; 74 | } else { 75 | $allowWhiteSpace = false; 76 | } 77 | } 78 | 79 | $this->allowWhiteSpace = (boolean) $allowWhiteSpace; 80 | if (null === self::$_unicodeEnabled) { 81 | self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false; 82 | } 83 | 84 | if (null === self::$_meansEnglishAlphabet) { 85 | $this->_locale = new Zend_Locale('auto'); 86 | self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(), 87 | array('ja', 'ko', 'zh') 88 | ); 89 | } 90 | 91 | } 92 | 93 | /** 94 | * Returns the allowWhiteSpace option 95 | * 96 | * @return boolean 97 | */ 98 | public function getAllowWhiteSpace() 99 | { 100 | return $this->allowWhiteSpace; 101 | } 102 | 103 | /** 104 | * Sets the allowWhiteSpace option 105 | * 106 | * @param boolean $allowWhiteSpace 107 | * @return Zend_Filter_Alpha Provides a fluent interface 108 | */ 109 | public function setAllowWhiteSpace($allowWhiteSpace) 110 | { 111 | $this->allowWhiteSpace = (boolean) $allowWhiteSpace; 112 | return $this; 113 | } 114 | 115 | /** 116 | * Defined by Zend_Filter_Interface 117 | * 118 | * Returns the string $value, removing all but alphabetic characters 119 | * 120 | * @param string $value 121 | * @return string 122 | */ 123 | public function filter($value) 124 | { 125 | $whiteSpace = $this->allowWhiteSpace ? '\s' : ''; 126 | if (!self::$_unicodeEnabled) { 127 | // POSIX named classes are not supported, use alternative a-zA-Z match 128 | $pattern = '/[^a-zA-Z' . $whiteSpace . ']/'; 129 | } else if (self::$_meansEnglishAlphabet) { 130 | //The Alphabet means english alphabet. 131 | $pattern = '/[^a-zA-Z' . $whiteSpace . ']/u'; 132 | } else { 133 | //The Alphabet means each language's alphabet. 134 | $pattern = '/[^\p{L}' . $whiteSpace . ']/u'; 135 | } 136 | 137 | return preg_replace($pattern, '', (string) $value); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /tests/PHPToolsTest/Namespacer/_files/Zend/Filter/Alnum.php: -------------------------------------------------------------------------------- 1 | toArray(); 71 | } else if (is_array($allowWhiteSpace)) { 72 | if (array_key_exists('allowwhitespace', $allowWhiteSpace)) { 73 | $allowWhiteSpace = $allowWhiteSpace['allowwhitespace']; 74 | } else { 75 | $allowWhiteSpace = false; 76 | } 77 | } 78 | 79 | $this->allowWhiteSpace = (boolean) $allowWhiteSpace; 80 | if (null === self::$_unicodeEnabled) { 81 | self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false; 82 | } 83 | 84 | if (null === self::$_meansEnglishAlphabet) { 85 | $this->_locale = new Zend_Locale('auto'); 86 | self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(), 87 | array('ja', 'ko', 'zh') 88 | ); 89 | } 90 | 91 | } 92 | 93 | /** 94 | * Returns the allowWhiteSpace option 95 | * 96 | * @return boolean 97 | */ 98 | public function getAllowWhiteSpace() 99 | { 100 | return $this->allowWhiteSpace; 101 | } 102 | 103 | /** 104 | * Sets the allowWhiteSpace option 105 | * 106 | * @param boolean $allowWhiteSpace 107 | * @return Zend_Filter_Alnum Provides a fluent interface 108 | */ 109 | public function setAllowWhiteSpace($allowWhiteSpace) 110 | { 111 | $this->allowWhiteSpace = (boolean) $allowWhiteSpace; 112 | return $this; 113 | } 114 | 115 | /** 116 | * Defined by Zend_Filter_Interface 117 | * 118 | * Returns the string $value, removing all but alphabetic and digit characters 119 | * 120 | * @param string $value 121 | * @return string 122 | */ 123 | public function filter($value) 124 | { 125 | $whiteSpace = $this->allowWhiteSpace ? '\s' : ''; 126 | if (!self::$_unicodeEnabled) { 127 | // POSIX named classes are not supported, use alternative a-zA-Z0-9 match 128 | $pattern = '/[^a-zA-Z0-9' . $whiteSpace . ']/'; 129 | } else if (self::$_meansEnglishAlphabet) { 130 | //The Alphabet means english alphabet. 131 | $pattern = '/[^a-zA-Z0-9' . $whiteSpace . ']/u'; 132 | } else { 133 | //The Alphabet means each language's alphabet. 134 | $pattern = '/[^\p{L}\p{N}' . $whiteSpace . ']/u'; 135 | } 136 | 137 | return preg_replace($pattern, '', (string) $value); 138 | } 139 | 140 | public function setArray(ArrayObject $o) 141 | { 142 | $return = Foo::FOO; 143 | return self::FOO; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /library/PHPTools/Namespacer/FileRegistry.php: -------------------------------------------------------------------------------- 1 | _fileNameProcessors[$objectId] = $fileNameProcessor; 25 | 26 | $this->_fileNameByOriginalFilePathIndex[$fileNameProcessor->getOriginalFilePath()] = $objectId; 27 | $this->_fileNameByOriginalRelativeFilePathIndex[$fileNameProcessor->getOriginalRelativeFilePath()] = $objectId; 28 | $this->_fileNameByOriginalClassNameIndex[$fileNameProcessor->getOriginalClassName()] = $objectId; 29 | $this->_fileNameByNewFullyQualifiedNameIndex[$fileNameProcessor->getNewFullyQualifiedName()] = $objectId; 30 | 31 | return $this; 32 | } 33 | 34 | public function registerFileContentProcessor(FileContentProcessor $fileContentProcessor) 35 | { 36 | $objectId = spl_object_hash($fileContentProcessor); 37 | $this->_fileContentProcessors[$objectId] = $fileContentProcessor; 38 | 39 | $fileNameProcessorObjectId = spl_object_hash($fileContentProcessor->getFileNameProcessor()); 40 | $this->_fileContentProcessorToFileNameProcessorIndex[$objectId] = $fileNameProcessorObjectId; 41 | } 42 | 43 | public function findByOriginalFilePath($originalFilePath) 44 | { 45 | if (array_key_exists($originalFilePath, $this->_fileNameByOriginalFilePathIndex)) { 46 | $objId = $this->_fileNameByOriginalFilePathIndex[$originalFilePath]; 47 | if ($objId && array_key_exists($objId, $this->_fileNameProcessors)) { 48 | return $this->_fileNameProcessors[$objId]; 49 | } 50 | } 51 | return false; 52 | } 53 | 54 | public function findByOriginalRelativeFilePath($originalRelativeFilePath) 55 | { 56 | if (array_key_exists($originalRelativeFilePath, $this->_fileNameByOriginalRelativeFilePathIndex)) { 57 | $objId = $this->_fileNameByOriginalRelativeFilePathIndex[$originalRelativeFilePath]; 58 | if ($objId && array_key_exists($objId, $this->_fileNameProcessors)) { 59 | return $this->_fileNameProcessors[$objId]; 60 | } 61 | } 62 | return false; 63 | } 64 | 65 | public function findByOriginalClassName($originalClassName) 66 | { 67 | if (array_key_exists($originalClassName, $this->_fileNameByOriginalClassNameIndex)) { 68 | $objId = $this->_fileNameByOriginalClassNameIndex[$originalClassName]; 69 | if ($objId && array_key_exists($objId, $this->_fileNameProcessors)) { 70 | return $this->_fileNameProcessors[$objId]; 71 | } 72 | } 73 | return false; 74 | } 75 | 76 | public function findByNewFullyQualifiedName($newFullyQualifiedName) 77 | { 78 | if (array_key_exists($newFullyQualifiedName, $this->_fileNameByNewFullyQualifiedNameIndex)) { 79 | $objId = $this->_fileNameByNewFullyQualifiedNameIndex[$newFullyQualifiedName]; 80 | if ($objId && array_key_exists($objId, $this->_fileNameProcessors)) { 81 | return $this->_fileNameProcessors[$objId]; 82 | } 83 | } 84 | return false; 85 | } 86 | 87 | public function getFileNameProcessorForContentProcessor(FileContentProcessor $fileContentProcessor) 88 | { 89 | $fcpObjectId = spl_object_hash($fileContentProcessor); 90 | 91 | $objectId = $this->_fileContentProcessorToFileNameProcessorIndex[$fcpObjectId]; 92 | return $this->_fileNameProcessors[$objectId]; 93 | } 94 | 95 | public function setIterationType($iterationType = self::ITERATE_NAMES) 96 | { 97 | $this->_iterationType = $iterationType; 98 | } 99 | 100 | public function getIterator() 101 | { 102 | switch ($this->_iterationType) { 103 | case self::ITERATE_CONTENTS: 104 | return new \ArrayIterator($this->_fileContentProcessors); 105 | case self::ITERATE_NAMES: 106 | default: 107 | return new \ArrayIterator($this->_fileNameConverters); 108 | } 109 | } 110 | 111 | public function count() 112 | { 113 | return count($this->_fileNameProcessors); 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /library/PHPTools/Namespacer/FileNameProcessor.php: -------------------------------------------------------------------------------- 1 | _libraryDirectory = $libraryDirectory; 21 | 22 | if (is_string($relativeFilePath)) { 23 | $this->_originalRelativeFilePath = $relativeFilePath; 24 | $this->_process(); 25 | } elseif (is_array($relativeFilePath)) { 26 | $options = $relativeFilePath; 27 | $this->_originalRelativeFilePath = $options['originalRelativeFilePath']; 28 | $this->_originalClassName = $options['originalClassName']; 29 | $this->_newRelativeFilePath = $options['newRelativeFilePath']; 30 | $this->_newNamespace = $options['newNamespace']; 31 | $this->_newClassName = $options['newClassName']; 32 | $this->_newFullyQualifiedName = $options['newFullyQualifiedName']; 33 | } 34 | } 35 | 36 | public function getOriginalFilePath() 37 | { 38 | return rtrim($this->_libraryDirectory, '/\\') . DIRECTORY_SEPARATOR . $this->_originalRelativeFilePath; 39 | } 40 | 41 | public function getOriginalRelativeFilePath() 42 | { 43 | return $this->_originalRelativeFilePath; 44 | } 45 | 46 | public function getOriginalClassName() 47 | { 48 | return $this->_originalClassName; 49 | } 50 | 51 | public function getLibraryDirectory() 52 | { 53 | return $this->_libraryDirectory; 54 | } 55 | 56 | public function getNewRelativeFilePath() 57 | { 58 | return $this->_newRelativeFilePath; 59 | } 60 | 61 | public function getNewFullyQualifiedName() 62 | { 63 | return $this->_newFullyQualifiedName; 64 | } 65 | 66 | public function getNewNamespace() 67 | { 68 | return $this->_newNamespace; 69 | } 70 | 71 | public function getNewClassName() 72 | { 73 | return $this->_newClassName; 74 | } 75 | 76 | protected function _process() 77 | { 78 | // change separators to underscore 79 | $this->_originalClassName = str_replace(array('/', '\\'), '_', $this->_originalRelativeFilePath); 80 | $this->_originalClassName = substr($this->_originalClassName, 0, -4); 81 | 82 | $originalClassParts = explode('_', $this->_originalClassName); 83 | $newClassParts = $originalClassParts; 84 | 85 | // does this class have sub parts? 86 | if (is_dir($this->_libraryDirectory . '/' . implode('/', $newClassParts))) { 87 | $lastSegment = end($newClassParts); 88 | $newClassParts[] = $lastSegment; 89 | } 90 | 91 | $this->_newNamespace = implode('\\', array_slice($newClassParts, 0, count($newClassParts)-1)); 92 | 93 | $lastClassPart = end($newClassParts); 94 | $this->_newClassName = $this->_createSafeClassName($lastClassPart); 95 | 96 | 97 | $this->_newFullyQualifiedName = $this->_newNamespace . '\\' . $this->_newClassName; 98 | $this->_newRelativeFilePath = str_replace('\\', '/', $this->_newFullyQualifiedName) . '.php'; 99 | 100 | } 101 | 102 | protected function _createSafeClassName($className) 103 | { 104 | if ($className === 'Abstract') { 105 | $className = 'Abstract' . substr($this->_newNamespace, strrpos($this->_newNamespace, '\\') + 1); 106 | } elseif ($className === 'Interface') { 107 | $className = substr($this->_newNamespace, strrpos($this->_newNamespace, '\\') + 1) . 'Interface'; 108 | } 109 | 110 | $reservedWords = array( 111 | 'and','array','as','break','case','catch','class','clone', 112 | 'const','continue','declare','default','do','else','elseif', 113 | 'enddeclare','endfor','endforeach','endif','endswitch','endwhile', 114 | 'extends','final','for','foreach','function','global', 115 | 'goto','if','implements','instanceof','namespace', 116 | 'new','or','private','protected','public','static','switch', 117 | 'throw','try','use','var','while','xor' 118 | ); 119 | 120 | if (in_array($className, $reservedWords)) { 121 | $className = $className . 'CLASS'; 122 | } 123 | 124 | return $className; 125 | } 126 | 127 | public function __toString() 128 | { 129 | return $this->_originalClassName . ' => ' . $this->_newFullyQualifiedName; 130 | } 131 | 132 | 133 | } -------------------------------------------------------------------------------- /library/PHPTools/SPL/SplClassLoader.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | 12 | namespace PHPTools\SPL; 13 | 14 | /** 15 | * SplClassLoader implementation that implements the technical interoperability 16 | * standards for PHP 5.3 namespaces and class names. 17 | * 18 | * http://groups.google.com/group/php-standards/web/final-proposal 19 | * 20 | * // Example which loads classes for the Doctrine Common package in the 21 | * // Doctrine\Common namespace. 22 | * $classLoader = new SplClassLoader('Doctrine\Common', '/path/to/doctrine'); 23 | * $classLoader->register(); 24 | * 25 | * @author Jonathan H. Wage 26 | * @author Roman S. Borschel 27 | * @author Matthew Weier O'Phinney 28 | * @author Kris Wallsmith 29 | * @author Fabien Potencier 30 | */ 31 | class SplClassLoader 32 | { 33 | private $_fileExtension = '.php'; 34 | private $_namespace; 35 | private $_includePath; 36 | private $_namespaceSeparator = '\\'; 37 | 38 | /** 39 | * Creates a new SplClassLoader that loads classes of the 40 | * specified namespace. 41 | * 42 | * @param string $ns The namespace to use. 43 | */ 44 | public function __construct($ns = null, $includePath = null) 45 | { 46 | $this->_namespace = $ns; 47 | $this->_includePath = $includePath; 48 | } 49 | 50 | /** 51 | * Sets the namespace separator used by classes in the namespace of this class loader. 52 | * 53 | * @param string $sep The separator to use. 54 | */ 55 | public function setNamespaceSeparator($sep) 56 | { 57 | $this->_namespaceSeparator = $sep; 58 | } 59 | 60 | /** 61 | * Gets the namespace seperator used by classes in the namespace of this class loader. 62 | * 63 | * @return void 64 | */ 65 | public function getNamespaceSeparator() 66 | { 67 | return $this->_namespaceSeparator; 68 | } 69 | 70 | /** 71 | * Sets the base include path for all class files in the namespace of this class loader. 72 | * 73 | * @param string $includePath 74 | */ 75 | public function setIncludePath($includePath) 76 | { 77 | $this->_includePath = $includePath; 78 | } 79 | 80 | /** 81 | * Gets the base include path for all class files in the namespace of this class loader. 82 | * 83 | * @return string $includePath 84 | */ 85 | public function getIncludePath() 86 | { 87 | return $this->_includePath; 88 | } 89 | 90 | /** 91 | * Sets the file extension of class files in the namespace of this class loader. 92 | * 93 | * @param string $fileExtension 94 | */ 95 | public function setFileExtension($fileExtension) 96 | { 97 | $this->_fileExtension = $fileExtension; 98 | } 99 | 100 | /** 101 | * Gets the file extension of class files in the namespace of this class loader. 102 | * 103 | * @return string $fileExtension 104 | */ 105 | public function getFileExtension() 106 | { 107 | return $this->_fileExtension; 108 | } 109 | 110 | /** 111 | * Installs this class loader on the SPL autoload stack. 112 | */ 113 | public function register() 114 | { 115 | spl_autoload_register(array($this, 'loadClass')); 116 | } 117 | 118 | /** 119 | * Uninstalls this class loader from the SPL autoloader stack. 120 | */ 121 | public function unregister() 122 | { 123 | spl_autoload_unregister(array($this, 'loadClass')); 124 | } 125 | 126 | /** 127 | * Loads the given class or interface. 128 | * 129 | * @param string $className The name of the class to load. 130 | * @return void 131 | */ 132 | public function loadClass($className) 133 | { 134 | $className = ltrim($className, $this->_namespaceSeparator); 135 | if (null === $this->_namespace || $this->_namespace.$this->_namespaceSeparator === substr($className, 0, strlen($this->_namespace.$this->_namespaceSeparator))) { 136 | $fileName = ''; 137 | $namespace = ''; 138 | if (false !== ($lastNsPos = strripos($className, $this->_namespaceSeparator))) { 139 | $namespace = substr($className, 0, $lastNsPos); 140 | $className = substr($className, $lastNsPos + 1); 141 | $fileName = str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR; 142 | } 143 | $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . $this->_fileExtension; 144 | 145 | require ($this->_includePath !== null ? $this->_includePath . DIRECTORY_SEPARATOR : '') . $fileName; 146 | } 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /library/PHPTools/Namespacer/CLIRunner.php: -------------------------------------------------------------------------------- 1 | run(); 17 | } 18 | 19 | public function __construct() 20 | { 21 | if (PHP_SAPI != 'cli') { 22 | throw new \RuntimeException('This class is only available in the CLI PHP Environment'); 23 | } 24 | } 25 | 26 | public function run($options = array()) 27 | { 28 | $namespacer = new Namespacer(); 29 | $this->_parseOptions($namespacer, $options); 30 | } 31 | 32 | protected function _parseOptions(Namespacer $namespacer, array $options = array()) 33 | { 34 | if (!$options) { 35 | 36 | $usersOptions = getopt( 37 | 'h::l::d::o::p::s::m::', 38 | array( 39 | 'help::', 40 | 'lib::', 41 | 'library-directory::', 42 | 'dir::', 43 | 'directory-filter::', 44 | 'out::', 45 | 'output-path::', 46 | 'prefix::', 47 | 'prefixes::', 48 | 'stats::', 49 | 'show-statistics::', 50 | 'map::', 51 | 'map-path::' 52 | ) 53 | ); 54 | 55 | $userToOfficialNames = array( 56 | 'h' => 'help', 57 | 'help' => 'help', 58 | 'l' => 'libraryDirectory', 59 | 'lib' => 'libraryDirectory', 60 | 'library-directory' => 'libraryDirectory', 61 | 'd' => 'directoryFilter', 62 | 'dir' => 'directoryFilter', 63 | 'directory-filter' => 'directoryFilter', 64 | 'o' => 'outputPath', 65 | 'out' => 'outputPath', 66 | 'output-path' => 'outputPath', 67 | 'p' => 'prefixes', 68 | 'prefix' => 'prefixes', 69 | 'prefixes' => 'prefixes', 70 | 's' => 'showStatistics', 71 | 'stats' => 'showStatistics', 72 | 'show-statistics' => 'showStatistics', 73 | 'm' => 'mapPath', 74 | 'map' => 'mapPath', 75 | 'map-path' => 'mapPath' 76 | ); 77 | 78 | $options = array(); 79 | 80 | foreach ($userToOfficialNames as $userOptionName => $officialName) { 81 | if (isset($usersOptions[$userOptionName])) { 82 | $options[$officialName] = $usersOptions[$userOptionName]; 83 | } 84 | } 85 | } 86 | 87 | if (isset($options['help'])) { 88 | $this->_showHelp(); 89 | return; 90 | } 91 | 92 | try { 93 | $namespacer->setOptions($options); 94 | $namespacer->convert(); 95 | } catch (\Exception $e) { 96 | echo 'Exception caught ' . get_class($e) . ' : ' . $e->getMessage(); 97 | exit(1); 98 | } 99 | 100 | } 101 | 102 | protected function _showHelp() 103 | { 104 | echo <<_filters as $filter) { 86 | $valueFiltered = $filter->filter($valueFiltered); 87 | } 88 | return $valueFiltered; 89 | } 90 | 91 | /** REMOVED ORIGINAL CODE, NO PURPOSE IN THIS TEST FILE */ 92 | 93 | /** 94 | * @deprecated 95 | * @see Zend_Filter::filterStatic() 96 | * 97 | * @param mixed $value 98 | * @param string $classBaseName 99 | * @param array $args OPTIONAL 100 | * @param array|string $namespaces OPTIONAL 101 | * @return mixed 102 | * @throws Zend_Filter_Exception 103 | */ 104 | public static function get($value, $classBaseName, array $args = array(), $namespaces = array()) 105 | { 106 | trigger_error( 107 | 'Zend_Filter::get() is deprecated as of 1.9.0; please update your code to utilize Zend_Filter::filterStatic()', 108 | E_USER_NOTICE 109 | ); 110 | 111 | return self::filterStatic($value, $classBaseName, $args, $namespaces); 112 | } 113 | 114 | /** 115 | * Returns a value filtered through a specified filter class, without requiring separate 116 | * instantiation of the filter object. 117 | * 118 | * The first argument of this method is a data input value, that you would have filtered. 119 | * The second argument is a string, which corresponds to the basename of the filter class, 120 | * relative to the Zend_Filter namespace. This method automatically loads the class, 121 | * creates an instance, and applies the filter() method to the data input. You can also pass 122 | * an array of constructor arguments, if they are needed for the filter class. 123 | * 124 | * @param mixed $value 125 | * @param string $classBaseName 126 | * @param array $args OPTIONAL 127 | * @param array|string $namespaces OPTIONAL 128 | * @return mixed 129 | * @throws Zend_Filter_Exception 130 | */ 131 | public static function filterStatic($value, $classBaseName, array $args = array(), $namespaces = array()) 132 | { 133 | $namespaces = array_merge((array) $namespaces, self::$_defaultNamespaces, array('Zend_Filter')); 134 | foreach ($namespaces as $namespace) { 135 | $className = $namespace . '_' . ucfirst($classBaseName); 136 | if (!class_exists($className, false)) { 137 | try { 138 | $file = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; 139 | if (Zend_Loader::isReadable($file)) { 140 | Zend_Loader::loadClass($className); 141 | } else { 142 | continue; 143 | } 144 | } catch (Zend_Exception $ze) { 145 | continue; 146 | } 147 | } 148 | 149 | $class = new ReflectionClass($className); 150 | if ($class->implementsInterface('Zend_Filter_Interface')) { 151 | if ($class->hasMethod('__construct')) { 152 | $object = $class->newInstanceArgs($args); 153 | } else { 154 | $object = $class->newInstance(); 155 | } 156 | return $object->filter($value); 157 | } 158 | } 159 | throw new Zend_Filter_Exception("Filter class not found from basename '$classBaseName'"); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /library/PHPTools/Namespacer/Namespacer.php: -------------------------------------------------------------------------------- 1 | setOptions($options); 23 | } 24 | $this->_fileRegistry = new FileRegistry(); 25 | } 26 | 27 | public function setOptions(Array $options) 28 | { 29 | foreach ($options as $optionName => $optionValue) { 30 | $this->setOption($optionName, $optionValue); 31 | } 32 | } 33 | 34 | public function setOption($optionName, $optionValue = true) 35 | { 36 | switch ($optionName) { 37 | case 'libraryDirectory': 38 | $this->_libraryDirectoryOriginal = $optionValue; 39 | $this->_libraryDirectory = realpath($this->_libraryDirectoryOriginal); 40 | if (!file_exists($this->_libraryDirectory)) { 41 | throw new \InvalidArgumentException('Library directory provided does not exist (' . $this->_libraryDirectory . ')'); 42 | } 43 | break; 44 | case 'directoryFilter': 45 | $this->_directoryFilter = $optionValue; 46 | break; 47 | case 'outputPath': 48 | $this->_outputPath = $optionValue; 49 | if (!file_exists(realpath($this->_outputPath))) { 50 | if (!file_exists(realpath(dirname($this->_outputPath)))) { 51 | throw new \InvalidArgumentException('The output path provided does not exist and cannot be created in ' . $this->_outputPath); 52 | } 53 | mkdir($this->_outputPath); 54 | } 55 | break; 56 | case 'mapPath': 57 | $this->_mapPath = $optionValue; 58 | if (!file_exists(realpath($this->_mapPath))) { 59 | if (!file_exists(realpath(dirname($this->_mapPath)))) { 60 | throw new \InvalidArgumentException('The output path provided does not exist and cannot be created in ' . $this->_mapPath); 61 | } 62 | mkdir($this->_mapPath); 63 | } 64 | break; 65 | case 'prefixes': 66 | $this->_prefixes = explode(',', $optionValue); 67 | break; 68 | case 'showStatistics': 69 | $this->_showStatistics = $optionValue; 70 | break; 71 | default: 72 | throw new \InvalidArgumentException('Option ' . $optionName . ' is not supporter by ' . __CLASS__); 73 | } 74 | } 75 | 76 | public function getOptions() 77 | { 78 | return array( 79 | 'libraryDirectory' => $this->_libraryDirectory, 80 | 'directoryFilter' => $this->_directoryFilter, 81 | 'outputPath' => $this->_outputPath, 82 | 'prefixes' => $this->_prefixes, 83 | 'showStatistics' => $this->_showStatistics 84 | ); 85 | } 86 | 87 | public function getFileRegistry() 88 | { 89 | return $this->_fileRegistry; 90 | } 91 | 92 | public function convert() 93 | { 94 | if (isset($this->_libraryDirectory)) { 95 | $rdi = $it = new \RecursiveDirectoryIterator($this->_libraryDirectory); 96 | 97 | if (isset($this->_directoryFilter)) { 98 | // use our RecursiveFilterIterator, not SPL's 99 | $it = new RecursiveFilterIterator($rdi, $this->_directoryFilter); 100 | } 101 | 102 | $buildFileMapFromDirectory = true; 103 | 104 | if ($this->_mapPath) { 105 | $mapFilePath = $this->_mapPath . '/PHPNamespacer-MappedClasses.xml'; 106 | $mapFileRealPath = realpath($mapFilePath); 107 | if (file_exists($mapFileRealPath)) { 108 | $this->_loadMapFile($mapFileRealPath); 109 | $buildFileMapFromDirectory = false; 110 | } else { 111 | $xmlWriter = new XMLWriter(); 112 | $xmlWriter->openURI($mapFilePath); 113 | $xmlWriter->setIndent(true); 114 | $xmlWriter->setIndentString(' '); 115 | $xmlWriter->startDocument('1.0'); 116 | $xmlWriter->startElement('mappedClasses'); 117 | $xmlWriter->writeAttribute('libraryDirectory', $this->_libraryDirectoryOriginal); 118 | } 119 | } 120 | 121 | if ($buildFileMapFromDirectory) { 122 | foreach (new \RecursiveIteratorIterator($rdi, \RecursiveIteratorIterator::SELF_FIRST) as $realFilePath => $fileInfo) { 123 | $relativeFilePath = substr($realFilePath, strlen($this->_libraryDirectory)+1); 124 | if (preg_match('#(\.svn|_svn|\.git)#', $relativeFilePath) || !preg_match('#\.php$#', $relativeFilePath)) { 125 | continue; 126 | } 127 | $fileNameProcessor = new FileNameProcessor($relativeFilePath, $this->_libraryDirectory); 128 | // add only classes that contain a matching prefix 129 | if (!$this->_prefixes || preg_match('#^' . implode('|', $this->_prefixes) . '#', $fileNameProcessor->getOriginalClassName())) { 130 | $this->_fileRegistry->registerFileNameProcessor($fileNameProcessor); 131 | if (isset($xmlWriter)) { 132 | $xmlWriter->startElement('mappedClass'); 133 | $xmlWriter->writeElement('originalRelativeFilePath', $fileNameProcessor->getOriginalRelativeFilePath()); 134 | $xmlWriter->writeElement('originalClassName', $fileNameProcessor->getOriginalClassName()); 135 | $xmlWriter->writeElement('newRelativeFilePath', $fileNameProcessor->getNewRelativeFilePath()); 136 | $xmlWriter->writeElement('newNamespace', $fileNameProcessor->getNewNamespace()); 137 | $xmlWriter->writeElement('newClassName', $fileNameProcessor->getNewClassName()); 138 | $xmlWriter->writeElement('newFullyQualifiedName', $fileNameProcessor->getNewFullyQualifiedName()); 139 | $xmlWriter->endElement(); 140 | } 141 | } 142 | } 143 | } 144 | 145 | if (isset($xmlWriter)) { 146 | $xmlWriter->endElement(); 147 | $xmlWriter->endDocument(); 148 | $xmlWriter->flush(); 149 | echo 'Number of classes written to map file: ' . count($this->_fileRegistry) . PHP_EOL; 150 | } 151 | 152 | if ($this->_outputPath) { 153 | 154 | foreach (new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::SELF_FIRST) as $realFilePath => $fileInfo) { 155 | if ($fileInfo->isFile()) { 156 | $relativeFilePath = substr($realFilePath, strlen($this->_libraryDirectory)+1); 157 | $fileNameProc = $this->_fileRegistry->findByOriginalRelativeFilePath($relativeFilePath); 158 | if ($fileNameProc) { 159 | $fileContentProcessor = new FileContentProcessor($fileNameProc, $this->_prefixes, $this->_fileRegistry); 160 | $this->_fileRegistry->registerFileContentProcessor($fileContentProcessor); 161 | } 162 | } 163 | } 164 | 165 | $this->_fileRegistry->setIterationType(FileRegistry::ITERATE_CONTENTS); 166 | foreach ($this->_fileRegistry as $fileContentProc) { 167 | $fileNameProc = $this->_fileRegistry->getFileNameProcessorForContentProcessor($fileContentProc); 168 | 169 | $base = dirname($fileNameProc->getNewRelativeFilePath()); 170 | if (!file_exists($this->_outputPath . '/' . $base)) { 171 | mkdir($this->_outputPath . '/' . $base, 0777, true); 172 | } 173 | 174 | file_put_contents($this->_outputPath . '/' . $fileNameProc->getNewRelativeFilePath(), $fileContentProc->getNewContents()); 175 | } 176 | } 177 | } else { 178 | throw new \RuntimeException('Neither a filePath or a libraryDirectory was supplied to the Namespacer.'); 179 | } 180 | 181 | } 182 | 183 | protected function _loadMapFile($mapFile) 184 | { 185 | echo 'Loading a map file found at ' . $mapFile . PHP_EOL; 186 | $mappedClassElementNames = array( 187 | 'originalRelativeFilePath', 188 | 'originalClassName', 189 | 'newRelativeFilePath', 190 | 'newNamespace', 191 | 'newClassName', 192 | 'newFullyQualifiedName', 193 | ); 194 | $reader = new XMLReader(); 195 | $reader->open($mapFile); 196 | 197 | $map = array(); 198 | while ($reader->read()) { 199 | if ($reader->name == 'mappedClasses' && $reader->nodeType == XMLReader::ELEMENT) { 200 | $libraryDirectory = $reader->getAttribute('libraryDirectory'); 201 | $realLibraryDirectory = realpath($libraryDirectory); 202 | if ($realLibraryDirectory != $this->_libraryDirectory) { 203 | throw new \UnexpectedValueException('The libraryDirectory located in the map file is not the same as the one provided for execution.'); 204 | } 205 | continue; 206 | } 207 | if ($reader->name == 'mappedClass' && $reader->nodeType == XMLReader::ELEMENT) { 208 | $mappedClass = array(); 209 | 210 | foreach ($reader->expand()->childNodes as $domNode) { 211 | if (in_array($domNode->nodeName, $mappedClassElementNames)) { 212 | $mappedClass[$domNode->nodeName] = $domNode->nodeValue; 213 | } 214 | } 215 | 216 | $fileNameProcessor = new FileNameProcessor($mappedClass, $libraryDirectory); 217 | $this->_fileRegistry->registerFileNameProcessor($fileNameProcessor); 218 | $reader->next(); 219 | } 220 | } 221 | 222 | } 223 | 224 | protected function _displayInfo($infoArray) 225 | { 226 | echo ' Class name found: ' . $infoArray['className'] . PHP_EOL; 227 | if (isset($infoArray['consumedClasses'])) { 228 | echo ' Classes consumed:' . PHP_EOL; 229 | foreach ($infoArray['consumedClasses'] as $consumedClass) { 230 | echo ' ' . $consumedClass . PHP_EOL; 231 | } 232 | } 233 | echo PHP_EOL; 234 | } 235 | 236 | } 237 | -------------------------------------------------------------------------------- /library/PHPTools/Namespacer/FileContentProcessor.php: -------------------------------------------------------------------------------- 1 | _fileNameProcessor = $fileNameProcessor; 27 | $this->_prefixes = $prefixes; 28 | $this->_fileRegistry = $fileRegistry; 29 | 30 | if (extension_loaded('docblock')) { 31 | $this->_canTokenizeDocblocks = true; 32 | } 33 | 34 | $this->_process(); 35 | } 36 | 37 | public function getFileNameProcessor() 38 | { 39 | return $this->_fileNameProcessor; 40 | } 41 | 42 | public function getInformation() 43 | { 44 | $info = array(); 45 | foreach ($this->_interestingTokens as $tokenType => $tokenInfo) { 46 | switch ($tokenType) { 47 | case 'className': 48 | $info['className'] = $tokenInfo->value; 49 | break; 50 | case 'consumedClass': 51 | $info['consumedClasses'] = array(); 52 | foreach ((array) $tokenInfo as $consumedClassToken) { 53 | if (!in_array($consumedClassToken->value, $info['consumedClasses'])) { 54 | $info['consumedClasses'][] = $consumedClassToken->value; 55 | } 56 | } 57 | break; 58 | } 59 | } 60 | return $info; 61 | } 62 | 63 | public function getNewContents() 64 | { 65 | if (!$this->_newTokens) { 66 | $this->convert(); 67 | } 68 | 69 | $contents = null; 70 | foreach ($this->_newTokens as $token) { 71 | if (is_array($token)) { 72 | $contents .= $token[1]; 73 | } else { 74 | $contents .= $token; 75 | } 76 | } 77 | 78 | return $contents; 79 | } 80 | 81 | protected function _process() 82 | { 83 | $this->_analyze(); 84 | $this->_generate(); 85 | } 86 | 87 | protected function _analyze() 88 | { 89 | $this->_originalContent = file_get_contents($this->_fileNameProcessor->getOriginalFilePath()); 90 | $this->_originalTokens = token_get_all($this->_originalContent); 91 | $this->_staticAnalysis(); 92 | // other analysis processes here? 93 | } 94 | 95 | protected function _staticAnalysis() 96 | { 97 | $context = null; 98 | 99 | foreach ($this->_originalTokens as $tokenNumber => $token) { 100 | if (is_array($token)) { 101 | $tokenName = token_name($token[0]); 102 | } else { 103 | $tokenName = 'string:' . $token; 104 | } 105 | 106 | if ($tokenNumber >= 3 && $context == 'INSIDE_OPEN_TAG') { 107 | $context = null; 108 | } 109 | 110 | // mostly for debugging 111 | $surroundingTokens = array(); 112 | $surroundingTokens[-2] = (isset($this->_originalTokens[$tokenNumber - 2])) ? $this->_originalTokens[$tokenNumber - 2] : null; 113 | $surroundingTokens[-1] = (isset($this->_originalTokens[$tokenNumber - 1])) ? $this->_originalTokens[$tokenNumber - 1] : null; 114 | $surroundingTokens[1] = (isset($this->_originalTokens[$tokenNumber + 1])) ? $this->_originalTokens[$tokenNumber + 1] : null; 115 | $surroundingTokens[2] = (isset($this->_originalTokens[$tokenNumber + 2])) ? $this->_originalTokens[$tokenNumber + 2] : null; 116 | 117 | switch ($tokenName) { 118 | case 'T_OPEN_TAG': 119 | if ($tokenNumber < 3) { 120 | $context = 'INSIDE_OPEN_TAG'; 121 | } 122 | break; 123 | case 'T_DOC_COMMENT': 124 | if ($context == 'INSIDE_OPEN_TAG') { 125 | $this->_registerInterestingToken('topOfFile', $tokenNumber + 1, true); 126 | $context = null; 127 | } 128 | $this->_registerInterestingToken('docblock', $tokenNumber, true); 129 | break; 130 | 131 | case 'T_INTERFACE': 132 | $context = 'INSIDE_CLASS_DECLARATION'; 133 | $this->_interestingInformation['isInterface'] = true; 134 | case 'T_CLASS': 135 | $context = 'INSIDE_CLASS_DECLARATION'; 136 | break; 137 | case 'T_ABSTRACT': 138 | $this->_interestingInformation['isAbstract'] = true; 139 | break; 140 | case 'T_EXTENDS': 141 | case 'T_IMPLEMENTS': 142 | $context = 'INSIDE_CLASS_SIGNATURE'; 143 | break; 144 | case 'T_NEW': 145 | $context = 'INSIDE_NEW_ASSIGNMENT'; 146 | break; 147 | case 'T_FUNCTION': 148 | $context = 'INSIDE_FUNCTION_SIGNATURE_START'; 149 | break; 150 | case 'T_CATCH': 151 | $context = 'INSIDE_CATCH_STATEMENT'; 152 | break; 153 | case 'string:{': 154 | $context = null; 155 | break; 156 | case 'string:(': 157 | if ($context == 'INSIDE_FUNCTION_SIGNATURE_START') { 158 | $context = 'INSIDE_FUNCTION_SIGNATURE'; 159 | } 160 | break; 161 | case 'string:)': 162 | if ($context == 'INSIDE_FUNCTION_SIGNATURE') { 163 | $context = null; 164 | } 165 | break; 166 | case 'T_DOUBLE_COLON': 167 | if (!in_array($this->_originalTokens[$tokenNumber-1][1], array('self', 'parent', 'static'))) { 168 | $this->_registerInterestingToken('consumedClass', $tokenNumber - 1); 169 | } 170 | break; 171 | case 'T_INSTANCEOF': 172 | if (!in_array($this->_originalTokens[$tokenNumber+2][1], array('self', 'parent', 'static'))) { 173 | $this->_registerInterestingToken('consumedClass', $tokenNumber + 2); 174 | } 175 | 176 | case 'T_STRING': 177 | switch ($context) { 178 | case 'INSIDE_CLASS_DECLARATION': 179 | $this->_registerInterestingToken('className', $tokenNumber, true); 180 | $context = null; 181 | break; 182 | case 'INSIDE_CLASS_SIGNATURE': 183 | $this->_registerInterestingToken('consumedClass', $tokenNumber); 184 | break; 185 | case 'INSIDE_NEW_ASSIGNMENT': 186 | $this->_registerInterestingToken('consumedClass', $tokenNumber); 187 | $context = null; 188 | break; 189 | case 'INSIDE_FUNCTION_SIGNATURE': 190 | $safeWords = array('true', 'false', 'null', 'self', 'parent', 'static'); 191 | $previousToken = $surroundingTokens[-1]; 192 | if (in_array($token[1], $safeWords) 193 | || (is_array($previousToken) && $previousToken[1] == '::')) { 194 | break; 195 | } 196 | $this->_registerInterestingToken('consumedClass', $tokenNumber); 197 | break; 198 | case 'INSIDE_CATCH_STATEMENT': 199 | $this->_registerInterestingToken('consumedClass', $tokenNumber); 200 | $context = null; 201 | break; 202 | } 203 | 204 | break; 205 | 206 | } 207 | 208 | } 209 | 210 | } 211 | 212 | protected function _generate() 213 | { 214 | 215 | $namespace = $this->_fileNameProcessor->getNewNamespace(); 216 | $className = $this->_fileNameProcessor->getNewClassName(); 217 | 218 | $prefixesRegex = implode('|', $this->_prefixes); 219 | 220 | if (!preg_match('#^' . $prefixesRegex . '#', $this->_fileNameProcessor->getOriginalClassName())) { 221 | $this->_newTokens = $this->_originalTokens; 222 | return; 223 | } 224 | 225 | // determine consumed classes 226 | $classCount = array(); 227 | if (isset($this->_interestingTokens['consumedClass'])) { 228 | foreach ($this->_interestingTokens['consumedClass'] as $consumedClassToken) { 229 | $origConsumedClassName = $consumedClassToken['value']; 230 | $consumedClassFileNameProc = $this->_fileRegistry->findByOriginalClassName($origConsumedClassName); 231 | if ($consumedClassFileNameProc) { 232 | $currentConsumedClassName = $consumedClassFileNameProc->getNewFullyQualifiedName(); 233 | } else { 234 | $currentConsumedClassName = $origConsumedClassName; 235 | } 236 | 237 | if (!isset($classCount[$currentConsumedClassName])) $classCount[$currentConsumedClassName] = 0; 238 | $classCount[$currentConsumedClassName]++; 239 | 240 | } 241 | } 242 | 243 | // compute uses 244 | if ($classCount) { 245 | 246 | $uses['declarations'] = $uses['translations'] = $uses = array(); 247 | 248 | foreach ($classCount as $consumedClassName => $numberOfOccurances) { 249 | if ($numberOfOccurances == 1) continue; 250 | if ((strpos($consumedClassName, '\\') !== false) && (strpos($consumedClassName, $namespace) !== 0)) { 251 | $consumedClassFileNameProc = $this->_fileRegistry->findByNewFullyQualifiedName($consumedClassName); 252 | $uses['declarations'][] = $ccn = $consumedClassFileNameProc->getNewNamespace(); 253 | $uses['translations'][$consumedClassName] = substr($ccn, strrpos($ccn, '\\')+1) . '\\' 254 | . str_replace($ccn . '\\', '', $consumedClassFileNameProc->getNewFullyQualifiedName()); 255 | } 256 | } 257 | } 258 | 259 | foreach ($this->_originalTokens as $tokenNumber => $token) { 260 | 261 | if (!array_key_exists($tokenNumber, $this->_interestingTokenIndex)) { 262 | $this->_newTokens[] = $token; 263 | continue; 264 | } 265 | 266 | // This token is interesting for some reason 267 | $interestingReasons = $this->_interestingTokenIndex[$tokenNumber]; 268 | 269 | foreach ($interestingReasons as $interestingReason) { 270 | 271 | switch ($interestingReason) { 272 | case 'topOfFile': 273 | $content = 'namespace ' . $namespace . ';' . "\n"; 274 | if (isset($uses['declarations']) && $uses['declarations']) { 275 | foreach ($uses['declarations'] as $useDeclaration) { 276 | $content .= 'use ' . $useDeclaration . ';' . "\n"; 277 | } 278 | } 279 | $this->_newTokens[] = "\n\n/**\n * @namespace\n */\n" . $content . "\n"; 280 | break; 281 | case 'docblock': 282 | if ($this->_canTokenizeDocblocks) { 283 | $docblockProc = new DocblockContentProcessor($token[1], $this->_prefixes, $this->_fileRegistry); 284 | $this->_newTokens[] = $docblockProc->getContents(); 285 | } else { 286 | $this->_newTokens[] = $token[1]; 287 | } 288 | break; 289 | case 'className': 290 | $this->_newTokens[] = $className; 291 | break; 292 | case 'consumedClass': 293 | $origConsumedClassName = $token[1]; 294 | $fileNameProc = $this->_fileRegistry->findByOriginalClassName($origConsumedClassName); 295 | if ($fileNameProc) { 296 | $newConsumedClass = $fileNameProc->getNewFullyQualifiedName(); 297 | if (strpos($newConsumedClass, $namespace) === 0) { 298 | $newConsumedClass = substr($newConsumedClass, strlen($namespace)+1); 299 | } else { 300 | $newConsumedClass = '\\' . $newConsumedClass; 301 | } 302 | } else { 303 | $newConsumedClass = '\\' . str_replace('_', '\\', $token[1]); 304 | } 305 | 306 | if (isset($uses['translations']) && $uses['translations'] && $newConsumedClass{0} == '\\') { 307 | $translationSearchClass = ltrim($newConsumedClass, '\\'); 308 | if (array_key_exists($translationSearchClass, $uses['translations'])) { 309 | $newConsumedClass = $uses['translations'][$translationSearchClass]; 310 | } 311 | } 312 | 313 | if (isset($uses['declarations']) && $uses['declarations'] && $newConsumedClass{0} == '\\') { 314 | $declarationSearchClass = ltrim($newConsumedClass, '\\'); 315 | foreach ($uses['declarations'] as $declarationSearchMatch) { 316 | if (strpos($declarationSearchClass, $declarationSearchMatch) === 0) { 317 | $newConsumedClass = substr($declarationSearchMatch, strrpos($declarationSearchMatch, '\\')+1) . substr($declarationSearchClass, strlen($declarationSearchMatch)); 318 | } 319 | } 320 | } 321 | 322 | $this->_newTokens[] = $newConsumedClass; 323 | break; 324 | default: 325 | $this->_newTokens[] = $token; 326 | break; 327 | } 328 | 329 | } 330 | 331 | } 332 | 333 | } 334 | 335 | protected function _registerInterestingToken($name, $tokenNumber, $isSingle = false) 336 | { 337 | $token = $this->_originalTokens[$tokenNumber]; 338 | 339 | if (count($token) != 3) { 340 | return; 341 | } 342 | 343 | $tokenObj = new \ArrayObject( 344 | array( 345 | 'number' => $tokenNumber, 346 | 'id' => $token[0], 347 | 'value' => $token[1], 348 | 'line' => $token[2], 349 | 'name' => token_name($token[0]) 350 | ), 351 | \ArrayObject::ARRAY_AS_PROPS 352 | ); 353 | 354 | if ($isSingle) { 355 | $this->_interestingTokens[$name] = $tokenObj; 356 | } else { 357 | if (!isset($this->_interestingTokens[$name])) { 358 | $this->_interestingTokens[$name] = array(); 359 | } 360 | $this->_interestingTokens[$name][] = $tokenObj; 361 | } 362 | 363 | if (!isset($this->_interestingTokenIndex[$tokenNumber])) { 364 | $this->_interestingTokenIndex[$tokenNumber] = array(); 365 | } 366 | 367 | $this->_interestingTokenIndex[$tokenNumber][] = $name; 368 | } 369 | 370 | public function __toString() 371 | { 372 | return 'File Contents for: ' . $this->_fileNameProcessor->getOriginalFilePath(); 373 | } 374 | 375 | 376 | } --------------------------------------------------------------------------------