Skip to content

civix (legacy)

Deprecation Notice

The following civix functions are deprecated. This page contains archived documentation.

XML-based Entities & DAOs

Historical Note: Legacy CiviCRM schema entities were defined in xml files which were used to generate DAO.php classes. The civix generate:entity now generates .entityType.php files instead of xml, and civix generate:entity-boilerplate is now obsolete. Archived documentation follows:

If you want your extension to store data in the database, then you will need to create a new entity.

  1. Pick a name for your entity.

    Make sure to use CamelCase here.

    This creates a skeletal file for your XML schema, your BAO, and your API.

  2. Edit the XML schema definitions that you just generated (in the xml folder). Define your desired fields.

  3. Generate your DAO and SQL files.

     civix generate:entity-boilerplate
    

    You can safely re-run this command after you make changes to your XML schema definition. But if your schema changes require database migrations for existing installations, then you'll need to write a migration manually in addition to re-generating your boilerplate.

  4. Generate a database upgrader.

     civix generate:upgrader
    

Even though you're not yet creating any upgrades for your extension, you need to do this step now so that CiviCRM will pick up auto_install.sql and auto_uninstall.sql later on.

  1. Re-install your extension.

     cv ext:uninstall myextension
     cv ext:enable myextension
    

Now your entity should be ready to use. Try it out with cv api4 MyEntity.create and cv api4 MyEntity.get. Then add some tests.

Add an APIv3 function

The CiviCRM API provides a way to expose functions for use by other developers. API functions allow implementing AJAX interfaces (using the CRM.$().crmAPI() helper), and they can also be called via REST, PHP, Smarty, Drush CLI, and more. Each API requires a two-part name: an entity name (such as "Contact", "Event", or "MyEntity") and an action name (such as "create" or "myaction").

Unfortunately Civix can only create v3 apis at the moment. Generally v4 CRUD apis are more useful since they allow your entities to be accessed from search-kit and form-builder. relevant issue & how to manually add

Get started by accessing the civix help:

civix help generate:api

Note

Action names must be lowercase. The javascript helpers CRM.api() and CRM.api3() force actions to be lowercase. This issue does not present itself in the API Explorer or when the api action is called via PHP, REST, or SMARTY.

Note

The API loader is very sensitive to case on some platforms. Be careful with capitalization, underscores and multiword action names. API calls can work in one context (Mac OSX filesystem, case-insensitive) and fail in another (Linux filesystem, case-sensitive).

You can make your API code with a command in this pattern:

civix generate:api NewEntity newaction

This creates one file:

  • api/v3/NewEntity/Newaction.php provides the API function civicrm_api3_new_entity_newaction() and the specification function _civicrm_api3_new_entity_newaction_spec(). Note that the parameters and return values must be processed in a particular way (as demonstrated by the auto-generated file).

For use with CiviCRM 4.3 and later, you can also add the --schedule option (e.g., --schedule Hourly). This will create another file:

  • api/v3/NewEntity/Newaction.mgd.php provides the scheduling record that will appear in the CiviCRM's job-manager.

When calling the API, follow these rules:

  • Entity-names are UpperCamelCase
  • Action-names are lowersmashedcase
  • Other variations may work when you call them. Some docs/explorers may show these in cases which work. However, if you try to do the same in new code, you may get a headache.

For example: cv api NewEntity.newaction civicrm_api3('NewEntity', 'newaction')

Tip

Read more about APIv4 architecture for help writing custom APIv4 implementations.

Deprecation Notice

You are discouraged from creating new custom searches using this legacy framework. The focus is now on using SearchKit.

If you do add custom searches be sure to add unit tests and run them regularly.

CiviCRM enables developers to define new search forms using customizable SQL logic and form layouts. Use this command to get started:

civix help generate:search

Then you could generate your basic search code for a MySearch class with:

civix generate:search MySearch

This command will create two files:

  • CRM/Myextension/Form/Search/MySearch.mgd.php stores metadata about the custom search. The format of the file is based on hook_civicrm_managed and the API.
  • CRM/Myextension/Form/Search/MySearch.php contains the form-builder and query-builder for the custom search.

Enabling the CustomSearch Extension

Because custom searches have been relegated to an extension and are no longer a core part of CiviCRM, you will need to require it in your info.xml:

  <requires>
    <ext>legacycustomsearches</ext>
  </requires>

If one of the existing searches is close to meeting your needs you may copy it instead and then customise the PHP, SQL and templates.

To make a new search based on an existing search first determine the name of the original search class within the civicrm/CRM/Contact/Form/Search/Custom directory of CiviCRM source tree. Then run the generate:search command from within your module directory.

For example, the zipcode search is in the class CRM_Contact_Form_Search_Custom_ZipCodeRange, so you can copy it with:

civix generate:search --copy CRM_Contact_Form_Search_Custom_ZipCodeRange MySearch

The "copy" option will create either two or three files depending on whether the original search screen defines its own Smarty template.

  1. Disable and re-enable your extension.
  2. Go to Search > Custom Searches... and find your new custom search listed at the bottom.

Now you have a working custom search, but how do you make it do something custom?

If your search extends anything other than contacts you probably need to add a function to prevent notices like this

 /**
  * @param CRM_Utils_Sort $sort
  * @param string $cacheKey
  * @param int $start
  * @param int $end
  *
  * @throws \CRM_Core_Exception
  */
  public function fillPrevNextCache($sort, $cacheKey, $start = 0, $end = self::CACHE_SIZE): void {
    return;
  }
See this (extremely outdated) wiki page for more information.

extension's managed directory (or when exporting Afforms, .aff.* files in the ang directory). 4. Afterwards you can optionally adjust the update and cleanup settings in the generated file.

Example: To export a saved search with all its related search displays and Afforms:

civix export SavedSearch 12
Example: To export an Afform, including its definition and layout files:
civix export Afform nameOfMyForm

Type civix export -h for more info about the command.

Add a basic quickform web page

CiviCRM uses a typical web-MVC architecture. To implement a basic web page, you must create a PHP controller class, create a Smarty template file, and create a routing rule. You can create the appropriate files by calling civix generate:page.

Once again you can review the output of this command to see the available options:

civix generate:page --help

Generally you will only need to supply the PHP class name and web-path, for example:

civix generate:page MyPage civicrm/my-page

This creates three files:

  • xml/Menu/myextension.xml defines request-routing rules and associates the controller ("CRM_Myextension_Page_Greeter") with the web path civicrm/my-page.
  • CRM/Myextension/Page/MyPage.php is the controller which coordinates any parsing, validation, business-logic, or database operations.
  • templates/CRM/Myextension/Page/MyPage.tpl is loaded automatically after the controller executes. It defines the markup that is eventually displayed. For more information on the syntax of this file, see the smarty guide.

The auto-generated code for the controller and view demonstrate a few basic operations, such as passing data from the controller to the view.

Note

After adding or modifying a route in the XML file, you must reset CiviCRMs "menu cache". Do this in the CiviCRM user interface (Administer>System Settings>Cleanup Caches and Update Paths), in a web browser by visiting /civicrm/menu/rebuild?reset=1 or, if using Drupal & Drush, by running drush cc civicrm.

Test your knowledge

A little quiz to test your knowledge:

Add a Quickform Page

Caution

The form system (based on QuickForm) is not well documented and the CiviCRM 5.x series have seen a growing number of forms based on Afform. Consider whether creating an Afform could better suit your needs.

CiviCRM uses a typical web-MVC architecture. To implement a basic web form, you must create a PHP controller class, create a Smarty template file, and create a routing rule. You can create the appropriate files by calling civix generate:form.

The form generation command has similar arguments to civix generate:page, requiring a class name and a web route:

civix generate:form FavoriteColor civicrm/favcolor

This creates three files:

  • xml/Menu/myextension.xml defines request-routing rules and associates the controller CRM_Myextension_Form_FavoriteColor with the web path civicrm/favcolor.
  • CRM/Myextension/Form/FavoriteColor.php is the controller which coordinates any parsing, validation, business-logic, or database operations. For more details on how this class works, see QuickForm Reference.
  • templates/CRM/Myextension/Form/FavoriteColor.tpl is loaded automatically after the controller executes. It defines the markup that is eventually displayed. For more information on the syntax of this file, see the smarty guide.

The auto-generated code for the controller and view demonstrate a few basic operations, such as adding a <select> element to the form.

Note

After adding or modifying a route in the XML file, you must reset CiviCRMs "menu cache". Do this in the CiviCRM user interface (Administer>System Settings>Cleanup Caches and Update Paths), in a web browser by visiting /civicrm/menu/rebuild?reset=1 or, if using Drupal & Drush, by running drush cc civicrm..

Test your knowledge

A little quiz to test your knowledge:

Add a case type

This command is now deprecated in favor of exporting a case type as a managed entity. Legacy documentation follows:

If you want to develop a custom case-type for CiviCase, then you can generate a skeletal CiviCase XML file.

Once again civix will give the details of options and arguments with this command:

civix help generate:case-type

This reports that civix expects a label argument and an optional name:

civix generate:case-type "Volunteer Training" Training

This creates two files:

  • xml/case/Training.xml defines the roles, activity types, and timelines associated with the new case type. For more in depth discussion of CiviCase XML, see CiviCase Configuration.
  • alltypes.civix.php(which may already exist) defines implementations of various hooks (notably hook_civicrm_caseTypes).

Add a report

CiviReport is Deprecated

CiviReport is being phased out in favor of SearchKit.

You can often achieve what you want to achieve using SearchKit and you should only generate CiviReports if you have determined SearchKit can't meet your use case.

In some cases you can take advantage of the alterReportVar hook to adjust the columns, sql, or event rows of an existing report to modify it to suit your needs instead of creating a new report. However, this is generally discouraged as changes to the report could break your extension.

To see the available report generation options activate the civix help:

civix generate:report --help

To create a new report specify the report PHP class name and the CiviCRM component, for example:

civix generate:report MyReport CiviContribute

This creates three files:

  • CRM/Myextension/Form/Report/MyReport.mgd.php stores metadata about the report in a format based on hook_civicrm_managed and the API.
  • CRM/Myextension/Form/Report/MyReport.php contains the form-builder and query-builder for the report. For details about its structure, see the CiviReport Reference.
  • templates/CRM/Myextension/Form/Report/MyReport.tpl contains the report's HTML template. This template usually delegates responsibility to a core template and does not need to be edited.

If one of the existing reports is close to meeting your needs, but requires further PHP or SQL customization, you may simply make a new report based on that report. To copy a report, find the class-name of the original report within the civicrm/CRM/Report/Form/ directory in the CiviCRM repository. Then run the civix generate:report command using the copy option from within your extension directory.

For example, this command will copy the activity report in the class CRM_Report_Form_Activity to a new report within your extension:

civix generate:report --copy CRM_Report_Form_Activity MyActivity Contact

Note

Copying a report like this and modifying it is likely to lead to maintenance issues similar to those related to overriding core files in an extension. In particular, bug fixes or other changes to code that you have copied will not automatically be applied to the copied code your new report. Often a better approach is to extend the class of the core report in your extension, then selectively override its functions. In the functions that you override, if possible run the original code and then just tweak the behaviour afterwards, i.e: at the beginning of thisFn(), call parent::thisFn() then add your code. For example:

```php
class CRM_myExtension_Form_Report_ExtendContributionDetails extends CRM_Report_Form_Contribute_Detail {
  public function from() {
    parent::from();
    // your code
  }
  ...
}
```

Note

To have your extension create an instance of your report template with configurations for columns, groups, filtering, etc. and then put it into the menu system, you need to make an additional entry in the CRM/Myextension/Form/Report/MyReport.mgd.php file. The additional entry needs some serialized data that is not easy to code but is easy to lookup for a configured report instance. So manually configure a report instance appropriately on a CiviCRM install running your extension (i.e. go to Administer > CiviReport > Create New Report from Template, then configure and save the instance). Then use APIv3 to get the ReportInstance values you need for your .mgd.php entry. Note that you need to specify the return fields as navigation_id is not returned by default. If you are not emailing the report, then the following should be sufficient, substituting the id for your report for 8 below:

$result = civicrm_api3('ReportInstance', 'get', [
'sequential' => 1,
'return' => ["title", "report_id", "name", "description", "permission", "grouprole", "is_active", "navigation_id", "is_reserved", "form_values"],
'id' => 8,
]);
Add an additional array entry into your .mgd.php that includes the elements of values array, adding a module entry, eg:

```
[
'module' => 'com.example.myextension',
'name' => 'My Enhanced Contribution Detail',
...
  'is_reserved' =>  0,
],
```