From 9bb46670bd3f1acd3b078cf2fd73925b5d94ed35 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Fri, 14 Feb 2020 17:24:40 -0800 Subject: [PATCH] info.xml - Allow extensions to define a list of tags Overview -------- This adopts a convention by which extensions may use `info.xml` to register tags, e.g. ```xml civicontribute payment-processor install-mandatory ``` Before ------ To add *any* metadata to `info.xml` files, you must update the parser and providing filtering/indexing. After ----- If you need to add very simple metadata (tags), you can do that without extra parsing code. The tag information can be accessed in the following ways: * Using the extension mapper ```php $mapper = CRM_Extension_System::singleton()->getMapper(); $allTags = $mapper->getAllTags(); $mandatoryExts = $mapper->getKeysByTag('install-mandatory'); ``` * The `Extension.get` API will return the list of tags for each ext --- CRM/Extension/Info.php | 12 +++++++ CRM/Extension/Mapper.php | 36 +++++++++++++++++++ .../info.xml | 3 ++ .../info.xml | 3 ++ tests/phpunit/CRM/Extension/MapperTest.php | 7 +++- tests/phpunit/api/v3/ExtensionTest.php | 4 ++- 6 files changed, 63 insertions(+), 2 deletions(-) diff --git a/CRM/Extension/Info.php b/CRM/Extension/Info.php index fddd975f49..43e185d326 100644 --- a/CRM/Extension/Info.php +++ b/CRM/Extension/Info.php @@ -44,6 +44,12 @@ class CRM_Extension_Info { */ public $requires = []; + /** + * @var array + * List of strings (tag-names). + */ + public $tags = []; + /** * Load extension info an XML file. * @@ -155,6 +161,12 @@ class CRM_Extension_Info { ]; } } + elseif ($attr === 'tags') { + $this->tags = []; + foreach ($val->tag as $tag) { + $this->tags[] = (string) $tag; + } + } elseif ($attr === 'requires') { $this->requires = $this->filterRequirements($val); } diff --git a/CRM/Extension/Mapper.php b/CRM/Extension/Mapper.php index 43426192cd..e38b20821e 100644 --- a/CRM/Extension/Mapper.php +++ b/CRM/Extension/Mapper.php @@ -388,6 +388,42 @@ class CRM_Extension_Mapper { return $keys; } + /** + * Get a list of extensions which match a given tag. + * + * @param string $tag + * Ex: 'foo' + * @return array + * Array(string $key). + * Ex: array("org.foo.bar"). + */ + public function getKeysByTag($tag) { + $allTags = $this->getAllTags(); + return $allTags[$tag] ?? []; + } + + /** + * Get a list of extension tags. + * + * @return array + * Ex: ['form-building' => ['org.civicrm.afform-gui', 'org.civicrm.afform-html']] + */ + public function getAllTags() { + $tags = Civi::cache('short')->get('extension_tags', NULL); + if ($tags !== NULL) { + return $tags; + } + + $tags = []; + $allInfos = $this->getAllInfos(); + foreach ($allInfos as $key => $info) { + foreach ($info->tags as $tag) { + $tags[$tag][] = $key; + } + } + return $tags; + } + /** * @return array * Ex: $result['org.civicrm.foobar'] = new CRM_Extension_Info(...). diff --git a/tests/extensions/test.extension.manager.moduletest/info.xml b/tests/extensions/test.extension.manager.moduletest/info.xml index 67b31e2e67..c8c5f8d008 100644 --- a/tests/extensions/test.extension.manager.moduletest/info.xml +++ b/tests/extensions/test.extension.manager.moduletest/info.xml @@ -1,4 +1,7 @@ moduletest test_extension_manager_moduletest + + mock + diff --git a/tests/extensions/test.extension.manager.paymenttest/info.xml b/tests/extensions/test.extension.manager.paymenttest/info.xml index 9e91db0e18..eb93e27054 100644 --- a/tests/extensions/test.extension.manager.paymenttest/info.xml +++ b/tests/extensions/test.extension.manager.paymenttest/info.xml @@ -19,4 +19,7 @@ 0 1 + + mock + diff --git a/tests/phpunit/CRM/Extension/MapperTest.php b/tests/phpunit/CRM/Extension/MapperTest.php index bbe4aeed1e..da9ba2c61e 100644 --- a/tests/phpunit/CRM/Extension/MapperTest.php +++ b/tests/phpunit/CRM/Extension/MapperTest.php @@ -124,6 +124,11 @@ class CRM_Extension_MapperTest extends CiviUnitTestCase { } } + public function testGetKeysByTag() { + $this->assertEquals([], $this->mapper->getKeysByTag('big-rock-candy-mountain')); + $this->assertEquals(['test.foo.bar'], $this->mapper->getKeysByTag('wakka')); + } + /** * @param CRM_Utils_Cache_Interface $cache * @param null $cacheKey @@ -143,7 +148,7 @@ class CRM_Extension_MapperTest extends CiviUnitTestCase { $basedir = rtrim($this->createTempDir('ext-'), '/'); mkdir("$basedir/weird"); mkdir("$basedir/weird/foobar"); - file_put_contents("$basedir/weird/foobar/info.xml", "oddball"); + file_put_contents("$basedir/weird/foobar/info.xml", "oddballwakka"); // not needed for now // file_put_contents("$basedir/weird/bar/oddball.php", "callAPISuccess('extension', 'get', ['options' => ['limit' => 0]]); $testExtensionResult = $this->callAPISuccess('extension', 'get', ['key' => 'test.extension.manager.paymenttest']); - $this->assertNotNull($result['values'][$testExtensionResult['id']]['typeInfo']); + $ext = $result['values'][$testExtensionResult['id']]; + $this->assertNotNull($ext['typeInfo']); + $this->assertEquals(['mock'], $ext['tags']); $this->assertTrue($result['count'] >= 6); } -- 2.25.1