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 strings (tag-names).
56 * Ex: [0 => ['name' => 'Alice', 'email' => 'a@b', 'homepage' => 'https://example.com', 'role' => 'Person']]
62 * The current maintainer at time of publication.
63 * This is deprecated in favor of $authors.
66 public $maintainer = NULL;
69 * Load extension info an XML file.
73 * @throws CRM_Extension_Exception_ParseException
74 * @return CRM_Extension_Info
76 public static function loadFromFile($file) {
77 list ($xml, $error) = CRM_Utils_XML
::parseFile($file);
79 throw new CRM_Extension_Exception_ParseException("Failed to parse info XML: $error");
82 $instance = new CRM_Extension_Info();
83 $instance->parse($xml);
88 * Load extension info a string.
90 * @param string $string
93 * @throws CRM_Extension_Exception_ParseException
94 * @return CRM_Extension_Info
96 public static function loadFromString($string) {
97 list ($xml, $error) = CRM_Utils_XML
::parseString($string);
99 throw new CRM_Extension_Exception_ParseException("Failed to parse info XML: $string");
102 $instance = new CRM_Extension_Info();
103 $instance->parse($xml);
108 * Build a reverse-dependency map.
110 * @param array $infos
111 * The universe of available extensions.
112 * Ex: $infos['org.civicrm.foobar'] = new CRM_Extension_Info().
114 * If "org.civicrm.api" is required by "org.civicrm.foo", then return
115 * array('org.civicrm.api' => array(CRM_Extension_Info[org.civicrm.foo])).
116 * Array(string $key => array $requiredBys).
118 public static function buildReverseMap($infos) {
120 foreach ($infos as $info) {
121 foreach ($info->requires
as $key) {
122 $revMap[$key][] = $info;
135 public function __construct($key = NULL, $type = NULL, $name = NULL, $label = NULL, $file = NULL) {
139 $this->label
= $label;
144 * Copy attributes from an XML document to $this
146 * @param SimpleXMLElement $info
148 public function parse($info) {
149 $this->key
= (string) $info->attributes()->key
;
150 $this->type
= (string) $info->attributes()->type
;
151 $this->file
= (string) $info->file
;
152 $this->label
= (string) $info->name
;
154 // Convert first level variables to CRM_Core_Extension properties
155 // and deeper into arrays. An exception for URLS section, since
156 // we want them in special format.
157 foreach ($info as $attr => $val) {
158 if (count($val->children()) == 0) {
159 $this->$attr = (string) $val;
161 elseif ($attr === 'urls') {
163 foreach ($val->url
as $url) {
164 $urlAttr = (string) $url->attributes()->desc
;
165 $this->urls
[$urlAttr] = (string) $url;
169 elseif ($attr === 'classloader') {
170 $this->classloader
= [];
171 foreach ($val->psr4
as $psr4) {
172 $this->classloader
[] = [
174 'prefix' => (string) $psr4->attributes()->prefix
,
175 'path' => (string) $psr4->attributes()->path
,
178 foreach ($val->psr0
as $psr0) {
179 $this->classloader
[] = [
181 'prefix' => (string) $psr0->attributes()->prefix
,
182 'path' => (string) $psr0->attributes()->path
,
186 elseif ($attr === 'tags') {
188 foreach ($val->tag
as $tag) {
189 $this->tags
[] = (string) $tag;
192 elseif ($attr === 'requires') {
193 $this->requires
= $this->filterRequirements($val);
195 elseif ($attr === 'maintainer') {
196 $this->maintainer
= CRM_Utils_XML
::xmlObjToArray($val);
198 'name' => (string) $val->author
,
199 'email' => (string) $val->email
,
200 'role' => 'Maintainer',
203 elseif ($attr === 'authors') {
204 foreach ($val->author
as $author) {
205 $this->authors
[] = $thisAuthor = CRM_Utils_XML
::xmlObjToArray($author);
206 if ('maintainer' === strtolower($thisAuthor['role'] ??
'')) {
207 $this->maintainer
= ['author' => $thisAuthor['name'], 'email' => $thisAuthor['email'] ??
NULL];
212 $this->$attr = CRM_Utils_XML
::xmlObjToArray($val);
218 * Filter out invalid requirements, e.g. extensions that have been moved to core.
220 * @param SimpleXMLElement $requirements
223 public function filterRequirements($requirements) {
225 $compatInfo = CRM_Extension_System
::getCompatibilityInfo();
226 foreach ($requirements->ext
as $ext) {
227 $ext = (string) $ext;
228 if (empty($compatInfo[$ext]['obsolete'])) {