From 9c84a124cd89491309eb3b458b0f85393b0d7d33 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Fri, 20 Dec 2019 15:47:02 -0500 Subject: [PATCH] Implement afform blocks for multi-value custom groups --- ext/afform/core/CRM/Afform/AfformScanner.php | 18 ++-- .../core/Civi/Api4/Action/Afform/Get.php | 98 +++++++++++++++++-- ext/afform/core/afform.php | 14 ++- .../tests/phpunit/CRM/Afform/UtilTest.php | 7 ++ 4 files changed, 117 insertions(+), 20 deletions(-) diff --git a/ext/afform/core/CRM/Afform/AfformScanner.php b/ext/afform/core/CRM/Afform/AfformScanner.php index ce7b96c6dc..4ee84cbda4 100644 --- a/ext/afform/core/CRM/Afform/AfformScanner.php +++ b/ext/afform/core/CRM/Afform/AfformScanner.php @@ -148,7 +148,13 @@ class CRM_Afform_AfformScanner { } } - public function getComputedFields($name) { + /** + * Adds 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']. $allPaths = $this->findFilePaths()[$name]; // $activeLayoutPath = $this->findFilePath($name, self::LAYOUT_FILE); @@ -156,11 +162,11 @@ class CRM_Afform_AfformScanner { $localLayoutPath = $this->createSiteLocalPath($name, self::LAYOUT_FILE); $localMetaPath = $this->createSiteLocalPath($name, self::METADATA_FILE); - $fields = []; - $fields['has_local'] = file_exists($localLayoutPath) || file_exists($localMetaPath); - $fields['has_base'] = ($fields['has_local'] && count($allPaths) > 1) - || (!$fields['has_local'] && count($allPaths) > 0); - return $fields; + $record['has_local'] = file_exists($localLayoutPath) || file_exists($localMetaPath); + if (!isset($record['has_base'])) { + $record['has_base'] = ($record['has_local'] && count($allPaths) > 1) + || (!$record['has_local'] && count($allPaths) > 0); + } } /** diff --git a/ext/afform/core/Civi/Api4/Action/Afform/Get.php b/ext/afform/core/Civi/Api4/Action/Afform/Get.php index a752f5a8c1..65b56ba5f1 100644 --- a/ext/afform/core/Civi/Api4/Action/Afform/Get.php +++ b/ext/afform/core/Civi/Api4/Action/Afform/Get.php @@ -2,6 +2,9 @@ namespace Civi\Api4\Action\Afform; +use Civi\Api4\CustomField; +use Civi\Api4\CustomGroup; + /** * @inheritDoc * @package Civi\Api4\Action\Afform @@ -13,23 +16,100 @@ 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') || $this->_isFieldSelected('has_base'); + $getLayout = $this->_isFieldSelected('layout'); + + $toGet = $this->_itemsToGet('name'); + $names = $toGet ?? array_keys($scanner->findFilePaths()); - $names = $this->_itemsToGet('name') ?? array_keys($scanner->findFilePaths()); + $values = $this->getAutoGenerated($names, $toGet, $getLayout); - $values = []; foreach ($names as $name) { $record = $scanner->getMeta($name); - if ($record && ($this->_isFieldSelected('has_local') || $this->_isFieldSelected('has_base'))) { - $record = array_merge($record, $scanner->getComputedFields($name)); + if (!$record && !isset($values[$name])) { + continue; + } + $values[$name] = array_merge($values[$name] ?? [], $record ?? []); + if ($getComputed) { + $scanner->addComputedFields($values[$name]); } - $layout = $this->_isFieldSelected('layout') ? $scanner->getLayout($name) : NULL; - if ($layout !== NULL) { - // FIXME check for validity? - $record['layout'] = $this->convertHtmlToOutput($layout); + if ($getLayout) { + $values[$name]['layout'] = $scanner->getLayout($name) ?? $values[$name]['layout'] ?? ''; } - $values[] = $record; } + if ($getLayout && $this->layoutFormat !== 'html') { + foreach ($values as $name => $record) { + $values[$name]['layout'] = $this->convertHtmlToOutput($record['layout']); + } + } + + return $values; + } + + /** + * Generates afform blocks from custom field sets. + * + * @param $names + * @param $toGet + * @param $getLayout + * @return array + * @throws \API_Exception + */ + protected function getAutoGenerated(&$names, $toGet, $getLayout) { + $values = $groupNames = []; + foreach ($toGet ?? [] as $name) { + if (strpos($name, 'blockCustom_') === 0 && strlen($name) > 12) { + $groupNames[] = substr($name, 12); + } + } + if ($toGet && !$groupNames) { + return $values; + } + $customApi = CustomGroup::get() + ->setCheckPermissions(FALSE) + ->setSelect(['name', 'title', 'help_pre', 'help_post']) + ->addWhere('is_multiple', '=', 1) + ->addWhere('is_active', '=', 1); + if ($groupNames) { + $customApi->addWhere('name', 'IN', $groupNames); + } + if ($getLayout) { + $customApi->addSelect('help_pre')->addSelect('help_post'); + $customApi->addChain('fields', CustomField::get() + ->setCheckPermissions(FALSE) + ->addSelect('name') + ->addWhere('custom_group_id', '=', '$id') + ->addWhere('is_active', '=', 1) + ->addOrderBy('weight', 'ASC') + ); + } + foreach ($customApi->execute() as $custom) { + $name = 'blockCustom_' . $custom['name']; + if (!in_array($name, $names)) { + $names[] = $name; + } + $item = [ + 'name' => $name, + 'requires' => [], + 'title' => ts('%1 block (default)', [1 => $custom['title']]), + 'description' => '', + 'is_public' => FALSE, + 'permission' => 'access CiviCRM', + 'block' => 'Custom_' . $custom['name'], + 'extends' => 'Contact', + 'repeatable' => TRUE, + 'has_base' => TRUE, + ]; + if ($getLayout) { + $item['layout'] = ($custom['help_pre'] ? '
' . $custom['help_pre'] . "
\n" : ''); + foreach ($custom['fields'] as $field) { + $item['layout'] .= "\n"; + } + $item['layout'] .= ($custom['help_post'] ? '
' . $custom['help_post'] . "
\n" : ''); + } + $values[$name] = $item; + } return $values; } diff --git a/ext/afform/core/afform.php b/ext/afform/core/afform.php index 7e14544012..3a4f8ae871 100644 --- a/ext/afform/core/afform.php +++ b/ext/afform/core/afform.php @@ -320,9 +320,13 @@ function _afform_reverse_deps_find($formName, $html, $revMap) { function afform_civicrm_alterAngular($angular) { $fieldMetadata = \Civi\Angular\ChangeSet::create('fieldMetadata') ->alterHtml(';\\.aff\\.html$;', function($doc, $path) { - /** @var \CRM_Afform_AfformScanner $scanner */ - $scanner = Civi::service('afform_scanner'); - $meta = $scanner->getMeta(basename($path, '.aff.html')); + try { + $module = \Civi::service('angular')->getModule(basename($path, '.aff.html')); + $meta = \Civi\Api4\Afform::get()->addWhere('name', '=', $module['_afform'])->addSelect('block')->setCheckPermissions(FALSE)->execute()->first(); + } + catch (Exception $e) { + } + $blockEntity = $meta['block'] ?? NULL; if (!$blockEntity) { $entities = _afform_getMetadata($doc); @@ -530,13 +534,13 @@ function _afform_angular_module_name($fileBaseName, $format = 'camel') { switch ($format) { case 'camel': $camelCase = ''; - foreach (explode('-', $fileBaseName) as $shortNamePart) { + foreach (preg_split('/[-_ ]/', $fileBaseName, NULL, PREG_SPLIT_NO_EMPTY) as $shortNamePart) { $camelCase .= ucfirst($shortNamePart); } return strtolower($camelCase{0}) . substr($camelCase, 1); case 'dash': - return strtolower(implode('-', array_filter(preg_split('/(?=[A-Z])/', $fileBaseName)))); + return strtolower(implode('-', preg_split('/[-_ ]|(?=[A-Z])/', $fileBaseName, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE))); default: throw new \Exception("Unrecognized format"); diff --git a/ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php b/ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php index d355dfe3af..e3884febf7 100644 --- a/ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php +++ b/ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php @@ -38,6 +38,13 @@ class CRM_Afform_UtilTest extends \PHPUnit\Framework\TestCase implements Headles $exs[] = ['abCd23', 'dash', 'ab-cd23']; $exs[] = ['AbCd23', 'dash', 'ab-cd23']; + $exs[] = ['Custom_fooBar', 'camel', 'customFooBar']; + $exs[] = ['Custom_Foo__Bar', 'camel', 'customFooBar']; + $exs[] = ['Custom Foo_ _Bar', 'camel', 'customFooBar']; + $exs[] = ['Custom_fooBar', 'dash', 'custom-foo-bar']; + $exs[] = ['Custom_Foo__Bar', 'dash', 'custom-foo-bar']; + $exs[] = ['Custom Foo_ _Bar', 'dash', 'custom-foo-bar']; + return $exs; } -- 2.25.1