GearmanParser.php 7.3 KB

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