From 87dde5ebb96416f98f1f76a82231be0eee8d696b Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Fri, 8 Feb 2019 19:56:03 -0500 Subject: [PATCH] AfformScanner - Use `ang/*.aff.json` file-naming convention __Before__: Scan each `$extension` for `$extension/afform/*/meta.json` __After__: Scan each `$extension` for `$extension/ang/*.aff.json` __Comments__: This is a significant breaking change for v0.2. It preserves some key design-goals from the old naming convention * The symbol in HTML (e.g. `afform-email`) should have symmetry with the file-name (e.g. `afform/Email/*` or `afform-email.*`) * The file-name in the base-code provided by an extension should match the file-name in the local override folder. However, the new naming convention also: * Makes it easier downstream to choose their own prefixes. We're not boxed-in or hard-coded to `afform-`. This will be useful, e.g., with distinguishing the stdlib from the business-forms that use the stdlib. * Puts Afform-Angular content in the same folder structure as Regular-Angular content. --- ext/afform/core/CRM/Afform/AfformScanner.php | 44 ++++++++-------- .../core/Civi/Api4/Action/Afform/Revert.php | 2 +- .../core/Civi/Api4/Traits/AfformCrudTrait.php | 8 +-- ext/afform/core/afform.php | 21 ++++---- .../tests/phpunit/CRM/Afform/UtilTest.php | 52 +++++++++++++++++++ 5 files changed, 90 insertions(+), 37 deletions(-) create mode 100644 ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php diff --git a/ext/afform/core/CRM/Afform/AfformScanner.php b/ext/afform/core/CRM/Afform/AfformScanner.php index fb03cffbc4..6c64f988e0 100644 --- a/ext/afform/core/CRM/Afform/AfformScanner.php +++ b/ext/afform/core/CRM/Afform/AfformScanner.php @@ -10,7 +10,7 @@ */ class CRM_Afform_AfformScanner { - const METADATA_FILE = 'meta.json'; + const METADATA_FILE = 'aff.json'; const DEFAULT_REQUIRES = 'afformCore'; @@ -28,6 +28,7 @@ class CRM_Afform_AfformScanner { 'group' => md5('afform_' . CRM_Core_Config_Runtime::getId() . $this->getSiteLocalPath()), 'prefetch' => FALSE, ]); + // $this->cache = new CRM_Utils_Cache_Arraycache([]); } /** @@ -51,7 +52,7 @@ class CRM_Afform_AfformScanner { foreach ($mapper->getModules() as $module) { /** @var $module CRM_Core_Module */ if ($module->is_active) { - $this->appendFilePaths($paths, dirname($mapper->keyToPath($module->name)) . DIRECTORY_SEPARATOR . 'afform', 20); + $this->appendFilePaths($paths, dirname($mapper->keyToPath($module->name)) . DIRECTORY_SEPARATOR . 'ang', 20); } } @@ -66,18 +67,18 @@ class CRM_Afform_AfformScanner { * * @param string $formName * Ex: 'view-individual' - * @param string $subFile - * Ex: 'meta.json' + * @param string $suffix + * Ex: 'aff.json' * @return string|NULL - * Ex: '/var/www/sites/default/files/civicrm/afform/view-individual' + * Ex: '/var/www/sites/default/files/civicrm/afform/view-individual.aff.json' */ - public function findFilePath($formName, $subFile) { + public function findFilePath($formName, $suffix) { $paths = $this->findFilePaths(); if (isset($paths[$formName])) { foreach ($paths[$formName] as $path) { - if (file_exists($path . DIRECTORY_SEPARATOR . $subFile)) { - return $path . DIRECTORY_SEPARATOR . $subFile; + if (file_exists($path . '.' . $suffix)) { + return $path . '.' . $suffix; } } } @@ -92,12 +93,12 @@ class CRM_Afform_AfformScanner { * @param string $formName * Ex: 'view-individual' * @param string $file - * Ex: 'meta.json' + * Ex: 'aff.json' * @return string|NULL - * Ex: '/var/www/sites/default/files/civicrm/afform/view-individual' + * Ex: '/var/www/sites/default/files/civicrm/afform/view-individual.aff.json' */ public function createSiteLocalPath($formName, $file) { - return $this->getSiteLocalPath() . DIRECTORY_SEPARATOR . $formName . DIRECTORY_SEPARATOR . $file; + return $this->getSiteLocalPath() . DIRECTORY_SEPARATOR . $formName . '.' . $file; } public function clear() { @@ -111,7 +112,7 @@ class CRM_Afform_AfformScanner { * Ex: 'view-individual' * @return array * An array with some mix of the following keys: name, title, description, client_route, server_route, requires. - * NOTE: This is only data available in meta.json. It does *NOT* include layout. + * NOTE: This is only data available in *.aff.json. It does *NOT* include layout. * Ex: [ * 'name' => 'view-individual', * 'title' => 'View an individual contact', @@ -142,7 +143,7 @@ class CRM_Afform_AfformScanner { * * @return array * A list of all forms, keyed by form name. - * NOTE: This is only data available in meta.json. It does *NOT* include layout. + * NOTE: This is only data available in *.aff.json. It does *NOT* include layout. * Ex: ['view-individual' => ['title' => 'View an individual contact', ...]] */ public function getMetas() { @@ -156,21 +157,18 @@ class CRM_Afform_AfformScanner { /** * @param array $formPaths * List of all form paths. - * Ex: ['foo' => [0 => '/var/www/org.example.foobar/afform//foo']] + * 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. */ private function appendFilePaths(&$formPaths, $parent, $priority) { - $parent = CRM_Utils_File::addTrailingSlash($parent); - if (is_dir($parent) && $handle = opendir($parent)) { - while (FALSE !== ($entry = readdir($handle))) { - if ($entry{0} !== '.' && is_dir($parent . $entry)) { - $formPaths[$entry][$priority] = $parent . $entry; - ksort($formPaths[$entry]); - } - } + $files = (array) glob("$parent/*." . self::METADATA_FILE); + foreach ($files as $file) { + $name = _afform_angular_module_name(preg_replace('/\.aff\.json$/', '', basename($file))); + $formPaths[$name][$priority] = preg_replace('/\.aff\.json$/', '', $file); + ksort($formPaths[$name]); } } @@ -183,7 +181,7 @@ class CRM_Afform_AfformScanner { private function getSiteLocalPath() { // TODO Allow a setting override. // return Civi::paths()->getPath(Civi::settings()->get('afformPath')); - return Civi::paths()->getPath('[civicrm.files]/afform'); + return Civi::paths()->getPath('[civicrm.files]/ang'); } } diff --git a/ext/afform/core/Civi/Api4/Action/Afform/Revert.php b/ext/afform/core/Civi/Api4/Action/Afform/Revert.php index 206d5addd6..895890adfe 100644 --- a/ext/afform/core/Civi/Api4/Action/Afform/Revert.php +++ b/ext/afform/core/Civi/Api4/Action/Afform/Revert.php @@ -13,7 +13,7 @@ class Revert extends Get { parent::_run($result); - $files = [\CRM_Afform_AfformScanner::METADATA_FILE, 'layout.html']; + $files = [\CRM_Afform_AfformScanner::METADATA_FILE, 'aff.html']; foreach ($result as $afform) { foreach ($files as $file) { diff --git a/ext/afform/core/Civi/Api4/Traits/AfformCrudTrait.php b/ext/afform/core/Civi/Api4/Traits/AfformCrudTrait.php index 668b90fbd2..6360c9f05d 100644 --- a/ext/afform/core/Civi/Api4/Traits/AfformCrudTrait.php +++ b/ext/afform/core/Civi/Api4/Traits/AfformCrudTrait.php @@ -23,7 +23,7 @@ trait AfformCrudTrait { $values = []; foreach ($names as $name) { $record = $scanner->getMeta($name); - $layout = $scanner->findFilePath($name, 'layout.html'); + $layout = $scanner->findFilePath($name, 'aff.html'); if ($layout) { // FIXME check for file existence+substance+validity $record['layout'] = $converter->convertHtmlToArray(file_get_contents($layout)); @@ -56,15 +56,15 @@ trait AfformCrudTrait { // FIXME validate all field data. $updates = _afform_fields_filter($record); - // Create or update layout.html. + // Create or update aff.html. if (isset($updates['layout'])) { - $layoutPath = $scanner->createSiteLocalPath($name, 'layout.html'); + $layoutPath = $scanner->createSiteLocalPath($name, 'aff.html'); \ CRM_Utils_File::createDir(dirname($layoutPath)); file_put_contents($layoutPath, $converter->convertArrayToHtml($updates['layout'])); // FIXME check for writability then success. Report errors. } - // Create or update meta.json. + // Create or update *.aff.json. $orig = \Civi\Api4\Afform::get() ->setCheckPermissions($this->getCheckPermissions()) ->addWhere('name', '=', $name) diff --git a/ext/afform/core/afform.php b/ext/afform/core/afform.php index ad8630867f..09700d2fef 100644 --- a/ext/afform/core/afform.php +++ b/ext/afform/core/afform.php @@ -156,7 +156,7 @@ function afform_civicrm_angularModules(&$angularModules) { $names = array_keys($scanner->findFilePaths()); foreach ($names as $name) { $meta = $scanner->getMeta($name); - $angularModules[_afform_angular_module_name($name)] = [ + $angularModules[_afform_angular_module_name($name, 'camel')] = [ 'ext' => E::LONG_NAME, 'js' => ['assetBuilder://afform.js?name=' . urlencode($name)], 'requires' => $meta['requires'], @@ -213,10 +213,10 @@ function afform_civicrm_buildAsset($asset, $params, &$mimeType, &$content) { $smarty = CRM_Core_Smarty::singleton(); $smarty->assign('afform', [ - 'camel' => _afform_angular_module_name($name), + 'camel' => _afform_angular_module_name($name, 'camel'), 'meta' => $meta, 'metaJson' => json_encode($meta), - 'layout' => file_get_contents($scanner->findFilePath($name, 'layout.html')) + 'layout' => file_get_contents($scanner->findFilePath($name, 'aff.html')) ]); $mimeType = 'text/javascript'; $content = $smarty->fetch('afform/AfformAngularModule.tpl'); @@ -247,21 +247,24 @@ function afform_civicrm_alterMenu(&$items) { } /** - * @param string $name - * Ex: fooBar + * @param string $fileBaseName + * Ex: foo-bar * @param string $format * 'camel' or 'dash'. * @return string * Ex: 'FooBar' or 'foo-bar'. */ -function _afform_angular_module_name($name, $format = 'camel') { +function _afform_angular_module_name($fileBaseName, $format = 'camel') { switch ($format) { case 'camel': - return 'afform' . strtoupper($name{0}) . substr($name, 1); + $camelCase = ''; + foreach (explode('-', $fileBaseName) as $shortNamePart) { + $camelCase .= ucfirst($shortNamePart); + } + return strtolower($camelCase{0}) . substr($camelCase, 1); case 'dash': - $camel = _afform_angular_module_name($name, 'camel'); - return strtolower(implode('-', array_filter(preg_split('/(?=[A-Z])/', $camel)))); + return strtolower(implode('-', array_filter(preg_split('/(?=[A-Z])/', $fileBaseName)))); 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 new file mode 100644 index 0000000000..32263e1ac2 --- /dev/null +++ b/ext/afform/core/tests/phpunit/CRM/Afform/UtilTest.php @@ -0,0 +1,52 @@ +installMe(__DIR__) + ->install(['org.civicrm.api4']) + ->apply(); + } + + public function getNameExamples() { + $exs = []; + $exs[] = ['ab-cd-ef', 'camel', 'abCdEf']; + $exs[] = ['abCd', 'camel', 'abCd']; + $exs[] = ['AbCd', 'camel', 'abCd']; + $exs[] = ['ab-cd', 'dash', 'ab-cd']; + $exs[] = ['abCd', 'dash', 'ab-cd']; + $exs[] = ['AbCd', 'dash', 'ab-cd']; + + $exs[] = ['ab-cd-ef23', 'camel', 'abCdEf23']; + $exs[] = ['abCd23', 'camel', 'abCd23']; + $exs[] = ['AbCd23', 'camel', 'abCd23']; + $exs[] = ['ab-cd23', 'dash', 'ab-cd23']; + $exs[] = ['abCd23', 'dash', 'ab-cd23']; + $exs[] = ['AbCd23', 'dash', 'ab-cd23']; + + return $exs; + } + + /** + * @param $inputFileName + * @param $toFormat + * @param $expected + * @dataProvider getNameExamples + */ + public function testNameConversion($inputFileName, $toFormat, $expected) { + $actual = _afform_angular_module_name($inputFileName, $toFormat); + $this->assertEquals($expected, $actual); + } + +} -- 2.25.1