### Simple release test scenario Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Sequence of upgrader.sh commands to run checks, clean databases and files, install a start version (3.3.0), and upgrade to a target version (3.4.1). Run run-checks first to verify setup. ```bash ./upgrader.sh run-checks ./upgrader.sh cleanup-dbs ./upgrader.sh cleanup-files ./upgrader.sh install 3.3.0-tarball ./upgrader.sh upgrade 3.4.1-tarball ``` -------------------------------- ### Log message for new user creation Source: https://github.com/civicrm/civicrm-core/blob/master/ext/standaloneusers/README.md Example log message indicating the creation of a new user with default credentials and all permissions. This message may appear in the local log if the installer does not display the default user account. ```text [notice] Created new user "admin" (user ID #1, contact ID #203) with default password "admin" and ALL permissions. ``` -------------------------------- ### Default user account output from installer Source: https://github.com/civicrm/civicrm-core/blob/master/ext/standaloneusers/README.md Example of the default user account output displayed by the installer. The credentials are shown in JSON format with keys adminUser, adminPass, and adminEmail. ```json "adminUser": "super", "adminPass": "O5fAlyXgdEU", "adminEmail": "admin@localhost.localdomain" ``` -------------------------------- ### run-install-scenario: Run install scenario tests Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Runs the PHPUnit install test suite. Changes to the PHPUnit script directory and executes the command stored in $PHPUNITCOMMAND with the test file $PU_INSTALLTEST. ```bash function run-install-scenario { upgecho "Running install scenario tests." echo "*** Take it away, Sebastian! " echo cd $PHPUNITSCRIPTDIR $PHPUNITCOMMAND $PU_INSTALLTEST echo } ``` -------------------------------- ### Install Elavon extension with cv Source: https://github.com/civicrm/civicrm-core/blob/master/ext/elavon/README.md Use this command to install the Elavon core extension via the command-line tool cv. ```bash cv en elavon ``` -------------------------------- ### Customize default credentials with cv core:install Source: https://github.com/civicrm/civicrm-core/blob/master/ext/standaloneusers/README.md Command to customize the default credentials during installation by passing the adminUser, adminPass, and adminEmail arguments to the installer. ```bash cv core:install ... \ -m 'extras.adminUser=zeta' \ -m 'extras.adminPass=SECRET' \ -m 'extras.adminEmail=zeta@example.com' ``` -------------------------------- ### Upgraded database schema verification scenario Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Sequence of upgrader.sh commands to install a clean version, dump its schema, then install an older version, upgrade it, dump the upgraded schema, and diff the two dumps to verify schema changes. ```bash ./upgrader.sh run-checks ./upgrader.sh cleanup-dbs ./upgrader.sh cleanup-files ./upgrader.sh install 3.4.1-tarball ./upgrader.sh dumpschema-cividb 3.4.1-clean.mysql ./upgrader.sh cleanup-dbs ./upgrader.sh cleanup-files ./upgrader.sh install 3.3.0-tarball ./upgrader.sh upgrade 3.4.1-tarball ./upgrader.sh dumpschema-cividb 3.4.1-upgraded.mysql diff 3.4.1-clean.mysql 3.4.1-upgraded.mysql ``` -------------------------------- ### Command Line Parameter Verification for Upgrader Script Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Validates the action and filename parameters. Exits with usage message if action is missing or required filename is not provided for install, upgrade, or dumpschema-cividb. ```bash PU_INSTALLTEST="WebTest_Release_InstallScript" PU_UPGRADETEST="WebTest_Release_UpgradeScript" PU_SUITE="WebTest_AllTests" echo USAGE="Usage: upgrader.sh ACTION [/path/to/file]" SELF=$(cd $(dirname $0); pwd -P)/$(basename $0) ACTION=$1 FILENAME=$2 if [ -z $ACTION ] ; then echo $USAGE exit 1 fi if [ $ACTION == "install" ] && [ -z $FILENAME ] ; then echo $USAGE echo "(Tarball parameter required for install)" exit 1 fi if [ $ACTION == "upgrade" ] && [ -z $FILENAME ] ; then echo $USAGE echo "(Tarball parameter required for upgrade)" exit 1 fi if [ $ACTION == "dumpschema-cividb" ] && [ -z $FILENAME ] ; then echo $USAGE echo "(Filename parameter required for dumpschema-cividb)" exit 1 fi ``` -------------------------------- ### Implement Mustache template support with ComposeBatchEvent listener Source: https://github.com/civicrm/civicrm-core/blob/master/ext/flexmailer/docs/develop/ComposeBatchEvent.md Registers a listener for the FlexMailer compose event and implements a naive Mustache template renderer. It checks the mailing's template type, skips tasks that already have content, fetches each contact individually, and sets the text and HTML mail parameters using the Mustache engine. This example is intentionally simplistic and does not batch queries, optimize compilation, or handle click-through tracking. ```php addResource(new \Symfony\Component\Config\Resource\FileResource(__FILE__)); $container->findDefinition('dispatcher')->addMethodCall('addListener', array(\Civi\FlexMailer\FlexMailer::EVENT_COMPOSE, '_mustache_compose_batch') ); } function _mustache_compose_batch(\Civi\FlexMailer\Event\ComposeBatchEvent $event) { if ($event->getMailing()->template_type !== 'mustache') { return; } $m = new Mustache_Engine(); foreach ($event->getTasks() as $task) { if ($task->hasContent()) { continue; } $contact = civicrm_api3('Contact', 'getsingle', array( 'id' => $task->getContactId(), )); $task->setMailParam('text', $m->render($event->getMailing()->body_text, $contact)); $task->setMailParam('html', $m->render($event->getMailing()->body_html, $contact)); } } ``` -------------------------------- ### Compile (S)CSS with composer Source: https://github.com/civicrm/civicrm-core/blob/master/ext/greenwich/README.md Use these commands from the composer root directory to compile (S)CSS. The first command compiles once, the second continues watching for changes. Compiled files are generated during composer install and should not be committed. ```bash cd /path/to/my/composer/root ## Compile (S)CSS - one time composer compile ## Compile (S)CSS - and continue watching for changes composer compile:watch ``` -------------------------------- ### Relay Civi import map to Drupal via hook_import_map_alter Source: https://github.com/civicrm/civicrm-core/blob/master/Civi/Esm/README.md Example of relaying the Civi import map to Drupal via hook_import_map_alter(). This is a simplified example; actual merging may require reviewing Drupal and Civi contracts. ```php // FILE: civicrm.module /** * Implements hook_import_map_alter(). */ function civicrm_import_map_alter(&$drupalImportMaps) { $civiImportMaps = Civi::service('esm.import_map')->get(); $drupalImportMaps = array_merge($drupalImportMaps, $civiImportMaps); } ``` -------------------------------- ### Load mixin polyfill in CiviCRM hooks Source: https://github.com/civicrm/civicrm-core/blob/master/mixin/polyfill.md Load the mixin polyfill during key CiviCRM hooks (config, install, enable) for a bespoke extension. The polyfill is only required if the CRM_Extension_MixInfo class is not already available, and it is invoked with the extension's full name, short name, and directory. ```php function _myext_mixin_polyfill() { if (!class_exists('CRM_Extension_MixInfo')) { $polyfill = __DIR__ . '/mixin/polyfill.php'; (require $polyfill)('org.example.myextension', 'myext', __DIR__); } } function myext_civicrm_config() { _myext_mixin_polyfill(); } function myext_civicrm_install() { _myext_mixin_polyfill(); } function myext_civicrm_enable() { _myext_mixin_polyfill(); } ``` -------------------------------- ### Schema field with localizable flag Source: https://github.com/civicrm/civicrm-core/blob/master/CRM/Upgrade/Incremental/sql/README.txt Example schema definition showing how to check if a field is localizable. The true element indicates that inserts must use the {localize} tag around that column. ```xml label Option Label varchar true 255 true Option string as displayed to users - e.g. the label in an HTML OPTION tag. 1.5 ``` -------------------------------- ### Render importmap script tag Source: https://github.com/civicrm/civicrm-core/blob/master/Civi/Esm/README.md Ensures the import-map is properly loaded so that recursive-dependencies may be resolved. Uses the 'esm.import_map' service to get the map and outputs it in a script tag. ```php $civicrmImportMap = json_encode(Civi::service('esm.import_map')->get()); echo "\n"; ``` -------------------------------- ### Complex orchestration with $bindToRoute AngularJS example Source: https://github.com/civicrm/civicrm-core/blob/master/ang/crmRouteBinder.md Suggested usage for orchestrating multiple filter sets with $bindToRouteable. It shows three filters (A, B, C) each bound to a URL parameter and watched to update corresponding data. This pattern is for complex scenarios with many URL parameters and dependent data loading. ```js angular.module('sandbox').config(function($routeProvider) { $routeProvider.when('/example-route', { reloadOnSearch: false, template: '
' + '
' + '
' + '
' + '
' + '
', controller: function($scope) { $scope.$bindToRoute({expr:'filterSetA', param:'a', default:{}}); $scope.$watchCollection('filterSetA', function(){ crmApi(...).then(function(...){ $scope.dataSetA = ...; }); }); $scope.$bindToRoute({expr:'filterSetB', param:'b', default:{}}); $scope.$watchCollection('filterSetB', function(){ crmApi(...).then(function(...){ $scope.dataSetB = ...; }); }); $scope.$bindToRoute({expr:'filterSetC', param:'c', default:{}}); $scope.$watchCollection('filterSetC', function(){ crmApi(...).then(function(...){ $scope.dataSetC = ...; }); }); } }); }); ``` -------------------------------- ### Select component ID into variable Source: https://github.com/civicrm/civicrm-core/blob/master/CRM/Upgrade/Incremental/sql/README.txt Example of selecting a component ID into a variable for use in an option value insert. The section explains that you should not hard-code integers for value and weight columns; use SELECT max() into a variable and increment it. ```sql SELECT @caseCompId := id FROM `civicrm_component` where `name` like 'CiviCase'; ``` -------------------------------- ### Set default ESM loader to 'drupal' in Drupal.php Source: https://github.com/civicrm/civicrm-core/blob/master/Civi/Esm/README.md Example of updating the Civi-Drupal integration to use the 'drupal' loader by default when Drupal version is 12.34 or higher. This is part of developing a new loader for Drupal. ```php // FILE: CRM/Utils/System/Drupal.php public function initialize() { parent::initialize(); Civi::dispatcher()->addListener('civi.esm.loader.default', function ($e) { if (version_compare(DRUPAL_VERSION', '12.34', '>=')) { $e->default = 'drupal'; } }); } ``` -------------------------------- ### Basic $bindToRoute AngularJS example Source: https://github.com/civicrm/civicrm-core/blob/master/ang/crmRouteBinder.md Basic use of $bindToRoute to sync a scoped variable with a URL parameter. The URL updates to include the serialized default value and the route is live-updated without reloading. This is for scenarios where you need more complex routing with multiple parameters. ```js angular.module('sandbox').config(function($routeProvider) { $routeProvider.when('/example-route', { reloadOnSearch: false, template: '', controller: function($scope) { $scope.$bindToRoute({ param: 'f', expr: 'filters', default: {foo: 'default-value'} }); } }); }); ``` -------------------------------- ### CiviCRM Standalone index.php - Main boot script Source: https://github.com/civicrm/civicrm-core/blob/master/setup/res/index.php.txt Sets the app root to the current directory, requires civicrm.standalone.php, and calls \Civi\Standalone\WebEntrypoint::index(). Commented alternatives show how to adjust the app root for subdirectory or parent directory searches. ```php register(); \Civi\Core\SettingsManager::bootSettings($settingsPath); ``` -------------------------------- ### Enable and test afform_mock extension Source: https://github.com/civicrm/civicrm-core/blob/master/ext/afform/mock/README.md Commands to enable the mock extension and run its tests. The first command changes to the extension directory, the second enables the extension via cv, and the last two run PHPUnit with the headless and e2e groups respectively. ```bash cd afform/mock cv en afform_mock phpunit6 --group headless phpunit6 --group e2e ``` -------------------------------- ### Compare physical and logical import paths Source: https://github.com/civicrm/civicrm-core/blob/master/Civi/Esm/README.md Compares physical-path and logical-path import statements. The first uses a full URL, the second uses a logical path that is shorter and adaptable to different deployments. ```javascript import { TableWidget } from 'https://example.com/sites/all/modules/civicrm/js/table-widget.js'; import { TableWidget } from 'civicrm/js/tab-widget.js'; ``` -------------------------------- ### Configuration Variables for CiviCRM Upgrader Script Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Defines database credentials, directory paths, and URLs used throughout the script. Must be edited before running the script. ```bash CIVIDBNAME= CIVIDBUSER= CIVIDBPASS= DRUPALDBNAME= DRUPALDBUSER= DRUPALDBPASS= DRUPALPRISTINEDBFILE= DRUPALDIR= MODULESDIR=$DRUPALDIR"/sites/all/modules" SETTINGSDIR=$DRUPALDIR"/sites/all" CIVICRMDIR=$MODULESDIR"/civicrm" DRUPALURL="http://url.url" CIVICRMURL=$DRUPALURL"/civicrm/dashboard" PHPUNITSCRIPTDIR="" PHPUNITCOMMAND="scripts/phpunit" ``` -------------------------------- ### run-tests: Run post-upgrade tests Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Runs the post-upgrade test suite. Changes to the PHPUnit script directory and executes the command stored in $PHPUNITCOMMAND with the test suite $PU_SUITE. ```bash function run-tests { upgecho "Running post upgrade tests." echo "*** Take it away, Sebastian! " echo cd $PHPUNITSCRIPTDIR $PHPUNITCOMMAND $PU_SUITE echo } ``` -------------------------------- ### Run headless unit tests with phpunit5 Source: https://github.com/civicrm/civicrm-core/blob/master/ext/flexmailer/docs/develop/index.md Run the headless unit tests for FlexMailer using PHPUnit and cv. ```bash $ phpunit5 ``` -------------------------------- ### Clone and enable flexmailer from git Source: https://github.com/civicrm/civicrm-core/blob/master/ext/flexmailer/docs/install.md Clones the flexmailer repository from git and enables the extension using cv. ```bash $ cd $(cv path -x .) $ git clone https://github.com/civicrm/org.civicrm.flexmailer.git $ cv en flexmailer ``` -------------------------------- ### run-upgrade-scenario: Run upgrade scenario tests Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Runs the PHPUnit upgrade test suite. Changes to the PHPUnit script directory and executes the command stored in $PHPUNITCOMMAND with the test file $PU_UPGRADETEST. ```bash function run-upgrade-scenario { upgecho "Running upgrade scenario tests." echo "*** Take it away, Sebastian! " echo cd $PHPUNITSCRIPTDIR $PHPUNITCOMMAND $PU_UPGRADETEST echo } ``` -------------------------------- ### Enable password authentication and test with curl Source: https://github.com/civicrm/civicrm-core/blob/master/ext/authx/README.md Activate password authentication by setting authx_header_cred to include 'pass' and 'jwt', then test with curl. The 'AuthX: Authenticate to services with password' permission must be granted. ```bash $ cv ev 'Civi::settings()->set("authx_header_cred", ["pass","jwt"]);' $ curl 'https://demouser:demopass@example.org/civicrm/authx/id' {"contact_id":203,"user_id":"2"} ``` -------------------------------- ### Action hub case statement for release-testing upgrader Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Dispatches on the $ACTION variable to run the corresponding release-testing workflow. Each branch first calls run-checks with 0 (or 1 for run-checks itself) and then invokes the relevant helper functions, such as remove-files, install-files, run-upgrade-scenario, or dump-schema. The case statement is wrapped by START/END Action hub comment markers. ```bash case $ACTION in run-checks) run-checks 1 ;; cleanup-files) run-checks 0 remove-files remove-settings ;; cleanup-dbs) run-checks 0 cleanup-drupdb cleanup-cividb ;; install) run-checks 0 install-files $FILENAME run-install-scenario ;; upgrade) run-checks 0 remove-files install-files $FILENAME run-upgrade-scenario ;; dumpschema-cividb) run-checks 0 dump-schema $FILENAME ;; tests) run-checks 0 run-tests ;; esac ``` -------------------------------- ### cleanup-cividb: Drop and recreate CiviCRM database Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Drops and recreates the CiviCRM database using mysqladmin with credentials from $CIVIDBUSER and $CIVIDBPASS. Output is suppressed to /dev/null. ```bash function cleanup-cividb { upgecho "Cleaning up CiviCRM db (dropped and created)." mysqladmin -f -u $CIVIDBUSER -p$CIVIDBPASS drop $CIVIDBNAME >> /dev/null 2>&1 mysqladmin -f -u $CIVIDBUSER -p$CIVIDBPASS create $CIVIDBNAME >> /dev/null 2>&1 } ``` -------------------------------- ### Open a dialog with dialogService.open Source: https://github.com/civicrm/civicrm-core/blob/master/ang/crmDialog.md Opens a dialog named 'someDialog' using the dialogService.open method, passing a template path, model, and options. The returned promise resolves with the dialog's output. ```javascript dialogService.open('someDialog', '~/Path/To/Some.html', model, options) .then(function(result){ console.log('received output from dialog', result); }); ``` -------------------------------- ### Download latest alpha or beta version Source: https://github.com/civicrm/civicrm-core/blob/master/ext/flexmailer/docs/install.md Downloads the latest alpha or beta version of the flexmailer extension using cv. ```bash $ cv dl --dev flexmailer ``` -------------------------------- ### Publish patches to CDN and test with patchmgr build Source: https://github.com/civicrm/civicrm-core/blob/master/tools/patches/README.md Builds and publishes patch files to the CDN using gcloud, then tests composer with the published patches. Requires write-access to the CDN and the gcloud CLI. ```bash ./tools/patches/bin/patchmgr build gcloud storage rsync -r tools/patches/dist gs://civicrm/patches ``` ```bash ./tools/patches/bin/patchmgr use-remote && composer install ``` -------------------------------- ### Queue an email by creating an EmailMessage Source: https://github.com/civicrm/civicrm-core/blob/master/ext/postbox/README.md Creates a new EmailMessage record to queue an email for sending. Uses API4 create action with FALSE for permissions check. Requires a contact ID, subject, body, and a site email address ID. ```php \Civi\Api4\EmailMessage::create(FALSE) ->addValue('to_contact_id', $contactId) ->addValue('subject', 'Test Email') ->addValue('body', 'Test content') ->addValue('from_site_email_address_id', 3) ->execute(); ``` -------------------------------- ### Listen to FlexMailer RunEvent with example_civicrm_container Source: https://github.com/civicrm/civicrm-core/blob/master/ext/flexmailer/docs/develop/RunEvent.md Registers a listener for the FlexMailer RunEvent using the container's dispatcher. The listener prints the job and mailing IDs when the event fires. Note that calling $event->stopPropagation() will stop FlexMailer's delivery process. ```php addResource(new \Symfony\Component\Config\Resource\FileResource(__FILE__)); $container->findDefinition('dispatcher')->addMethodCall('addListener', array(\Civi\FlexMailer\FlexMailer::EVENT_RUN, '_example_run') ); } function _example_run(\Civi\FlexMailer\Event\RunEvent $event) { printf("Starting work on job #%d for mailing #%d\n", $event->getJob()->id, $event->getMailing()->id); } ``` -------------------------------- ### install-files: Extract files from tarball Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Extracts a tarball (first argument) into the modules directory $MODULESDIR. Uses tar with verbose output suppressed. ```bash function install-files { upgecho "Installing files from $FILENAME." cd $MODULESDIR tar xzvf $1 >> /dev/null 2>&1 } ``` -------------------------------- ### Enable automatic upgrade snapshots with CIVICRM_UPGRADE_SNAPSHOT Source: https://github.com/civicrm/civicrm-core/blob/master/release-notes/5.50.0.md Add this constant to the settings file to enable automatic snapshots of database tables before upgrade steps. The feature is disabled by default; snapshots are stored in tables prefixed with 'snap_civicrm_' and cleaned up after a number of minor version upgrades. ```php define('CIVICRM_UPGRADE_SNAPSHOT', TRUE); ``` -------------------------------- ### Switch ESM loader via civicrm.setting.php, cv, or CRM.api3 Source: https://github.com/civicrm/civicrm-core/blob/master/Civi/Esm/README.md Commands to switch the ESM loader between 'browser' and 'shim' via configuration file, CLI, or browser console. Use these when a conflict arises between Civi ESM and a UF's loader. ```php $civicrm_setting['domain']['esm_loader'] = 'browser'; ``` ```php $civicrm_setting['domain']['esm_loader'] = 'shim'; ``` ```bash cv vset esm_loader=browser ``` ```bash cv vset esm_loader=shim ``` ```javascript CRM.api3('Setting', 'create', {esm_loader: "browser"}) ``` ```javascript CRM.api3('Setting', 'create', {esm_loader: "shim"}) ``` -------------------------------- ### Download latest bleeding-edge code from archive Source: https://github.com/civicrm/civicrm-core/blob/master/ext/flexmailer/docs/install.md Downloads the latest bleeding-edge code from the master branch archive. ```bash $ cv dl org.civicrm.flexmailer@https://github.com/civicrm/org.civicrm.flexmailer/archive/master.zip ``` -------------------------------- ### $scope.$bindToRoute(options) Source: https://github.com/civicrm/civicrm-core/blob/master/ang/crmRouteBinder.md Documentation for the $scope.$bindToRoute() method, which synchronizes a scoped variable with a URL query parameter. ```APIDOC ## $scope.$bindToRoute(options) ### Description Binds a scoped variable to a URL query parameter, keeping them in sync. When the URL changes, the scope variable updates; when the scope variable changes, the URL updates. ### Method N/A (AngularJS scope method) ### Endpoint N/A (AngularJS scope method) ### Parameters #### options (object) - Required - **expr** (string) - Required - The name of a scoped variable to sync. - **param** (string) - Required - The name of a query-parameter to sync. If the param is included in the URL, it will initialize the expr. - **format** (string) - Optional - The type of data to put in param. May be one of: `json` (default), `raw`, `int`, `bool`. - **default** (object) - Optional - The default data. If the param is not included in the URL, it will initialize the expr. - **deep** (boolean) - Optional - By default the json format will be watched using a shallow comparison. For nested objects and arrays enable this option. ### Request Example ```js $scope.$bindToRoute({ param: 'f', expr: 'filters', default: {foo: 'default-value'} }); ``` ### Response #### Success Response No return value. The URL and scope variable are kept in sync. #### Response Example N/A ``` -------------------------------- ### Apply local patches with patchmgr use-local Source: https://github.com/civicrm/civicrm-core/blob/master/tools/patches/README.md Applies local patch files from tools/patches/raw/ and reinstalls dependencies. Run after adding, modifying, renaming, or deleting patch files; repeat if the patch needs more revision. ```bash ./tools/patches/bin/patchmgr use-local && composer install ``` -------------------------------- ### Enable iframe extension with cv en Source: https://github.com/civicrm/civicrm-core/blob/master/ext/iframe/README.md Enables the iframe extension during its incubation period via CLI or API. Run this command before using the iframe connector. ```bash cv en iframe ``` -------------------------------- ### cleanup-drupdb: Restore Drupal database from pristine copy Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Drops and recreates the Drupal database, then loads a pristine copy from $DRUPALPRISTINEDBFILE. Uses mysqladmin and mysql with credentials from $DRUPALDBUSER and $DRUPALDBPASS. ```bash function cleanup-drupdb { upgecho "Cleaning up Drupal db (pristine copy loaded)." mysqladmin -f -u $DRUPALDBUSER -p$DRUPALDBPASS drop $DRUPALDBNAME >> /dev/null 2>&1 mysqladmin -f -u $DRUPALDBUSER -p$DRUPALDBPASS create $DRUPALDBNAME >> /dev/null 2>&1 mysql -u $DRUPALDBUSER -p$DRUPALDBPASS $DRUPALDBNAME < $DRUPALPRISTINEDBFILE } ``` -------------------------------- ### Define custom batch logic with WalkBatchesEvent Source: https://github.com/civicrm/civicrm-core/blob/master/ext/flexmailer/docs/develop/WalkBatchesEvent.md Register a listener for the FlexMailer EVENT_WALK event and implement a callback that stops standard delivery and visits custom batches of FlexMailerTask objects. Use this to chunk email deliveries according to your own strategy. ```php addResource(new \Symfony\Component\Config\Resource\FileResource(__FILE__)); $container->findDefinition('dispatcher')->addMethodCall('addListener', array(\Civi\FlexMailer\FlexMailer::EVENT_WALK, '_example_walk_batches') ); } function _example_walk_batches(\Civi\FlexMailer\Event\WalkBatchesEvent $event) { // Disable standard delivery $event->stopPropagation(); while (...) { $tasks = array(); $task[] = new FlexMailerTask(...); $task[] = new FlexMailerTask(...); $task[] = new FlexMailerTask(...); $event->visit($tasks); } } ``` -------------------------------- ### Send email with JWT sign-in link Source: https://github.com/civicrm/civicrm-core/blob/master/ext/authx/README.md Generate a URL with the JWT passed as an '_authx' parameter and send an email containing the login link. ```php $url = CRM_Utils_System::url('civicrm/dashboard', [ '_authx' => "Bearer $token", '_authxSes' => 1, ], TRUE, NULL, FALSE); $html = sprintf('Here is your login link: %s', htmlentities($url), htmlentities($url)); CRM_Utils_Mail::send([...'html' => $html...]); ``` -------------------------------- ### remove-settings: Remove civicrm.settings.php Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Deletes the CiviCRM settings file at $SETTINGSDIR/civicrm.settings.php. Logs the action with upgecho. ```bash function remove-settings { upgecho "Removing civicrm.settings.php. ($SETTINGSDIR/civicrm.settings.php is gone!)" rm -rf $SETTINGSDIR"/civicrm.settings.php" } ``` -------------------------------- ### Utility Functions for Upgrader Script Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Defines functions for echoing messages and running pre-flight checks. The run-checks function validates file readability, directory writability, and existence of required paths, exiting on errors. ```bash function upgecho { echo "*** Upgrader (action: $ACTION): $1 " } function errecho { upgecho "## ERROR: $1 " } function run-checks { SILENT=$1 CHECKS=0 if [ $SILENT -eq 1 ] ; then upgecho "Starting checks..." fi if [ $ACTION == "install" ] && [ ! -r $FILENAME ] ; then errecho "Tarball: \"$FILENAME\" doesn't exist or is not readable." CHECKS=1 fi if [ $ACTION == "upgrade" ] && [ ! -r $FILENAME ] ; then errecho "Tarball: \"$FILENAME\" doesn't exist or is not readable." CHECKS=1 fi if [ ! -r $DRUPALPRISTINEDBFILE ] ; then errecho "Drupal pristine database file: \"$DRUPALPRISTINEDBFILE\" doesn't exist or is not readable." CHECKS=1 fi if [ ! -w $DRUPALDIR ] ; then errecho "Drupal directory (value: $DRUPALDIR) does not exist or not writable." CHECKS=1 fi if [ ! -w $MODULESDIR ] ; then errecho "Drupal modules directory (value: $MODULESDIR) does not exist or not writable." CHECKS=1 fi if [ -d $CIVICRMDIR ] ; then upgecho "CiviCRM directory (value: $CIVICRMDIR) already exists, but maybe it's not a problem." fi if [ $CHECKS -eq 1 ] ; then errecho "Quitting due to errors: see messages above." exit 1 fi if [ $SILENT -eq 1 ] ; then upgecho "Action: $ACTION" upgecho "Tarball: $FILENAME" upgecho "Script path: $SELF" upgecho "Drupal location: $DRUPALDIR" upgecho "CiviCRM will be installed to: $CIVICRMDIR" upgecho "CiviCRM Database credentials: u: $CIVIDBUSER, p: $CIVIDBPASS, n: $CIVIDBNAME" upgecho "Drupal Database credentials: u: $DRUPALDBUSER, p: $DRUPALDBPASS, n: $DRUPALDBNAME" upgecho "Done with checks, everything seems fine." fi } ``` -------------------------------- ### af-api4-action with options Source: https://github.com/civicrm/civicrm-core/blob/master/ext/afform/core/ang/afCore/Api4Action.md Usage with additional options for status messages and success/error handling. Includes a comment about an automated flag. ```html ``` -------------------------------- ### Password authentication not enabled by default Source: https://github.com/civicrm/civicrm-core/blob/master/ext/authx/README.md Shows the HTTP 401 response when password authentication is not enabled. ```bash $ curl 'https://demouser:demopass@example.org/civicrm/authx/id' HTTP 401 Password authentication is not supported ``` -------------------------------- ### dump-schema: Dump CiviCRM database schema Source: https://github.com/civicrm/civicrm-core/blob/master/tools/scripts/release-testing/upgrader.sh.txt Dumps the CiviCRM database schema (no data) to the file specified as the first argument. Uses mysqldump with credentials from $CIVIDBUSER and $CIVIDBPASS. ```bash function dump-schema { mysqldump --no-data -u $CIVIDBUSER -p$CIVIDBPASS $CIVIDBNAME > $1 } ``` -------------------------------- ### Inspect FlexMailer event listeners with cv debug:event-dispatcher Source: https://github.com/civicrm/civicrm-core/blob/master/ext/flexmailer/docs/develop/index.md Inspect the default listeners for FlexMailer events using the cv CLI command. The output shows the order of listeners for each event, which is important because FlexMailer events resemble pipelines where listener order matters. ```bash $ cv debug:event-dispatcher /flexmail/ [Event] civi.flexmailer.checkSendable +-------+------------------------------------------------------------+ | Order | Callable | +-------+------------------------------------------------------------+ | #1 | Civi\FlexMailer\Listener\Abdicator->onCheckSendable() | | #2 | Civi\FlexMailer\Listener\RequiredFields->onCheckSendable() | | #3 | Civi\FlexMailer\Listener\RequiredTokens->onCheckSendable() | +-------+------------------------------------------------------------+ [Event] civi.flexmailer.walk +-------+---------------------------------------------------+ | Order | Callable | +-------+---------------------------------------------------+ | #1 | Civi\FlexMailer\Listener\DefaultBatcher->onWalk() | +-------+---------------------------------------------------+ [Event] civi.flexmailer.compose +-------+-------------------------------------------------------+ | Order | Callable | +-------+-------------------------------------------------------+ | #1 | Civi\FlexMailer\Listener\BasicHeaders->onCompose() | | #2 | Civi\FlexMailer\Listener\ToHeader->onCompose() | | #3 | Civi\FlexMailer\Listener\BounceTracker->onCompose() | | #4 | Civi\FlexMailer\Listener\DefaultComposer->onCompose() | | #5 | Civi\FlexMailer\Listener\Attachments->onCompose() | | #6 | Civi\FlexMailer\Listener\OpenTracker->onCompose() | | #7 | Civi\FlexMailer\Listener\HookAdapter->onCompose() | +-------+-------------------------------------------------------+ [Event] civi.flexmailer.send +-------+--------------------------------------------------+ | Order | Callable | +-------+--------------------------------------------------+ | #1 | Civi\FlexMailer\Listener\DefaultSender->onSend() | +-------+--------------------------------------------------+ ``` -------------------------------- ### Define import map for civicrm prefix Source: https://github.com/civicrm/civicrm-core/blob/master/Civi/Esm/README.md Defines an import map for native browser-based imports, mapping the logical prefix 'civicrm/' to a physical URL. This is required for using logical paths in ESM imports. ```html ``` -------------------------------- ### Insert with {$domainID} placeholder Source: https://github.com/civicrm/civicrm-core/blob/master/CRM/Upgrade/Incremental/sql/README.txt Use {$domainID} in incremental upgrade SQL templates that include domain_id. This placeholder is defined in CRM_Upgrade_Form::processLocales() and is available to all incremental .tpl files. ```sql INSERT INTO `civicrm_report_instance` ( `domain_id`, `title`, `report_id`, `description`, `permission`, `form_values`) VALUES ( {$domainID}, 'Mailing Detail Report', 'mailing/detail', 'Provides reporting on Intended and Successful Deliveries, Unsubscribes and Opt-outs, Replies and Forwards.', '', '{literal}a:30:{s:6:"fields";a:6:{s:9:"sort_name";s:1:"1";s:12:"mailing_name";s:1:"1";s:11:"delivery_id";s:1:"1";s:14:"unsubscribe_id";s:1:"1";s:9:"optout_id";s:1:"1";s:5:"email";s:1:"1";}s:12:"sort_name_op";s:3:"has";s:15:"sort_name_value";s:0:"";s:6:"id_min";s:0:"";s:6:"id_max";s:0:"";s:5:"id_op";s:3:"lte";s:8:"id_value";s:0:"";s:13:"mailing_id_op";s:2:"in";s:16:"mailing_id_value";a:0:{}s:18:"delivery_status_op";s:2:"eq";s:21:"delivery_status_value";s:0:"";s:18:"is_unsubscribed_op";s:2:"eq";s:21:"is_unsubscribed_value";s:0:"";s:12:"is_optout_op";s:2:"eq";s:15:"is_optout_value";s:0:"";s:13:"is_replied_op";s:2:"eq";s:16:"is_replied_value";s:0:"";s:15:"is_forwarded_op";s:2:"eq";s:18:"is_forwarded_value";s:0:"";s:6:"gid_op";s:2:"in";s:9:"gid_value";a:0:{}s:9:"order_bys";a:1:{i:1;a:2:{s:6:"column";s:9:"sort_name";s:5:"order";s:3:"ASC";}}s:11:"description";s:21:"Mailing Detail Report";s:13:"email_subject";s:0:"";s:8:"email_to";s:0:"";s:8:"email_cc";s:0:"";s:10:"permission";s:1:"0";s:9:"parent_id";s:0:"";s:6:"groups";s:0:"";s:9:"domain_id";i:1;}{/literal}'); ``` -------------------------------- ### Embed CiviCRM page on Standalone with iframe=1 Source: https://github.com/civicrm/civicrm-core/blob/master/ext/iframe/README.md Embeds a CiviCRM page on Standalone by adding the query parameter `?iframe=1` to the page URL. ```html ``` -------------------------------- ### Configure requestLimits maxQueryString in web.config Source: https://github.com/civicrm/civicrm-core/wiki/Installation-under-Windows-(IIS) Add these lines to the web.config file on a Windows Server to increase the maximum query string length to 8192 characters, resolving DataTable Ajax errors caused by long querystrings that return a 404. ```xml ``` -------------------------------- ### Replace FlexMailer delivery with batch web-service using SendBatchEvent Source: https://github.com/civicrm/civicrm-core/blob/master/ext/flexmailer/docs/develop/SendBatchEvent.md Registers a listener for the FlexMailer EVENT_SEND event and replaces the built-in delivery mechanism with a batch-oriented web-service call. The listener stops propagation to disable standard delivery, serializes the event's tasks, and POSTs them to a remote endpoint. ```php addResource(new \Symfony\Component\Config\Resource\FileResource(__FILE__)); $container->findDefinition('dispatcher')->addMethodCall('addListener', array(\Civi\FlexMailer\FlexMailer::EVENT_SEND, '_example_send_batch') ); } function _example_send_batch(\Civi\FlexMailer\Event\SendBatchEvent $event) { // Disable standard delivery $event->stopPropagation(); $context = stream_context_create(array( 'http' => array( 'method' => 'POST', 'header' => 'Content-type: application/vnd.php.serialize', 'content' => serialize($event->getTasks()), ), )); return file_get_contents('https://example.org/batch-delivery', FALSE, $context); } ``` -------------------------------- ### Register ESM module with logical imports Source: https://github.com/civicrm/civicrm-core/blob/master/Civi/Esm/README.md Registers a JavaScript module that uses the logical paths defined in the import map. The comments show how each import maps to a physical file in the extension. ```php Civi::resources()->addModule(' import { FooClass } from "foo/foo.dist.js"; // Maps to MY_EXTENSION/js/foo/foo.dist.js import { barFunc } from "bar/bar.funcs.js"; // Maps to MY_EXTENSION/packages/bar/dist/bar.funcs.js barFunc("Hello", new FooClass()); '); ``` -------------------------------- ### Add import map prefixes in extension hook Source: https://github.com/civicrm/civicrm-core/blob/master/Civi/Esm/README.md Adds logical prefixes to the import map from an extension. Use this hook to register your extension's ESM files so they can be imported via short logical paths. ```php function myext_civicrm_esmImportMap(\Civi\Esm\ImportMap $importMap): void { $importMap->addPrefix('foo/', E::LONG_NAME, 'js/foo/'); $importMap->addPrefix('bar/', E::LONG_NAME, 'packages/bar/dist/'); } ``` -------------------------------- ### Encode JWT token for AuthX authentication Source: https://github.com/civicrm/civicrm-core/blob/master/ext/authx/README.md Prepare a JWT token on the server using Civi::service('crypto.jwt')->encode(). The token includes an expiration time, subject contact ID, and scope 'authx'. ```php $token = Civi::service('crypto.jwt')->encode([ 'exp' => time() + 5*60, // Expires in 5 minutes 'sub' => 'cid:203', // Subject (contact ID) 'scope' => 'authx', // Allow general authentication ]); ``` -------------------------------- ### Embed CiviCRM page on Drupal/Backdrop with iframe.php Source: https://github.com/civicrm/civicrm-core/blob/master/ext/iframe/README.md Embeds a CiviCRM page on Drupal or Backdrop by prefixing the path with `iframe.php/`. ```html ``` -------------------------------- ### Embed CiviCRM page on WordPress with _cvwpif=1 Source: https://github.com/civicrm/civicrm-core/blob/master/ext/iframe/README.md Embeds a CiviCRM page on WordPress by adding the query parameter `?_cvwpif=1` to the page URL. ```html ``` -------------------------------- ### Disable Have I Been Pwned integration in civicrm.settings.php Source: https://github.com/civicrm/civicrm-core/blob/master/ext/standaloneusers/README.md Add this line to civicrm.settings.php to disable the Have I Been Pwned password checking integration. The constant CIVICRM_HIBP_URL is set to an empty string. ```php // Disable haveibeenpwned checking. define('CIVICRM_HIBP_URL', ''); ``` -------------------------------- ### Basic af-api4-action usage Source: https://github.com/civicrm/civicrm-core/blob/master/ext/afform/core/ang/afCore/Api4Action.md Basic usage of the af-api4-action directive to delete a contact when the button is clicked. ```html ```