PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Tool/Framework/Provider/Signature.php

http://github.com/zendframework/zf2
PHP | 388 lines | 210 code | 39 blank | 139 comment | 21 complexity | cdc6e72e5d621abd9adad0e5e87fa762 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Tool
  17. * @subpackage Framework
  18. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. /**
  22. * @namespace
  23. */
  24. namespace Zend\Tool\Framework\Provider;
  25. use Zend\Tool\Framework\Provider,
  26. Zend\Tool\Framework\RegistryEnabled;
  27. /**
  28. * The purpose of Zend\Tool\Framework\Provider\Signature is to derive
  29. * callable signatures from the provided provider.
  30. *
  31. * @uses \Zend\Code\Reflection\ClassReflection
  32. * @uses \Zend\Tool\Framework\Action\Base
  33. * @uses \Zend\Tool\Framework\Provider\Exception
  34. * @uses \Zend\Tool\Framework\RegistryEnabled
  35. * @category Zend
  36. * @package Zend_Tool
  37. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  38. * @license http://framework.zend.com/license/new-bsd New BSD License
  39. */
  40. class Signature implements RegistryEnabled
  41. {
  42. /**
  43. * @var \Zend\Tool\Framework\Registry
  44. */
  45. protected $_registry = null;
  46. /**
  47. * @var \Zend\Tool\Framework\Provider
  48. */
  49. protected $_provider = null;
  50. /**
  51. * @var string
  52. */
  53. protected $_name = null;
  54. /**
  55. * @var array
  56. */
  57. protected $_specialties = array();
  58. /**
  59. * @var array
  60. */
  61. protected $_actionableMethods = array();
  62. /**
  63. * @var unknown_type
  64. */
  65. protected $_actions = array();
  66. /**
  67. * @var \Zend\Code\Reflection\ClassReflection
  68. */
  69. protected $_providerReflection = null;
  70. /**
  71. * @var bool
  72. */
  73. protected $_isProcessed = false;
  74. /**
  75. * Constructor
  76. *
  77. * @param \Zend\Tool\Framework\Provider $provider
  78. */
  79. public function __construct(Provider $provider)
  80. {
  81. $this->_provider = $provider;
  82. $this->_providerReflection = new \Zend\Code\Reflection\ClassReflection($provider);
  83. }
  84. /**
  85. * setRegistry()
  86. *
  87. * @param \Zend\Tool\Framework\Registry $registry
  88. * @return \Zend\Tool\Framework\Provider\Signature
  89. */
  90. public function setRegistry(\Zend\Tool\Framework\Registry $registry)
  91. {
  92. $this->_registry = $registry;
  93. return $this;
  94. }
  95. public function process()
  96. {
  97. if ($this->_isProcessed) {
  98. return;
  99. }
  100. $this->_process();
  101. }
  102. /**
  103. * getName() of the provider
  104. *
  105. * @return string
  106. */
  107. public function getName()
  108. {
  109. return $this->_name;
  110. }
  111. /**
  112. * Get the provider for this signature
  113. *
  114. * @return \Zend\Tool\Framework\Provider
  115. */
  116. public function getProvider()
  117. {
  118. return $this->_provider;
  119. }
  120. /**
  121. * getProviderReflection()
  122. *
  123. * @return \Zend\Code\Reflection\ClassReflection
  124. */
  125. public function getProviderReflection()
  126. {
  127. return $this->_providerReflection;
  128. }
  129. /**
  130. * getSpecialities()
  131. *
  132. * @return array
  133. */
  134. public function getSpecialties()
  135. {
  136. return $this->_specialties;
  137. }
  138. /**
  139. * getActions()
  140. *
  141. * @return array Array of Actions
  142. */
  143. public function getActions()
  144. {
  145. return $this->_actions;
  146. }
  147. /**
  148. * getActionableMethods()
  149. *
  150. * @return array
  151. */
  152. public function getActionableMethods()
  153. {
  154. return $this->_actionableMethods;
  155. }
  156. /**
  157. * getActionableMethod() - Get an actionable method by name, this will return an array of
  158. * useful information about what can be exectued on this provider
  159. *
  160. * @param string $methodName
  161. * @return array
  162. */
  163. public function getActionableMethod($methodName)
  164. {
  165. if (isset($this->_actionableMethods[$methodName])) {
  166. return $this->_actionableMethods[$methodName];
  167. }
  168. return false;
  169. }
  170. /**
  171. * getActionableMethodByActionName() - Get an actionable method by its action name, this
  172. * will return an array of useful information about what can be exectued on this provider
  173. *
  174. * @param string $actionName
  175. * @return array
  176. */
  177. public function getActionableMethodByActionName($actionName, $specialtyName = '_Global')
  178. {
  179. foreach ($this->_actionableMethods as $actionableMethod) {
  180. if ($actionName == $actionableMethod['actionName']
  181. && $specialtyName == $actionableMethod['specialty']) {
  182. return $actionableMethod;
  183. }
  184. }
  185. return false;
  186. }
  187. /**
  188. * _process() is called at construction time and is what will build the signature information
  189. * for determining what is actionable
  190. *
  191. */
  192. protected function _process()
  193. {
  194. $this->_isProcessed = true;
  195. $this->_processName();
  196. $this->_processSpecialties();
  197. $this->_processActionableMethods();
  198. }
  199. /**
  200. * _processName();
  201. *
  202. */
  203. protected function _processName()
  204. {
  205. if (method_exists($this->_provider, 'getName')) {
  206. $this->_name = $this->_provider->getName();
  207. }
  208. if ($this->_name == null) {
  209. $className = get_class($this->_provider);
  210. $name = $className;
  211. if (strpos($name, '_')) {
  212. $name = substr($name, strrpos($name, '_')+1);
  213. }
  214. $name = substr($className, strrpos($className, '\\')+1);
  215. $name = preg_replace('#(Provider|Manifest)$#', '', $name);
  216. $this->_name = $name;
  217. }
  218. }
  219. /**
  220. * _processSpecialties() - Break out the specialty names for this provider
  221. *
  222. */
  223. protected function _processSpecialties()
  224. {
  225. $specialties = array();
  226. if ($this->_providerReflection->hasMethod('getSpecialties')) {
  227. $specialties = $this->_provider->getSpecialties();
  228. if (!is_array($specialties)) {
  229. throw new Exception\RuntimeException(
  230. 'Provider ' . get_class($this->_provider) . ' must return an array for method getSpecialties().'
  231. );
  232. }
  233. } else {
  234. $defaultProperties = $this->_providerReflection->getDefaultProperties();
  235. $specialties = (isset($defaultProperties['_specialties'])) ? $defaultProperties['_specialties'] : array();
  236. if (!is_array($specialties)) {
  237. throw new Exception\RuntimeException(
  238. 'Provider ' . get_class($this->_provider) . '\'s property $_specialties must be an array.'
  239. );
  240. }
  241. }
  242. $this->_specialties = array_merge(array('_Global'), $specialties);
  243. }
  244. /**
  245. * _processActionableMethods() - process all methods that can be called on this provider.
  246. *
  247. */
  248. protected function _processActionableMethods()
  249. {
  250. $specialtyRegex = '#(.*)(' . implode('|', $this->_specialties) . ')$#i';
  251. $methods = $this->_providerReflection->getMethods();
  252. $actionableMethods = array();
  253. foreach ($methods as $method) {
  254. $methodName = $method->getName();
  255. /**
  256. * the following will determine what methods are actually actionable
  257. * public, non-static, non-underscore prefixed, classes that dont
  258. * contain the name "
  259. */
  260. if (!$method->getDeclaringClass()->isInstantiable()
  261. || !$method->isPublic()
  262. || $methodName[0] == '_'
  263. || $method->isStatic()
  264. || in_array($methodName, array('getContextClasses', 'getName')) // other protected public methods will nee to go here
  265. ) {
  266. continue;
  267. }
  268. /**
  269. * check to see if the method was a required method by a Zend\Tool\* interface
  270. */
  271. foreach ($method->getDeclaringClass()->getInterfaces() as $methodDeclaringClassInterface) {
  272. if (strpos($methodDeclaringClassInterface->getName(), 'Zend\\Tool\\') === 0
  273. && $methodDeclaringClassInterface->hasMethod($methodName)) {
  274. continue 2;
  275. }
  276. }
  277. $actionableName = ucfirst($methodName);
  278. if (substr($actionableName, -6) == 'Action') {
  279. $actionableName = substr($actionableName, 0, -6);
  280. }
  281. $actionableMethods[$methodName]['methodName'] = $methodName;
  282. $matches = null;
  283. if (preg_match($specialtyRegex, $actionableName, $matches)) {
  284. $actionableMethods[$methodName]['actionName'] = $matches[1];
  285. $actionableMethods[$methodName]['specialty'] = $matches[2];
  286. } else {
  287. $actionableMethods[$methodName]['actionName'] = $actionableName;
  288. $actionableMethods[$methodName]['specialty'] = '_Global';
  289. }
  290. // get the action, and create non-existent actions when they dont exist (the true part below)
  291. $action = $this->_registry->getActionRepository()->getAction($actionableMethods[$methodName]['actionName']);
  292. if ($action == null) {
  293. $action = new \Zend\Tool\Framework\Action\Base($actionableMethods[$methodName]['actionName']);
  294. $this->_registry->getActionRepository()->addAction($action);
  295. }
  296. $actionableMethods[$methodName]['action'] = $action;
  297. if (!in_array($actionableMethods[$methodName]['action'], $this->_actions)) {
  298. $this->_actions[] = $actionableMethods[$methodName]['action'];
  299. }
  300. $parameterInfo = array();
  301. $position = 1;
  302. foreach ($method->getParameters() as $parameter) {
  303. $currentParam = $parameter->getName();
  304. $parameterInfo[$currentParam]['position'] = $position++;
  305. $parameterInfo[$currentParam]['optional'] = $parameter->isOptional();
  306. $parameterInfo[$currentParam]['default'] = ($parameter->isOptional()) ? $parameter->getDefaultValue() : null;
  307. $parameterInfo[$currentParam]['name'] = $currentParam;
  308. $parameterInfo[$currentParam]['type'] = 'string';
  309. $parameterInfo[$currentParam]['description'] = null;
  310. }
  311. $matches = null;
  312. if (($docComment = $method->getDocComment()) != '' &&
  313. (preg_match_all('/@param\s+(\w+)+\s+(\$\S+)\s+(.*?)(?=(?:\*\s*@)|(?:\*\/))/s', $docComment, $matches)))
  314. {
  315. for ($i=0; $i <= count($matches[0])-1; $i++) {
  316. $currentParam = ltrim($matches[2][$i], '$');
  317. if ($currentParam != '' && isset($parameterInfo[$currentParam])) {
  318. $parameterInfo[$currentParam]['type'] = $matches[1][$i];
  319. $descriptionSource = $matches[3][$i];
  320. if ($descriptionSource != '') {
  321. $parameterInfo[$currentParam]['description'] = trim($descriptionSource);
  322. }
  323. }
  324. }
  325. }
  326. $actionableMethods[$methodName]['parameterInfo'] = $parameterInfo;
  327. }
  328. $this->_actionableMethods = $actionableMethods;
  329. }
  330. }