Depends.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <?php
  2. namespace ba;
  3. use Throwable;
  4. use think\Exception;
  5. /**
  6. * 依赖管理
  7. */
  8. class Depends
  9. {
  10. /**
  11. * json 文件内容
  12. * @var array
  13. */
  14. protected array $jsonContent = [];
  15. public function __construct(protected string $json, protected string $type = 'npm')
  16. {
  17. }
  18. /**
  19. * 获取 json 文件内容
  20. * @param bool $realTime 获取实时内容
  21. * @return array
  22. * @throws Throwable
  23. */
  24. public function getContent(bool $realTime = false): array
  25. {
  26. if (!file_exists($this->json)) {
  27. throw new Exception($this->json . ' file does not exist!');
  28. }
  29. if ($this->jsonContent && !$realTime) return $this->jsonContent;
  30. $content = @file_get_contents($this->json);
  31. $this->jsonContent = json_decode($content, true);
  32. if (!$this->jsonContent) {
  33. throw new Exception($this->json . ' file read failure!');
  34. }
  35. return $this->jsonContent;
  36. }
  37. /**
  38. * 设置 json 文件内容
  39. * @param array $content
  40. * @throws Throwable
  41. */
  42. public function setContent(array $content = []): void
  43. {
  44. if (!$content) $content = $this->jsonContent;
  45. if (!isset($content['name'])) {
  46. throw new Exception('Depend content file content is incomplete');
  47. }
  48. $content = json_encode($content, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
  49. $result = @file_put_contents($this->json, $content . PHP_EOL);
  50. if (!$result) {
  51. throw new Exception('File has no write permission:' . $this->json);
  52. }
  53. }
  54. /**
  55. * 获取依赖项
  56. * @param bool $devEnv 是否是获取开发环境依赖
  57. * @return array
  58. * @throws Throwable
  59. */
  60. public function getDepends(bool $devEnv = false): array
  61. {
  62. try {
  63. $content = $this->getContent();
  64. } catch (Throwable) {
  65. return [];
  66. }
  67. if ($this->type == 'npm') {
  68. return $devEnv ? $content['devDependencies'] : $content['dependencies'];
  69. } else {
  70. return $devEnv ? $content['require-dev'] : $content['require'];
  71. }
  72. }
  73. /**
  74. * 是否存在某个依赖
  75. * @param string $name 依赖名称
  76. * @param bool $devEnv 是否是获取开发环境依赖
  77. * @return bool|string false或者依赖版本号
  78. * @throws Throwable
  79. */
  80. public function hasDepend(string $name, bool $devEnv = false): bool|string
  81. {
  82. $depends = $this->getDepends($devEnv);
  83. return $depends[$name] ?? false;
  84. }
  85. /**
  86. * 添加依赖
  87. * @param array $depends 要添加的依赖数组["xxx" => ">=7.1.0",]
  88. * @param bool $devEnv 是否添加为开发环境依赖
  89. * @param bool $cover 覆盖模式
  90. * @return void
  91. * @throws Throwable
  92. */
  93. public function addDepends(array $depends, bool $devEnv = false, bool $cover = false): void
  94. {
  95. $content = $this->getContent(true);
  96. $dKey = $devEnv ? ($this->type == 'npm' ? 'devDependencies' : 'require-dev') : ($this->type == 'npm' ? 'dependencies' : 'require');
  97. if (!$cover) {
  98. foreach ($depends as $key => $item) {
  99. if (isset($content[$dKey][$key])) {
  100. throw new Exception($key . ' depend already exists!');
  101. }
  102. }
  103. }
  104. $content[$dKey] = array_merge($content[$dKey], $depends);
  105. $this->setContent($content);
  106. }
  107. /**
  108. * 删除依赖
  109. * @param array $depends 要删除的依赖数组["php", "w7corp/easyWechat"]
  110. * @param bool $devEnv 是否为开发环境删除依赖
  111. * @return void
  112. * @throws Throwable
  113. */
  114. public function removeDepends(array $depends, bool $devEnv = false): void
  115. {
  116. $content = $this->getContent(true);
  117. $dKey = $devEnv ? ($this->type == 'npm' ? 'devDependencies' : 'require-dev') : ($this->type == 'npm' ? 'dependencies' : 'require');
  118. foreach ($depends as $item) {
  119. if (isset($content[$dKey][$item])) {
  120. unset($content[$dKey][$item]);
  121. }
  122. }
  123. $this->setContent($content);
  124. }
  125. /**
  126. * 获取 composer.json 的 config 字段
  127. */
  128. public function getComposerConfig(): array
  129. {
  130. try {
  131. $content = $this->getContent();
  132. } catch (Throwable) {
  133. return [];
  134. }
  135. return $content['config'];
  136. }
  137. /**
  138. * 设置 composer.json 的 config 字段
  139. * @throws Throwable
  140. */
  141. public function setComposerConfig(array $config, bool $cover = true): void
  142. {
  143. $content = $this->getContent(true);
  144. // 配置冲突检查
  145. if (!$cover) {
  146. foreach ($config as $key => $item) {
  147. if (is_array($item)) {
  148. foreach ($item as $configKey => $configItem) {
  149. if (isset($content['config'][$key][$configKey]) && $content['config'][$key][$configKey] != $configItem) {
  150. throw new Exception(__('composer config %s conflict', [$configKey]));
  151. }
  152. }
  153. } elseif (isset($content['config'][$key]) && $content['config'][$key] != $item) {
  154. throw new Exception(__('composer config %s conflict', [$key]));
  155. }
  156. }
  157. }
  158. foreach ($config as $key => $item) {
  159. if (is_array($item)) {
  160. foreach ($item as $configKey => $configItem) {
  161. $content['config'][$key][$configKey] = $configItem;
  162. }
  163. } else {
  164. $content['config'][$key] = $item;
  165. }
  166. }
  167. $this->setContent($content);
  168. }
  169. /**
  170. * 删除 composer 配置项
  171. * @throws Throwable
  172. */
  173. public function removeComposerConfig(array $config): void
  174. {
  175. if (!$config) return;
  176. $content = $this->getContent(true);
  177. foreach ($config as $key => $item) {
  178. if (isset($content['config'][$key])) {
  179. if (is_array($item)) {
  180. foreach ($item as $configKey => $configItem) {
  181. if (isset($content['config'][$key][$configKey])) unset($content['config'][$key][$configKey]);
  182. }
  183. // 没有子级配置项了
  184. if (!$content['config'][$key]) {
  185. unset($content['config'][$key]);
  186. }
  187. } else {
  188. unset($content['config'][$key]);
  189. }
  190. }
  191. }
  192. $this->setContent($content);
  193. }
  194. }