-
-
Save prolic/1662677 to your computer and use it in GitHub Desktop.
Zend Framework 2.0 style autoloader classmap generator task for Phing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Phing task to generate a Zend Framework style autoloader classmap file | |
* | |
* This task requires ZF 2.x to be in your include_path. You can run phing like | |
* so to enforce this: | |
* | |
* $ export PHP_COMMAND="php -d include_path=.:<path to zf library>:<path to pear>" | |
* $ phing ... | |
* | |
* Usage example in a phing build.xml file: | |
* | |
* <target name="generate-classmap"> | |
* <taskdef classname="phing.tasks.ZfClassmapTask" name="classmap" /> | |
* | |
* <!-- generate a classmap for library classes --> | |
* <classmap outputFile="${builddir}/library/autoload_classmap.php"> | |
* <dirset dir="${builddir}/library"> | |
* <include name="Zend" /> | |
* <include name="MyLibrary" /> | |
* </dirset> | |
* </classmap> | |
* | |
* <!-- generate a classmap for the MyApplication module --> | |
* <classmap outputFile="${builddir}/module/MyApplication/autoload_classmap.php"> | |
* <dirset dir="${builddir}/module" includes="MyApplication" /> | |
* </classmap> | |
* </target> | |
* | |
* This will generate a classmap file named 'library/autoload_classmap.php' in | |
* the ${builddir} directory (defined by a property), taking the "Zend" and | |
* "MyLibrary" directories under ${builddir}/library into account when searching | |
* for classes. | |
* | |
*/ | |
require_once 'phing/Task.php'; | |
class ZfClassmapTask extends Task | |
{ | |
/** | |
* the source files | |
* | |
* @var DirSet | |
*/ | |
protected $dirsets = array(); | |
/** | |
* Define output file name | |
* | |
* @var string | |
*/ | |
protected $outputFile = "autoload_classmap.php"; | |
/** | |
* Define output directory | |
* | |
* @var string | |
*/ | |
protected $outputDir = null; | |
/** | |
* Whether the build should fail, if errors occured | |
* | |
* @var boolean | |
*/ | |
protected $failonerror = false; | |
/** | |
* Nested creator, adds a set of directories | |
* | |
*/ | |
public function createDirSet() | |
{ | |
$num = array_push($this->dirsets, new DirSet()); | |
return $this->dirsets[$num - 1]; | |
} | |
/** | |
* Whether the build should fail, if an error occured. | |
* | |
* @param boolean $value | |
*/ | |
public function setFailonerror($value) | |
{ | |
$this->failonerror = $value; | |
} | |
/** | |
* Set the output file | |
* | |
* @param string $outputFile | |
*/ | |
public function setOutputFile($outputFile) | |
{ | |
$outputDir = realpath(dirname($outputFile)); | |
if (! $outputDir) { | |
throw new BuildException("Output directory '$outputDir' does not exist"); | |
} | |
$this->outputDir = $outputDir; | |
$this->outputFile = basename($outputFile); | |
} | |
/** | |
* The init method: Do init steps. | |
*/ | |
public function init() | |
{ | |
if (false === @include_once('Zend/Loader/StandardAutoloader.php')) { | |
throw new BuildException("Unable to locate Zend Framework 2.x in include path"); | |
} | |
$loader = new Zend\Loader\StandardAutoloader(); | |
$loader->register(); | |
} | |
/** | |
* The main entry point method. | |
*/ | |
public function main() | |
{ | |
if (null === $this->outputDir) { | |
$this->outputDir = getcwd(); | |
} | |
foreach ($this->dirsets as $ds) { /* @var $ds DirSet */ | |
try { | |
$dirs = $ds->getDirectoryScanner($this->project)->getIncludedDirectories(); | |
$fullPath = realpath($ds->getDir($this->project)); | |
$map = new stdClass(); | |
foreach ($dirs as $dir) { | |
$dir = $fullPath . "/" . $dir; | |
$this->log("Processing library dir: $dir"); | |
$locator = new Zend\File\ClassFileLocator($dir); | |
foreach($locator as $file) { | |
$this->addFileToMap($file, $map); | |
} | |
} | |
$this->writeMapFile($map); | |
} catch (BuildException $be) { | |
// directory doesn't exist or is not readable | |
if ($this->failonerror) { | |
throw $be; | |
} else { | |
$this->log($be->getMessage(), $this->quiet ? Project::MSG_VERBOSE : Project::MSG_WARN); | |
} | |
} | |
} | |
} | |
protected function addFileToMap(SplFileInfo $file, stdClass $map) | |
{ | |
$filename = $this->getRelativePathFromMapFile($file); | |
$namespace = empty($file->namespace) ? '' : $file->namespace . '\\'; | |
$map->{$namespace . $file->classname} = "/" . ltrim($filename, "/"); | |
} | |
protected function writeMapFile(stdClass $map) | |
{ | |
$maxKeyLength = $this->findLongestKeyLength($map) + 2; | |
$output = "<?php\n\n" . | |
"/**\n" . | |
" * Zend Framework autoloader classmap\n" . | |
" *\n" . | |
" * Auto-generated by Phing\\" . __CLASS__ . " at " . date(DATE_RFC2822) . "\n" . | |
" */\n\n" . | |
"return "; | |
$classmap = var_export((array) $map, true); | |
// Remove unnecessary double-backslashes | |
$classmap = str_replace('\\\\', '\\', $classmap); | |
// Exchange "array (" width "array(" | |
$classmap = str_replace('array (', 'array(', $classmap); | |
$replaceFunc = function ($match) use ($maxKeyLength) { | |
return sprintf(" %-{$maxKeyLength}s => __DIR__ .", $match[1]); | |
}; | |
$output .= preg_replace_callback('/^\s+([^=]+)\s+=>/m', $replaceFunc, $classmap) . ';'; | |
$outputFile = $this->outputDir . '/' . $this->outputFile; | |
if (! @file_put_contents($outputFile, $output)) { | |
throw new BuildException("Unable to write classmap to $outputFile"); | |
} | |
$this->log("Wrote autoloader classmap file to $outputFile"); | |
} | |
/** | |
* Get relative path to a class file from the classmap file path | |
* | |
* @param SplFileInfo $file | |
* @return string | |
*/ | |
protected function getRelativePathFromMapFile(SplFileInfo $file) | |
{ | |
if (strpos($file->getPath(), $this->outputDir) === 0) { | |
$relativePath = substr($file->getPath(), strlen($this->outputDir) + 1) . '/'; | |
} else { | |
$relative = array(); | |
$filePathParts = explode('/', $file->getPath()); | |
$outputDirParts = explode('/', $this->outputDir); | |
foreach ($outputDirParts as $index => $part) { | |
if (isset($filePathParts[$index]) && $filePathParts[$index] == $part) { | |
continue; | |
} | |
$relative[] = '..'; | |
} | |
foreach ($filePathParts as $index => $part ) { | |
if (isset($outputDirParts[$index]) && $outputDirParts[$index] == $part) { | |
continue; | |
} | |
$relative[] = $part; | |
} | |
$relativePath = implode('/', $relative) . '/'; | |
} | |
return $relativePath . $file->getFilename(); | |
} | |
/** | |
* Get the length of the longest key in an object | |
* | |
* @param stdClass $map | |
* @return integer | |
*/ | |
protected function findLongestKeyLength(stdClass $map) | |
{ | |
$max = 0; | |
foreach(array_keys(get_object_vars($map)) as $key) { | |
$max = max($max, strlen($key)); | |
} | |
return $max; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment