2f14314c078bb685890b78b02e05476cb7ec5fd9
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 +--------------------------------------------------------------------+
13 * Metadata for an extension (e.g. the extension's "info.xml" file)
16 * @copyright CiviCRM LLC https://civicrm.org/licensing
18 class CRM_Extension_Info
{
21 * Extension info file name.
23 const FILENAME
= 'info.xml';
36 * Each item is a specification like:
37 * array('type'=>'psr4', 'namespace'=>'Foo\Bar', 'path'=>'/foo/bar').
39 public $classloader = [];
43 * Each item is they key-name of an extension required by this extension.
45 public $requires = [];
49 * List of expected mixins.
56 * List of strings (tag-names).
63 * Ex: [0 => ['name' => 'Alice', 'email' => 'a@b', 'homepage' => 'https://example.com', 'role' => 'Person']]
69 * The current maintainer at time of publication.
70 * This is deprecated in favor of $authors.
73 public $maintainer = NULL;
77 * The name of a class which handles the install/upgrade lifecycle.
78 * @see \CRM_Extension_Upgrader_Interface
80 public $upgrader = NULL;
83 * Load extension info an XML file.
87 * @throws CRM_Extension_Exception_ParseException
88 * @return CRM_Extension_Info
90 public static function loadFromFile($file) {
91 list ($xml, $error) = CRM_Utils_XML
::parseFile($file);
93 throw new CRM_Extension_Exception_ParseException("Failed to parse info XML: $error");
96 $instance = new CRM_Extension_Info();
97 $instance->parse($xml);
102 * Load extension info a string.
104 * @param string $string
107 * @throws CRM_Extension_Exception_ParseException
108 * @return CRM_Extension_Info
110 public static function loadFromString($string) {
111 list ($xml, $error) = CRM_Utils_XML
::parseString($string);
112 if ($xml === FALSE) {
113 throw new CRM_Extension_Exception_ParseException("Failed to parse info XML: $string");
116 $instance = new CRM_Extension_Info();
117 $instance->parse($xml);
122 * Build a reverse-dependency map.
124 * @param array $infos
125 * The universe of available extensions.
126 * Ex: $infos['org.civicrm.foobar'] = new CRM_Extension_Info().
128 * If "org.civicrm.api" is required by "org.civicrm.foo", then return
129 * array('org.civicrm.api' => array(CRM_Extension_Info[org.civicrm.foo])).
130 * Array(string $key => array $requiredBys).
132 public static function buildReverseMap($infos) {
134 foreach ($infos as $info) {
135 foreach ($info->requires
as $key) {
136 $revMap[$key][] = $info;
149 public function __construct($key = NULL, $type = NULL, $name = NULL, $label = NULL, $file = NULL) {
153 $this->label
= $label;
158 * Copy attributes from an XML document to $this
160 * @param SimpleXMLElement $info
162 public function parse($info) {
163 $this->key
= (string) $info->attributes()->key
;
164 $this->type
= (string) $info->attributes()->type
;
165 $this->file
= (string) $info->file
;
166 $this->label
= (string) $info->name
;
167 $this->upgrader
= (string) $info->upgrader
;
169 // Convert first level variables to CRM_Core_Extension properties
170 // and deeper into arrays. An exception for URLS section, since
171 // we want them in special format.
172 foreach ($info as $attr => $val) {
173 if (count($val->children()) == 0) {
174 $this->$attr = trim((string) $val);
176 elseif ($attr === 'urls') {
178 foreach ($val->url
as $url) {
179 $urlAttr = (string) $url->attributes()->desc
;
180 $this->urls
[$urlAttr] = (string) $url;
184 elseif ($attr === 'classloader') {
185 $this->classloader
= [];
186 foreach ($val->psr4
as $psr4) {
187 $this->classloader
[] = [
189 'prefix' => (string) $psr4->attributes()->prefix
,
190 'path' => (string) $psr4->attributes()->path
,
193 foreach ($val->psr0
as $psr0) {
194 $this->classloader
[] = [
196 'prefix' => (string) $psr0->attributes()->prefix
,
197 'path' => (string) $psr0->attributes()->path
,
201 elseif ($attr === 'tags') {
203 foreach ($val->tag
as $tag) {
204 $this->tags
[] = (string) $tag;
207 elseif ($attr === 'mixins') {
209 foreach ($val->mixin
as $mixin) {
210 $this->mixins
[] = (string) $mixin;
213 elseif ($attr === 'requires') {
214 $this->requires
= $this->filterRequirements($val);
216 elseif ($attr === 'maintainer') {
217 $this->maintainer
= CRM_Utils_XML
::xmlObjToArray($val);
219 'name' => (string) $val->author
,
220 'email' => (string) $val->email
,
221 'role' => 'Maintainer',
224 elseif ($attr === 'authors') {
225 foreach ($val->author
as $author) {
226 $this->authors
[] = $thisAuthor = CRM_Utils_XML
::xmlObjToArray($author);
227 if ('maintainer' === strtolower($thisAuthor['role'] ??
'')) {
228 $this->maintainer
= ['author' => $thisAuthor['name'], 'email' => $thisAuthor['email'] ??
NULL];
233 $this->$attr = CRM_Utils_XML
::xmlObjToArray($val);
239 * Filter out invalid requirements, e.g. extensions that have been moved to core.
241 * @param SimpleXMLElement $requirements
244 public function filterRequirements($requirements) {
246 $compatInfo = CRM_Extension_System
::getCompatibilityInfo();
247 foreach ($requirements->ext
as $ext) {
248 $ext = (string) $ext;
249 if (empty($compatInfo[$ext]['obsolete'])) {