File indexing completed on 2024-12-29 05:28:08

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Tool
0017  * @subpackage Framework
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 /**
0024  * @see Zend_Reflection_Class
0025  */
0026 // require_once 'Zend/Reflection/Class.php';
0027 
0028 /**
0029  * @see Zend_Tool_Framework_Registry
0030  */
0031 // require_once 'Zend/Tool/Framework/Registry/EnabledInterface.php';
0032 
0033 /**
0034  * @see Zend_Tool_Framework_Action_Base
0035  */
0036 // require_once 'Zend/Tool/Framework/Action/Base.php';
0037 
0038 /**
0039  * The purpose of Zend_Tool_Framework_Provider_Signature is to derive
0040  * callable signatures from the provided provider.
0041  *
0042  * @category   Zend
0043  * @package    Zend_Tool
0044  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0045  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0046  */
0047 class Zend_Tool_Framework_Provider_Signature implements Zend_Tool_Framework_Registry_EnabledInterface
0048 {
0049 
0050     /**
0051      * @var Zend_Tool_Framework_Registry
0052      */
0053     protected $_registry = null;
0054 
0055     /**
0056      * @var Zend_Tool_Framework_Provider_Interface
0057      */
0058     protected $_provider = null;
0059 
0060     /**
0061      * @var string
0062      */
0063     protected $_name = null;
0064 
0065     /**
0066      * @var array
0067      */
0068     protected $_specialties = array();
0069 
0070     /**
0071      * @var array
0072      */
0073     protected $_actionableMethods = array();
0074 
0075     /**
0076      * @var unknown_type
0077      */
0078     protected $_actions = array();
0079 
0080     /**
0081      * @var Zend_Reflection_Class
0082      */
0083     protected $_providerReflection = null;
0084 
0085     /**
0086      * @var bool
0087      */
0088     protected $_isProcessed = false;
0089 
0090     /**
0091      * Constructor
0092      *
0093      * @param Zend_Tool_Framework_Provider_Interface $provider
0094      */
0095     public function __construct(Zend_Tool_Framework_Provider_Interface $provider)
0096     {
0097         $this->_provider = $provider;
0098         $this->_providerReflection = new Zend_Reflection_Class($provider);
0099     }
0100 
0101     /**
0102      * setRegistry()
0103      *
0104      * @param Zend_Tool_Framework_Registry_Interface $registry
0105      * @return Zend_Tool_Framework_Provider_Signature
0106      */
0107     public function setRegistry(Zend_Tool_Framework_Registry_Interface $registry)
0108     {
0109         $this->_registry = $registry;
0110         return $this;
0111     }
0112 
0113     public function process()
0114     {
0115         if ($this->_isProcessed) {
0116             return;
0117         }
0118 
0119         $this->_process();
0120     }
0121 
0122     /**
0123      * getName() of the provider
0124      *
0125      * @return unknown
0126      */
0127     public function getName()
0128     {
0129         return $this->_name;
0130     }
0131 
0132     /**
0133      * Get the provider for this signature
0134      *
0135      * @return Zend_Tool_Framework_Provider_Interface
0136      */
0137     public function getProvider()
0138     {
0139         return $this->_provider;
0140     }
0141 
0142     /**
0143      * getProviderReflection()
0144      *
0145      * @return Zend_Reflection_Class
0146      */
0147     public function getProviderReflection()
0148     {
0149         return $this->_providerReflection;
0150     }
0151 
0152     /**
0153      * getSpecialities()
0154      *
0155      * @return array
0156      */
0157     public function getSpecialties()
0158     {
0159         return $this->_specialties;
0160     }
0161 
0162     /**
0163      * getActions()
0164      *
0165      * @return array Array of Actions
0166      */
0167     public function getActions()
0168     {
0169         return $this->_actions;
0170     }
0171 
0172     /**
0173      * getActionableMethods()
0174      *
0175      * @return array
0176      */
0177     public function getActionableMethods()
0178     {
0179         return $this->_actionableMethods;
0180     }
0181 
0182     /**
0183      * getActionableMethod() - Get an actionable method by name, this will return an array of
0184      * useful information about what can be exectued on this provider
0185      *
0186      * @param string $methodName
0187      * @return array
0188      */
0189     public function getActionableMethod($methodName)
0190     {
0191         if (isset($this->_actionableMethods[$methodName])) {
0192             return $this->_actionableMethods[$methodName];
0193         }
0194 
0195         return false;
0196     }
0197 
0198     /**
0199      * getActionableMethodByActionName() - Get an actionable method by its action name, this
0200      * will return an array of useful information about what can be exectued on this provider
0201      *
0202      * @param string $actionName
0203      * @return array
0204      */
0205     public function getActionableMethodByActionName($actionName, $specialtyName = '_Global')
0206     {
0207         foreach ($this->_actionableMethods as $actionableMethod) {
0208             if ($actionName == $actionableMethod['actionName']
0209                 && $specialtyName == $actionableMethod['specialty']) {
0210                 return $actionableMethod;
0211             }
0212         }
0213 
0214         return false;
0215     }
0216 
0217     /**
0218      * _process() is called at construction time and is what will build the signature information
0219      * for determining what is actionable
0220      *
0221      */
0222     protected function _process()
0223     {
0224         $this->_isProcessed = true;
0225         $this->_processName();
0226         $this->_processSpecialties();
0227         $this->_processActionableMethods();
0228     }
0229 
0230     /**
0231      * _processName();
0232      *
0233      */
0234     protected function _processName()
0235     {
0236         if (method_exists($this->_provider, 'getName')) {
0237             $this->_name = $this->_provider->getName();
0238         }
0239 
0240         if ($this->_name == null) {
0241             $className = get_class($this->_provider);
0242             $name = $className;
0243             if (strpos($name, '_')) {
0244                 $name = substr($name, strrpos($name, '_')+1);
0245             }
0246             $name = preg_replace('#(Provider|Manifest)$#', '', $name);
0247             $this->_name = $name;
0248         }
0249     }
0250 
0251     /**
0252      * _processSpecialties() - Break out the specialty names for this provider
0253      *
0254      */
0255     protected function _processSpecialties()
0256     {
0257         $specialties = array();
0258 
0259         if ($this->_providerReflection->hasMethod('getSpecialties')) {
0260             $specialties = $this->_provider->getSpecialties();
0261             if (!is_array($specialties)) {
0262                 // require_once 'Zend/Tool/Framework/Provider/Exception.php';
0263                 throw new Zend_Tool_Framework_Provider_Exception(
0264                     'Provider ' . get_class($this->_provider) . ' must return an array for method getSpecialties().'
0265                     );
0266             }
0267         } else {
0268             $defaultProperties = $this->_providerReflection->getDefaultProperties();
0269             $specialties = (isset($defaultProperties['_specialties'])) ? $defaultProperties['_specialties'] : array();
0270             if (!is_array($specialties)) {
0271                 // require_once 'Zend/Tool/Framework/Provider/Exception.php';
0272                 throw new Zend_Tool_Framework_Provider_Exception(
0273                     'Provider ' . get_class($this->_provider) . '\'s property $_specialties must be an array.'
0274                     );
0275             }
0276         }
0277 
0278         $this->_specialties = array_merge(array('_Global'), $specialties);
0279 
0280     }
0281 
0282     /**
0283      * _processActionableMethods() - process all methods that can be called on this provider.
0284      *
0285      */
0286     protected function _processActionableMethods()
0287     {
0288 
0289         $specialtyRegex = '#(.*)(' . implode('|', $this->_specialties) . ')$#i';
0290 
0291 
0292         $methods = $this->_providerReflection->getMethods();
0293 
0294         $actionableMethods = array();
0295         foreach ($methods as $method) {
0296 
0297             $methodName = $method->getName();
0298 
0299             /**
0300              * the following will determine what methods are actually actionable
0301              * public, non-static, non-underscore prefixed, classes that dont
0302              * contain the name "
0303              */
0304             if (!$method->getDeclaringClass()->isInstantiable()
0305                 || !$method->isPublic()
0306                 || $methodName[0] == '_'
0307                 || $method->isStatic()
0308                 || in_array($methodName, array('getContextClasses', 'getName')) // other protected public methods will nee to go here
0309                 ) {
0310                 continue;
0311             }
0312 
0313             /**
0314              * check to see if the method was a required method by a Zend_Tool_* interface
0315              */
0316             foreach ($method->getDeclaringClass()->getInterfaces() as $methodDeclaringClassInterface) {
0317                 if (strpos($methodDeclaringClassInterface->getName(), 'Zend_Tool_') === 0
0318                     && $methodDeclaringClassInterface->hasMethod($methodName)) {
0319                     continue 2;
0320                 }
0321             }
0322 
0323             $actionableName = ucfirst($methodName);
0324 
0325             if (substr($actionableName, -6) == 'Action') {
0326                 $actionableName = substr($actionableName, 0, -6);
0327             }
0328 
0329             $actionableMethods[$methodName]['methodName'] = $methodName;
0330 
0331             $matches = null;
0332             if (preg_match($specialtyRegex, $actionableName, $matches)) {
0333                 $actionableMethods[$methodName]['actionName'] = $matches[1];
0334                 $actionableMethods[$methodName]['specialty'] = $matches[2];
0335             } else {
0336                 $actionableMethods[$methodName]['actionName'] = $actionableName;
0337                 $actionableMethods[$methodName]['specialty'] = '_Global';
0338             }
0339 
0340             // get the action, and create non-existent actions when they dont exist (the true part below)
0341             $action = $this->_registry->getActionRepository()->getAction($actionableMethods[$methodName]['actionName']);
0342             if ($action == null) {
0343                 $action = new Zend_Tool_Framework_Action_Base($actionableMethods[$methodName]['actionName']);
0344                 $this->_registry->getActionRepository()->addAction($action);
0345             }
0346             $actionableMethods[$methodName]['action'] = $action;
0347 
0348             if (!in_array($actionableMethods[$methodName]['action'], $this->_actions)) {
0349                 $this->_actions[] = $actionableMethods[$methodName]['action'];
0350             }
0351 
0352             $parameterInfo = array();
0353             $position = 1;
0354             foreach ($method->getParameters() as $parameter) {
0355                 $currentParam = $parameter->getName();
0356                 $parameterInfo[$currentParam]['position']    = $position++;
0357                 $parameterInfo[$currentParam]['optional']    = $parameter->isOptional();
0358                 $parameterInfo[$currentParam]['default']     = ($parameter->isOptional()) ? $parameter->getDefaultValue() : null;
0359                 $parameterInfo[$currentParam]['name']        = $currentParam;
0360                 $parameterInfo[$currentParam]['type']        = 'string';
0361                 $parameterInfo[$currentParam]['description'] = null;
0362             }
0363 
0364             $matches = null;
0365             if (($docComment = $method->getDocComment()) != '' &&
0366                 (preg_match_all('/@param\s+(\w+)+\s+(\$\S+)\s+(.*?)(?=(?:\*\s*@)|(?:\*\/))/s', $docComment, $matches)))
0367             {
0368                 for ($i=0; $i <= count($matches[0])-1; $i++) {
0369                     $currentParam = ltrim($matches[2][$i], '$');
0370 
0371                     if ($currentParam != '' && isset($parameterInfo[$currentParam])) {
0372 
0373                         $parameterInfo[$currentParam]['type'] = $matches[1][$i];
0374 
0375                         $descriptionSource = $matches[3][$i];
0376 
0377                         if ($descriptionSource != '') {
0378                             $parameterInfo[$currentParam]['description'] = trim($descriptionSource);
0379                         }
0380 
0381                     }
0382 
0383                 }
0384 
0385             }
0386 
0387             $actionableMethods[$methodName]['parameterInfo'] = $parameterInfo;
0388 
0389         }
0390 
0391         $this->_actionableMethods = $actionableMethods;
0392     }
0393 
0394 }