Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial Commit into GitHub master repo

  • Loading branch information...
commit 4763cfa6d22cf21261b0bb08f8501aef3af6350f 0 parents
Ralph Schindler authored
10 README
@@ -0,0 +1,10 @@
+PHPTools
+========
+
+Namespacer
+----------
+
+This tool is to help facilitate the conversion of PHP5 Prefixed code
+(ZF or PEAR standards code) to PHP 5.3 Namespaced code.
+
+.. more info ..
16 bin/php-namespacer.php
@@ -0,0 +1,16 @@
+#!/usr/bin/env php
+<?php
+
+error_reporting(E_STRICT | E_ALL);
+
+$libraryDirectory = dirname(__FILE__) . '/../library/';
+
+if (!class_exists('SplClassLoader')) {
+ require_once $libraryDirectory . '/PHPTools/SPL/SplClassLoader.php';
+ $loader = new \PHPTools\SPL\SplClassLoader('PHPTools', $libraryDirectory);
+} else {
+ $loader = new \SplClassLoader('PHPTools', $libraryDirectory);
+}
+
+$loader->register();
+$cliRunner = \PHPTools\Namespacer\CLIRunner::main();
137 library/PHPTools/Namespacer/CLIRunner.php
@@ -0,0 +1,137 @@
+<?php
+
+namespace PHPTools\Namespacer;
+
+class CLIRunner
+{
+
+ public static function main()
+ {
+ $cliRunner = new self();
+ $cliRunner->run();
+ }
+
+ public function __construct()
+ {
+ if (PHP_SAPI != 'cli') {
+ throw new \RuntimeException('This class is only available in the CLI PHP Environment');
+ }
+ }
+
+ public function run()
+ {
+ $namespacer = new Namespacer();
+ $this->_parseOptions($namespacer);
+ }
+
+ protected function _parseOptions(Namespacer $namespacer)
+ {
+ $usersOptions = getopt(
+ 'h::l::d::o::p::s::m::',
+ array(
+ 'help::',
+ 'lib::',
+ 'library-directory::',
+ 'dir::',
+ 'directory-filter::',
+ 'out::',
+ 'output-path::',
+ 'prefix::',
+ 'prefixes::',
+ 'stats::',
+ 'show-statistics::',
+ 'map::',
+ 'map-path::'
+ )
+ );
+
+ $userToOfficialNames = array(
+ 'h' => 'help',
+ 'help' => 'help',
+ 'l' => 'libraryDirectory',
+ 'lib' => 'libraryDirectory',
+ 'library-directory' => 'libraryDirectory',
+ 'd' => 'directoryFilter',
+ 'dir' => 'directoryFilter',
+ 'directory-filter' => 'directoryFilter',
+ 'o' => 'outputPath',
+ 'out' => 'outputPath',
+ 'output-path' => 'outputPath',
+ 'p' => 'prefixes',
+ 'prefix' => 'prefixes',
+ 'prefixes' => 'prefixes',
+ 's' => 'showStatistics',
+ 'stats' => 'showStatistics',
+ 'show-statistics' => 'showStatistics',
+ 'm' => 'mapPath',
+ 'map' => 'mapPath',
+ 'map-path' => 'mapPath'
+ );
+
+ $options = array();
+
+ foreach ($userToOfficialNames as $userOptionName => $officialName) {
+ if (isset($usersOptions[$userOptionName])) {
+ $options[$officialName] = $usersOptions[$userOptionName];
+ }
+ }
+
+ if (isset($options['help'])) {
+ $this->_showHelp();
+ return;
+ }
+
+ try {
+ $namespacer->setOptions($options);
+ $namespacer->convert();
+ } catch (\Exception $e) {
+ echo 'Exception caught ' . get_class($e) . ' : ' . $e->getMessage();
+ exit(1);
+ }
+
+ }
+
+ protected function _showHelp()
+ {
+ echo <<<EOS
+This tool is intended to be used to namespace previously prefixed library
+code developed with a PEAR/ZF coding standard in place. It will attempt
+to find all class names and convert them to namespaces. Furthermore, it
+will attempt to find any references to those classes in method signatures,
+and body code, and docblocks and convert those to known translations.
+
+Usage:
+ (Option should be passed in a form that php's getopt() can parse.)
+ php path/to/Namespace/Namespacer.php [options]
+
+Options:
+ -h, --help
+ This help screen.
+ -l, --lib, --library-directory
+ The library directory to iterate, this would be the same directory
+ you would anticipate registered as an include_path.
+ -d, --dir, --directory-filter
+ The part of the library directory you want to operate on.
+ -o, --out, --output-path
+ If supplied, this directory will be where converted files are
+ written to.
+ -p, --prefix, --prefixes
+ The base prefix to mind when converting. Can be comma separated
+ list.
+ -m, --map, --map-path
+ The directory where an xml file will be produced that will list
+ the file and class translations that were used.
+
+Notes:
+ * library and directory are separate entities b/c library will be
+ first scanned to identify all names in general usage. Directory
+ will be used to filter out the relative path that is to be
+ considered the working set of file that the converter should
+ convert.
+
+
+EOS;
+ }
+
+}
+
89 library/PHPTools/Namespacer/DocblockContentProcessor.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace PHPTools\Namespacer;
+
+class DocblockContentProcessor
+{
+
+ protected $_content = null;
+ protected $_prefixes = array();
+ protected $_newTokens = array();
+
+ /**
+ * @var \Namespacer\FileRegistry
+ */
+ protected $_fileRegistry = null;
+
+ public function __construct($docblockContent, $prefixes = array(), FileRegistry $fileRegistry = null)
+ {
+ $this->_content = $docblockContent;
+ $this->_prefixes = $prefixes;
+ $this->_fileRegistry = $fileRegistry;
+ $this->_generate();
+ }
+
+ public function getContents()
+ {
+ $content = '';
+ foreach ($this->_newTokens as $newToken) {
+ $content .= $newToken[1];
+ }
+ return $content;
+ }
+
+ protected function _generate()
+ {
+ $tokens = docblock_tokenize($this->_content);
+ $context = null;
+
+ $this->_newTokens = array();
+
+ foreach ($tokens as $token) {
+ $newToken = array();
+ $tokenName = docblock_token_name($token[0]);
+ switch ($tokenName) {
+ case 'DOCBLOCK_TAG':
+ switch ($token[1]) {
+ case '@var':
+ case '@uses':
+ case '@param':
+ case '@return':
+ case '@throws':
+ $context = 'INSIDE_TYPE_TAG';
+ break;
+ }
+ $this->_newTokens[] = $token;
+ break;
+ case 'DOCBLOCK_TEXT':
+ if ($context == 'INSIDE_TYPE_TAG') {
+ $matches = array();
+ $prefixRegex = implode('|', $this->_prefixes);
+ if (preg_match('#.*(' . $prefixRegex . '_[\\w_]*).*#', $token[1], $matches)) {
+ $className = $matches[1];
+ $fileNameProc = $this->_fileRegistry->findByOriginalClassName($className);
+ if ($fileNameProc) {
+ $newClassName = '\\' . $fileNameProc->getNewFullyQualifiedName();
+ $tokenContent = preg_replace('#' . $className . '#', $newClassName, $matches[0]);
+ $newToken[1] = $tokenContent;
+ $this->_newTokens[] = $newToken;
+ } else {
+ $this->_newTokens[] = $token;
+ }
+
+ } else {
+ $this->_newTokens[] = $token;
+ }
+ $context = null;
+ } else {
+ $this->_newTokens[] = $token;
+ }
+ break;
+ default:
+ $this->_newTokens[] = $token;
+ break;
+ }
+ }
+
+ }
+
+}
358 library/PHPTools/Namespacer/FileContentProcessor.php
@@ -0,0 +1,358 @@
+<?php
+
+namespace PHPTools\Namespacer;
+
+class FileContentProcessor
+{
+ protected $_fileNameProcessor = null;
+ protected $_prefixes = array();
+ protected $_fileRegistry = null;
+ protected $_canTokenizeDocblocks = false;
+
+ protected $_libraryDirectory = null;
+ protected $_relativeFilePath = null;
+
+ protected $_originalContent = null;
+ protected $_originalTokens = null;
+
+ protected $_interestingInformation = array();
+ protected $_interestingTokens = array();
+ protected $_interestingTokenIndex = array();
+
+ protected $_newTokens = array();
+
+ public function __construct(FileNameProcessor $fileNameProcessor, $prefixes = array(), FileRegistry $fileRegistry = null)
+ {
+ $this->_fileNameProcessor = $fileNameProcessor;
+ $this->_prefixes = $prefixes;
+ $this->_fileRegistry = $fileRegistry;
+
+ if (extension_loaded('docblock')) {
+ $this->_canTokenizeDocblocks = true;
+ }
+
+ $this->_process();
+ }
+
+ public function getFileNameProcessor()
+ {
+ return $this->_fileNameProcessor;
+ }
+
+ public function getInformation()
+ {
+ $info = array();
+ foreach ($this->_interestingTokens as $tokenType => $tokenInfo) {
+ switch ($tokenType) {
+ case 'className':
+ $info['className'] = $tokenInfo->value;
+ break;
+ case 'consumedClass':
+ $info['consumedClasses'] = array();
+ foreach ((array) $tokenInfo as $consumedClassToken) {
+ if (!in_array($consumedClassToken->value, $info['consumedClasses'])) {
+ $info['consumedClasses'][] = $consumedClassToken->value;
+ }
+ }
+ break;
+ }
+ }
+ return $info;
+ }
+
+ public function getNewContents()
+ {
+ if (!$this->_newTokens) {
+ $this->convert();
+ }
+
+ $contents = null;
+ foreach ($this->_newTokens as $token) {
+ if (is_array($token)) {
+ $contents .= $token[1];
+ } else {
+ $contents .= $token;
+ }
+ }
+
+ return $contents;
+ }
+
+ protected function _process()
+ {
+ $this->_analyze();
+ $this->_generate();
+ }
+
+ protected function _analyze()
+ {
+ $this->_originalContent = file_get_contents($this->_fileNameProcessor->getOriginalFilePath());
+ $this->_originalTokens = token_get_all($this->_originalContent);
+ $this->_staticAnalysis();
+ // other analysis processes here?
+ }
+
+ protected function _staticAnalysis()
+ {
+ $context = null;
+
+ foreach ($this->_originalTokens as $tokenNumber => $token) {
+ if (is_array($token)) {
+ $tokenName = token_name($token[0]);
+ } else {
+ $tokenName = 'string:' . $token;
+ }
+
+ if ($tokenNumber >= 3 && $context == 'INSIDE_OPEN_TAG') {
+ $context = null;
+ }
+
+ switch ($tokenName) {
+ case 'T_OPEN_TAG':
+ if ($tokenNumber < 3) {
+ $context = 'INSIDE_OPEN_TAG';
+ }
+ break;
+ case 'T_DOC_COMMENT':
+ if ($context == 'INSIDE_OPEN_TAG') {
+ $this->_registerInterestingToken('topOfFile', $tokenNumber + 1, true);
+ $context = null;
+ }
+ $this->_registerInterestingToken('docblock', $tokenNumber, true);
+ break;
+
+ case 'T_INTERFACE':
+ $context = 'INSIDE_CLASS_DECLARATION';
+ $this->_interestingInformation['isInterface'] = true;
+ case 'T_CLASS':
+ $context = 'INSIDE_CLASS_DECLARATION';
+ break;
+ case 'T_ABSTRACT':
+ $this->_interestingInformation['isAbstract'] = true;
+ break;
+ case 'T_EXTENDS':
+ case 'T_IMPLEMENTS':
+ $context = 'INSIDE_CLASS_SIGNATURE';
+ break;
+ case 'T_NEW':
+ $context = 'INSIDE_NEW_ASSIGNMENT';
+ break;
+ case 'T_FUNCTION':
+ $context = 'INSIDE_FUNCTION_SIGNATURE_START';
+ break;
+ case 'T_CATCH':
+ $context = 'INSIDE_CATCH_STATEMENT';
+ break;
+ case 'string:{':
+ $context = null;
+ break;
+ case 'string:(':
+ if ($context == 'INSIDE_FUNCTION_SIGNATURE_START') {
+ $context = 'INSIDE_FUNCTION_SIGNATURE';
+ }
+ break;
+ case 'string:)':
+ if ($context == 'INSIDE_FUNCTION_SIGNATURE') {
+ $context = null;
+ }
+ break;
+ case 'T_DOUBLE_COLON':
+ if (!in_array($this->_originalTokens[$tokenNumber-1][1], array('self', 'parent', 'static'))) {
+ $this->_registerInterestingToken('consumedClass', $tokenNumber - 1);
+ }
+ break;
+ case 'T_INSTANCEOF':
+ if (!in_array($this->_originalTokens[$tokenNumber+2][1], array('self', 'parent', 'static'))) {
+ $this->_registerInterestingToken('consumedClass', $tokenNumber + 2);
+ }
+
+ case 'T_STRING':
+ switch ($context) {
+ case 'INSIDE_CLASS_DECLARATION':
+ $this->_registerInterestingToken('className', $tokenNumber, true);
+ $context = null;
+ break;
+ case 'INSIDE_CLASS_SIGNATURE':
+ $this->_registerInterestingToken('consumedClass', $tokenNumber);
+ break;
+ case 'INSIDE_NEW_ASSIGNMENT':
+ $this->_registerInterestingToken('consumedClass', $tokenNumber);
+ $context = null;
+ break;
+ case 'INSIDE_FUNCTION_SIGNATURE':
+ $safeWords = array('true', 'false', 'null', 'self', 'parent', 'static');
+ $previousToken = $this->_originalTokens[$tokenNumber -1];
+ if (!in_array($token[1], $safeWords) && (is_array($previousToken) && $previousToken[1] != '::')) {
+ $this->_registerInterestingToken('consumedClass', $tokenNumber);
+ }
+ break;
+ case 'INSIDE_CATCH_STATEMENT':
+ $this->_registerInterestingToken('consumedClass', $tokenNumber);
+ $context = null;
+ break;
+ }
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ protected function _generate()
+ {
+
+ $namespace = $this->_fileNameProcessor->getNewNamespace();
+ $className = $this->_fileNameProcessor->getNewClassName();
+
+ $prefixesRegex = implode('|', $this->_prefixes);
+
+ if (!preg_match('#^' . $prefixesRegex . '#', $this->_fileNameProcessor->getOriginalClassName())) {
+ $this->_newTokens = $this->_originalTokens;
+ return;
+ }
+
+ // determine consumed classes
+ $classCount = array();
+ if (isset($this->_interestingTokens['consumedClass'])) {
+ foreach ($this->_interestingTokens['consumedClass'] as $consumedClassToken) {
+ $origConsumedClassName = $consumedClassToken['value'];
+ $consumedClassFileNameProc = $this->_fileRegistry->findByOriginalClassName($origConsumedClassName);
+ if ($consumedClassFileNameProc) {
+ $currentConsumedClassName = $consumedClassFileNameProc->getNewFullyQualifiedName();
+ } else {
+ $currentConsumedClassName = $origConsumedClassName;
+ }
+
+ if (!isset($classCount[$currentConsumedClassName])) $classCount[$currentConsumedClassName] = 0;
+ $classCount[$currentConsumedClassName]++;
+
+ }
+ }
+
+ // compute uses
+ if ($classCount) {
+
+ $uses['declarations'] = $uses['translations'] = $uses = array();
+
+ foreach ($classCount as $consumedClassName => $numberOfOccurances) {
+ if ($numberOfOccurances == 1) continue;
+ if ((strpos($consumedClassName, '\\') !== false) && (strpos($consumedClassName, $namespace) !== 0)) {
+ $consumedClassFileNameProc = $this->_fileRegistry->findByNewFullyQualifiedName($consumedClassName);
+ $uses['declarations'][] = $ccn = $consumedClassFileNameProc->getNewNamespace();
+ $uses['translations'][$consumedClassName] = substr($ccn, strrpos($ccn, '\\')+1) . '\\'
+ . str_replace($ccn . '\\', '', $consumedClassFileNameProc->getNewFullyQualifiedName());
+ }
+ }
+ }
+
+ foreach ($this->_originalTokens as $tokenNumber => $token) {
+
+ if (!array_key_exists($tokenNumber, $this->_interestingTokenIndex)) {
+ $this->_newTokens[] = $token;
+ continue;
+ }
+
+ // This token is interesting for some reason
+ $interestingReasons = $this->_interestingTokenIndex[$tokenNumber];
+
+ foreach ($interestingReasons as $interestingReason) {
+
+ switch ($interestingReason) {
+ case 'topOfFile':
+ $content = 'namespace ' . $namespace . ';' . "\n";
+ if (isset($uses['declarations']) && $uses['declarations']) {
+ foreach ($uses['declarations'] as $useDeclaration) {
+ $content .= 'use ' . $useDeclaration . ';' . "\n";
+ }
+ }
+ $this->_newTokens[] = "\n\n/**\n * @namespace\n */\n" . $content . "\n";
+ break;
+ case 'docblock':
+ if ($this->_canTokenizeDocblocks) {
+ $docblockProc = new DocblockContentProcessor($token[1], $this->_prefixes, $this->_fileRegistry);
+ $this->_newTokens[] = $docblockProc->getContents();
+ } else {
+ $this->_newTokens[] = $token[1];
+ }
+ break;
+ case 'className':
+ $this->_newTokens[] = $className;
+ break;
+ case 'consumedClass':
+ $origConsumedClassName = $token[1];
+ $fileNameProc = $this->_fileRegistry->findByOriginalClassName($origConsumedClassName);
+ if ($fileNameProc) {
+ $newConsumedClass = $fileNameProc->getNewFullyQualifiedName();
+ if (strpos($newConsumedClass, $namespace) === 0) {
+ $newConsumedClass = substr($newConsumedClass, strlen($namespace)+1);
+ } else {
+ $newConsumedClass = '\\' . $newConsumedClass;
+ }
+ } else {
+ $newConsumedClass = '\\' . str_replace('_', '\\', $token[1]);
+ }
+
+ if (isset($uses['translations']) && $uses['translations']) {
+ $translationSearchClass = ltrim($newConsumedClass, '\\');
+ if (array_key_exists($translationSearchClass, $uses['translations'])) {
+ $newConsumedClass = $uses['translations'][$translationSearchClass];
+ }
+ }
+
+ $this->_newTokens[] = $newConsumedClass;
+ break;
+ default:
+ $this->_newTokens[] = $token;
+ break;
+ }
+
+ }
+
+ }
+
+ }
+
+ protected function _registerInterestingToken($name, $tokenNumber, $isSingle = false)
+ {
+ $token = $this->_originalTokens[$tokenNumber];
+
+ if (count($token) != 3) {
+ return;
+ }
+
+ $tokenObj = new \ArrayObject(
+ array(
+ 'number' => $tokenNumber,
+ 'id' => $token[0],
+ 'value' => $token[1],
+ 'line' => $token[2],
+ 'name' => token_name($token[0])
+ ),
+ \ArrayObject::ARRAY_AS_PROPS
+ );
+
+ if ($isSingle) {
+ $this->_interestingTokens[$name] = $tokenObj;
+ } else {
+ if (!isset($this->_interestingTokens[$name])) {
+ $this->_interestingTokens[$name] = array();
+ }
+ $this->_interestingTokens[$name][] = $tokenObj;
+ }
+
+ if (!isset($this->_interestingTokenIndex[$tokenNumber])) {
+ $this->_interestingTokenIndex[$tokenNumber] = array();
+ }
+
+ $this->_interestingTokenIndex[$tokenNumber][] = $name;
+ }
+
+ public function __toString()
+ {
+ return 'File Contents for: ' . $this->_fileNameProcessor->getOriginalFilePath();
+ }
+
+
+}
102 library/PHPTools/Namespacer/FileNameProcessor.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace PHPTools\Namespacer;
+
+class FileNameProcessor
+{
+
+ protected $_libraryPath = null;
+ protected $_originalRelativeFilePath = null;
+ protected $_originalClassName = null;
+
+ protected $_newRelativeFilePath = null;
+
+ protected $_newNamespace = null;
+ protected $_newClassName = null;
+ protected $_newFullyQualifiedName = null;
+
+ public function __construct($relativeFilePath, $libraryPath)
+ {
+ $this->_originalRelativeFilePath = $relativeFilePath;
+ $this->_libraryPath = $libraryPath;
+ $this->_process();
+ }
+
+ public function getOriginalFilePath()
+ {
+ return rtrim($this->_libraryPath, '/') . '/' . $this->_originalRelativeFilePath;
+ }
+
+ public function getOriginalRelativeFilePath()
+ {
+ return $this->_originalRelativeFilePath;
+ }
+
+ public function getOriginalClassName()
+ {
+ return $this->_originalClassName;
+ }
+
+ public function getLibraryPath()
+ {
+ return $this->_libraryPath;
+ }
+
+ public function getNewRelativeFilePath()
+ {
+ return $this->_newRelativeFilePath;
+ }
+
+ public function getNewFullyQualifiedName()
+ {
+ return $this->_newFullyQualifiedName;
+ }
+
+ public function getNewNamespace()
+ {
+ return $this->_newNamespace;
+ }
+
+ public function getNewClassName()
+ {
+ return $this->_newClassName;
+ }
+
+ protected function _process()
+ {
+ // change separators to underscore
+ $this->_originalClassName = str_replace(array('/', '\\'), '_', $this->_originalRelativeFilePath);
+ $this->_originalClassName = substr($this->_originalClassName, 0, -4);
+
+ $originalClassParts = explode('_', $this->_originalClassName);
+ $newClassParts = $originalClassParts;
+
+ // does this class have sub parts?
+ if (is_dir($this->_libraryPath . '/' . implode('/', $newClassParts))) {
+ $lastSegment = end($newClassParts);
+ $newClassParts[] = $lastSegment;
+ }
+
+ $this->_newNamespace = implode('\\', array_slice($newClassParts, 0, count($newClassParts)-1));
+ $this->_newClassName = end($newClassParts);
+
+ if ($this->_newClassName === 'Abstract') {
+ $this->_newClassName = 'Abstract' .
+ substr($this->_newNamespace, strrpos($this->_newNamespace, '\\') + 1);
+ } elseif ($this->_newClassName === 'Interface') {
+ $this->_newClassName = substr($this->_newNamespace, strrpos($this->_newNamespace, '\\') + 1)
+ . 'Interface';
+ }
+
+ $this->_newFullyQualifiedName = $this->_newNamespace . '\\' . $this->_newClassName;
+ $this->_newRelativeFilePath = str_replace('\\', '/', $this->_newFullyQualifiedName) . '.php';
+
+ }
+
+ public function __toString()
+ {
+ return $this->_originalClassName . ' => ' . $this->_newFullyQualifiedName;
+ }
+
+
+}
111 library/PHPTools/Namespacer/FileRegistry.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace PHPTools\Namespacer;
+
+class FileRegistry implements \IteratorAggregate
+{
+
+ const ITERATE_NAMES = 'iterateNames';
+ const ITERATE_CONTENTS = 'iterateContents';
+
+ protected $_fileNameProcessors = array();
+ protected $_fileContentProcessors = array();
+
+ protected $_iterationType = self::ITERATE_NAMES;
+
+ protected $_fileNameByFilePathIndex = array();
+ protected $_fileNameByRelativeFilePathIndex = array();
+ protected $_fileNameByOriginalClassNameIndex = array();
+ protected $_fileContentProcessorToFileNameProcessorIndex = array();
+
+ public function registerFileNameProcessor(FileNameProcessor $fileNameProcessor)
+ {
+ $objectId = spl_object_hash($fileNameProcessor);
+ $this->_fileNameProcessors[$objectId] = $fileNameProcessor;
+
+ $this->_fileNameByOriginalFilePathIndex[$fileNameProcessor->getOriginalFilePath()] = $objectId;
+ $this->_fileNameByOriginalRelativeFilePathIndex[$fileNameProcessor->getOriginalRelativeFilePath()] = $objectId;
+ $this->_fileNameByOriginalClassNameIndex[$fileNameProcessor->getOriginalClassName()] = $objectId;
+ $this->_fileNameByNewFullyQualifiedNameIndex[$fileNameProcessor->getNewFullyQualifiedName()] = $objectId;
+
+ return $this;
+ }
+
+ public function registerFileContentProcessor(FileContentProcessor $fileContentProcessor)
+ {
+ $objectId = spl_object_hash($fileContentProcessor);
+ $this->_fileContentProcessors[$objectId] = $fileContentProcessor;
+
+ $fileNameProcessorObjectId = spl_object_hash($fileContentProcessor->getFileNameProcessor());
+ $this->_fileContentProcessorToFileNameProcessorIndex[$objectId] = $fileNameProcessorObjectId;
+ }
+
+ public function findByOriginalFilePath($originalFilePath)
+ {
+ if (array_key_exists($originalFilePath, $this->_fileNameByOriginalFilePathIndex)) {
+ $objId = $this->_fileNameByOriginalFilePathIndex[$originalFilePath];
+ if ($objId && array_key_exists($objId, $this->_fileNameProcessors)) {
+ return $this->_fileNameProcessors[$objId];
+ }
+ }
+ return false;
+ }
+
+ public function findByOriginalRelativeFilePath($originalRelativeFilePath)
+ {
+ if (array_key_exists($originalRelativeFilePath, $this->_fileNameByOriginalRelativeFilePathIndex)) {
+ $objId = $this->_fileNameByOriginalRelativeFilePathIndex[$originalRelativeFilePath];
+ if ($objId && array_key_exists($objId, $this->_fileNameProcessors)) {
+ return $this->_fileNameProcessors[$objId];
+ }
+ }
+ return false;
+ }
+
+ public function findByOriginalClassName($originalClassName)
+ {
+ if (array_key_exists($originalClassName, $this->_fileNameByOriginalClassNameIndex)) {
+ $objId = $this->_fileNameByOriginalClassNameIndex[$originalClassName];
+ if ($objId && array_key_exists($objId, $this->_fileNameProcessors)) {
+ return $this->_fileNameProcessors[$objId];
+ }
+ }
+ return false;
+ }
+
+ public function findByNewFullyQualifiedName($newFullyQualifiedName)
+ {
+ if (array_key_exists($newFullyQualifiedName, $this->_fileNameByNewFullyQualifiedNameIndex)) {
+ $objId = $this->_fileNameByNewFullyQualifiedNameIndex[$newFullyQualifiedName];
+ if ($objId && array_key_exists($objId, $this->_fileNameProcessors)) {
+ return $this->_fileNameProcessors[$objId];
+ }
+ }
+ return false;
+ }
+
+ public function getFileNameProcessorForContentProcessor(FileContentProcessor $fileContentProcessor)
+ {
+ $fcpObjectId = spl_object_hash($fileContentProcessor);
+
+ $objectId = $this->_fileContentProcessorToFileNameProcessorIndex[$fcpObjectId];
+ return $this->_fileNameProcessors[$objectId];
+ }
+
+ public function setIterationType($iterationType = self::ITERATE_NAMES)
+ {
+ $this->_iterationType = $iterationType;
+ }
+
+ public function getIterator()
+ {
+ switch ($this->_iterationType) {
+ case self::ITERATE_CONTENTS:
+ return new \ArrayIterator($this->_fileContentProcessors);
+ case self::ITERATE_NAMES:
+ default:
+ return new \ArrayIterator($this->_fileNameConverters);
+ }
+ }
+
+}
177 library/PHPTools/Namespacer/Namespacer.php
@@ -0,0 +1,177 @@
+<?php
+
+namespace PHPTools\Namespacer;
+
+class Namespacer
+{
+
+ protected $_libraryDirectory = null;
+ protected $_filePath = null;
+ protected $_directoryFilter = null;
+ protected $_outputPath = null;
+ protected $_mapPath = null;
+ protected $_prefixes = array();
+ protected $_showStatistics = false;
+ protected $_fileRegistry = null;
+
+ public function __construct($options = array())
+ {
+ if ($options) {
+ $this->setOptions($options);
+ }
+ $this->_fileRegistry = new FileRegistry();
+ }
+
+ public function setOptions(Array $options)
+ {
+ foreach ($options as $optionName => $optionValue) {
+ $this->setOption($optionName, $optionValue);
+ }
+ }
+
+ public function setOption($optionName, $optionValue = true)
+ {
+ switch ($optionName) {
+ case 'libraryDirectory':
+ $this->_libraryDirectory = realpath($optionValue);
+ if (!file_exists($this->_libraryDirectory)) {
+ throw new \InvalidArgumentException('Library directory provided does not exist (' . $this->_libraryDirectory . ')');
+ }
+ break;
+ case 'directoryFilter':
+ $this->_directoryFilter = $optionValue;
+ break;
+ case 'outputPath':
+ $this->_outputPath = $optionValue;
+ if (!file_exists(realpath($this->_outputPath))) {
+ if (!file_exists(realpath(dirname($this->_outputPath)))) {
+ throw new \InvalidArgumentException('The output path provided does not exist and cannot be created in ' . $this->_outputPath);
+ }
+ mkdir($this->_outputPath);
+ }
+ break;
+ case 'mapPath':
+ $this->_mapPath = $optionValue;
+ if (!file_exists(realpath($this->_mapPath))) {
+ if (!file_exists(realpath(dirname($this->_mapPath)))) {
+ throw new \InvalidArgumentException('The output path provided does not exist and cannot be created in ' . $this->_mapPath);
+ }
+ mkdir($this->_mapPath);
+ }
+ break;
+ case 'prefixes':
+ $this->_prefixes = explode(',', $optionValue);
+ break;
+ case 'showStatistics':
+ $this->_showStatistics = $optionValue;
+ break;
+ default:
+ throw new \InvalidArgumentException('Option ' . $optionName . ' is not supporter by ' . __CLASS__);
+ }
+ }
+
+ public function getOptions()
+ {
+ return array(
+ 'libraryDirectory' => $this->_libraryDirectory,
+ 'directoryFilter' => $this->_directoryFilter,
+ 'outputPath' => $this->_outputPath,
+ 'prefixes' => $this->_prefixes,
+ 'showStatistics' => $this->_showStatistics
+ );
+ }
+
+ public function getFileRegistry()
+ {
+ return $this->_fileRegistry;
+ }
+
+ public function convert()
+ {
+ if (isset($this->_libraryDirectory)) {
+ $rdi = $it = new \RecursiveDirectoryIterator($this->_libraryDirectory);
+
+ if (isset($this->_directoryFilter)) {
+ // use our RecursiveFilterIterator, not SPL's
+ $it = new RecursiveFilterIterator($rdi, $this->_directoryFilter);
+ }
+
+ if ($this->_mapPath) {
+ $xmlWriter = new \XMLWriter();
+ $xmlWriter->openURI($this->_mapPath . '/PHPNamespacer-MappedClasses.xml');
+ $xmlWriter->setIndent(true);
+ $xmlWriter->setIndentString(' ');
+ $xmlWriter->startDocument('1.0');
+ $xmlWriter->startElement('MappedClasses');
+ $xmlWriter->writeAttribute('libraryPath', $this->_libraryDirectory);
+ }
+
+ foreach (new \RecursiveIteratorIterator($rdi) as $realFilePath => $fileInfo) {
+ $relativeFilePath = substr($realFilePath, strlen($this->_libraryDirectory)+1);
+ $fileNameProcessor = new FileNameProcessor($relativeFilePath, $this->_libraryDirectory);
+ // add only classes that contain a matching prefix
+ if (!$this->_prefixes || preg_match('#^' . implode('|', $this->_prefixes) . '#', $fileNameProcessor->getOriginalClassName())) {
+ $this->_fileRegistry->registerFileNameProcessor($fileNameProcessor);
+ if (isset($xmlWriter)) {
+ $xmlWriter->startElement('MappedClass');
+ $xmlWriter->writeElement('originalRelativeFilePath', $fileNameProcessor->getOriginalRelativeFilePath());
+ $xmlWriter->writeElement('originalClassName', $fileNameProcessor->getOriginalClassName());
+ $xmlWriter->writeElement('newRelativeFilePath', $fileNameProcessor->getNewRelativeFilePath());
+ $xmlWriter->writeElement('newNamespace', $fileNameProcessor->getNewNamespace());
+ $xmlWriter->writeElement('newClassName', $fileNameProcessor->getNewClassName());
+ $xmlWriter->writeElement('newFullyQualifiedName', $fileNameProcessor->getNewFullyQualifiedName());
+ $xmlWriter->endElement();
+ }
+ }
+ }
+
+ foreach (new \RecursiveIteratorIterator($it) as $realFilePath => $fileinfo) {
+ if ($fileinfo->isFile()) {
+ $fileNameProc = $this->_fileRegistry->findByOriginalFilePath($realFilePath);
+ if ($fileNameProc) {
+ $fileContentProcessor = new FileContentProcessor($fileNameProc, $this->_prefixes, $this->_fileRegistry);
+ $this->_fileRegistry->registerFileContentProcessor($fileContentProcessor);
+ }
+ }
+ }
+
+ if (isset($xmlWriter)) {
+ $xmlWriter->endElement();
+ $xmlWriter->endDocument();
+ $xmlWriter->flush();
+ }
+
+ if ($this->_outputPath) {
+
+ $this->_fileRegistry->setIterationType(FileRegistry::ITERATE_CONTENTS);
+ foreach ($this->_fileRegistry as $fileContentProc) {
+ $fileNameProc = $this->_fileRegistry->getFileNameProcessorForContentProcessor($fileContentProc);
+
+ $base = dirname($fileNameProc->getNewRelativeFilePath());
+ if (!file_exists($this->_outputPath . '/' . $base)) {
+ mkdir($this->_outputPath . '/' . $base, 0777, true);
+ }
+
+ file_put_contents($this->_outputPath . '/' . $fileNameProc->getNewRelativeFilePath(), $fileContentProc->getNewContents());
+ }
+ }
+ } else {
+ throw new \RuntimeException('Neither a filePath or a libraryDirectory was supplied to the Namespacer.');
+ }
+
+ }
+
+
+ protected function _displayInfo($infoArray)
+ {
+ echo ' Class name found: ' . $infoArray['className'] . PHP_EOL;
+ if (isset($infoArray['consumedClasses'])) {
+ echo ' Classes consumed:' . PHP_EOL;
+ foreach ($infoArray['consumedClasses'] as $consumedClass) {
+ echo ' ' . $consumedClass . PHP_EOL;
+ }
+ }
+ echo PHP_EOL;
+ }
+
+}
69 library/PHPTools/Namespacer/RecursiveFilterIterator.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace PHPTools\Namespacer;
+
+class RecursiveFilterIterator extends \RecursiveFilterIterator
+{
+
+ protected $_filter = null;
+ protected $_topDirectory = null;
+
+ /**
+ * constructor
+ *
+ * @param RecursiveIterator $iterator
+ * @param string $filter
+ */
+ public function __construct(\RecursiveIterator $iterator, $filter, $topDirectory = null)
+ {
+ $this->_filter = $filter;
+ if ($topDirectory == null) {
+ $iterator->rewind();
+ $this->_topDirectory = (string) $iterator->current()->getPath();
+ } else {
+ $this->_topDirectory = $topDirectory;
+ }
+ parent::__construct($iterator);
+ }
+
+
+ public function accept()
+ {
+ if ($this->isDot()) {
+ return false;
+ }
+
+ if ($this->isDir()) {
+ return true;
+ }
+
+ $relativeFileName = substr($this->current()->getRealPath(), strlen($this->_topDirectory)+1);
+ if (preg_match('#^' . preg_quote($this->_filter) . '#', $relativeFileName)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * getChildren() - overridden from RecursiveFilterIterator to allow the persistence of
+ * the $_denyDirectoryPattern and the $_acceptFilePattern when sub iterators of this filter
+ * are needed to be created.
+ *
+ * @return Zend_Tool_Framework_Loader_IncludePathLoader_RecursiveFilterIterator
+ */
+ public function getChildren()
+ {
+ if (empty($this->ref)) {
+ $this->ref = new \ReflectionClass($this);
+ }
+
+ return $this->ref->newInstance(
+ $this->getInnerIterator()->getChildren(),
+ $this->_filter,
+ $this->_topDirectory
+ );
+ }
+
+
+}
149 library/PHPTools/SPL/SplClassLoader.php
@@ -0,0 +1,149 @@
+<?php
+/**
+ * Userland implementation for systems that do not have the SplClassLoader extension
+ * in place. See Class Docblock for more details.
+ *
+ * To be used only when \SplClassLoader is not available.
+ * Taken from http://gist.github.com/221634
+ *
+ * @author Ralph Schinder <ralph.schindler@zend.com>
+ */
+
+namespace PHPTools\SPL;
+
+/**
+ * SplClassLoader implementation that implements the technical interoperability
+ * standards for PHP 5.3 namespaces and class names.
+ *
+ * http://groups.google.com/group/php-standards/web/final-proposal
+ *
+ * // Example which loads classes for the Doctrine Common package in the
+ * // Doctrine\Common namespace.
+ * $classLoader = new SplClassLoader('Doctrine\Common', '/path/to/doctrine');
+ * $classLoader->register();
+ *
+ * @author Jonathan H. Wage <jonwage@gmail.com>
+ * @author Roman S. Borschel <roman@code-factory.org>
+ * @author Matthew Weier O'Phinney <matthew@zend.com>
+ * @author Kris Wallsmith <kris.wallsmith@gmail.com>
+ * @author Fabien Potencier <fabien.potencier@symfony-project.org>
+ */
+class SplClassLoader
+{
+ private $_fileExtension = '.php';
+ private $_namespace;
+ private $_includePath;
+ private $_namespaceSeparator = '\\';
+
+ /**
+ * Creates a new <tt>SplClassLoader</tt> that loads classes of the
+ * specified namespace.
+ *
+ * @param string $ns The namespace to use.
+ */
+ public function __construct($ns = null, $includePath = null)
+ {
+ $this->_namespace = $ns;
+ $this->_includePath = $includePath;
+ }
+
+ /**
+ * Sets the namespace separator used by classes in the namespace of this class loader.
+ *
+ * @param string $sep The separator to use.
+ */
+ public function setNamespaceSeparator($sep)
+ {
+ $this->_namespaceSeparator = $sep;
+ }
+
+ /**
+ * Gets the namespace seperator used by classes in the namespace of this class loader.
+ *
+ * @return void
+ */
+ public function getNamespaceSeparator()
+ {
+ return $this->_namespaceSeparator;
+ }
+
+ /**
+ * Sets the base include path for all class files in the namespace of this class loader.
+ *
+ * @param string $includePath
+ */
+ public function setIncludePath($includePath)
+ {
+ $this->_includePath = $includePath;
+ }
+
+ /**
+ * Gets the base include path for all class files in the namespace of this class loader.
+ *
+ * @return string $includePath
+ */
+ public function getIncludePath()
+ {
+ return $this->_includePath;
+ }
+
+ /**
+ * Sets the file extension of class files in the namespace of this class loader.
+ *
+ * @param string $fileExtension
+ */
+ public function setFileExtension($fileExtension)
+ {
+ $this->_fileExtension = $fileExtension;
+ }
+
+ /**
+ * Gets the file extension of class files in the namespace of this class loader.
+ *
+ * @return string $fileExtension
+ */
+ public function getFileExtension()
+ {
+ return $this->_fileExtension;
+ }
+
+ /**
+ * Installs this class loader on the SPL autoload stack.
+ */
+ public function register()
+ {
+ spl_autoload_register(array($this, 'loadClass'));
+ }
+
+ /**
+ * Uninstalls this class loader from the SPL autoloader stack.
+ */
+ public function unregister()
+ {
+ spl_autoload_unregister(array($this, 'loadClass'));
+ }
+
+ /**
+ * Loads the given class or interface.
+ *
+ * @param string $className The name of the class to load.
+ * @return void
+ */
+ public function loadClass($className)
+ {
+ $className = ltrim($className, $this->_namespaceSeparator);
+ if (null === $this->_namespace || $this->_namespace.$this->_namespaceSeparator === substr($className, 0, strlen($this->_namespace.$this->_namespaceSeparator))) {
+ $fileName = '';
+ $namespace = '';
+ if (false !== ($lastNsPos = strripos($className, $this->_namespaceSeparator))) {
+ $namespace = substr($className, 0, $lastNsPos);
+ $className = substr($className, $lastNsPos + 1);
+ $fileName = str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
+ }
+ $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . $this->_fileExtension;
+
+ require ($this->_includePath !== null ? $this->_includePath . DIRECTORY_SEPARATOR : '') . $fileName;
+ }
+ }
+
+}
64 tests/PHPToolsTest/Namespacer/DocblockContentProcessorTest.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace PHPToolsTest\Namespacer;
+use PHPTools\Namespacer\DocblockContentProcessor as DocblockContentProcessor;
+
+class DocblockContentProcessorTest extends \PHPUnit_Framework_TestCase
+{
+
+ public function setup()
+ {
+ $this->_fileRegistry = new \PHPTools\Namespacer\FileRegistry;
+
+ $libraryDirectory = realpath(dirname(__FILE__) . '/_files/');
+
+ foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($libraryDirectory)) as $realFilePath => $fileInfo) {
+ $relativeFilePath = substr($realFilePath, strlen($libraryDirectory)+1);
+ $fileNameProcessor = new \PHPTools\Namespacer\FileNameProcessor($relativeFilePath, $libraryDirectory);
+ $this->_fileRegistry->registerFileNameProcessor($fileNameProcessor);
+ }
+
+ }
+
+ public function teardown()
+ {
+ $this->_fileRegistry = null;
+ }
+
+ public function testTrue()
+ {
+ $docblock = <<<EOS
+/**
+ * Some Text
+ *
+ * Foo
+ *
+ * @uses Zend_Filter
+ * @uses Zend_Filter_Alpha
+ * @param Zend_Filter \$filter
+ * @param string \$foo
+ *
+ * @return bool
+ */
+EOS;
+
+
+ $expected = <<<EOS
+/**
+ * Some Text
+ *
+ * Foo
+ *
+ * @uses \Zend\Filter\Filter
+ * @uses \Zend\Filter\Alpha
+ * @param \Zend\Filter\Filter \$filter
+ * @param string \$foo
+ *
+ * @return bool
+ */
+EOS;
+ $dcp = new DocblockContentProcessor($docblock, array('Zend'), $this->_fileRegistry);
+ $this->assertEquals($expected, $dcp->getContents());
+ }
+
+}
38 tests/PHPToolsTest/Namespacer/FileNameProcessorTest.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace PHPToolsTest\Namespacer;
+use PHPTools\Namespacer\FileNameProcessor as FileNameProcessor;
+
+class FileNameProcessorTest extends \PHPUnit_Framework_TestCase
+{
+
+ public function testOriginalValuesAreComputedAndPreservedWorks()
+ {
+ $fnc = new FileNameProcessor('Zend/Validate/Alpha.php', './foo/bar');
+
+ $this->assertEquals('./foo/bar/Zend/Validate/Alpha.php', $fnc->getOriginalFilePath(), 'Original file path not preserved.');
+ $this->assertEquals('Zend/Validate/Alpha.php', $fnc->getOriginalRelativeFilePath(), 'Original file path not preserved.');
+ $this->assertEquals('Zend_Validate_Alpha', $fnc->getOriginalClassName(), 'Original class not computed or preserved.');
+ }
+
+ public function testAbstractNamingWorks()
+ {
+ $fnc = new FileNameProcessor('Zend/Validate/Abstract.php', './foo/bar');
+
+ $this->assertEquals('Zend\Validate', $fnc->getNewNamespace(), 'New namespace not computed correctly.');
+ $this->assertEquals('AbstractValidate', $fnc->getNewClassName(), 'New class name not computed correctly.');
+ $this->assertEquals('Zend\Validate\AbstractValidate', $fnc->getNewFullyQualifiedName(), 'New FQN not computed correctly.');
+ $this->assertEquals('Zend/Validate/AbstractValidate.php', $fnc->getNewRelativeFilePath(), 'New file path not computed correctly.');
+ }
+
+ public function testClassMovedIntoNamespaceWorks()
+ {
+ $fnc = new FileNameProcessor('Zend/Filter.php', realpath(dirname(__FILE__) . '/_files/'));
+
+ $this->assertEquals('Zend\Filter', $fnc->getNewNamespace(), 'New namespace not computed correctly.');
+ $this->assertEquals('Filter', $fnc->getNewClassName(), 'New class name not computed correctly.');
+ $this->assertEquals('Zend\Filter\Filter', $fnc->getNewFullyQualifiedName(), 'New FQN not computed correctly.');
+ $this->assertEquals('Zend/Filter/Filter.php', $fnc->getNewRelativeFilePath(), 'New file path not computed correctly.');
+ }
+
+}
6 tests/PHPToolsTest/Namespacer/_files/Foo/Bar/Bar1.php
@@ -0,0 +1,6 @@
+<?php
+
+class Foo_Bar_Bar1
+{
+
+}
12 tests/PHPToolsTest/Namespacer/_files/Foo/Bar/Bar2.php
@@ -0,0 +1,12 @@
+<?php
+
+class Foo_Bar_Bar2
+{
+
+ public function doSomething()
+ {
+
+ }
+
+
+}
26 tests/PHPToolsTest/Namespacer/_files/Foo/Foo.php
@@ -0,0 +1,26 @@
+<?php
+
+
+class Foo_Foo
+{
+
+ public function getBar()
+ {
+ $x = new ArrayObject();
+ $y = new Foo_Bar_Bar1();
+ }
+
+
+
+ /**
+ *
+ * @param Foo_Bar_Bar1 $bar
+ * @return Foo_Bar_Bar2
+ */
+ public function setBar($bar)
+ {
+ $x = null;
+ return $x;
+ }
+
+}
161 tests/PHPToolsTest/Namespacer/_files/Zend/Filter.php
@@ -0,0 +1,161 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category Zend
+ * @package Zend_Filter
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @uses Zend_Filter_Exception
+ * @uses Zend_Filter_Interface
+ * @uses Zend_Loader
+ * @category Zend
+ * @package Zend_Filter
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Filter implements Zend_Filter_Interface
+{
+
+ /**
+ * Adds a filter to the chain
+ *
+ * @param Zend_Filter_Interface $filter
+ * @param string $placement
+ * @return Zend_Filter Provides a fluent interface
+ */
+ public function addFilter(Zend_Filter_Interface $filter, $placement = self::CHAIN_APPEND)
+ {
+ }
+
+ /**
+ * Add a filter to the end of the chain
+ *
+ * @param Zend_Filter_Interface $filter
+ * @return Zend_Filter Provides a fluent interface
+ */
+ public function appendFilter(Zend_Filter_Interface $filter)
+ {
+ }
+
+ /**
+ * Add a filter to the start of the chain
+ *
+ * @param Zend_Filter_Interface $filter
+ * @return Zend_Filter Provides a fluent interface
+ */
+ public function prependFilter(Zend_Filter_Interface $filter)
+ {
+ }
+
+ /**
+ * Get all the filters
+ *
+ * @return array
+ */
+ public function getFilters()
+ {
+ }
+
+ /**
+ * Returns $value filtered through each filter in the chain
+ *
+ * Filters are run in the order in which they were added to the chain (FIFO)
+ *
+ * @param mixed $value
+ * @return mixed
+ */
+ public function filter($value)
+ {
+ $valueFiltered = $value;
+ foreach ($this->_filters as $filter) {
+ $valueFiltered = $filter->filter($valueFiltered);
+ }
+ return $valueFiltered;
+ }
+
+ /** REMOVED ORIGINAL CODE, NO PURPOSE IN THIS TEST FILE */
+
+ /**
+ * @deprecated
+ * @see Zend_Filter::filterStatic()
+ *
+ * @param mixed $value
+ * @param string $classBaseName
+ * @param array $args OPTIONAL
+ * @param array|string $namespaces OPTIONAL
+ * @return mixed
+ * @throws Zend_Filter_Exception
+ */
+ public static function get($value, $classBaseName, array $args = array(), $namespaces = array())
+ {
+ trigger_error(
+ 'Zend_Filter::get() is deprecated as of 1.9.0; please update your code to utilize Zend_Filter::filterStatic()',
+ E_USER_NOTICE
+ );
+
+ return self::filterStatic($value, $classBaseName, $args, $namespaces);
+ }
+
+ /**
+ * Returns a value filtered through a specified filter class, without requiring separate
+ * instantiation of the filter object.
+ *
+ * The first argument of this method is a data input value, that you would have filtered.
+ * The second argument is a string, which corresponds to the basename of the filter class,
+ * relative to the Zend_Filter namespace. This method automatically loads the class,
+ * creates an instance, and applies the filter() method to the data input. You can also pass
+ * an array of constructor arguments, if they are needed for the filter class.
+ *
+ * @param mixed $value
+ * @param string $classBaseName
+ * @param array $args OPTIONAL
+ * @param array|string $namespaces OPTIONAL
+ * @return mixed
+ * @throws Zend_Filter_Exception
+ */
+ public static function filterStatic($value, $classBaseName, array $args = array(), $namespaces = array())
+ {
+ $namespaces = array_merge((array) $namespaces, self::$_defaultNamespaces, array('Zend_Filter'));
+ foreach ($namespaces as $namespace) {
+ $className = $namespace . '_' . ucfirst($classBaseName);
+ if (!class_exists($className, false)) {
+ try {
+ $file = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
+ if (Zend_Loader::isReadable($file)) {
+ Zend_Loader::loadClass($className);
+ } else {
+ continue;
+ }
+ } catch (Zend_Exception $ze) {
+ continue;
+ }
+ }
+
+ $class = new ReflectionClass($className);
+ if ($class->implementsInterface('Zend_Filter_Interface')) {
+ if ($class->hasMethod('__construct')) {
+ $object = $class->newInstanceArgs($args);
+ } else {
+ $object = $class->newInstance();
+ }
+ return $object->filter($value);
+ }
+ }
+ throw new Zend_Filter_Exception("Filter class not found from basename '$classBaseName'");
+ }
+}
145 tests/PHPToolsTest/Namespacer/_files/Zend/Filter/Alnum.php
@@ -0,0 +1,145 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category Zend
+ * @package Zend_Filter
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @uses Zend_Filter_Interface
+ * @uses Zend_Locale
+ * @category Zend
+ * @package Zend_Filter
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Filter_Alnum implements Zend_Filter_Interface
+{
+ /**
+ * Whether to allow white space characters; off by default
+ *
+ * @var boolean
+ * @deprecated
+ */
+ public $allowWhiteSpace;
+
+ /**
+ * Is PCRE is compiled with UTF-8 and Unicode support
+ *
+ * @var mixed
+ **/
+ protected static $_unicodeEnabled;
+
+ /**
+ * Locale in browser.
+ *
+ * @var Zend_Locale object
+ */
+ protected $_locale;
+
+ /**
+ * The Alphabet means english alphabet.
+ *
+ * @var boolean
+ */
+ protected static $_meansEnglishAlphabet;
+
+ /**
+ * Sets default option values for this instance
+ *
+ * @param boolean $allowWhiteSpace
+ * @return void
+ */
+ public function __construct($allowWhiteSpace = false)
+ {
+ if ($allowWhiteSpace instanceof Zend_Config) {
+ $allowWhiteSpace = $allowWhiteSpace->toArray();
+ } else if (is_array($allowWhiteSpace)) {
+ if (array_key_exists('allowwhitespace', $allowWhiteSpace)) {
+ $allowWhiteSpace = $allowWhiteSpace['allowwhitespace'];
+ } else {
+ $allowWhiteSpace = false;
+ }
+ }
+
+ $this->allowWhiteSpace = (boolean) $allowWhiteSpace;
+ if (null === self::$_unicodeEnabled) {
+ self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false;
+ }
+
+ if (null === self::$_meansEnglishAlphabet) {
+ $this->_locale = new Zend_Locale('auto');
+ self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(),
+ array('ja', 'ko', 'zh')
+ );
+ }
+
+ }
+
+ /**
+ * Returns the allowWhiteSpace option
+ *
+ * @return boolean
+ */
+ public function getAllowWhiteSpace()
+ {
+ return $this->allowWhiteSpace;
+ }
+
+ /**
+ * Sets the allowWhiteSpace option
+ *
+ * @param boolean $allowWhiteSpace
+ * @return Zend_Filter_Alnum Provides a fluent interface
+ */
+ public function setAllowWhiteSpace($allowWhiteSpace)
+ {
+ $this->allowWhiteSpace = (boolean) $allowWhiteSpace;
+ return $this;
+ }
+
+ /**
+ * Defined by Zend_Filter_Interface
+ *
+ * Returns the string $value, removing all but alphabetic and digit characters
+ *
+ * @param string $value
+ * @return string
+ */
+ public function filter($value)
+ {
+ $whiteSpace = $this->allowWhiteSpace ? '\s' : '';
+ if (!self::$_unicodeEnabled) {
+ // POSIX named classes are not supported, use alternative a-zA-Z0-9 match
+ $pattern = '/[^a-zA-Z0-9' . $whiteSpace . ']/';
+ } else if (self::$_meansEnglishAlphabet) {
+ //The Alphabet means english alphabet.
+ $pattern = '/[^a-zA-Z0-9' . $whiteSpace . ']/u';
+ } else {
+ //The Alphabet means each language's alphabet.
+ $pattern = '/[^\p{L}\p{N}' . $whiteSpace . ']/u';
+ }
+
+ return preg_replace($pattern, '', (string) $value);
+ }
+
+ public function setArray(ArrayObject $o)
+ {
+ $return = Foo::FOO;
+ return self::FOO;
+ }
+}
139 tests/PHPToolsTest/Namespacer/_files/Zend/Filter/Alpha.php
@@ -0,0 +1,139 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category Zend
+ * @package Zend_Filter
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id$
+ */
+
+/**
+ * @uses Zend_Filter_Interface
+ * @uses Zend_Locale
+ * @category Zend
+ * @package Zend_Filter
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_Filter_Alpha implements Zend_Filter_Interface
+{
+ /**
+ * Whether to allow white space characters; off by default
+ *
+ * @var boolean
+ * @deprecated
+ */
+ public $allowWhiteSpace;
+
+ /**
+ * Is PCRE is compiled with UTF-8 and Unicode support
+ *
+ * @var mixed
+ **/
+ protected static $_unicodeEnabled;
+
+ /**
+ * Locale in browser.
+ *
+ * @var Zend_Locale object
+ */
+ protected $_locale;
+
+ /**
+ * The Alphabet means english alphabet.
+ *
+ * @var boolean
+ */
+ protected static $_meansEnglishAlphabet;
+
+ /**
+ * Sets default option values for this instance
+ *
+ * @param boolean $allowWhiteSpace
+ * @return void
+ */
+ public function __construct($allowWhiteSpace = false)
+ {
+ if ($allowWhiteSpace instanceof Zend_Config) {
+ $allowWhiteSpace = $allowWhiteSpace->toArray();
+ } else if (is_array($allowWhiteSpace)) {
+ if (array_key_exists('allowwhitespace', $allowWhiteSpace)) {
+ $allowWhiteSpace = $allowWhiteSpace['allowwhitespace'];
+ } else {
+ $allowWhiteSpace = false;
+ }
+ }
+
+ $this->allowWhiteSpace = (boolean) $allowWhiteSpace;
+ if (null === self::$_unicodeEnabled) {
+ self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false;
+ }
+
+ if (null === self::$_meansEnglishAlphabet) {
+ $this->_locale = new Zend_Locale('auto');
+ self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(),
+ array('ja', 'ko', 'zh')
+ );
+ }
+
+ }
+
+ /**
+ * Returns the allowWhiteSpace option
+ *
+ * @return boolean
+ */
+ public function getAllowWhiteSpace()
+ {
+ return $this->allowWhiteSpace;
+ }
+
+ /**
+ * Sets the allowWhiteSpace option
+ *
+ * @param boolean $allowWhiteSpace
+ * @return Zend_Filter_Alpha Provides a fluent interface
+ */
+ public function setAllowWhiteSpace($allowWhiteSpace)
+ {
+ $this->allowWhiteSpace = (boolean) $allowWhiteSpace;
+ return $this;
+ }
+
+ /**
+ * Defined by Zend_Filter_Interface
+ *
+ * Returns the string $value, removing all but alphabetic characters
+ *
+ * @param string $value
+ * @return string
+ */
+ public function filter($value)
+ {
+ $whiteSpace = $this->allowWhiteSpace ? '\s' : '';
+ if (!self::$_unicodeEnabled) {
+ // POSIX named classes are not supported, use alternative a-zA-Z match
+ $pattern = '/[^a-zA-Z' . $whiteSpace . ']/';
+ } else if (self::$_meansEnglishAlphabet) {
+ //The Alphabet means english alphabet.
+ $pattern = '/[^a-zA-Z' . $whiteSpace . ']/u';
+ } else {
+ //The Alphabet means each language's alphabet.
+ $pattern = '/[^\p{L}' . $whiteSpace . ']/u';
+ }
+
+ return preg_replace($pattern, '', (string) $value);
+ }
+}
11 tests/bootstrap.php
@@ -0,0 +1,11 @@
+<?php
+
+$libraryDirectory = realpath(dirname(__FILE__) . '/../library/');
+
+if (!class_exists('SplClassLoader')) {
+ require_once $libraryDirectory . '/PHPTools/SPL/SplClassLoader.php';
+ $loader = new \PHPTools\SPL\SplClassLoader('PHPTools', $libraryDirectory);
+} else {
+ $loader = new \SplClassLoader('PHPTools', $libraryDirectory);
+}
+$loader->register();
7 tests/phpunit.xml
@@ -0,0 +1,7 @@
+<phpunit bootstrap="./bootstrap.php">
+<testsuites>
+ <testsuite name="My Test Suite">
+ <directory>./</directory>
+ </testsuite>
+</testsuites>
+</phpunit>
Please sign in to comment.
Something went wrong with that request. Please try again.