Changeset 492

Show
Ignore:
Timestamp:
04/13/07 13:56:11 (2 years ago)
Author:
mikey
Message:

switch to new annotation parser

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/main/php/net/stubbles/reflection/annotations/stubAnnotationFactory.php

    r432 r492  
    2525     * @var array 
    2626     */ 
    27     private static $prefixes = array('stub'); 
     27    private static $prefixes    = array('stub'); 
     28    /** 
     29     * instance of the annotation parser 
     30     * 
     31     * @var  stubAnnotationStateParser 
     32     */ 
     33    private static $parser      = null; 
     34    /** 
     35     * list of annotation data 
     36     * 
     37     * @var  array<string,array<string,array<string,array<string,string>>>> 
     38     */ 
     39    private static $annotations = array(); 
    2840 
    2941    /** 
     
    4355        } 
    4456 
    45         // Fast annotation check 
    46         $start = stripos($comment, '@' . $annotationName); 
    47         if (false === $start) { 
    48             return null; 
     57        $hash = md5($comment); 
     58        if (isset(self::$annotations[$hash]) == false) { 
     59            if (null == self::$parser) { 
     60                self::$parser = new stubAnnotationStateParser(); 
     61            } 
     62             
     63            self::$annotations[$hash] = self::$parser->parse($comment); 
    4964        } 
    5065 
    51         list($annotationClass,$data) = self::parseAnnotation($comment, $annotationName); 
    52         if (false === $data) { 
    53             throw new ReflectionException('Error evaluating annotation: ' . $annotationName . substr($comment, $start, $strlen)); 
     66        if (isset(self::$annotations[$hash][$annotationName]) == false) { 
     67            throw new ReflectionException('Can not find annotation ' . $annotationName); 
    5468        } 
    55  
    56         $annotationClass = self::findAnnotationClass($annotationClass); 
    57  
    58         $annotation = new $annotationClass(); 
     69         
     70        $annotationClass = self::findAnnotationClass(self::$annotations[$hash][$annotationName]['type']); 
     71        $annotation      = new $annotationClass(); 
    5972 
    6073        if (($annotation instanceof stubAnnotation) == false) { 
    6174            throw new ReflectionException('The annotation: ' . $annotationName . ' is not an instance of net.stubbles.reflection.annotations.stubAnnotation.'); 
    6275        } 
    63         $annotationType = self::findAnnotationClass($annotationName, true); 
    64         if (!is_a($annotation, $annotationType)) { 
    65             throw new ReflectionException('The annotation: ' . $annotationName . ' is not an instance of ' . $annotationType . '.'); 
     76         
     77        if (self::$annotations[$hash][$annotationName]['type'] != $annotationName) { 
     78            $annotationType = self::findAnnotationClass($annotationName, true); 
     79            if (is_a($annotation, $annotationType) == false) { 
     80                throw new ReflectionException('The annotation: ' . $annotationName . ' is not an instance of ' . $annotationType . '.'); 
     81            } 
    6682        } 
     83         
    6784        if (self::isApplicable($annotation, $target) == false) { 
    6885            throw new ReflectionException('The annotation: ' . $annotationName . ' is not applicable for the given type.'); 
    6986        } 
    70  
    71         $annotation = self::build($annotation, $data); 
     87         
     88        self::build($annotation, self::$annotations[$hash][$annotationName]['params']); 
    7289        $annotation->setAnnotationName($annotationName); 
    7390        stubAnnotationCache::put($target, $targetName, $annotationName, $annotation); 
    7491        return $annotation; 
    75     } 
    76  
    77     /** 
    78      * Helper method to parse an annotation 
    79      * 
    80      * @param string $comment 
    81      * @param string $annotationName 
    82      * @return array 
    83      * 
    84      * @todo Speed up parsing 
    85      */ 
    86     private static function parseAnnotation($comment, $annotationName) { 
    87         // remove start and end of the comment 
    88         $comment = trim(str_replace(array('/**', '*/'), '', $comment)); 
    89  
    90         $parts = explode('@', $comment); 
    91         $annoLength = strlen($annotationName); 
    92         foreach ($parts as $annotation) { 
    93             // quick compare 
    94             if (strncmp($annotation, $annotationName, $annoLength) != 0) { 
    95                 continue; 
    96             } 
    97             $params = substr($annotation, $annoLength); 
    98  
    99             // check, whether annotation needs casting 
    100             if ($params{0} === '[') { 
    101                 $end = strpos($params, ']'); 
    102                 if (false == $end) { 
    103                     throw new ReflectionException('Could not parse annotation'); 
    104                 } 
    105                  
    106                 $annotationClass = substr($params, 1, $end-1); 
    107                 $params = substr($params, $end+1); 
    108             } else { 
    109                 $annotationClass = $annotationName; 
    110             } 
    111  
    112             // check for empty annotation 
    113             $params = trim(str_replace('*', '', $params)); 
    114             if ('' === $params) { 
    115                 return array($annotationClass, array()); 
    116             } 
    117  
    118             if ('(' === $params{0}) { 
    119                 $params = substr($params, 1, strlen($params) - 2); 
    120             } 
    121  
    122             $tmpParams = explode(',', $params); 
    123             if (count($tmpParams) === 1 && false === strchr($tmpParams[0], '=')) { 
    124                 return array($annotationClass, array('value' => trim($tmpParams[0]))); 
    125             } 
    126  
    127             $params = array(); 
    128             foreach ($tmpParams as $param) { 
    129                 $param = trim($param); 
    130                 if (false === strchr($param, '=')) { 
    131                     throw new ReflectionException('Unable to parse the annotation.'); 
    132                 } 
    133  
    134                 $tmp = explode('=', $param); 
    135                 if (count($tmp) != 2) { 
    136                     throw new ReflectionException('Unable to parse the annotation.'); 
    137                 } 
    138                  
    139                 list($paramName,$paramValue) = $tmp; 
    140                 $params[trim($paramName)] = trim($paramValue); 
    141             } 
    142  
    143             return array($annotationClass, $params); 
    144         } 
    14592    } 
    14693 
     
    162109     * @param   stubAnnotation  $annotation  the annotation to build 
    163110     * @param   array           $data        data for annotation 
    164      * @return  stubAnnotation 
    165111     * @throws  ReflectionException  in case setting a data value fails 
    166112     */ 
    167113    public static function build(stubAnnotation $annotation, array $data) 
    168114    { 
    169         $refClass   = new ReflectionClass($annotation); 
     115        $refClass = new ReflectionClass($annotation); 
    170116        foreach ($data as $name => $value) { 
    171117            if ($refClass->hasMethod('set' . ucfirst($name)) == true) { 
    172                 $refMethod = $refClass->getMethod('set' . ucfirst($name)); 
    173                 if ($refMethod->isPublic() == false || $refMethod->isStatic() == true) { 
    174                     throw new ReflectionException('Annotation value for "' . $name . '" can not be set: setter with this name is static or not public.'); 
    175                 } 
    176                 $refMethod->invoke($annotation, $value); 
     118                $refClass->getMethod('set' . ucfirst($name))->invoke($annotation, $value); 
    177119            } elseif ($refClass->hasProperty($name) == true) { 
    178                 $refProperty = $refClass->getProperty($name); 
    179                 if ($refProperty->isPublic() == false || $refProperty->isStatic() == true) { 
    180                     throw new ReflectionException('Annotation value for "' . $name . '" can not be set: property with this name is static or not public.'); 
    181                 } 
    182                 $refProperty->setValue($annotation, $value); 
     120                $refClass->getProperty($name)->setValue($annotation, $value); 
    183121            } else { 
    184122                throw new ReflectionException('Annotation value for "' . $name . '" can not be set: no public setter and no public property exists with this name.'); 
    185123            } 
    186124        } 
    187         return $annotation; 
    188125    } 
    189126 
     
    209146     * Add a new annotation prefix 
    210147     * 
    211      * @param string $prefix 
     148     * @param string $prefix 
    212149     */ 
    213     public static function addAnnotationPrefix($prefix) { 
     150    public static function addAnnotationPrefix($prefix) 
     151    { 
    214152        self::$prefixes[] = $prefix; 
    215153    } 
     
    221159     * or a method that has one of the prefixes defined in $prefixes and the postfix 'Annotation'. 
    222160     * 
    223      * @param string $annotationClass 
    224      * @return string 
    225      * @see    addAnnotationPrefix() 
     161     * @param   string $annotationClass 
     162     * @return string 
     163     * @see    addAnnotationPrefix() 
    226164     */ 
    227     private static function findAnnotationClass($annotationClass, $allowInterface = false) { 
     165    private static function findAnnotationClass($annotationClass, $allowInterface = false) 
     166    { 
    228167        if (class_exists($annotationClass, false) == true) { 
    229168            return $annotationClass; 
    230169        } 
    231         if ($allowInterface && interface_exists($annotationClass, false)) { 
     170         
     171        if (true == $allowInterface && interface_exists($annotationClass, false) == true) { 
    232172            return $annotationClass; 
    233173        } 
     174         
    234175        $annotationClassname = $annotationClass  . 'Annotation'; 
    235176        foreach (self::$prefixes as $prefix) { 
    236             if (class_exists($prefix . $annotationClassname)) { 
     177            if (class_exists($prefix . $annotationClassname) == true) { 
    237178                return $prefix . $annotationClassname; 
    238179            } 
    239             if ($allowInterface && interface_exists($prefix . $annotationClassname, false)) { 
     180             
     181            if (true == $allowInterface && interface_exists($prefix . $annotationClassname, false) == true) { 
    240182                return $prefix . $annotationClassname; 
    241183            } 
    242184        } 
     185         
    243186        throw new ReflectionException('Error parsing annotation: Class ' . $annotationClass . ' does not exist'); 
    244187    } 
  • trunk/src/test/php/net/stubbles/rdbms/persistence/MockMultiplePrimaryKeyPersistable.php

    r482 r492  
    1212 * @package     stubbles 
    1313 * @subpackage  rdbms_persistence_test 
    14  * @DBTable(name=foo
     14 * @DBTable(name='foo'
    1515 */ 
    1616class MockMultiplePrimaryKeyPersistable extends stubAbstractPersistable 
     
    2727     * 
    2828     * @return  string 
    29      * @DBColumn(name=id,type=INT,size=10,isUnsigned=true,isPrimaryKey=true) 
     29     * @DBColumn(name='id', type='INT', size=10, isUnsigned=true, isPrimaryKey=true) 
    3030     */ 
    3131    public function getId() 
     
    4747     * method that has a DBColumn annotation 
    4848     * 
    49      * @DBColumn(name=id2,type=VARCHAR,size=10,isPrimaryKey=true) 
     49     * @DBColumn(name='id2', type='VARCHAR', size=10, isPrimaryKey=true) 
    5050     */ 
    5151    public function getSecondPrimaryKey() 
  • trunk/src/test/php/net/stubbles/rdbms/persistence/MockSinglePrimaryKeyPersistable.php

    r482 r492  
    1212 * @package     stubbles 
    1313 * @subpackage  rdbms_persistence_test 
    14  * @DBTable(name=foo
     14 * @DBTable(name='foo'
    1515 */ 
    1616class MockSinglePrimaryKeyPersistable extends stubAbstractPersistable 
     
    3333     * 
    3434     * @return  string 
    35      * @DBColumn(name=id,type=INT,size=10,isUnsigned=true,isPrimaryKey=true) 
     35     * @DBColumn(name='id', type='INT', size=10, isUnsigned=true, isPrimaryKey=true) 
    3636     */ 
    3737    public function getId() 
     
    5858     * method that has a DBColumn annotation 
    5959     * 
    60      * @DBColumn(name=bar,type=VARCHAR,size=10,isNullable=true,setterMethod=setBar
     60     * @DBColumn(name='bar', type='VARCHAR', size=10, isNullable=true, setterMethod='setBar'
    6161     */ 
    6262    public function withAnnotation() 
     
    7878     * method that has a DBColumn annotation 
    7979     * 
    80      * @DBColumn(name=default,type=VARCHAR,size=10,defaultValue=example,setterMethod=setDefaultValue
     80     * @DBColumn(name='default', type='VARCHAR', size=10, defaultValue='example', setterMethod='setDefaultValue'
    8181     */ 
    8282    public function withDefaultValue() 
     
    8787    /** 
    8888     * method that has a DBColumn annotation but from another table 
    89      * ,condition="`foo`.`id` = `blub`.`id`" 
     89     * , condition="`foo`.`id` = `blub`.`id`" 
    9090     * 
    91      * @DBColumn(name=baz,type=VARCHAR,size=10) 
    92      * @DBJoin(name=blub,type=INNER,conditionType=ON
     91     * @DBColumn(name='baz', type='VARCHAR', size=10) 
     92     * @DBJoin(name='blub', type='INNER', conditionType='ON'
    9393     */ 
    9494    public function otherTable() 
  • trunk/src/test/php/net/stubbles/rdbms/persistence/finder/stubDatabaseFinderTestCase.php

    r482 r492  
    1717 * This is a class not implementing the persistable interface. 
    1818 * 
    19  * @DBTable(name=bar
     19 * @DBTable(name='bar'
    2020 */ 
    2121class TestNonPersistable { } 
     
    2323 * This is a persistable that requires arguments in the constructor. 
    2424 * 
    25  * @DBTable(name=bar
     25 * @DBTable(name='bar'
    2626 */ 
    2727class MockInstanceArgsPersistable extends stubAbstractPersistable 
  • trunk/src/test/php/net/stubbles/reflection/annotations/stubAnnotationFactoryBuildTestCase.php

    r432 r492  
    88 */ 
    99stubClassLoader::load('net.stubbles.reflection.annotations.stubAnnotationFactory'); 
    10 Mock::generate('stubAnnotation'); 
    1110class stubMethodAnnotation implements stubAnnotation 
    1211{ 
     
    2625     
    2726    private function setBar2($bar) {} 
    28      
    29     public static function setBaz($baz) {} 
    30      
     27 
    3128    public function setAnnotationName($name) {} 
    3229    public function getAnnotationName() {} 
     
    5249{ 
    5350    /** 
    54      * annotation to use for tests 
    55      * 
    56      * @var  stubAnnotation 
    57      */ 
    58     protected $mockStubAnnotation; 
    59      
    60     /** 
    61      * create test environment 
    62      */ 
    63     public function setUp() 
    64     { 
    65         $this->mockStubAnnotation = new MockStubAnnotation(); 
    66     } 
    67      
    68     /** 
    69      * check that building the annotation works correct 
    70      */ 
    71     public function testBuildWithEmptyData() 
    72     { 
    73         $mockStubAnnotation = new MockStubAnnotation(); 
    74         $data   = array(); 
    75         $result = stubAnnotationFactory::build($mockStubAnnotation, $data); 
    76         $this->assertReference($result, $mockStubAnnotation); 
    77     } 
    78      
    79     /** 
    8051     * check that building the annotation works correct 
    8152     */ 
     
    8354    { 
    8455        $stubAnnotation = new stubMethodAnnotation(); 
    85         $data   = array('foo' => 'bar'); 
    86         $result = stubAnnotationFactory::build($stubAnnotation, $data); 
    87         $this->assertReference($result, $stubAnnotation); 
     56        $data           = array('foo' => 'bar'); 
     57        stubAnnotationFactory::build($stubAnnotation, $data); 
    8858        $this->assertEqual($stubAnnotation->getFoo(), 'bar'); 
    8959    } 
     
    9565    { 
    9666        $stubAnnotation = new stubMethodAnnotation(); 
    97         $data   = array('bar' => 'baz'); 
     67        $data           = array('bar' => 'baz'); 
    9868        $this->expectException('ReflectionException'); 
    99         $result = stubAnnotationFactory::build($stubAnnotation, $data); 
     69        stubAnnotationFactory::build($stubAnnotation, $data); 
    10070    } 
    10171     
     
    10676    { 
    10777        $stubAnnotation = new stubMethodAnnotation(); 
    108         $data   = array('bar2' => 'baz2'); 
     78        $data           = array('bar2' => 'baz2'); 
    10979        $this->expectException('ReflectionException'); 
    110         $result = stubAnnotationFactory::build($stubAnnotation, $data); 
     80        stubAnnotationFactory::build($stubAnnotation, $data); 
    11181    } 
    112      
    113     /** 
    114      * check that building the annotation works correct 
    115      */ 
    116     public function testBuildWithStaticMethod() 
    117     { 
    118         $stubAnnotation = new stubMethodAnnotation(); 
    119         $data   = array('baz' => 'foo'); 
    120         $this->expectException('ReflectionException'); 
    121         $result = stubAnnotationFactory::build($stubAnnotation, $data); 
    122     } 
    123      
     82 
    12483    /** 
    12584     * check that building the annotation works correct 
     
    12887    { 
    12988        $stubAnnotation = new stubPropertyAnnotation(); 
    130         $data   = array('foo' => 'bar'); 
    131         $result = stubAnnotationFactory::build($stubAnnotation, $data); 
    132         $this->assertReference($result, $stubAnnotation); 
     89        $data           = array('foo' => 'bar'); 
     90        stubAnnotationFactory::build($stubAnnotation, $data); 
    13391        $this->assertEqual($stubAnnotation->foo, 'bar'); 
    13492    } 
     
    14098    { 
    14199        $stubAnnotation = new stubPropertyAnnotation(); 
    142         $data   = array('bar' => 'baz'); 
     100        $data           = array('bar' => 'baz'); 
    143101        $this->expectException('ReflectionException'); 
    144         $result = stubAnnotationFactory::build($stubAnnotation, $data); 
     102        stubAnnotationFactory::build($stubAnnotation, $data); 
    145103    } 
    146104     
     
    151109    { 
    152110        $stubAnnotation = new stubPropertyAnnotation(); 
    153         $data   = array('bar2' => 'baz2'); 
     111        $data           = array('bar2' => 'baz2'); 
    154112        $this->expectException('ReflectionException'); 
    155         $result = stubAnnotationFactory::build($stubAnnotation, $data); 
     113        stubAnnotationFactory::build($stubAnnotation, $data); 
    156114    } 
    157      
    158     /** 
    159      * check that building the annotation works correct 
    160      */ 
    161     public function testBuildWithStaticProperty() 
    162     { 
    163         $stubAnnotation = new stubPropertyAnnotation(); 
    164         $data   = array('baz' => 'foo'); 
    165         $this->expectException('ReflectionException'); 
    166         $result = stubAnnotationFactory::build($stubAnnotation, $data); 
    167     } 
    168      
     115 
    169116    /** 
    170117     * check that building the annotation works correct 
     
    173120    { 
    174121        $stubAnnotation = new stubPropertyAnnotation(); 
    175         $data   = array('example' => 'foo'); 
     122        $data           = array('example' => 'foo'); 
    176123        $this->expectException('ReflectionException'); 
    177         $result = stubAnnotationFactory::build($stubAnnotation, $data); 
     124        stubAnnotationFactory::build($stubAnnotation, $data); 
    178125    } 
    179126} 
  • trunk/src/test/php/net/stubbles/reflection/annotations/stubAnnotationFactoryTestCase.php

    r432 r492  
    6969 * 
    7070 * @MyAnnotation( 
    71  *     foo=bar
     71 *     foo='bar'
    7272 *     argh=true, 
    73  *     veggie=cucumber 
     73 *     veggie='cucumber' 
    7474 * ) 
    7575 */ 
     
    9191     * @var  string 
    9292     */ 
    93     protected $comment = "/**\n * a test docblock\n * \n * \n * @param  string  \$foo\n * @StubAnnotation(foo = blub);\n */"; 
     93    protected $comment = "/**\n * a test docblock\n * \n * \n * @param  string  \$foo\n * @StubAnnotation(foo = 'blub');\n */"; 
    9494     
    9595    protected $commentComplex = '/** 
     
    9898 * @access public 
    9999 * @MyAnnotation( 
    100  *     foo=bar
    101  *     argh=45, veggie=tomato 
     100 *     foo="bar"
     101 *     argh=45, veggie="tomato" 
    102102 * ) 
    103103 * @AnotherAnnotation(true) 
     
    141141        $castedAnnotation = stubAnnotationFactory::create($this->commentComplex, 'CastedAnnotation', stubAnnotation::TARGET_CLASS, 'MyClass'); 
    142142        $this->assertIsA($castedAnnotation, 'AnotherAnnotation'); 
    143         $this->assertEqual('false', $castedAnnotation->value); 
     143        $this->assertFalse($castedAnnotation->value); 
    144144         
    145         $nonExistingAnnotation = stubAnnotationFactory::create($this->commentComplex, 'NonExisting', stubAnnotation::TARGET_CLASS, 'MyClass'); 
    146         $this->assertNull($nonExistingAnnotation); 
     145        $this->expectException('ReflectionException'); 
     146        stubAnnotationFactory::create($this->commentComplex, 'NonExisting', stubAnnotation::TARGET_CLASS, 'MyClass'); 
    147147    } 
    148148 
  • trunk/src/test/php/net/stubbles/xml/stubXMLSerializerTestCase.php

    r393 r492  
    2929 * Simple Test class to test the XMLSerializer 
    3030 * 
    31  * @XMLTag(tagName=foo
     31 * @XMLTag(tagName='foo'
    3232 */ 
    3333class XMLSerializerFoo { 
     
    3737     * 
    3838     * @var int 
    39      * @XMLTag(tagName=bar
     39     * @XMLTag(tagName='bar'
    4040     */ 
    4141    public $bar = 42; 
     
    4545     * 
    4646     * @var string 
    47      * @XMLAttribute(attributeName=bar
     47     * @XMLAttribute(attributeName='bar'
    4848     */ 
    4949    public $scalar = "test"; 
     
    6161 * Simple Test class to test the XMLSerializer 
    6262 * 
    63  * @XMLTag(tagName=container
     63 * @XMLTag(tagName='container'
    6464 */ 
    6565class XMLSerializerList { 
     
    6969     * 
    7070     * @var int 
    71      * @XMLTag(tagName=list,elementTagName=item
     71     * @XMLTag(tagName='list', elementTagName='item'
    7272     */ 
    7373    public $bar = array('one', 'two', 'three'); 
     
    7777 * Simple Test class to test the XMLSerializer 
    7878 * 
    79  * @XMLTag(tagName=class
     79 * @XMLTag(tagName='class'
    8080 */ 
    8181class XMLSerializerMethods { 
     
    8989     * 
    9090     * @return string 
    91      * @XMLAttribute(attributeName=method
     91     * @XMLAttribute(attributeName='method'
    9292     */ 
    9393    public function getValue() { 
     
    9999 * Simple Test class to test the XMLSerializer 
    100100 * 
    101  * @XMLTag(tagName=testObject
    102  * @XMLProperties[XMLMatcher](pattern=/^([a-zA-Z]{3})$/
     101 * @XMLTag(tagName='testObject'
     102 * @XMLProperties[XMLMatcher](pattern='/^([a-zA-Z]{3})$/'
    103103 */ 
    104104class XMLSerializerPropertyMatcher { 
     
    112112 * Simple Test class to test the XMLSerializer 
    113113 * 
    114  * @XMLTag(tagName=testObject
    115  * @XMLMethods[XMLMatcher](pattern=/^get(F.+)/
     114 * @XMLTag(tagName='testObject'
     115 * @XMLMethods[XMLMatcher](pattern='/^get(F.+)/'
    116116 */ 
    117117class XMLSerializerMethodMatcher {