فهرست منبع

ZF-6973, ZF-6962, ZF-6956, ZF-6722, ZF-6444
- Added DefaultValue class to handle property default value types
- Added meaningful fromReflection method to Zend_CodeGenerator_Php_Property class

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@16344 44c647ce-9c0f-0410-b52a-842ac1e357ba

ralph 16 سال پیش
والد
کامیت
756fcc1df9

+ 56 - 7
library/Zend/CodeGenerator/Php/Property.php

@@ -26,6 +26,11 @@
 require_once 'Zend/CodeGenerator/Php/Member/Abstract.php';
 
 /**
+ * @see Zend_CodeGenerator_Php_Property_DefaultValue
+ */
+require_once 'Zend/CodeGenerator/Php/Property/DefaultValue.php';
+
+/**
  * @category   Zend
  * @package    Zend_CodeGenerator
  * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
@@ -33,6 +38,7 @@ require_once 'Zend/CodeGenerator/Php/Member/Abstract.php';
  */
 class Zend_CodeGenerator_Php_Property extends Zend_CodeGenerator_Php_Member_Abstract 
 {
+    
     /**
      * @var bool
      */
@@ -49,8 +55,32 @@ class Zend_CodeGenerator_Php_Property extends Zend_CodeGenerator_Php_Member_Abst
      * @param Zend_Reflection_Property $reflectionProperty
      * @return Zend_CodeGenerator_Php_Property
      */
-    public static function fromReflection(Zend_Reflection_Property $reflectionProperty) {
+    public static function fromReflection(Zend_Reflection_Property $reflectionProperty)
+    {
         $property = new self();
+        
+        $property->setName($reflectionProperty->getName());
+        
+        $allDefaultProperties = $reflectionProperty->getDeclaringClass()->getDefaultProperties();
+        
+        $property->setDefaultValue($allDefaultProperties[$reflectionProperty->getName()]);
+        
+        if ($reflectionProperty->getDocComment() != '') {
+            $property->setDocblock(Zend_CodeGenerator_Php_Docblock::fromReflection($reflectionProperty->getDocComment()));
+        }
+        
+        if ($reflectionProperty->isStatic()) {
+            $property->setStatic(true);
+        }
+        
+        if ($reflectionProperty->isPrivate()) {
+            $property->setVisibility(self::VISIBILITY_PRIVATE);
+        } elseif ($reflectionProperty->isProtected()) {
+            $property->setVisibility(self::VISIBILITY_PROTECTED);
+        } else {
+            $property->setVisibility(self::VISIBILITY_PUBLIC);
+        }
+        
         $property->setSourceDirty(false);
         
         return $property;
@@ -77,23 +107,34 @@ class Zend_CodeGenerator_Php_Property extends Zend_CodeGenerator_Php_Member_Abst
     {
         return ($this->_isConst) ? true : false;
     }
-    
+
     /**
      * setDefaultValue()
      *
-     * @param string $defaultValue
+     * @param Zend_CodeGenerator_Php_Property_DefaultValue|string|array $defaultValue
      * @return Zend_CodeGenerator_Php_Property
      */
     public function setDefaultValue($defaultValue)
     {
+        // if it looks like
+        if (is_array($defaultValue) 
+            && array_key_exists('value', $defaultValue)
+            && array_key_exists('type', $defaultValue)) {
+            $defaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue($defaultValue);
+        }
+        
+        if (!($defaultValue instanceof Zend_CodeGenerator_Php_Property_DefaultValue)) {
+            $defaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue(array('value' => $defaultValue));
+        }
+        
         $this->_defaultValue = $defaultValue;
         return $this;
     }
-    
+
     /**
      * getDefaultValue()
      *
-     * @return string
+     * @return Zend_CodeGenerator_Php_Property_DefaultValue
      */
     public function getDefaultValue()
     {
@@ -110,9 +151,17 @@ class Zend_CodeGenerator_Php_Property extends Zend_CodeGenerator_Php_Member_Abst
         $name         = $this->getName();
         $defaultValue = $this->getDefaultValue();
         if ($this->isConst()) {
-            $string = '    ' . 'const ' . $name . ' = \'' . $defaultValue . '\';';
+            if ($defaultValue != null && !$defaultValue->isValidConstantType()) {
+                require_once 'Zend/CodeGenerator/Php/Exception.php';
+                throw new Zend_CodeGenerator_Php_Exception('The property ' . $this->_name . ' is said to be '
+                    . 'constant but does not have a valid constant value.');
+            }
+            $string = $this->_indentation . 'const ' . $name . ' = ' 
+                . (($defaultValue !== null) ? $defaultValue->generate() : 'null;');
         } else {
-            $string = '    ' . $this->getVisibility() . ' $' . $name . ' = ' . ((null !== $defaultValue) ? '\'' . $defaultValue . '\'' : 'null') . ';';
+            $string = $this->_indentation . $this->getVisibility() 
+                . (($this->isStatic()) ? ' static' : '') . ' $' . $name . ' = '
+                . (($defaultValue !== null) ? $defaultValue->generate() : 'null;');
         }
         return $string; 
     }

+ 314 - 0
library/Zend/CodeGenerator/Php/Property/DefaultValue.php

@@ -0,0 +1,314 @@
+<?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-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_CodeGenerator_Php_Abstract
+ */
+require_once 'Zend/CodeGenerator/Php/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_CodeGenerator
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_CodeGenerator_Php_Property_DefaultValue extends Zend_CodeGenerator_Php_Abstract
+{
+    /**#@+
+     * Constant values
+     */
+    const TYPE_AUTO     = 'auto';
+    const TYPE_BOOLEAN  = 'boolean';
+    const TYPE_BOOL     = 'bool';
+    const TYPE_NUMBER   = 'number';
+    const TYPE_INTEGER  = 'integer';
+    const TYPE_INT      = 'int';
+    const TYPE_FLOAT    = 'float';
+    const TYPE_DOUBLE   = 'double';
+    const TYPE_STRING   = 'string';
+    const TYPE_ARRAY    = 'array';
+    const TYPE_CONSTANT = 'constant';
+    const TYPE_NULL     = 'null';
+    const TYPE_OTHER    = 'other';
+    /**#@-*/
+    
+    /**
+     * @var array of reflected constants
+     */
+    protected static $_constants = array();
+    
+    /**
+     * @var mixed
+     */
+    protected $_value = null;
+    
+    /**
+     * @var string
+     */
+    protected $_type  = self::TYPE_AUTO;
+    
+    /**
+     * @var int
+     */
+    protected $_arrayDepth = 1;
+
+    /**
+     * _init()
+     *
+     * This method will prepare the constant array for this class
+     */
+    protected function _init()
+    {
+        $reflect = new ReflectionClass(get_class($this));
+        self::$_constants = $reflect->getConstants();
+        unset($reflect);
+    }
+    
+    /**
+     * isValidConstantType()
+     *
+     * @return bool
+     */
+    public function isValidConstantType()
+    {
+        if ($this->_type == self::TYPE_AUTO) {
+            $type = $this->_getAutoDeterminedType($this->_value);
+        }
+        
+        // valid types for constants
+        $scalarTypes = array(
+            self::TYPE_BOOLEAN,
+            self::TYPE_BOOL,
+            self::TYPE_NUMBER,
+            self::TYPE_INTEGER,
+            self::TYPE_INT,
+            self::TYPE_FLOAT,
+            self::TYPE_DOUBLE,
+            self::TYPE_STRING,
+            self::TYPE_CONSTANT,
+            self::TYPE_NULL
+            );
+        
+        return in_array($type, $scalarTypes);
+    }
+    
+    /**
+     * setValue()
+     *
+     * @param mixed $value
+     * @return Zend_CodeGenerator_Php_Property_DefaultValue
+     */
+    public function setValue($value)
+    {
+        $this->_value = $value;
+        return $this;
+    }
+    
+    /**
+     * getValue()
+     *
+     * @return mixed
+     */
+    public function getValue()
+    {
+        return $this->_value;
+    }
+    
+    /**
+     * setType()
+     *
+     * @param string $type
+     * @return Zend_CodeGenerator_Php_Property_DefaultValue
+     */
+    public function setType($type)
+    {
+        $this->_type = $type;
+        return $this;
+    }
+    
+    /**
+     * getType()
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->_type;
+    }
+    
+    /**
+     * setArrayDepth()
+     *
+     * @param int $arrayDepth
+     * @return Zend_CodeGenerator_Php_Property_DefaultValue
+     */
+    public function setArrayDepth($arrayDepth)
+    {
+        $this->_arrayDepth = $arrayDepth;
+        return $this;
+    }
+    
+    /**
+     * getArrayDepth()
+     *
+     * @return int
+     */
+    public function getArrayDepth()
+    {
+        return $this->_arrayDepth;
+    }
+    
+    /**
+     * _getValidatedType()
+     *
+     * @param string $type
+     * @return string
+     */
+    protected function _getValidatedType($type)
+    {
+        if (($constName = array_search($type, self::$_constants)) !== false) {
+            return $type;
+        }
+        
+        return self::TYPE_AUTO;
+    }
+    
+    /**
+     * _getAutoDeterminedType()
+     *
+     * @param mixed $value
+     * @return string
+     */
+    public function _getAutoDeterminedType($value)
+    {
+        switch (gettype($value)) {
+            case 'boolean':
+                return self::TYPE_BOOLEAN;
+            case 'integer':
+                return self::TYPE_INT;
+            case 'string':
+                return self::TYPE_STRING;
+            case 'double':
+            case 'float':
+            case 'integer':
+                return self::TYPE_NUMBER;
+            case 'array':
+                return self::TYPE_ARRAY;
+            case 'NULL':
+                return self::TYPE_NULL;
+            case 'object':
+            case 'resource':
+            case 'unknown type':
+            default:
+                return self::TYPE_OTHER;
+        }
+        
+        return self::TYPE_OTHER;
+    }
+    
+    /**
+     * generate()
+     *
+     * @return string
+     */
+    public function generate()
+    {
+        $type = $this->_type;
+        
+        if ($type != self::TYPE_AUTO) {
+            $type = $this->_getValidatedType($type);
+        }
+        
+        $value = $this->_value;
+        
+        if ($type == self::TYPE_AUTO) {
+            $type = $this->_getAutoDeterminedType($value);
+            
+            if ($type == self::TYPE_ARRAY) {
+                $rii = new RecursiveIteratorIterator(
+                    $it = new RecursiveArrayIterator($value),
+                    RecursiveIteratorIterator::SELF_FIRST
+                    );
+                foreach ($rii as $curKey => $curValue) {
+                    if (!$curValue instanceof Zend_CodeGenerator_Php_Property_DefaultValue) {
+                        $curValue = new self(array('value' => $curValue));
+                        $rii->getSubIterator()->offsetSet($curKey, $curValue);
+                    }
+                    $curValue->setArrayDepth($rii->getDepth());
+                }
+                $value = $rii->getSubIterator()->getArrayCopy();
+            }
+            
+        }
+        
+        $output = '';
+        
+        switch ($type) {
+            case self::TYPE_STRING:
+                $output .= "'" . $value . "'";
+                break;
+            case self::TYPE_NUMBER:
+            case self::TYPE_INTEGER:
+            case self::TYPE_INT:
+            case self::TYPE_FLOAT:
+            case self::TYPE_DOUBLE:
+            case self::TYPE_NULL:
+            case self::TYPE_CONSTANT:
+                $output .= $value;
+                break;
+            case self::TYPE_ARRAY:
+                $output .= 'array(';
+                $curArrayMultiblock = false;
+                if (count($value) > 1) {
+                    $curArrayMultiblock = true;
+                    $output .= PHP_EOL . str_repeat($this->_indentation, $this->_arrayDepth+1);
+                }
+                $outputParts = array();
+                $noKeyIndex = 0;
+                foreach ($value as $n => $v) {
+                    $v->setArrayDepth($this->_arrayDepth + 1);
+                    $partV = $v->generate();
+                    $partV = substr($partV, 0, strlen($partV)-1);
+                    if ($n === $noKeyIndex) {
+                        $outputParts[] = $partV;
+                        $noKeyIndex++;
+                    } else {
+                        $outputParts[] = (is_int($n) ? $n : "'" . $n . "'") . ' => ' . $partV;
+                    }
+                   
+                }
+                $output .= implode(',' . PHP_EOL . str_repeat($this->_indentation, $this->_arrayDepth+1), $outputParts);
+                if ($curArrayMultiblock == true) {
+                    $output .= PHP_EOL . str_repeat($this->_indentation, $this->_arrayDepth+1);
+                }
+                $output .= ')';
+                break;
+            case self::TYPE_OTHER:
+            default:
+                throw new Exception('I dont know this type');
+        }
+        
+        $output .= ';';
+        
+        return $output;
+    }
+}

+ 127 - 0
tests/Zend/CodeGenerator/Php/Property/DefaultValueTest.php

@@ -0,0 +1,127 @@
+<?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 UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * @see TestHelper
+ */
+require_once dirname(__FILE__) . '/../../../../TestHelper.php';
+
+require_once 'Zend/CodeGenerator/Php/Property/DefaultValue.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_CodeGenerator
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * 
+ * @group Zend_CodeGenerator_Php
+ */
+class Zend_CodeGenerator_Php_Property_DefaultValueTest extends PHPUnit_Framework_TestCase
+{
+    
+    public function testPropertyDefaultValueConstructor()
+    {
+        $propDefaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue();
+        $this->isInstanceOf($propDefaultValue, 'Zend_CodeGenerator_Php_Property_DefaultValue');
+    }
+    
+    public function testPropertyDefaultValueIsSettable()
+    {
+        $propDefaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue();
+        $propDefaultValue->setValue('foo');
+        $this->assertEquals('foo', $propDefaultValue->getValue());
+        //$this->assertEquals('\'foo\';', $propDefaultValue->generate());
+    }
+    
+    public function testPropertyDefaultValueCanHandleStrings()
+    {
+        $propDefaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue();
+        $propDefaultValue->setValue('foo');
+        $this->assertEquals('\'foo\';', $propDefaultValue->generate());
+    }
+    
+    public function testPropertyDefaultValueCanHandleArray()
+    {
+        $propDefaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue();
+        $propDefaultValue->setValue(array('foo'));
+        $this->assertEquals('array(\'foo\');', $propDefaultValue->generate());
+    }
+    
+    public function testPropertyDefaultValueCanHandleUnquotedString()
+    {
+        $propDefaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue();
+        $propDefaultValue->setValue('PHP_EOL');
+        $propDefaultValue->setType('constant');
+        $this->assertEquals('PHP_EOL;', $propDefaultValue->generate());
+        
+        $propDefaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue();
+        $propDefaultValue->setValue(5);
+        $this->assertEquals('5;', $propDefaultValue->generate());
+
+        $propDefaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue();
+        $propDefaultValue->setValue(5.25);
+        $this->assertEquals('5.25;', $propDefaultValue->generate());
+    }
+    
+    public function testPropertyDefaultValueCanHandleComplexArrayOfTypes()
+    {
+        $targetValue = array(
+            5, 
+            'one' => 1,
+            'two' => '2',
+            array(
+                'foo',
+                'bar',
+                array(
+                    'baz1',
+                    'baz2'
+                    )
+                ),
+            new Zend_CodeGenerator_Php_Property_DefaultValue(array('value' => 'PHP_EOL', 'type' => 'constant'))
+            );
+        
+        $expectedSource = <<<EOS
+array(
+        5,
+        'one' => 1,
+        'two' => '2',
+        array(
+            'foo',
+            'bar',
+            array(
+                'baz1',
+                'baz2'
+                )
+            ),
+        PHP_EOL
+        );
+EOS;
+            
+        $propDefaultValue = new Zend_CodeGenerator_Php_Property_DefaultValue();
+        $propDefaultValue->setValue($targetValue);
+        $generatedTargetSource = $propDefaultValue->generate();
+        $this->assertEquals($expectedSource, $generatedTargetSource);
+        
+    }
+    
+    
+}

+ 81 - 2
tests/Zend/CodeGenerator/Php/PropertyTest.php

@@ -26,6 +26,8 @@ require_once dirname(__FILE__) . '/../../../TestHelper.php';
 
 require_once 'Zend/CodeGenerator/Php/Property.php';
 
+require_once 'Zend/Reflection/Class.php';
+
 /**
  * @category   Zend
  * @package    Zend_CodeGenerator
@@ -38,12 +40,89 @@ require_once 'Zend/CodeGenerator/Php/Property.php';
 class Zend_CodeGenerator_Php_PropertyTest extends PHPUnit_Framework_TestCase
 {
     
-    public function testConstructor()
+    public function setup()
+    {
+        if (!class_exists('Zend_CodeGenerator_Php_TestClassWithManyProperties')) {
+            require_once dirname(__FILE__) . '/_files/TestClassWithManyProperties.php';
+        }
+    }
+    
+    public function testPropertyConstructor()
     {
         $codeGenProperty = new Zend_CodeGenerator_Php_Property();
         $this->isInstanceOf($codeGenProperty, 'Zend_CodeGenerator_Php_Property');
     }
     
+    public function testPropertyReturnsSimpleValue()
+    {
+        $codeGenProperty = new Zend_CodeGenerator_Php_Property(array('name' => 'someVal', 'defaultValue' => 'some string value'));
+        $this->assertEquals('    public $someVal = \'some string value\';', $codeGenProperty->generate());
+    }
+    
+    public function testPropertyMultilineValue()
+    {
+        $targetValue = array(
+            5, 
+            'one' => 1,
+            'two' => '2',
+            );
+        
+        $expectedSource = <<<EOS
+    public \$myFoo = array(
+        5,
+        'one' => 1,
+        'two' => '2'
+        );
+EOS;
+
+        $property = new Zend_CodeGenerator_Php_Property(array(
+            'name' => 'myFoo',
+            'defaultValue' => $targetValue
+            ));
+        
+        $this->assertEquals($expectedSource, $property->generate());
+    }
     
+    public function testPropertyCanProduceContstantModifier()
+    {
+        $codeGenProperty = new Zend_CodeGenerator_Php_Property(array('name' => 'someVal', 'defaultValue' => 'some string value', 'const' => true));
+        $this->assertEquals('    const someVal = \'some string value\';', $codeGenProperty->generate());
+    }
+    
+    public function testPropertyCanProduceStaticModifier()
+    {
+        $codeGenProperty = new Zend_CodeGenerator_Php_Property(array('name' => 'someVal', 'defaultValue' => 'some string value', 'static' => true));
+        $this->assertEquals('    public static $someVal = \'some string value\';', $codeGenProperty->generate());
+    }
+    
+    /**
+     * @group ZF-6444
+     *
+     */
+    public function testPropertyWillLoadFromReflection()
+    {
+        $reflectionClass = new Zend_Reflection_Class('Zend_CodeGenerator_Php_TestClassWithManyProperties');
+        
+        // test property 1       
+        $reflProp = $reflectionClass->getProperty('_bazProperty');
+       
+        $cgProp = Zend_CodeGenerator_Php_Property::fromReflection($reflProp);
+        
+        $this->assertEquals('_bazProperty', $cgProp->getName());
+        $this->assertEquals(array(true, false, true), $cgProp->getDefaultValue()->getValue());
+        $this->assertEquals('private', $cgProp->getVisibility());
+        
+        $reflProp = $reflectionClass->getProperty('_bazStaticProperty');
+        
+        
+        // test property 2
+        $cgProp = Zend_CodeGenerator_Php_Property::fromReflection($reflProp);
+        
+        $this->assertEquals('_bazStaticProperty', $cgProp->getName());
+        $this->assertEquals(Zend_CodeGenerator_Php_TestClassWithManyProperties::FOO, $cgProp->getDefaultValue()->getValue());
+        $this->assertTrue($cgProp->isStatic());
+        $this->assertEquals('private', $cgProp->getVisibility());
+    }
+
     
-}
+}

+ 31 - 0
tests/Zend/CodeGenerator/Php/_files/TestClassWithManyProperties.php

@@ -0,0 +1,31 @@
+<?php
+
+class Zend_CodeGenerator_Php_TestClassWithManyProperties
+{
+    
+    const FOO = 'foo';
+    
+    public static $fooStaticProperty = null;
+    
+    public $fooProperty = true;
+    
+    protected static $_barStaticProperty = 1;
+    
+    protected $_barProperty = 1.1115;
+    
+    private static $_bazStaticProperty = self::FOO;
+    
+    private $_bazProperty = array(true, false, true);
+    
+    protected $_complexType = array(
+        5,
+        'one' => 1,
+        'two' => '2',
+        array(
+            'bar',
+            'baz',
+            //PHP_EOL
+            )
+        );
+    
+}