web/Zend/CodeGenerator/Php/File.php
changeset 0 4eba9c11703f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/Zend/CodeGenerator/Php/File.php	Mon Dec 13 18:29:26 2010 +0100
@@ -0,0 +1,465 @@
+<?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_CodeGenerator
+ * @subpackage PHP
+ * @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: File.php 20096 2010-01-06 02:05:09Z bkarwin $
+ */
+
+/**
+ * @see Zend_CodeGenerator_Php_Abstract
+ */
+require_once 'Zend/CodeGenerator/Php/Abstract.php';
+
+/**
+ * @see Zend_CodeGenerator_Php_Class
+ */
+require_once 'Zend/CodeGenerator/Php/Class.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_CodeGenerator
+ * @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_CodeGenerator_Php_File extends Zend_CodeGenerator_Php_Abstract
+{
+
+    /**
+     * @var array Array of Zend_CodeGenerator_Php_File
+     */
+    protected static $_fileCodeGenerators = array();
+
+    /**#@+
+     * @var string
+     */
+    protected static $_markerDocblock = '/* Zend_CodeGenerator_Php_File-DocblockMarker */';
+    protected static $_markerRequire = '/* Zend_CodeGenerator_Php_File-RequireMarker: {?} */';
+    protected static $_markerClass = '/* Zend_CodeGenerator_Php_File-ClassMarker: {?} */';
+    /**#@-*/
+
+    /**
+     * @var string
+     */
+    protected $_filename = null;
+
+    /**
+     * @var Zend_CodeGenerator_Php_Docblock
+     */
+    protected $_docblock = null;
+
+    /**
+     * @var array
+     */
+    protected $_requiredFiles = array();
+
+    /**
+     * @var array
+     */
+    protected $_classes = array();
+
+    /**
+     * @var string
+     */
+    protected $_body = null;
+
+    public static function registerFileCodeGenerator(Zend_CodeGenerator_Php_File $fileCodeGenerator, $fileName = null)
+    {
+        if ($fileName == null) {
+            $fileName = $fileCodeGenerator->getFilename();
+        }
+
+        if ($fileName == '') {
+            require_once 'Zend/CodeGenerator/Php/Exception.php';
+            throw new Zend_CodeGenerator_Php_Exception('FileName does not exist.');
+        }
+
+        // cannot use realpath since the file might not exist, but we do need to have the index
+        // in the same DIRECTORY_SEPARATOR that realpath would use:
+        $fileName = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $fileName);
+
+        self::$_fileCodeGenerators[$fileName] = $fileCodeGenerator;
+
+    }
+
+    /**
+     * fromReflectedFilePath() - use this if you intend on generating code generation objects based on the same file.
+     * This will keep previous changes to the file in tact during the same PHP process
+     *
+     * @param string $filePath
+     * @param bool $usePreviousCodeGeneratorIfItExists
+     * @param bool $includeIfNotAlreadyIncluded
+     * @return Zend_CodeGenerator_Php_File
+     */
+    public static function fromReflectedFileName($filePath, $usePreviousCodeGeneratorIfItExists = true, $includeIfNotAlreadyIncluded = true)
+    {
+        $realpath = realpath($filePath);
+
+        if ($realpath === false) {
+            if ( ($realpath = Zend_Reflection_file::findRealpathInIncludePath($filePath)) === false) {
+                require_once 'Zend/CodeGenerator/Php/Exception.php';
+                throw new Zend_CodeGenerator_Php_Exception('No file for ' . $realpath . ' was found.');
+            }
+        }
+
+        if ($usePreviousCodeGeneratorIfItExists && isset(self::$_fileCodeGenerators[$realpath])) {
+            return self::$_fileCodeGenerators[$realpath];
+        }
+
+        if ($includeIfNotAlreadyIncluded && !in_array($realpath, get_included_files())) {
+            include $realpath;
+        }
+
+        $codeGenerator = self::fromReflection(($fileReflector = new Zend_Reflection_File($realpath)));
+
+        if (!isset(self::$_fileCodeGenerators[$fileReflector->getFileName()])) {
+            self::$_fileCodeGenerators[$fileReflector->getFileName()] = $codeGenerator;
+        }
+
+        return $codeGenerator;
+    }
+
+    /**
+     * fromReflection()
+     *
+     * @param Zend_Reflection_File $reflectionFile
+     * @return Zend_CodeGenerator_Php_File
+     */
+    public static function fromReflection(Zend_Reflection_File $reflectionFile)
+    {
+        $file = new self();
+
+        $file->setSourceContent($reflectionFile->getContents());
+        $file->setSourceDirty(false);
+
+        $body = $reflectionFile->getContents();
+
+        // @todo this whole area needs to be reworked with respect to how body lines are processed
+        foreach ($reflectionFile->getClasses() as $class) {
+            $file->setClass(Zend_CodeGenerator_Php_Class::fromReflection($class));
+            $classStartLine = $class->getStartLine(true);
+            $classEndLine = $class->getEndLine();
+
+            $bodyLines = explode("\n", $body);
+            $bodyReturn = array();
+            for ($lineNum = 1; $lineNum <= count($bodyLines); $lineNum++) {
+                if ($lineNum == $classStartLine) {
+                    $bodyReturn[] = str_replace('?', $class->getName(), self::$_markerClass);  //'/* Zend_CodeGenerator_Php_File-ClassMarker: {' . $class->getName() . '} */';
+                    $lineNum = $classEndLine;
+                } else {
+                    $bodyReturn[] = $bodyLines[$lineNum - 1]; // adjust for index -> line conversion
+                }
+            }
+            $body = implode("\n", $bodyReturn);
+            unset($bodyLines, $bodyReturn, $classStartLine, $classEndLine);
+        }
+
+        if (($reflectionFile->getDocComment() != '')) {
+            $docblock = $reflectionFile->getDocblock();
+            $file->setDocblock(Zend_CodeGenerator_Php_Docblock::fromReflection($docblock));
+
+            $bodyLines = explode("\n", $body);
+            $bodyReturn = array();
+            for ($lineNum = 1; $lineNum <= count($bodyLines); $lineNum++) {
+                if ($lineNum == $docblock->getStartLine()) {
+                    $bodyReturn[] = str_replace('?', $class->getName(), self::$_markerDocblock);  //'/* Zend_CodeGenerator_Php_File-ClassMarker: {' . $class->getName() . '} */';
+                    $lineNum = $docblock->getEndLine();
+                } else {
+                    $bodyReturn[] = $bodyLines[$lineNum - 1]; // adjust for index -> line conversion
+                }
+            }
+            $body = implode("\n", $bodyReturn);
+            unset($bodyLines, $bodyReturn, $classStartLine, $classEndLine);
+        }
+
+        $file->setBody($body);
+
+        return $file;
+    }
+
+    /**
+     * setDocblock() Set the docblock
+     *
+     * @param Zend_CodeGenerator_Php_Docblock|array|string $docblock
+     * @return Zend_CodeGenerator_Php_File
+     */
+    public function setDocblock($docblock)
+    {
+        if (is_string($docblock)) {
+            $docblock = array('shortDescription' => $docblock);
+        }
+
+        if (is_array($docblock)) {
+            $docblock = new Zend_CodeGenerator_Php_Docblock($docblock);
+        } elseif (!$docblock instanceof Zend_CodeGenerator_Php_Docblock) {
+            require_once 'Zend/CodeGenerator/Php/Exception.php';
+            throw new Zend_CodeGenerator_Php_Exception('setDocblock() is expecting either a string, array or an instance of Zend_CodeGenerator_Php_Docblock');
+        }
+
+        $this->_docblock = $docblock;
+        return $this;
+    }
+
+    /**
+     * Get docblock
+     *
+     * @return Zend_CodeGenerator_Php_Docblock
+     */
+    public function getDocblock()
+    {
+        return $this->_docblock;
+    }
+
+    /**
+     * setRequiredFiles
+     *
+     * @param array $requiredFiles
+     * @return Zend_CodeGenerator_Php_File
+     */
+    public function setRequiredFiles($requiredFiles)
+    {
+        $this->_requiredFiles = $requiredFiles;
+        return $this;
+    }
+
+    /**
+     * getRequiredFiles()
+     *
+     * @return array
+     */
+    public function getRequiredFiles()
+    {
+        return $this->_requiredFiles;
+    }
+
+    /**
+     * setClasses()
+     *
+     * @param array $classes
+     * @return Zend_CodeGenerator_Php_File
+     */
+    public function setClasses(Array $classes)
+    {
+        foreach ($classes as $class) {
+            $this->setClass($class);
+        }
+        return $this;
+    }
+
+    /**
+     * getClass()
+     *
+     * @param string $name
+     * @return Zend_CodeGenerator_Php_Class
+     */
+    public function getClass($name = null)
+    {
+        if ($name == null) {
+            reset($this->_classes);
+            return current($this->_classes);
+        }
+
+        return $this->_classes[$name];
+    }
+
+    /**
+     * setClass()
+     *
+     * @param Zend_CodeGenerator_Php_Class|array $class
+     * @return Zend_CodeGenerator_Php_File
+     */
+    public function setClass($class)
+    {
+        if (is_array($class)) {
+            $class = new Zend_CodeGenerator_Php_Class($class);
+            $className = $class->getName();
+        } elseif ($class instanceof Zend_CodeGenerator_Php_Class) {
+            $className = $class->getName();
+        } else {
+            require_once 'Zend/CodeGenerator/Php/Exception.php';
+            throw new Zend_CodeGenerator_Php_Exception('Expecting either an array or an instance of Zend_CodeGenerator_Php_Class');
+        }
+
+        // @todo check for dup here
+
+        $this->_classes[$className] = $class;
+        return $this;
+    }
+
+    /**
+     * setFilename()
+     *
+     * @param string $filename
+     * @return Zend_CodeGenerator_Php_File
+     */
+    public function setFilename($filename)
+    {
+        $this->_filename = $filename;
+        return $this;
+    }
+
+    /**
+     * getFilename()
+     *
+     * @return string
+     */
+    public function getFilename()
+    {
+        return $this->_filename;
+    }
+
+    /**
+     * getClasses()
+     *
+     * @return array Array of Zend_CodeGenerator_Php_Class
+     */
+    public function getClasses()
+    {
+        return $this->_classes;
+    }
+
+    /**
+     * setBody()
+     *
+     * @param string $body
+     * @return Zend_CodeGenerator_Php_File
+     */
+    public function setBody($body)
+    {
+        $this->_body = $body;
+        return $this;
+    }
+
+    /**
+     * getBody()
+     *
+     * @return string
+     */
+    public function getBody()
+    {
+        return $this->_body;
+    }
+
+    /**
+     * isSourceDirty()
+     *
+     * @return bool
+     */
+    public function isSourceDirty()
+    {
+        if (($docblock = $this->getDocblock()) && $docblock->isSourceDirty()) {
+            return true;
+        }
+
+        foreach ($this->_classes as $class) {
+            if ($class->isSourceDirty()) {
+                return true;
+            }
+        }
+
+        return parent::isSourceDirty();
+    }
+
+    /**
+     * generate()
+     *
+     * @return string
+     */
+    public function generate()
+    {
+        if ($this->isSourceDirty() === false) {
+            return $this->_sourceContent;
+        }
+
+        $output = '';
+
+        // start with the body (if there), or open tag
+        if (preg_match('#(?:\s*)<\?php#', $this->getBody()) == false) {
+            $output = '<?php' . self::LINE_FEED;
+        }
+
+        // if there are markers, put the body into the output
+        $body = $this->getBody();
+        if (preg_match('#/\* Zend_CodeGenerator_Php_File-(.*?)Marker:#', $body)) {
+            $output .= $body;
+            $body    = '';
+        }
+
+        // Add file docblock, if any
+        if (null !== ($docblock = $this->getDocblock())) {
+            $docblock->setIndentation('');
+            $regex = preg_quote(self::$_markerDocblock, '#');
+            if (preg_match('#'.$regex.'#', $output)) {
+                $output  = preg_replace('#'.$regex.'#', $docblock->generate(), $output, 1);
+            } else {
+                $output .= $docblock->generate() . self::LINE_FEED;
+            }
+        }
+
+        // newline
+        $output .= self::LINE_FEED;
+
+        // process required files
+        // @todo marker replacement for required files
+        $requiredFiles = $this->getRequiredFiles();
+        if (!empty($requiredFiles)) {
+            foreach ($requiredFiles as $requiredFile) {
+                $output .= 'require_once \'' . $requiredFile . '\';' . self::LINE_FEED;
+            }
+
+            $output .= self::LINE_FEED;
+        }
+
+        // process classes
+        $classes = $this->getClasses();
+        if (!empty($classes)) {
+            foreach ($classes as $class) {
+                $regex = str_replace('?', $class->getName(), self::$_markerClass);
+                $regex = preg_quote($regex, '#');
+                if (preg_match('#'.$regex.'#', $output)) {
+                    $output = preg_replace('#'.$regex.'#', $class->generate(), $output, 1);
+                } else {
+                    $output .= $class->generate() . self::LINE_FEED;
+                }
+            }
+
+        }
+
+        if (!empty($body)) {
+
+            // add an extra space betwee clsses and
+            if (!empty($classes)) {
+                $output .= self::LINE_FEED;
+            }
+
+            $output .= $body;
+        }
+
+        return $output;
+    }
+
+    public function write()
+    {
+        if ($this->_filename == '' || !is_writable(dirname($this->_filename))) {
+            require_once 'Zend/CodeGenerator/Php/Exception.php';
+            throw new Zend_CodeGenerator_Php_Exception('This code generator object is not writable.');
+        }
+        file_put_contents($this->_filename, $this->generate());
+        return $this;
+    }
+
+}