ProcessBuilderFactory.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. <?php
  2. /*
  3. * This file is part of Alchemy\BinaryDriver.
  4. *
  5. * (c) Alchemy <info@alchemy.fr>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Alchemy\BinaryDriver;
  11. use Alchemy\BinaryDriver\Exception\InvalidArgumentException;
  12. use Symfony\Component\Process\Process;
  13. use Symfony\Component\Process\ProcessBuilder;
  14. class ProcessBuilderFactory implements ProcessBuilderFactoryInterface
  15. {
  16. /**
  17. * The binary path
  18. *
  19. * @var String
  20. */
  21. protected $binary;
  22. /**
  23. * The timeout for the generated processes
  24. *
  25. * @var integer|float
  26. */
  27. private $timeout;
  28. /**
  29. * An internal ProcessBuilder.
  30. *
  31. * Note that this one is used only if Symfony ProcessBuilder has method
  32. * setPrefix (2.3)
  33. *
  34. * @var ProcessBuilder
  35. */
  36. private $builder;
  37. /**
  38. * Tells whether Symfony LTS ProcessBuilder should be emulated or not.
  39. *
  40. * This symfony version provided a brand new ::setPrefix method.
  41. *
  42. * @var Boolean
  43. */
  44. public static $emulateSfLTS;
  45. /**
  46. * Constructor
  47. *
  48. * @param String $binary The path to the binary
  49. *
  50. * @throws InvalidArgumentException In case binary path is invalid
  51. */
  52. public function __construct($binary)
  53. {
  54. $this->detectEmulation();
  55. if (!self::$emulateSfLTS) {
  56. $this->builder = new ProcessBuilder();
  57. }
  58. $this->useBinary($binary);
  59. }
  60. /**
  61. * Covenient method for unit testing
  62. *
  63. * @return type
  64. */
  65. public function getBuilder()
  66. {
  67. return $this->builder;
  68. }
  69. /**
  70. * Covenient method for unit testing
  71. *
  72. * @param ProcessBuilder $builder
  73. * @return ProcessBuilderFactory
  74. */
  75. public function setBuilder(ProcessBuilder $builder)
  76. {
  77. $this->builder = $builder;
  78. return $this;
  79. }
  80. /**
  81. * @inheritdoc
  82. */
  83. public function getBinary()
  84. {
  85. return $this->binary;
  86. }
  87. /**
  88. * @inheritdoc
  89. */
  90. public function useBinary($binary)
  91. {
  92. if (!is_executable($binary)) {
  93. throw new InvalidArgumentException(sprintf('`%s` is not an executable binary', $binary));
  94. }
  95. $this->binary = $binary;
  96. if (!static::$emulateSfLTS) {
  97. $this->builder->setPrefix($binary);
  98. }
  99. return $this;
  100. }
  101. /**
  102. * @inheritdoc
  103. */
  104. public function setTimeout($timeout)
  105. {
  106. $this->timeout = $timeout;
  107. if (!static::$emulateSfLTS) {
  108. $this->builder->setTimeout($this->timeout);
  109. }
  110. return $this;
  111. }
  112. /**
  113. * @inheritdoc
  114. */
  115. public function getTimeout()
  116. {
  117. return $this->timeout;
  118. }
  119. /**
  120. * @inheritdoc
  121. */
  122. public function create($arguments = array())
  123. {
  124. if (null === $this->binary) {
  125. throw new InvalidArgumentException('No binary set');
  126. }
  127. if (!is_array($arguments)) {
  128. $arguments = array($arguments);
  129. }
  130. if (static::$emulateSfLTS) {
  131. array_unshift($arguments, $this->binary);
  132. if (method_exists('Symfony\Component\Process\ProcessUtils', 'escapeArgument')) {
  133. $script = implode(' ', array_map(array('Symfony\Component\Process\ProcessUtils', 'escapeArgument'), $arguments));
  134. } else {
  135. $script = $arguments;
  136. }
  137. $env = array_replace($_ENV, $_SERVER);
  138. $env = array_filter($env, function ($value) {
  139. return !is_array($value);
  140. });
  141. return new Process($script, null, $env, null, $this->timeout);
  142. } else {
  143. return $this->builder
  144. ->setArguments($arguments)
  145. ->getProcess();
  146. }
  147. }
  148. private function detectEmulation()
  149. {
  150. if (null !== static::$emulateSfLTS) {
  151. return $this;
  152. }
  153. static::$emulateSfLTS = !method_exists('Symfony\Component\Process\ProcessBuilder', 'setPrefix');
  154. return $this;
  155. }
  156. }