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

/src/Includes/Decorator/DataStructure/Graph/Classes.php

https://github.com/ckdimka/core
PHP | 547 lines | 244 code | 40 blank | 263 comment | 3 complexity | c53ca4702cce66eab28b099254d4269d MD5 | raw file
  1. <?php
  2. // vim: set ts=4 sw=4 sts=4 et:
  3. /**
  4. * LiteCommerce
  5. *
  6. * NOTICE OF LICENSE
  7. *
  8. * This source file is subject to the Open Software License (OSL 3.0)
  9. * that is bundled with this package in the file LICENSE.txt.
  10. * It is also available through the world-wide-web at this URL:
  11. * http://opensource.org/licenses/osl-3.0.php
  12. * If you did not receive a copy of the license and are unable to
  13. * obtain it through the world-wide-web, please send an email
  14. * to licensing@litecommerce.com so we can send you a copy immediately.
  15. *
  16. * @category LiteCommerce
  17. * @package XLite
  18. * @subpackage Decorator
  19. * @author Creative Development LLC <info@cdev.ru>
  20. * @copyright Copyright (c) 2011 Creative Development LLC <info@cdev.ru>. All rights reserved
  21. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  22. * @link http://www.litecommerce.com/
  23. * @see ____file_see____
  24. * @since 1.0.0
  25. */
  26. namespace Includes\Decorator\DataStructure\Graph;
  27. /**
  28. * Classes
  29. *
  30. * @package XLite
  31. * @see ____class_see____
  32. * @since 1.0.0
  33. */
  34. class Classes extends \Includes\DataStructure\Graph
  35. {
  36. /**
  37. * Reflection object
  38. *
  39. * @var \ReflectionClass
  40. * @access protected
  41. * @see ____var_see____
  42. * @since 1.0.0
  43. */
  44. protected $reflection;
  45. /**
  46. * File path
  47. *
  48. * @var string
  49. * @see ____var_see____
  50. * @since 1.0.0
  51. */
  52. protected $file;
  53. /**
  54. * Flag for so called "low-level" nodes
  55. *
  56. * @var boolean
  57. * @access protected
  58. * @see ____var_see____
  59. * @since 1.0.0
  60. */
  61. protected $isLowLevelNode;
  62. /**
  63. * Flag for so called "top-level" stub nodes
  64. *
  65. * @var boolean
  66. * @access protected
  67. * @see ____var_see____
  68. * @since 1.0.0
  69. */
  70. protected $isTopLevelNode;
  71. /**
  72. * Flag to determine if node was changed (e.g. its key was modified)
  73. *
  74. * @var boolean
  75. * @access protected
  76. * @see ____var_see____
  77. * @since 1.0.0
  78. */
  79. protected $isChanged;
  80. // ------------------------------ Constructor and common getters -
  81. /**
  82. * Constructor
  83. *
  84. * @param string $key Node unique key OPTIONAL
  85. * @param string $file File name OPTIONAL
  86. *
  87. * @return void
  88. * @see ____func_see____
  89. * @since 1.0.0
  90. */
  91. public function __construct($key = self::ROOT_NODE_KEY, $file = null)
  92. {
  93. parent::__construct($key);
  94. $this->file = $file;
  95. }
  96. /**
  97. * Alias
  98. *
  99. * @return string
  100. * @see ____func_see____
  101. * @since 1.0.0
  102. */
  103. public function getClass()
  104. {
  105. return $this->prepareClassName($this->getKey());
  106. }
  107. /**
  108. * Getter for the flag
  109. *
  110. * @return boolean
  111. * @access public
  112. * @see ____func_see____
  113. * @since 1.0.0
  114. */
  115. public function isLowLevelNode()
  116. {
  117. return $this->isLowLevelNode;
  118. }
  119. /**
  120. * Getter for the flag
  121. *
  122. * @return boolean
  123. * @access public
  124. * @see ____func_see____
  125. * @since 1.0.0
  126. */
  127. public function isTopLevelNode()
  128. {
  129. return $this->isTopLevelNode;
  130. }
  131. /**
  132. * Return name of parent class
  133. *
  134. * @return string
  135. * @access public
  136. * @see ____func_see____
  137. * @since 1.0.0
  138. */
  139. public function getParentClass()
  140. {
  141. return $this->getReflection()->parentClass;
  142. }
  143. /**
  144. * Return list of class implementing interfaces
  145. *
  146. * @return array
  147. * @access public
  148. * @see ____func_see____
  149. * @since 1.0.0
  150. */
  151. public function getInterfaces()
  152. {
  153. return $this->getReflection()->interfaces;
  154. }
  155. /**
  156. * Check if class implements interface
  157. *
  158. * @param string $interface Name of interface to check
  159. *
  160. * @return boolean
  161. * @access public
  162. * @see ____func_see____
  163. * @since 1.0.0
  164. */
  165. public function isImplements($interface)
  166. {
  167. return in_array($this->prepareClassName($interface), $this->getInterfaces());
  168. }
  169. /**
  170. * Check if class decorates another one
  171. *
  172. * @return boolean
  173. * @access public
  174. * @see ____func_see____
  175. * @since 1.0.0
  176. */
  177. public function isDecorator()
  178. {
  179. return $this->isImplements('XLite\Base\IDecorator');
  180. }
  181. /**
  182. * Return name of the module where the class defined
  183. *
  184. * @return string
  185. * @access public
  186. * @see ____func_see____
  187. * @since 1.0.0
  188. */
  189. public function getModuleName()
  190. {
  191. return \Includes\Utils\ModulesManager::getModuleNameByClassName($this->getClass());
  192. }
  193. /**
  194. * Return top-level child
  195. *
  196. * @return self
  197. * @access public
  198. * @see ____func_see____
  199. * @since 1.0.0
  200. */
  201. public function getTopLevelNode()
  202. {
  203. return $this->isDecorator() && ($children = $this->getChildren()) ? reset($children)->{__FUNCTION__}() : $this;
  204. }
  205. // ------------------------------ Methods to modify graph -
  206. /**
  207. * Set node key
  208. *
  209. * @param string $key Key to set
  210. *
  211. * @return void
  212. * @access public
  213. * @see ____func_see____
  214. * @since 1.0.0
  215. */
  216. public function setKey($key)
  217. {
  218. // Preserve Reflection
  219. $this->getReflection();
  220. parent::setKey($key);
  221. // Set flag
  222. $this->isChanged = true;
  223. }
  224. /**
  225. * Mark node as "low-level"
  226. *
  227. * @return void
  228. * @access public
  229. * @see ____func_see____
  230. * @since 1.0.0
  231. */
  232. public function setLowLevelNodeFlag()
  233. {
  234. $this->isLowLevelNode = true;
  235. }
  236. /**
  237. * Mark node as "top-level"
  238. *
  239. * @return void
  240. * @access public
  241. * @see ____func_see____
  242. * @since 1.0.0
  243. */
  244. public function setTopLevelNodeFlag()
  245. {
  246. $this->isTopLevelNode = true;
  247. }
  248. // ------------------------------ Methods to get paths and source code -
  249. /**
  250. * Name of the origin class file
  251. *
  252. * @return string
  253. * @see ____func_see____
  254. * @since 1.0.0
  255. */
  256. public function getFile()
  257. {
  258. return $this->file;
  259. }
  260. /**
  261. * Transform class name into the relative path
  262. *
  263. * @return string
  264. * @access public
  265. * @see ____func_see____
  266. * @since 1.0.0
  267. */
  268. public function getPath()
  269. {
  270. return \Includes\Utils\Converter::getClassFile($this->getClass());
  271. }
  272. /**
  273. * Prepare source code of the class
  274. *
  275. * @param self $parent Parent node OPTIONAL
  276. *
  277. * @return string
  278. * @access public
  279. * @see ____func_see____
  280. * @since 1.0.0
  281. */
  282. public function getSource(self $parent = null)
  283. {
  284. return $this->isChanged || $this->isDecorator()
  285. ? $this->getActualSource($parent)
  286. : ($this->isTopLevelNode() ? $this->getEmptySource($parent) : $this->getRegularSource());
  287. }
  288. /**
  289. * Actualize and return source code for node
  290. *
  291. * @param self $parent Parent node OPTIONAL
  292. *
  293. * @return string
  294. * @access protected
  295. * @see ____func_see____
  296. * @since 1.0.0
  297. */
  298. protected function getActualSource(self $parent = null)
  299. {
  300. $this->getReflection()->docComment = $this->isLowLevelNode()
  301. ? '/**' . PHP_EOL . ' * MOVED' . PHP_EOL . ' */'
  302. : null;
  303. return \Includes\Decorator\Utils\Tokenizer::getSourceCode(
  304. $this->getFile(),
  305. $this->getActualNamespace(),
  306. $this->getClassBaseName(),
  307. $this->getActualParentClassName($parent),
  308. $this->getReflection()->docComment
  309. );
  310. }
  311. /**
  312. * Return source code for "top-level" decorator node
  313. *
  314. * @param self $parent Parent node OPTIONAL
  315. *
  316. * @return string
  317. * @access protected
  318. * @see ____func_see____
  319. * @since 1.0.0
  320. */
  321. protected function getEmptySource(self $parent = null)
  322. {
  323. return '<?php' . PHP_EOL . PHP_EOL
  324. . (($namespace = $this->getActualNamespace()) ? ('namespace ' . $namespace . ';' . PHP_EOL . PHP_EOL) : '')
  325. . (($comment = $this->getReflection()->docComment) ? ($comment . PHP_EOL) : '')
  326. . ($this->getReflection()->isFinal ? 'final ' : '')
  327. . ($this->getReflection()->isAbstract ? 'abstract ' : '')
  328. . ($this->getReflection()->isInterface ? 'interface' : 'class') . ' ' . $this->getClassBaseName()
  329. . (($class = $this->getActualParentClassName($parent)) ? (' extends ' . $class) : '')
  330. . (($interfaces = $this->getInterfaces()) ? (' implements \\' . implode(', \\', $interfaces)) : '')
  331. . PHP_EOL . '{' . PHP_EOL . '}';
  332. }
  333. /**
  334. * Return source code for regular node
  335. *
  336. * @return string
  337. * @access protected
  338. * @see ____func_see____
  339. * @since 1.0.0
  340. */
  341. protected function getRegularSource()
  342. {
  343. return \Includes\Utils\FileManager::read($this->getFile());
  344. }
  345. /**
  346. * Return actual parent class name
  347. *
  348. * @param self $parent Node to get class name
  349. *
  350. * @return string
  351. * @access protected
  352. * @see ____func_see____
  353. * @since 1.0.0
  354. */
  355. protected function getActualParentClassName(self $parent = null)
  356. {
  357. return ($parent && ($class = $parent->getClass())) ? ('\\' . $this->prepareClassName($class)) : null;
  358. }
  359. /**
  360. * Return namespace by class name
  361. *
  362. * @return string
  363. * @access protected
  364. * @see ____func_see____
  365. * @since 1.0.0
  366. */
  367. protected function getActualNamespace()
  368. {
  369. list(, $namespace) = $this->getClassNameParts();
  370. return $namespace ? $this->prepareClassName(implode('\\', $namespace)) : null;
  371. }
  372. /**
  373. * Return base part of the class name
  374. *
  375. * @return string
  376. * @access protected
  377. * @see ____func_see____
  378. * @since 1.0.0
  379. */
  380. protected function getClassBaseName()
  381. {
  382. list($basename, ) = $this->getClassNameParts();
  383. return $this->prepareClassName($basename);
  384. }
  385. /**
  386. * Parse class name into parts
  387. *
  388. * @return array
  389. * @access protected
  390. * @see ____func_see____
  391. * @since 1.0.0
  392. */
  393. protected function getClassNameParts()
  394. {
  395. $parts = explode('\\', $this->getClass());
  396. return array(array_pop($parts), $parts);
  397. }
  398. // ------------------------------ Tags -
  399. /**
  400. * Get tag info
  401. *
  402. * @param string $name Tag name
  403. *
  404. * @return array
  405. * @access public
  406. * @see ____func_see____
  407. * @since 1.0.0
  408. */
  409. public function getTag($name)
  410. {
  411. return \Includes\Utils\ArrayManager::getIndex($this->getTags(), strtolower($name), true);
  412. }
  413. /**
  414. * Parse and return all tags
  415. *
  416. * @return array
  417. * @access public
  418. * @see ____func_see____
  419. * @since 1.0.0
  420. */
  421. public function getTags()
  422. {
  423. if (!isset($this->tags)) {
  424. $this->tags = \Includes\Decorator\Utils\Operator::getTags($this->getReflection()->docComment);
  425. }
  426. return $this->tags;
  427. }
  428. // ------------------------------ Auxiliary methods -
  429. /**
  430. * Return the ReflectionClass object for the current node
  431. *
  432. * @return \ReflectionClass
  433. * @access public
  434. * @see ____func_see____
  435. * @since 1.0.0
  436. */
  437. public function getReflection()
  438. {
  439. if (!isset($this->reflection)) {
  440. $this->reflection = new \StdClass();
  441. $util = '\Includes\Decorator\Utils\Tokenizer';
  442. if ($util::getDecoratorFlag()) {
  443. $util = '\Includes\Decorator\Utils\Tokenizer';
  444. $this->reflection->parentClass = $util::getParentClassName($this->getFile());
  445. $this->reflection->interfaces = $util::getInterfaces($this->getFile());
  446. $this->reflection->docComment = $util::getDockBlock($this->getFile());
  447. $this->reflection->isFinal = $util::getFlag($this->getFile(), T_FINAL);
  448. $this->reflection->isAbstract = $util::getFlag($this->getFile(), T_ABSTRACT);
  449. $this->reflection->isInterface = (bool) $util::getInterfaceName($this->getFile());
  450. // :KLUDGE: the "StaticRoutines" plugin support
  451. $this->reflection->hasStaticConstructor = $util::hasMethod(
  452. $this->getFile(),
  453. \Includes\Decorator\Plugin\StaticRoutines\Main::STATIC_CONSTRUCTOR_METHOD
  454. );
  455. } else {
  456. $reflection = new \ReflectionClass($this->getClass());
  457. $this->reflection->parentClass = ($class = $reflection->getParentClass()) ? $class->getName() : null;
  458. $this->reflection->interfaces = (array) $reflection->getInterfaceNames();
  459. $this->reflection->docComment = $reflection->getDocComment();
  460. $this->reflection->isFinal = $reflection->isFinal();
  461. $this->reflection->isAbstract = $reflection->isAbstract();
  462. $this->reflection->isInterface = $reflection->isInterface();
  463. // :KLUDGE: the "StaticRoutines" plugin support
  464. $this->reflection->hasStaticConstructor = $reflection->hasMethod(
  465. \Includes\Decorator\Plugin\StaticRoutines\Main::STATIC_CONSTRUCTOR_METHOD
  466. );
  467. }
  468. $this->reflection->parentClass = $this->prepareClassName($this->reflection->parentClass);
  469. $this->reflection->interfaces = array_map(array($this, 'prepareClassName'), $this->reflection->interfaces);
  470. }
  471. return $this->reflection;
  472. }
  473. /**
  474. * Prepare class name
  475. *
  476. * @param string $class Class name to prepare
  477. *
  478. * @return string
  479. * @access protected
  480. * @see ____func_see____
  481. * @since 1.0.0
  482. */
  483. protected function prepareClassName($class)
  484. {
  485. return \Includes\Utils\Converter::trimLeadingChars($class, '\\');
  486. }
  487. }