/phpBB/phpbb/composer/manager.php

https://github.com/phpbb/phpbb · PHP · 332 lines · 156 code · 51 blank · 125 comment · 9 complexity · a42d27f59e9093713aa2bab4519ce895 MD5 · raw file

  1. <?php
  2. /**
  3. *
  4. * This file is part of the phpBB Forum Software package.
  5. *
  6. * @copyright (c) phpBB Limited <https://www.phpbb.com>
  7. * @license GNU General Public License, version 2 (GPL-2.0)
  8. *
  9. * For full copyright and license information, please see
  10. * the docs/CREDITS.txt file.
  11. *
  12. */
  13. namespace phpbb\composer;
  14. use Composer\IO\IOInterface;
  15. use phpbb\cache\driver\driver_interface;
  16. use phpbb\composer\exception\runtime_exception;
  17. /**
  18. * Class to manage packages through composer.
  19. */
  20. class manager implements manager_interface
  21. {
  22. /**
  23. * @var installer Composer packages installer
  24. */
  25. protected $installer;
  26. /**
  27. * @var driver_interface Cache instance
  28. */
  29. protected $cache;
  30. /**
  31. * @var string Type of packages (phpbb-packages per example)
  32. */
  33. protected $package_type;
  34. /**
  35. * @var string Prefix used for the exception's language string
  36. */
  37. protected $exception_prefix;
  38. /**
  39. * @var array|null Caches the managed packages list (for the current type)
  40. */
  41. private $managed_packages;
  42. /**
  43. * @var array|null Caches the managed packages list (for all phpBB types)
  44. */
  45. private $all_managed_packages;
  46. /**
  47. * @var array|null Caches the available packages list
  48. */
  49. private $available_packages;
  50. /**
  51. * @param installer $installer Installer object
  52. * @param driver_interface $cache Cache object
  53. * @param string $package_type Composer type of managed packages
  54. * @param string $exception_prefix Exception prefix to use
  55. */
  56. public function __construct(installer $installer, driver_interface $cache, $package_type, $exception_prefix)
  57. {
  58. $this->installer = $installer;
  59. $this->cache = $cache;
  60. $this->package_type = $package_type;
  61. $this->exception_prefix = $exception_prefix;
  62. }
  63. /**
  64. * {@inheritdoc}
  65. */
  66. public function install(array $packages, IOInterface $io = null)
  67. {
  68. $packages = $this->normalize_version($packages);
  69. $already_managed = array_intersect(array_keys($this->get_managed_packages()), array_keys($packages));
  70. if (count($already_managed) !== 0)
  71. {
  72. throw new runtime_exception($this->exception_prefix, 'ALREADY_INSTALLED', [implode('|', $already_managed)]);
  73. }
  74. $this->pre_install($packages, $io);
  75. $managed_packages = array_merge($this->get_all_managed_packages(), $packages);
  76. ksort($managed_packages);
  77. $this->installer->install($managed_packages, [], $io);
  78. $this->post_install($packages, $io);
  79. $this->managed_packages = null;
  80. }
  81. /**
  82. * Hook called before installing the packages
  83. *
  84. * @param array $packages Packages to update.
  85. * Each entry may be a name or an array associating a version constraint to a name
  86. * @param IOInterface|null $io IO object used for the output
  87. */
  88. protected function pre_install(array $packages, IOInterface $io = null)
  89. {
  90. }
  91. /**
  92. * Hook called after installing the packages
  93. *
  94. * @param array $packages Packages to update.
  95. * Each entry may be a name or an array associating a version constraint to a name
  96. * @param IOInterface|null $io IO object used for the output
  97. */
  98. protected function post_install(array $packages, IOInterface $io = null)
  99. {
  100. }
  101. /**
  102. * {@inheritdoc}
  103. */
  104. public function update(array $packages, IOInterface $io = null)
  105. {
  106. $packages = $this->normalize_version($packages);
  107. $not_managed = array_diff_key($packages, $this->get_managed_packages());
  108. if (count($not_managed) !== 0)
  109. {
  110. throw new runtime_exception($this->exception_prefix, 'NOT_MANAGED', [implode('|', array_keys($not_managed))]);
  111. }
  112. $this->pre_update($packages, $io);
  113. $managed_packages = array_merge($this->get_all_managed_packages(), $packages);
  114. ksort($managed_packages);
  115. $this->installer->install($managed_packages, array_keys($packages), $io);
  116. $this->post_update($packages, $io);
  117. }
  118. /**
  119. * Hook called before updating the packages
  120. *
  121. * @param array $packages Packages to update.
  122. * Each entry may be a name or an array associating a version constraint to a name
  123. * @param IOInterface|null $io IO object used for the output
  124. */
  125. protected function pre_update(array $packages, IOInterface $io = null)
  126. {
  127. }
  128. /**
  129. * Hook called after updating the packages
  130. *
  131. * @param array $packages Packages to update.
  132. * Each entry may be a name or an array associating a version constraint to a name
  133. * @param IOInterface|null $io IO object used for the output
  134. */
  135. protected function post_update(array $packages, IOInterface $io = null)
  136. {
  137. }
  138. /**
  139. * {@inheritdoc}
  140. */
  141. public function remove(array $packages, IOInterface $io = null)
  142. {
  143. $packages = $this->normalize_version($packages);
  144. $not_managed = array_diff_key($packages, $this->get_managed_packages());
  145. if (count($not_managed) !== 0)
  146. {
  147. throw new runtime_exception($this->exception_prefix, 'NOT_MANAGED', [implode('|', array_keys($not_managed))]);
  148. }
  149. $this->pre_remove($packages, $io);
  150. $managed_packages = array_diff_key($this->get_all_managed_packages(), $packages);
  151. ksort($managed_packages);
  152. $this->installer->install($managed_packages, array_keys($packages), $io);
  153. $this->post_remove($packages, $io);
  154. $this->managed_packages = null;
  155. }
  156. /**
  157. * Hook called before removing the packages
  158. *
  159. * @param array $packages Packages to update.
  160. * Each entry may be a name or an array associating a version constraint to a name
  161. * @param IOInterface|null $io IO object used for the output
  162. */
  163. protected function pre_remove(array $packages, IOInterface $io = null)
  164. {
  165. }
  166. /**
  167. * Hook called after removing the packages
  168. *
  169. * @param array $packages Packages to update.
  170. * Each entry may be a name or an array associating a version constraint to a name
  171. * @param IOInterface|null $io IO object used for the output
  172. */
  173. protected function post_remove(array $packages, IOInterface $io = null)
  174. {
  175. }
  176. /**
  177. * {@inheritdoc}
  178. */
  179. public function is_managed($package)
  180. {
  181. return array_key_exists($package, $this->get_managed_packages());
  182. }
  183. /**
  184. * {@inheritdoc}
  185. */
  186. public function get_managed_packages()
  187. {
  188. if ($this->managed_packages === null)
  189. {
  190. $this->managed_packages = $this->installer->get_installed_packages($this->package_type);
  191. }
  192. return $this->managed_packages;
  193. }
  194. /**
  195. * {@inheritdoc}
  196. */
  197. public function get_all_managed_packages()
  198. {
  199. if ($this->all_managed_packages === null)
  200. {
  201. $this->all_managed_packages = $this->installer->get_installed_packages(explode(',', installer::PHPBB_TYPES));
  202. }
  203. return $this->all_managed_packages;
  204. }
  205. /**
  206. * {@inheritdoc}
  207. */
  208. public function get_available_packages()
  209. {
  210. if ($this->available_packages === null)
  211. {
  212. $this->available_packages = $this->cache->get('_composer_' . $this->package_type . '_available');
  213. if (!$this->available_packages)
  214. {
  215. $this->available_packages = $this->installer->get_available_packages($this->package_type);
  216. $this->cache->put('_composer_' . $this->package_type . '_available', $this->available_packages, 24*60*60);
  217. }
  218. }
  219. return $this->available_packages;
  220. }
  221. /**
  222. * {@inheritdoc}
  223. */
  224. public function reset_cache()
  225. {
  226. $this->cache->destroy('_composer_' . $this->package_type . '_available');
  227. $this->available_packages = null;
  228. $this->managed_packages = null;
  229. $this->all_managed_packages = null;
  230. }
  231. /**
  232. * {@inheritdoc}
  233. */
  234. public function start_managing($package, $io)
  235. {
  236. throw new \phpbb\exception\runtime_exception('COMPOSER_UNSUPPORTED_OPERATION', (array) $this->package_type);
  237. }
  238. /**
  239. * {@inheritdoc}
  240. */
  241. public function check_requirements()
  242. {
  243. return $this->installer->check_requirements();
  244. }
  245. /**
  246. * Normalize a packages/version array. Every entry can have 3 different forms:
  247. * - $package => $version
  248. * - $indice => $package:$version
  249. * - $indice => $package
  250. * They are converted to he form:
  251. * - $package => $version ($version is set to '*' for the third form)
  252. *
  253. * @param array $packages
  254. *
  255. * @return array
  256. */
  257. protected function normalize_version(array $packages)
  258. {
  259. $normalized_packages = [];
  260. foreach ($packages as $package => $version)
  261. {
  262. if (is_numeric($package))
  263. {
  264. if (strpos($version, ':') !== false)
  265. {
  266. $parts = explode(':', $version);
  267. $normalized_packages[$parts[0]] = $parts[1];
  268. }
  269. else
  270. {
  271. $normalized_packages[$version] = '*';
  272. }
  273. }
  274. else
  275. {
  276. $normalized_packages[$package] = $version;
  277. }
  278. }
  279. return $normalized_packages;
  280. }
  281. }