Io.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Code\Generator;
  7. use Magento\Framework\Exception\FileSystemException;
  8. /**
  9. * Manages generated code.
  10. */
  11. class Io
  12. {
  13. /**
  14. * Default code generation directory
  15. * Should correspond the value from \Magento\Framework\Filesystem
  16. */
  17. const DEFAULT_DIRECTORY = 'generated/code';
  18. /**
  19. * Path to directory where new file must be created
  20. *
  21. * @var string
  22. */
  23. private $_generationDirectory;
  24. /**
  25. * @var \Magento\Framework\Filesystem\Driver\File
  26. */
  27. private $filesystemDriver;
  28. /**
  29. * @param \Magento\Framework\Filesystem\Driver\File $filesystemDriver
  30. * @param null|string $generationDirectory
  31. */
  32. public function __construct(
  33. \Magento\Framework\Filesystem\Driver\File $filesystemDriver,
  34. $generationDirectory = null
  35. ) {
  36. $this->filesystemDriver = $filesystemDriver;
  37. $this->initGeneratorDirectory($generationDirectory);
  38. }
  39. /**
  40. * Get path to generation directory
  41. *
  42. * @param null|string $directory
  43. * @return string
  44. */
  45. protected function initGeneratorDirectory($directory = null)
  46. {
  47. if ($directory) {
  48. $this->_generationDirectory = rtrim($directory, '/') . '/';
  49. } else {
  50. $this->_generationDirectory = realpath(__DIR__ . '/../../../../') . '/' . self::DEFAULT_DIRECTORY . '/';
  51. }
  52. }
  53. /**
  54. * @param string $className
  55. * @return string
  56. */
  57. public function getResultFileDirectory($className)
  58. {
  59. $fileName = $this->generateResultFileName($className);
  60. $pathParts = explode('/', $fileName);
  61. unset($pathParts[count($pathParts) - 1]);
  62. return implode('/', $pathParts) . '/';
  63. }
  64. /**
  65. * @param string $className
  66. * @return string
  67. */
  68. public function generateResultFileName($className)
  69. {
  70. return $this->_generationDirectory . ltrim(str_replace(['\\', '_'], '/', $className), '/') . '.php';
  71. }
  72. /**
  73. * @param string $fileName
  74. * @param string $content
  75. * @throws FileSystemException
  76. * @return bool
  77. */
  78. public function writeResultFile($fileName, $content)
  79. {
  80. /**
  81. * Rename is atomic on *nix systems, while file_put_contents is not. Writing to a
  82. * temporary file whose name is process-unique and renaming to the real location helps
  83. * avoid race conditions. Race condition can occur if the compiler has not been run, when
  84. * multiple processes are attempting to access the generated file simultaneously.
  85. */
  86. $content = "<?php\n" . $content;
  87. $tmpFile = $fileName . "." . getmypid();
  88. $this->filesystemDriver->filePutContents($tmpFile, $content);
  89. try {
  90. $success = $this->filesystemDriver->rename($tmpFile, $fileName);
  91. } catch (FileSystemException $e) {
  92. if (!$this->fileExists($fileName)) {
  93. throw $e;
  94. } else {
  95. /**
  96. * Due to race conditions, file may have already been written, causing rename to fail. As long as
  97. * the file exists, everything is okay.
  98. */
  99. $success = true;
  100. }
  101. }
  102. return $success;
  103. }
  104. /**
  105. * @return bool
  106. */
  107. public function makeGenerationDirectory()
  108. {
  109. return $this->_makeDirectory($this->_generationDirectory);
  110. }
  111. /**
  112. * @param string $className
  113. * @return bool
  114. */
  115. public function makeResultFileDirectory($className)
  116. {
  117. return $this->_makeDirectory($this->getResultFileDirectory($className));
  118. }
  119. /**
  120. * @return string
  121. */
  122. public function getGenerationDirectory()
  123. {
  124. return $this->_generationDirectory;
  125. }
  126. /**
  127. * @param string $fileName
  128. * @return bool
  129. */
  130. public function fileExists($fileName)
  131. {
  132. return $this->filesystemDriver->isExists($fileName);
  133. }
  134. /**
  135. * Wrapper for include
  136. *
  137. * @param string $fileName
  138. * @return mixed
  139. * @codeCoverageIgnore
  140. */
  141. public function includeFile($fileName)
  142. {
  143. return include $fileName;
  144. }
  145. /**
  146. * @param string $directory
  147. * @return bool
  148. */
  149. private function _makeDirectory($directory)
  150. {
  151. if ($this->filesystemDriver->isWritable($directory)) {
  152. return true;
  153. }
  154. try {
  155. if (!$this->filesystemDriver->isDirectory($directory)) {
  156. $this->filesystemDriver->createDirectory($directory);
  157. }
  158. return true;
  159. } catch (FileSystemException $e) {
  160. return false;
  161. }
  162. }
  163. }