GearmanParser.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. <?php
  2. /**
  3. * Gearman Bundle for Symfony2
  4. *
  5. * @author Marc Morera <yuhu@mmoreram.com>
  6. * @since 2013
  7. */
  8. namespace Mmoreram\GearmanBundle\Service;
  9. use Symfony\Component\Finder\Finder;
  10. use Symfony\Component\HttpKernel\KernelInterface;
  11. use Doctrine\Common\Annotations\Reader;
  12. use Doctrine\Common\Annotations\AnnotationRegistry;
  13. use ReflectionClass;
  14. use Mmoreram\GearmanBundle\Module\WorkerCollection;
  15. use Mmoreram\GearmanBundle\Module\WorkerClass as Worker;
  16. use Mmoreram\GearmanBundle\Driver\Gearman\Work as WorkAnnotation;
  17. /**
  18. * Gearman parsing methods
  19. *
  20. * This class has responability of parsing, if needed, all defined bundle files
  21. * looking for some Workers.
  22. *
  23. * @author Marc Morera <yuhu@mmoreram.com>
  24. */
  25. class GearmanParser
  26. {
  27. /**
  28. * @var Array
  29. *
  30. * Bundles loaded by kernel
  31. */
  32. private $kernelBundles;
  33. /**
  34. * @var Kernel
  35. *
  36. * Kernel object
  37. */
  38. private $kernel;
  39. /**
  40. * @var Reader
  41. *
  42. * Annotation Reader
  43. */
  44. private $reader;
  45. /**
  46. * @var Finder
  47. *
  48. * Finder
  49. */
  50. private $finder;
  51. /**
  52. * @var Array
  53. *
  54. * Bundles available to perform search
  55. */
  56. private $bundles;
  57. /**
  58. * @var array
  59. *
  60. * Collection of servers to connect
  61. */
  62. private $servers;
  63. /**
  64. * @var array
  65. *
  66. * Default settings defined by user in config.yml
  67. */
  68. private $defaultSettings;
  69. /**
  70. * Construct method
  71. *
  72. * @param KernelInterface $kernel Kernel instance
  73. * @param Reader $reader Reader
  74. * @param Finder $finder Finder
  75. * @param array $bundles Bundle array where to parse workers, defined on condiguration
  76. * @param array $servers Server list defined on configuration
  77. * @param array $defaultSettings Default settings defined on configuration
  78. */
  79. public function __construct(KernelInterface $kernel, Reader $reader, Finder $finder, array $bundles, array $servers, array $defaultSettings)
  80. {
  81. $this->kernelBundles = $kernel->getBundles();
  82. $this->kernel = $kernel;
  83. $this->reader = $reader;
  84. $this->finder = $finder;
  85. $this->bundles = $bundles;
  86. $this->servers = $servers;
  87. $this->defaultSettings = $defaultSettings;
  88. }
  89. /**
  90. * Loads Worker Collection from parsed files
  91. *
  92. * @return WorkerCollection collection of all info
  93. */
  94. public function load()
  95. {
  96. list($paths, $excludedPaths) = $this->loadNamespaceMap($this->kernelBundles, $this->bundles);
  97. return $this->parseNamespaceMap($this->finder, $this->reader, $paths, $excludedPaths);
  98. }
  99. /**
  100. * Return Gearman bundle settings, previously loaded by method load()
  101. *
  102. * If settings are not loaded, a SettingsNotLoadedException Exception is thrown
  103. *
  104. * @param array $kernelBundles Kernel bundles
  105. * @param array $bundles Bundle array of settings
  106. *
  107. * @return array Return an array containing paths and ignore paths
  108. */
  109. public function loadNamespaceMap(array $kernelBundles, array $bundles)
  110. {
  111. $paths = array();
  112. $excludedPaths = array();
  113. /**
  114. * Iteratinc all bundle settings
  115. */
  116. foreach ($bundles as $bundleSettings) {
  117. if (!$bundleSettings['active']) {
  118. break;
  119. }
  120. $bundleNamespace = $bundleSettings['name'];
  121. $bundlePath = $kernelBundles[$bundleNamespace]->getPath();
  122. if (!empty($bundleSettings['include'])) {
  123. foreach ($bundleSettings['include'] as $include) {
  124. $paths[] = rtrim(rtrim($bundlePath, '/') . '/' . $include, '/') . '/';
  125. }
  126. } else {
  127. /**
  128. * If no include is set, include all namespace
  129. */
  130. $paths[] = rtrim($bundlePath, '/') . '/';
  131. }
  132. foreach ($bundleSettings['ignore'] as $ignore) {
  133. $excludedPaths[] = trim($ignore, '/');
  134. }
  135. }
  136. return array(
  137. $paths,
  138. $excludedPaths,
  139. );
  140. }
  141. /**
  142. * Perform a parsing inside all namespace map
  143. *
  144. * Creates an empty worker collection and, if exist some parseable files
  145. * parse them, filling this object
  146. *
  147. * @param Finder $finder Finder
  148. * @param Reader $reader Reader
  149. * @param array $paths Paths where to look for
  150. * @param array $excludedPaths Paths to ignore
  151. *
  152. * @return WorkerCollection collection of all info
  153. */
  154. public function parseNamespaceMap(Finder $finder, Reader $reader, array $paths, array $excludedPaths)
  155. {
  156. $workerCollection = new WorkerCollection;
  157. if (!empty($paths)) {
  158. $finder
  159. ->files()
  160. ->followLinks()
  161. ->exclude($excludedPaths)
  162. ->in($paths)
  163. ->name('*.php');
  164. $this->parseFiles($finder, $reader, $workerCollection);
  165. }
  166. return $workerCollection;
  167. }
  168. /**
  169. * Load all workers with their jobs
  170. *
  171. * @param Finder $finder Finder
  172. * @param Reader $reader Reader
  173. * @param WorkerCollection $workerCollection Worker collection
  174. *
  175. * @return GearmanParser self Object
  176. */
  177. public function parseFiles(Finder $finder, Reader $reader, WorkerCollection $workerCollection)
  178. {
  179. /**
  180. * Every file found is parsed
  181. */
  182. foreach ($finder as $file) {
  183. /**
  184. * File is accepted to be parsed
  185. */
  186. $classNamespace = $this->getFileClassNamespace($file->getRealpath());
  187. $reflectionClass = new ReflectionClass($classNamespace);
  188. $classAnnotations = $reader->getClassAnnotations($reflectionClass);
  189. /**
  190. * Every annotation found is parsed
  191. */
  192. foreach ($classAnnotations as $annotation) {
  193. /**
  194. * Annotation is only laoded if is typeof WorkAnnotation
  195. */
  196. if ($annotation instanceof WorkAnnotation) {
  197. /**
  198. * Creates new Worker element with all its Job data
  199. */
  200. $worker = new Worker($annotation, $reflectionClass, $reader, $this->servers, $this->defaultSettings);
  201. $workerCollection->add($worker);
  202. }
  203. }
  204. }
  205. return $this;
  206. }
  207. /**
  208. * Returns file class namespace, if exists
  209. *
  210. * @param string $file A PHP file path
  211. *
  212. * @return string|false Full class namespace if found, false otherwise
  213. */
  214. public function getFileClassNamespace($file)
  215. {
  216. $filenameBlock = explode('/', $file);
  217. $filename = explode('.', end($filenameBlock), 2);
  218. $filename = reset($filename);
  219. preg_match('/\snamespace\s+(.+?);/s', file_get_contents($file), $match);
  220. return is_array($match) && isset($match[1])
  221. ? $match[1] . '\\' . $filename
  222. : false;
  223. }
  224. }