PageRenderTime 39ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/civicrm/CRM/Extension/Info.php

https://github.com/nysenate/Bluebird-CRM
PHP | 256 lines | 132 code | 20 blank | 104 comment | 7 complexity | 7dc495db6aa907d237ef81a98a8f3017 MD5 | raw file
Possible License(s): JSON, BSD-3-Clause, MPL-2.0-no-copyleft-exception, AGPL-1.0, GPL-2.0, AGPL-3.0, Apache-2.0, MIT, GPL-3.0, CC-BY-4.0, LGPL-2.1, BSD-2-Clause, LGPL-3.0
  1. <?php
  2. /*
  3. +--------------------------------------------------------------------+
  4. | Copyright CiviCRM LLC. All rights reserved. |
  5. | |
  6. | This work is published under the GNU AGPLv3 license with some |
  7. | permitted exceptions and without any warranty. For full license |
  8. | and copyright information, see https://civicrm.org/licensing |
  9. +--------------------------------------------------------------------+
  10. */
  11. /**
  12. * Metadata for an extension (e.g. the extension's "info.xml" file)
  13. *
  14. * @package CRM
  15. * @copyright CiviCRM LLC https://civicrm.org/licensing
  16. */
  17. class CRM_Extension_Info {
  18. /**
  19. * Extension info file name.
  20. */
  21. const FILENAME = 'info.xml';
  22. /**
  23. * @var string
  24. */
  25. public $key = NULL;
  26. public $type = NULL;
  27. public $name = NULL;
  28. public $label = NULL;
  29. public $file = NULL;
  30. /**
  31. * @var array
  32. * Each item is a specification like:
  33. * array('type'=>'psr4', 'namespace'=>'Foo\Bar', 'path'=>'/foo/bar').
  34. */
  35. public $classloader = [];
  36. /**
  37. * @var array
  38. * Each item is they key-name of an extension required by this extension.
  39. */
  40. public $requires = [];
  41. /**
  42. * @var array
  43. * List of expected mixins.
  44. * Ex: ['civix@2.0.0']
  45. */
  46. public $mixins = [];
  47. /**
  48. * @var array
  49. * List of strings (tag-names).
  50. */
  51. public $tags = [];
  52. /**
  53. * @var array
  54. * List of authors.
  55. * Ex: [0 => ['name' => 'Alice', 'email' => 'a@b', 'homepage' => 'https://example.com', 'role' => 'Person']]
  56. */
  57. public $authors = [];
  58. /**
  59. * @var array|null
  60. * The current maintainer at time of publication.
  61. * This is deprecated in favor of $authors.
  62. * @deprecated
  63. */
  64. public $maintainer = NULL;
  65. /**
  66. * @var string|null
  67. * The name of a class which handles the install/upgrade lifecycle.
  68. * @see \CRM_Extension_Upgrader_Interface
  69. */
  70. public $upgrader = NULL;
  71. /**
  72. * Load extension info an XML file.
  73. *
  74. * @param $file
  75. *
  76. * @throws CRM_Extension_Exception_ParseException
  77. * @return CRM_Extension_Info
  78. */
  79. public static function loadFromFile($file) {
  80. list ($xml, $error) = CRM_Utils_XML::parseFile($file);
  81. if ($xml === FALSE) {
  82. throw new CRM_Extension_Exception_ParseException("Failed to parse info XML: $error");
  83. }
  84. $instance = new CRM_Extension_Info();
  85. $instance->parse($xml);
  86. return $instance;
  87. }
  88. /**
  89. * Load extension info a string.
  90. *
  91. * @param string $string
  92. * XML content.
  93. *
  94. * @throws CRM_Extension_Exception_ParseException
  95. * @return CRM_Extension_Info
  96. */
  97. public static function loadFromString($string) {
  98. list ($xml, $error) = CRM_Utils_XML::parseString($string);
  99. if ($xml === FALSE) {
  100. throw new CRM_Extension_Exception_ParseException("Failed to parse info XML: $string");
  101. }
  102. $instance = new CRM_Extension_Info();
  103. $instance->parse($xml);
  104. return $instance;
  105. }
  106. /**
  107. * Build a reverse-dependency map.
  108. *
  109. * @param array $infos
  110. * The universe of available extensions.
  111. * Ex: $infos['org.civicrm.foobar'] = new CRM_Extension_Info().
  112. * @return array
  113. * If "org.civicrm.api" is required by "org.civicrm.foo", then return
  114. * array('org.civicrm.api' => array(CRM_Extension_Info[org.civicrm.foo])).
  115. * Array(string $key => array $requiredBys).
  116. */
  117. public static function buildReverseMap($infos) {
  118. $revMap = [];
  119. foreach ($infos as $info) {
  120. foreach ($info->requires as $key) {
  121. $revMap[$key][] = $info;
  122. }
  123. }
  124. return $revMap;
  125. }
  126. /**
  127. * @param null $key
  128. * @param null $type
  129. * @param null $name
  130. * @param null $label
  131. * @param null $file
  132. */
  133. public function __construct($key = NULL, $type = NULL, $name = NULL, $label = NULL, $file = NULL) {
  134. $this->key = $key;
  135. $this->type = $type;
  136. $this->name = $name;
  137. $this->label = $label;
  138. $this->file = $file;
  139. }
  140. /**
  141. * Copy attributes from an XML document to $this
  142. *
  143. * @param SimpleXMLElement $info
  144. */
  145. public function parse($info) {
  146. $this->key = (string) $info->attributes()->key;
  147. $this->type = (string) $info->attributes()->type;
  148. $this->file = (string) $info->file;
  149. $this->label = (string) $info->name;
  150. $this->upgrader = (string) $info->upgrader;
  151. // Convert first level variables to CRM_Core_Extension properties
  152. // and deeper into arrays. An exception for URLS section, since
  153. // we want them in special format.
  154. foreach ($info as $attr => $val) {
  155. if (count($val->children()) == 0) {
  156. $this->$attr = trim((string) $val);
  157. }
  158. elseif ($attr === 'urls') {
  159. $this->urls = [];
  160. foreach ($val->url as $url) {
  161. $urlAttr = (string) $url->attributes()->desc;
  162. $this->urls[$urlAttr] = (string) $url;
  163. }
  164. ksort($this->urls);
  165. }
  166. elseif ($attr === 'classloader') {
  167. $this->classloader = [];
  168. foreach ($val->psr4 as $psr4) {
  169. $this->classloader[] = [
  170. 'type' => 'psr4',
  171. 'prefix' => (string) $psr4->attributes()->prefix,
  172. 'path' => (string) $psr4->attributes()->path,
  173. ];
  174. }
  175. foreach ($val->psr0 as $psr0) {
  176. $this->classloader[] = [
  177. 'type' => 'psr0',
  178. 'prefix' => (string) $psr0->attributes()->prefix,
  179. 'path' => (string) $psr0->attributes()->path,
  180. ];
  181. }
  182. }
  183. elseif ($attr === 'tags') {
  184. $this->tags = [];
  185. foreach ($val->tag as $tag) {
  186. $this->tags[] = (string) $tag;
  187. }
  188. }
  189. elseif ($attr === 'mixins') {
  190. $this->mixins = [];
  191. foreach ($val->mixin as $mixin) {
  192. $this->mixins[] = (string) $mixin;
  193. }
  194. }
  195. elseif ($attr === 'requires') {
  196. $this->requires = $this->filterRequirements($val);
  197. }
  198. elseif ($attr === 'maintainer') {
  199. $this->maintainer = CRM_Utils_XML::xmlObjToArray($val);
  200. $this->authors[] = [
  201. 'name' => (string) $val->author,
  202. 'email' => (string) $val->email,
  203. 'role' => 'Maintainer',
  204. ];
  205. }
  206. elseif ($attr === 'authors') {
  207. foreach ($val->author as $author) {
  208. $this->authors[] = $thisAuthor = CRM_Utils_XML::xmlObjToArray($author);
  209. if ('maintainer' === strtolower($thisAuthor['role'] ?? '')) {
  210. $this->maintainer = ['author' => $thisAuthor['name'], 'email' => $thisAuthor['email'] ?? NULL];
  211. }
  212. }
  213. }
  214. else {
  215. $this->$attr = CRM_Utils_XML::xmlObjToArray($val);
  216. }
  217. }
  218. }
  219. /**
  220. * Filter out invalid requirements, e.g. extensions that have been moved to core.
  221. *
  222. * @param SimpleXMLElement $requirements
  223. * @return array
  224. */
  225. public function filterRequirements($requirements) {
  226. $filtered = [];
  227. $compatInfo = CRM_Extension_System::getCompatibilityInfo();
  228. foreach ($requirements->ext as $ext) {
  229. $ext = (string) $ext;
  230. if (empty($compatInfo[$ext]['obsolete'])) {
  231. $filtered[] = $ext;
  232. }
  233. }
  234. return $filtered;
  235. }
  236. }