From: Coleman Watts Date: Mon, 1 Nov 2021 17:27:51 +0000 (-0400) Subject: Afform - Provide `base_module` calculated field to APIv4 Afform.get X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=dc36dc4db7d6a45764664499411a6c421a3c6ff2;p=civicrm-core.git Afform - Provide `base_module` calculated field to APIv4 Afform.get This extra Afform field mirrors the functionality of the field of the same name from ManagedEntity APIv4 trait: it returns the name of the extension in which an Afform is packaged. --- diff --git a/CRM/Extension/Mapper.php b/CRM/Extension/Mapper.php index 3e0c9dd14e..dd989c8413 100644 --- a/CRM/Extension/Mapper.php +++ b/CRM/Extension/Mapper.php @@ -480,8 +480,7 @@ class CRM_Extension_Mapper { /** * Get a list of all installed modules, including enabled and disabled ones * - * @return array - * CRM_Core_Module + * @return CRM_Core_Module[] */ public function getModules() { $result = []; diff --git a/Civi/Api4/Generic/BasicGetAction.php b/Civi/Api4/Generic/BasicGetAction.php index 1f784cc6b9..5c615968cd 100644 --- a/Civi/Api4/Generic/BasicGetAction.php +++ b/Civi/Api4/Generic/BasicGetAction.php @@ -107,6 +107,7 @@ class BasicGetAction extends AbstractGetAction { $fields = $this->entityFields(); foreach ($records as &$values) { foreach ($this->entityFields() as $field) { + $values += [$field['name'] => NULL]; if (!empty($field['options'])) { foreach (FormattingUtil::$pseudoConstantSuffixes as $suffix) { $pseudofield = $field['name'] . ':' . $suffix; diff --git a/ext/afform/core/CRM/Afform/AfformScanner.php b/ext/afform/core/CRM/Afform/AfformScanner.php index f7a7125f4b..8d02738fe7 100644 --- a/ext/afform/core/CRM/Afform/AfformScanner.php +++ b/ext/afform/core/CRM/Afform/AfformScanner.php @@ -49,10 +49,9 @@ class CRM_Afform_AfformScanner { $mapper = CRM_Extension_System::singleton()->getMapper(); foreach ($mapper->getModules() as $module) { - /** @var $module CRM_Core_Module */ try { if ($module->is_active) { - $this->appendFilePaths($paths, dirname($mapper->keyToPath($module->name)) . DIRECTORY_SEPARATOR . 'ang', 20); + $this->appendFilePaths($paths, dirname($mapper->keyToPath($module->name)) . DIRECTORY_SEPARATOR . 'ang', $module->name); } } catch (CRM_Extension_Exception_MissingException $e) { @@ -60,7 +59,7 @@ class CRM_Afform_AfformScanner { } } - $this->appendFilePaths($paths, $this->getSiteLocalPath(), 10); + $this->appendFilePaths($paths, $this->getSiteLocalPath(), ''); $this->cache->set('afformAllPaths', $paths); return $paths; @@ -157,23 +156,19 @@ class CRM_Afform_AfformScanner { } /** - * Adds has_local & has_base to an afform metadata record + * Adds base_module, has_local & has_base to an afform metadata record * * @param array $record */ public function addComputedFields(&$record) { $name = $record['name']; - // Ex: $allPaths['viewIndividual'][0] == '/var/www/foo/afform/view-individual']. + // Ex: $allPaths['viewIndividual']['org.civicrm.foo'] == '/var/www/foo/afform/view-individual']. $allPaths = $this->findFilePaths()[$name] ?? []; - // $activeLayoutPath = $this->findFilePath($name, self::LAYOUT_FILE); - // $activeMetaPath = $this->findFilePath($name, self::METADATA_FILE); - $localLayoutPath = $this->createSiteLocalPath($name, self::LAYOUT_FILE); - $localMetaPath = $this->createSiteLocalPath($name, self::METADATA_FILE); - - $record['has_local'] = file_exists($localLayoutPath) || file_exists($localMetaPath); + // Empty string key refers to the site local path + $record['has_local'] = isset($allPaths['']); if (!isset($record['has_base'])) { - $record['has_base'] = ($record['has_local'] && count($allPaths) > 1) - || (!$record['has_local'] && count($allPaths) > 0); + $record['base_module'] = \CRM_Utils_Array::first(array_filter(array_keys($allPaths))); + $record['has_base'] = !empty($record['base_module']); } } @@ -211,16 +206,17 @@ class CRM_Afform_AfformScanner { * Ex: ['foo' => [0 => '/var/www/org.example.foobar/ang']] * @param string $parent * Ex: '/var/www/org.example.foobar/afform/' - * @param int $priority - * Lower priority files override higher priority files. + * @param string $module + * Name of module or '' empty string for local files. */ - private function appendFilePaths(&$formPaths, $parent, $priority) { + private function appendFilePaths(&$formPaths, $parent, $module) { $files = preg_grep(self::FILE_REGEXP, (array) glob("$parent/*")); foreach ($files as $file) { $fileBase = preg_replace(self::FILE_REGEXP, '', $file); $name = basename($fileBase); - $formPaths[$name][$priority] = $fileBase; + $formPaths[$name][$module] = $fileBase; + // Local files get top priority ksort($formPaths[$name]); } } diff --git a/ext/afform/core/Civi/Api4/Action/Afform/Get.php b/ext/afform/core/Civi/Api4/Action/Afform/Get.php index 629083e655..cfd32556cf 100644 --- a/ext/afform/core/Civi/Api4/Action/Afform/Get.php +++ b/ext/afform/core/Civi/Api4/Action/Afform/Get.php @@ -17,7 +17,7 @@ class Get extends \Civi\Api4\Generic\BasicGetAction { public function getRecords() { /** @var \CRM_Afform_AfformScanner $scanner */ $scanner = \Civi::service('afform_scanner'); - $getComputed = $this->_isFieldSelected('has_local', 'has_base'); + $getComputed = $this->_isFieldSelected('has_local', 'has_base', 'base_module'); $getLayout = $this->_isFieldSelected('layout'); $getSearchDisplays = $this->_isFieldSelected('search_displays'); $values = []; diff --git a/ext/afform/core/Civi/Api4/Afform.php b/ext/afform/core/Civi/Api4/Afform.php index 4e5f0c977f..c1f481e20d 100644 --- a/ext/afform/core/Civi/Api4/Afform.php +++ b/ext/afform/core/Civi/Api4/Afform.php @@ -3,6 +3,7 @@ namespace Civi\Api4; use Civi\Api4\Generic\BasicBatchAction; +use Civi\Api4\Generic\BasicGetFieldsAction; /** * User-configurable forms. @@ -138,7 +139,7 @@ class Afform extends Generic\AbstractEntity { * @return Generic\BasicGetFieldsAction */ public static function getFields($checkPermissions = TRUE) { - return (new Generic\BasicGetFieldsAction('Afform', __FUNCTION__, function($self) { + return (new Generic\BasicGetFieldsAction('Afform', __FUNCTION__, function(BasicGetFieldsAction $self) { $fields = [ [ 'name' => 'name', @@ -222,14 +223,24 @@ class Afform extends Generic\AbstractEntity { 'name' => 'has_local', 'type' => 'Extra', 'data_type' => 'Boolean', + 'description' => 'Whether a local copy is saved on site', 'readonly' => TRUE, ]; $fields[] = [ 'name' => 'has_base', 'type' => 'Extra', 'data_type' => 'Boolean', + 'description' => 'Is provided by an extension', 'readonly' => TRUE, ]; + $fields[] = [ + 'name' => 'base_module', + 'type' => 'Extra', + 'data_type' => 'String', + 'description' => 'Name of extension which provides this form', + 'readonly' => TRUE, + 'options' => $self->getLoadOptions() ? \CRM_Core_PseudoConstant::getExtensions() : TRUE, + ]; $fields[] = [ 'name' => 'search_displays', 'type' => 'Extra', diff --git a/ext/afform/core/tests/phpunit/Civi/Afform/AfformGetTest.php b/ext/afform/core/tests/phpunit/Civi/Afform/AfformGetTest.php index b8d0f9d8b0..8be0dc3fb1 100644 --- a/ext/afform/core/tests/phpunit/Civi/Afform/AfformGetTest.php +++ b/ext/afform/core/tests/phpunit/Civi/Afform/AfformGetTest.php @@ -52,6 +52,7 @@ class AfformGetTest extends \PHPUnit\Framework\TestCase implements HeadlessInter $this->assertEquals($this->formName, $result['name']); $this->assertFalse($result['has_base']); $this->assertArrayNotHasKey('has_local', $result); + $this->assertArrayNotHasKey('base_module', $result); } public function testGetSearchDisplays() { diff --git a/ext/afform/mock/tests/phpunit/api/v4/AfformTest.php b/ext/afform/mock/tests/phpunit/api/v4/AfformTest.php index ffb62766f8..af4854f74e 100644 --- a/ext/afform/mock/tests/phpunit/api/v4/AfformTest.php +++ b/ext/afform/mock/tests/phpunit/api/v4/AfformTest.php @@ -54,7 +54,7 @@ class api_v4_AfformTest extends api_v4_AfformTestCase { $message = 'The initial Afform.get should return default data'; $result = Civi\Api4\Afform::get() - ->addSelect('*', 'has_base', 'has_local') + ->addSelect('*', 'has_base', 'has_local', 'base_module') ->addWhere('name', '=', $formName)->execute(); $this->assertEquals($formName, $result[0]['name'], $message); $this->assertEquals($get($originalMetadata, 'title'), $get($result[0], 'title'), $message); @@ -65,6 +65,7 @@ class api_v4_AfformTest extends api_v4_AfformTestCase { $this->assertTrue(is_array($result[0]['layout']), $message); $this->assertEquals(TRUE, $get($result[0], 'has_base'), $message); $this->assertEquals(FALSE, $get($result[0], 'has_local'), $message); + $this->assertEquals('org.civicrm.afform-mock', $get($result[0], 'base_module'), $message); $message = 'After updating with Afform.create, the revised data should be returned'; $result = Civi\Api4\Afform::update() @@ -78,7 +79,7 @@ class api_v4_AfformTest extends api_v4_AfformTestCase { $message = 'After updating, the Afform.get API should return blended data'; $result = Civi\Api4\Afform::get() - ->addSelect('*', 'has_base', 'has_local') + ->addSelect('*', 'has_base', 'has_local', 'base_module') ->addWhere('name', '=', $formName)->execute(); $this->assertEquals($formName, $result[0]['name'], $message); $this->assertEquals($get($originalMetadata, 'title'), $get($result[0], 'title'), $message); @@ -89,11 +90,12 @@ class api_v4_AfformTest extends api_v4_AfformTestCase { $this->assertTrue(is_array($result[0]['layout']), $message); $this->assertEquals(TRUE, $get($result[0], 'has_base'), $message); $this->assertEquals(TRUE, $get($result[0], 'has_local'), $message); + $this->assertEquals('org.civicrm.afform-mock', $get($result[0], 'base_module'), $message); Civi\Api4\Afform::revert()->addWhere('name', '=', $formName)->execute(); $message = 'After reverting, the final Afform.get should return default data'; $result = Civi\Api4\Afform::get() - ->addSelect('*', 'has_base', 'has_local') + ->addSelect('*', 'has_base', 'has_local', 'base_module') ->addWhere('name', '=', $formName)->execute(); $this->assertEquals($formName, $result[0]['name'], $message); $this->assertEquals($get($originalMetadata, 'title'), $get($result[0], 'title'), $message); @@ -103,6 +105,7 @@ class api_v4_AfformTest extends api_v4_AfformTestCase { $this->assertTrue(is_array($result[0]['layout']), $message); $this->assertEquals(TRUE, $get($result[0], 'has_base'), $message); $this->assertEquals(FALSE, $get($result[0], 'has_local'), $message); + $this->assertEquals('org.civicrm.afform-mock', $get($result[0], 'base_module'), $message); } public function getFormatExamples() { diff --git a/tests/phpunit/api/v4/Action/BasicActionsTest.php b/tests/phpunit/api/v4/Action/BasicActionsTest.php index 53edd99f55..d67a61598c 100644 --- a/tests/phpunit/api/v4/Action/BasicActionsTest.php +++ b/tests/phpunit/api/v4/Action/BasicActionsTest.php @@ -279,7 +279,7 @@ class BasicActionsTest extends UnitTestCase implements HookInterface { foreach (MockBasicEntity::get()->addSelect('*')->execute() as $result) { ksort($result); - $this->assertEquals(['color', 'group', 'identifier', 'shape', 'size', 'weight'], array_keys($result)); + $this->assertEquals(['color', 'foo', 'fruit', 'group', 'identifier', 'shape', 'size', 'weight'], array_keys($result)); } $result = MockBasicEntity::get() diff --git a/tests/phpunit/api/v4/Action/GetFromArrayTest.php b/tests/phpunit/api/v4/Action/GetFromArrayTest.php index c41b100203..7b6f802a25 100644 --- a/tests/phpunit/api/v4/Action/GetFromArrayTest.php +++ b/tests/phpunit/api/v4/Action/GetFromArrayTest.php @@ -76,6 +76,7 @@ class GetFromArrayTest extends UnitTestCase { ], [ 'field1' => 3, + 'field3' => NULL, ], [ 'field1' => 4,