PageRenderTime 25ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/classes/Mibew/Plugin/PluginInfo.php

https://gitlab.com/fabiorf/chat
PHP | 383 lines | 182 code | 44 blank | 157 comment | 23 complexity | bf62643f82bbadb1454a7f22e2ff59cc MD5 | raw file
  1. <?php
  2. /*
  3. * This file is a part of Mibew Messenger.
  4. *
  5. * Copyright 2005-2015 the original author or authors.
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. namespace Mibew\Plugin;
  20. use vierbergenlars\SemVer\version as Version;
  21. use vierbergenlars\SemVer\expression as VersionExpression;
  22. /**
  23. * Provides a handy wrapper for plugin info.
  24. */
  25. class PluginInfo
  26. {
  27. /**
  28. * Name of the plugin.
  29. * @var string
  30. */
  31. protected $pluginName;
  32. /**
  33. * Name of the plugin's class.
  34. * @var string|null
  35. */
  36. protected $pluginClass = null;
  37. /**
  38. * The current state of the plugin.
  39. * @var State|null
  40. */
  41. protected $pluginState = null;
  42. /**
  43. * Class constructor.
  44. *
  45. * @param string $plugin_name Name of the plguin.
  46. * @throws \InvalidArgumentException If the plugin name isn't correct.
  47. * @throws \RuntimeException If the plugin does not exist.
  48. */
  49. public function __construct($plugin_name)
  50. {
  51. if (!Utils::isValidPluginName($plugin_name)) {
  52. throw new \InvalidArgumentException('Wrong plugin name');
  53. }
  54. if (!Utils::pluginExists($plugin_name)) {
  55. throw new \RuntimeException('Plugin is not found');
  56. }
  57. $this->pluginName = $plugin_name;
  58. }
  59. /**
  60. * Returns current state of the plugin.
  61. *
  62. * @return State
  63. */
  64. public function getState()
  65. {
  66. if (is_null($this->pluginState)) {
  67. $state = State::loadByName($this->pluginName);
  68. if (!$state) {
  69. // There is no appropriate state in the database. Use a new one.
  70. $state = new State();
  71. $state->pluginName = $this->pluginName;
  72. $state->version = false;
  73. $state->installed = false;
  74. $state->enabled = false;
  75. }
  76. $this->pluginState = $state;
  77. }
  78. return $this->pluginState;
  79. }
  80. /**
  81. * Clears state of the plugin attached to the info object.
  82. *
  83. * Also the method deletes state from database but only if it's stored
  84. * where.
  85. */
  86. public function clearState()
  87. {
  88. if (!is_null($this->pluginState)) {
  89. if ($this->pluginState->id) {
  90. // Remove state only if it's in the database.
  91. $this->pluginState->delete();
  92. }
  93. $this->pluginState = null;
  94. }
  95. }
  96. /**
  97. * Returns fully qualified plugin's class.
  98. *
  99. * @return string
  100. */
  101. public function getClass()
  102. {
  103. if (is_null($this->pluginClass)) {
  104. $this->pluginClass = Utils::getPluginClassName($this->pluginName);
  105. }
  106. return $this->pluginClass;
  107. }
  108. /**
  109. * Returns name of the plugin.
  110. *
  111. * @return string
  112. */
  113. public function getName()
  114. {
  115. return $this->pluginName;
  116. }
  117. /**
  118. * Returns current version of the plugin.
  119. *
  120. * @return string
  121. */
  122. public function getVersion()
  123. {
  124. return call_user_func(array($this->getClass(), 'getVersion'));
  125. }
  126. /**
  127. * Returns installed version of the plugin.
  128. *
  129. * Notice that in can differs from
  130. * {@link \Mibew\Plugin\PluginInfo::getVersion()} results if the plugin's
  131. * files are updated without database changes.
  132. *
  133. * @return string
  134. */
  135. public function getInstalledVersion()
  136. {
  137. return $this->getState()->version;
  138. }
  139. /**
  140. * Returns dependencies of the plugin.
  141. *
  142. * @return array Dependencies list. See
  143. * {@link \Mibew\Plugin\PluginInterface::getDependencies()} for details of
  144. * the array structure.
  145. */
  146. public function getDependencies()
  147. {
  148. return call_user_func(array($this->getClass(), 'getDependencies'));
  149. }
  150. /**
  151. * Returns system requirements of the plugin.
  152. *
  153. * @return array Requirements list. See
  154. * {@link \Mibew\Plugin\PluginInterface::getSystemRequirements()} for
  155. * details of the array structure.
  156. */
  157. public function getSystemRequirements()
  158. {
  159. return call_user_func(array($this->getClass(), 'getSystemRequirements'));
  160. }
  161. /**
  162. * Returns list of dependent plugins.
  163. *
  164. * @return array List of plugins names.
  165. */
  166. public function getDependentPlugins()
  167. {
  168. $dependent_plugins = array();
  169. foreach (Utils::discoverPlugins() as $plugin_name) {
  170. $plugin = new PluginInfo($plugin_name);
  171. if (array_key_exists($this->getName(), $plugin->getDependencies())) {
  172. $dependent_plugins[] = $plugin_name;
  173. }
  174. }
  175. return $dependent_plugins;
  176. }
  177. /**
  178. * Creates an instance of the plugin.
  179. *
  180. * @param array $configs Configurations array that will be passed to
  181. * plugin's constructor.
  182. * @return \Mibew\Plugin\PluginInterface
  183. */
  184. public function getInstance($configs = array())
  185. {
  186. $plugin_class = $this->getClass();
  187. return new $plugin_class($configs);
  188. }
  189. /**
  190. * Checks if the plugin is enabled.
  191. *
  192. * @return bool
  193. */
  194. public function isEnabled()
  195. {
  196. return $this->getState()->enabled;
  197. }
  198. /**
  199. * Checks if the plugin is installed.
  200. *
  201. * @return bool
  202. */
  203. public function isInstalled()
  204. {
  205. return $this->getState()->installed;
  206. }
  207. /**
  208. * Checks if the plugin needs to be updated.
  209. *
  210. * @return bool
  211. */
  212. public function needsUpdate()
  213. {
  214. return $this->isInstalled()
  215. && (version_compare($this->getVersion(), $this->getInstalledVersion()) > 0);
  216. }
  217. /**
  218. * Checks if the plugin has unsatisfied system requirements.
  219. *
  220. * @return bool
  221. */
  222. public function hasUnsatisfiedSystemRequirements()
  223. {
  224. $system_info = Utils::getSystemInfo();
  225. foreach ($this->getSystemRequirements() as $lib => $required_version) {
  226. // Check if the library exists
  227. if (!isset($system_info[$lib])) {
  228. return true;
  229. }
  230. // Check exact version of the library
  231. $version_constrain = new VersionExpression($required_version);
  232. if (!$version_constrain->satisfiedBy(new Version($system_info[$lib]))) {
  233. return true;
  234. }
  235. }
  236. return false;
  237. }
  238. /**
  239. * Checks if the plugin can be enabled.
  240. *
  241. * @return boolean
  242. */
  243. public function canBeEnabled()
  244. {
  245. if ($this->isEnabled()) {
  246. // The plugin cannot be enabled twice
  247. return false;
  248. }
  249. if ($this->hasUnsatisfiedSystemRequirements()) {
  250. return false;
  251. }
  252. // Make sure all plugin's dependencies exist, are enabled and have
  253. // appropriate versions
  254. foreach ($this->getDependencies() as $plugin_name => $required_version) {
  255. if (!Utils::pluginExists($plugin_name)) {
  256. return false;
  257. }
  258. $plugin = new PluginInfo($plugin_name);
  259. if (!$plugin->isInstalled() || !$plugin->isEnabled()) {
  260. return false;
  261. }
  262. $version_constrain = new VersionExpression($required_version);
  263. if (!$version_constrain->satisfiedBy(new Version($plugin->getInstalledVersion()))) {
  264. return false;
  265. }
  266. }
  267. return true;
  268. }
  269. /**
  270. * Checks if the plugin can be disabled.
  271. *
  272. * @return boolean
  273. */
  274. public function canBeDisabled()
  275. {
  276. if (!$this->isEnabled()) {
  277. // The plugin was not enabled thus it cannot be disabled
  278. return false;
  279. }
  280. // Make sure that the plugin has no enabled dependent plugins.
  281. foreach ($this->getDependentPlugins() as $plugin_name) {
  282. $plugin = new PluginInfo($plugin_name);
  283. if ($plugin->isEnabled()) {
  284. return false;
  285. }
  286. }
  287. return true;
  288. }
  289. /**
  290. * Checks if the plugin can be uninstalled.
  291. *
  292. * @return boolean
  293. */
  294. public function canBeUninstalled()
  295. {
  296. if ($this->isEnabled()) {
  297. // Enabled plugin cannot be uninstalled
  298. return false;
  299. }
  300. // Make sure that the plugin has no installed dependent plugins.
  301. foreach ($this->getDependentPlugins() as $plugin_name) {
  302. $plugin = new PluginInfo($plugin_name);
  303. if ($plugin->isInstalled()) {
  304. return false;
  305. }
  306. }
  307. return true;
  308. }
  309. /**
  310. * Checks if the plugin can be updated.
  311. *
  312. * @return boolean
  313. */
  314. public function canBeUpdated()
  315. {
  316. if (!$this->needsUpdate()) {
  317. return false;
  318. }
  319. foreach (array_keys($this->getDependencies()) as $dependency_name) {
  320. $dependency = new PluginInfo($dependency_name);
  321. if ($dependency->needsUpdate()) {
  322. return false;
  323. }
  324. }
  325. return true;
  326. }
  327. /**
  328. * Creates plugin info object based on a state object.
  329. *
  330. * @param State $state A state of the plugin.
  331. * @return PluginInfo
  332. */
  333. public static function fromState(State $state)
  334. {
  335. $info = new self($state->pluginName);
  336. $info->pluginState = $state;
  337. return $info;
  338. }
  339. }