<?php 
 
/* 
 Copyright (c) 2009 hamcrest.org 
 */ 
 
/** 
 * Represents a single static factory method from a {@link Matcher} class. 
 * 
 * @todo Search method in file contents for func_get_args() to replace factoryVarArgs. 
 */ 
class FactoryMethod 
{ 
    /** 
     * @var FactoryClass 
     */ 
    private $class; 
 
    /** 
     * @var ReflectionMethod 
     */ 
    private $reflector; 
 
    /** 
     * @var array of string 
     */ 
    private $comment; 
 
    /** 
     * @var bool 
     */ 
    private $isVarArgs; 
 
    /** 
     * @var array of FactoryCall 
     */ 
    private $calls; 
 
    /** 
     * @var array FactoryParameter 
     */ 
    private $parameters; 
 
    public function __construct(FactoryClass $class, ReflectionMethod $reflector) 
    { 
        $this->class = $class; 
        $this->reflector = $reflector; 
        $this->extractCommentWithoutLeadingShashesAndStars(); 
        $this->extractFactoryNamesFromComment(); 
        $this->extractParameters(); 
    } 
 
    public function extractCommentWithoutLeadingShashesAndStars() 
    { 
        $this->comment = explode("\n", $this->reflector->getDocComment()); 
        foreach ($this->comment as &$line) { 
            $line = preg_replace('#^\s*(/\\*+|\\*+/|\\*)\s?#', '', $line); 
        } 
        $this->trimLeadingBlankLinesFromComment(); 
        $this->trimTrailingBlankLinesFromComment(); 
    } 
 
    public function trimLeadingBlankLinesFromComment() 
    { 
        while (count($this->comment) > 0) { 
            $line = array_shift($this->comment); 
            if (trim($line) != '') { 
                array_unshift($this->comment, $line); 
                break; 
            } 
        } 
    } 
 
    public function trimTrailingBlankLinesFromComment() 
    { 
        while (count($this->comment) > 0) { 
            $line = array_pop($this->comment); 
            if (trim($line) != '') { 
                array_push($this->comment, $line); 
                break; 
            } 
        } 
    } 
 
    public function extractFactoryNamesFromComment() 
    { 
        $this->calls = array(); 
        for ($i = 0; $i < count($this->comment); $i++) { 
            if ($this->extractFactoryNamesFromLine($this->comment[$i])) { 
                unset($this->comment[$i]); 
            } 
        } 
        $this->trimTrailingBlankLinesFromComment(); 
    } 
 
    public function extractFactoryNamesFromLine($line) 
    { 
        if (preg_match('/^\s*@factory(\s+(.+))?$/', $line, $match)) { 
            $this->createCalls( 
                $this->extractFactoryNamesFromAnnotation( 
                    isset($match[2]) ? trim($match[2]) : null 
                ) 
            ); 
            return true; 
        } 
        return false; 
    } 
 
    public function extractFactoryNamesFromAnnotation($value) 
    { 
        $primaryName = $this->reflector->getName(); 
        if (empty($value)) { 
            return array($primaryName); 
        } 
        preg_match_all('/(\.{3}|-|[a-zA-Z_][a-zA-Z_0-9]*)/', $value, $match); 
        $names = $match[0]; 
        if (in_array('...', $names)) { 
            $this->isVarArgs = true; 
        } 
        if (!in_array('-', $names) && !in_array($primaryName, $names)) { 
            array_unshift($names, $primaryName); 
        } 
        return $names; 
    } 
 
    public function createCalls(array $names) 
    { 
        $names = array_unique($names); 
        foreach ($names as $name) { 
            if ($name != '-' && $name != '...') { 
                $this->calls[] = new FactoryCall($this, $name); 
            } 
        } 
    } 
 
    public function extractParameters() 
    { 
        $this->parameters = array(); 
        if (!$this->isVarArgs) { 
            foreach ($this->reflector->getParameters() as $parameter) { 
                $this->parameters[] = new FactoryParameter($this, $parameter); 
            } 
        } 
    } 
 
    public function getParameterDeclarations() 
    { 
        if ($this->isVarArgs || !$this->hasParameters()) { 
            return ''; 
        } 
        $params = array(); 
        foreach ($this->parameters as /** @var $parameter FactoryParameter */ 
                 $parameter) { 
            $params[] = $parameter->getDeclaration(); 
        } 
        return implode(', ', $params); 
    } 
 
    public function getParameterInvocations() 
    { 
        if ($this->isVarArgs) { 
            return ''; 
        } 
        $params = array(); 
        foreach ($this->parameters as $parameter) { 
            $params[] = $parameter->getInvocation(); 
        } 
        return implode(', ', $params); 
    } 
 
 
    public function getClass() 
    { 
        return $this->class; 
    } 
 
    public function getClassName() 
    { 
        return $this->class->getName(); 
    } 
 
    public function getName() 
    { 
        return $this->reflector->name; 
    } 
 
    public function isFactory() 
    { 
        return count($this->calls) > 0; 
    } 
 
    public function getCalls() 
    { 
        return $this->calls; 
    } 
 
    public function acceptsVariableArguments() 
    { 
        return $this->isVarArgs; 
    } 
 
    public function hasParameters() 
    { 
        return !empty($this->parameters); 
    } 
 
    public function getParameters() 
    { 
        return $this->parameters; 
    } 
 
    public function getFullName() 
    { 
        return $this->getClassName() . '::' . $this->getName(); 
    } 
 
    public function getCommentText() 
    { 
        return implode(PHP_EOL, $this->comment); 
    } 
 
    public function getComment($indent = '') 
    { 
        $comment = $indent . '/**'; 
        foreach ($this->comment as $line) { 
            $comment .= PHP_EOL . rtrim($indent . ' * ' . $line); 
        } 
        $comment .= PHP_EOL . $indent . ' */'; 
        return $comment; 
    } 
} 
 
 |