GearmanParser.php 7.2 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 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 KernelInterface
  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(
  79. KernelInterface $kernel,
  80. Reader $reader,
  81. Finder $finder,
  82. array $bundles,
  83. array $servers,
  84. array $defaultSettings
  85. )
  86. {
  87. $this->kernelBundles = $kernel->getBundles();
  88. $this->kernel = $kernel;
  89. $this->reader = $reader;
  90. $this->finder = $finder;
  91. $this->bundles = $bundles;
  92. $this->servers = $servers;
  93. $this->defaultSettings = $defaultSettings;
  94. }
  95. /**
  96. * Loads Worker Collection from parsed files
  97. *
  98. * @return WorkerCollection collection of all info
  99. */
  100. public function load()
  101. {
  102. list($paths, $excludedPaths) = $this->loadNamespaceMap($this->kernelBundles, $this->bundles);
  103. return $this->parseNamespaceMap($this->finder, $this->reader, $paths, $excludedPaths);
  104. }
  105. /**
  106. * Return Gearman bundle settings, previously loaded by method load()
  107. *
  108. * If settings are not loaded, a SettingsNotLoadedException Exception is thrown
  109. *
  110. * @param array $kernelBundles Kernel bundles
  111. * @param array $bundles Bundle array of settings
  112. *
  113. * @return array Return an array containing paths and ignore paths
  114. */
  115. public function loadNamespaceMap(array $kernelBundles, array $bundles)
  116. {
  117. $paths = array();
  118. $excludedPaths = array();
  119. /**
  120. * Iteratinc all bundle settings
  121. */
  122. foreach ($bundles as $bundleSettings) {
  123. if (!$bundleSettings['active']) {
  124. break;
  125. }
  126. $bundleNamespace = $bundleSettings['name'];
  127. $bundlePath = $kernelBundles[$bundleNamespace]->getPath();
  128. if (!empty($bundleSettings['include'])) {
  129. foreach ($bundleSettings['include'] as $include) {
  130. $paths[] = rtrim(rtrim($bundlePath, '/') . '/' . $include, '/') . '/';
  131. }
  132. } else {
  133. /**
  134. * If no include is set, include all namespace
  135. */
  136. $paths[] = rtrim($bundlePath, '/') . '/';
  137. }
  138. foreach ($bundleSettings['ignore'] as $ignore) {
  139. $excludedPaths[] = trim($ignore, '/');
  140. }
  141. }
  142. return array(
  143. $paths,
  144. $excludedPaths,
  145. );
  146. }
  147. /**
  148. * Perform a parsing inside all namespace map
  149. *
  150. * Creates an empty worker collection and, if exist some parseable files
  151. * parse them, filling this object
  152. *
  153. * @param Finder $finder Finder
  154. * @param Reader $reader Reader
  155. * @param array $paths Paths where to look for
  156. * @param array $excludedPaths Paths to ignore
  157. *
  158. * @return WorkerCollection collection of all info
  159. */
  160. public function parseNamespaceMap(
  161. Finder $finder,
  162. Reader $reader,
  163. array $paths,
  164. array $excludedPaths
  165. )
  166. {
  167. $workerCollection = new WorkerCollection;
  168. if (!empty($paths)) {
  169. $finder
  170. ->files()
  171. ->followLinks()
  172. ->exclude($excludedPaths)
  173. ->in($paths)
  174. ->name('*.php');
  175. $this->parseFiles($finder, $reader, $workerCollection);
  176. }
  177. return $workerCollection;
  178. }
  179. /**
  180. * Load all workers with their jobs
  181. *
  182. * @param Finder $finder Finder
  183. * @param Reader $reader Reader
  184. * @param WorkerCollection $workerCollection Worker collection
  185. *
  186. * @return GearmanParser self Object
  187. */
  188. public function parseFiles(
  189. Finder $finder,
  190. Reader $reader,
  191. WorkerCollection $workerCollection
  192. )
  193. {
  194. /**
  195. * Every file found is parsed
  196. */
  197. foreach ($finder as $file) {
  198. /**
  199. * File is accepted to be parsed
  200. */
  201. $classNamespace = $this->getFileClassNamespace($file->getRealpath());
  202. $reflectionClass = new ReflectionClass($classNamespace);
  203. $classAnnotations = $reader->getClassAnnotations($reflectionClass);
  204. /**
  205. * Every annotation found is parsed
  206. */
  207. foreach ($classAnnotations as $annotation) {
  208. /**
  209. * Annotation is only laoded if is typeof WorkAnnotation
  210. */
  211. if ($annotation instanceof WorkAnnotation) {
  212. /**
  213. * Creates new Worker element with all its Job data
  214. */
  215. $worker = new Worker($annotation, $reflectionClass, $reader, $this->servers, $this->defaultSettings);
  216. $workerCollection->add($worker);
  217. }
  218. }
  219. }
  220. return $this;
  221. }
  222. /**
  223. * Returns file class namespace, if exists
  224. *
  225. * @param string $file A PHP file path
  226. *
  227. * @return string|false Full class namespace if found, false otherwise
  228. */
  229. public function getFileClassNamespace($file)
  230. {
  231. $filenameBlock = explode(DIRECTORY_SEPARATOR, $file);
  232. $filename = explode('.', end($filenameBlock), 2);
  233. $filename = reset($filename);
  234. preg_match('/\snamespace\s+(.+?);/s', file_get_contents($file), $match);
  235. return is_array($match) && isset($match[1])
  236. ? $match[1] . '\\' . $filename
  237. : false;
  238. }
  239. }