### 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
labelOption Labelvarchartrue255trueOption 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
```