GearmanParser.php 7.1 KB

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