GearmanParser.php 7.3 KB

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