Skip to content
Snippets Groups Projects
architecture.md 10.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • Erich's avatar
    Erich committed
    # The codebase
    
    This chapter provides a general overview of the codebase organisation.
    
    
    Erich Schulz's avatar
    Erich Schulz committed
    !!! tip
        In order to explore the directories inside the CiviCRM repository it is
        generally quickest to to make a local clone of the CiviCRM from GitHub,
        or better yet install the [buildkit](/requirements/#buildkit).
    
    Erich's avatar
    Erich committed
    
    !!! tip
        The CiviCRM codebase is object oriented. If you aren't familiar with object
        oriented programming, spend a little time reading some beginner tutorials on
        the net.
    
    ## Namespaces
    Classes in CiviCRM must be placed in one of two folders:
    
    
    Erich's avatar
    Erich committed
    ***`CRM`*** (e.g.: `CRM_Core_Invoke`)
    
    Erich's avatar
    Erich committed
    classes use PEAR-style class-naming conventions that were common up until
    PHP 5.2. Class names include underscores and MUST NOT use the PHP
    "[namespace](http://php.net/namespace)"
    
    Erich's avatar
    Erich committed
    directive. Use `CRM` style when creating classes that plug into existing `CRM`
    
    Erich's avatar
    Erich committed
    subsystems such
    as payment processors (CRM_Core_Payment) and reports (CRM_Report).
    
    
    Erich's avatar
    Erich committed
    ***`Civi`*** (e.g.: `\Civi\API\Kernel`)
    
    Erich's avatar
    Erich committed
    "Civi" classes use PHP 5.3 namespaces. They MUST use the
    "[namespace](http://php.net/namespace)" directive.
    Namespaces are designated with "\".
    
    
    Erich's avatar
    Erich committed
    !!! note
    
    Erich's avatar
    Erich committed
        At time of writing (May 2014, before Civi 4.5), some classes may not load
    
    Erich's avatar
    Erich committed
        properly if they are in `Civi` – for example, the payment system will only load
        payment-processor classes in `CRM_Core_Payment`. If you encounter problems like
        this, please submit an issue or patch.
    
    Erich's avatar
    Erich committed
    
    
    Erich's avatar
    Erich committed
    !!! tip
        The `Civi` namespace uses composer's PSR-0 autoloader. This autoloader does not
    
    Erich's avatar
    Erich committed
        support custom PHP overrides.
    
    Erich's avatar
    Erich committed
        Use `Civi` when creating new object-oriented subsystems (like `\Civi\API`).
    
    Erich's avatar
    Erich committed
    
    ## Business logic
    
    Erich's avatar
    Erich committed
    Most of the business logic of CiviCRM, is found in the CRM directory (`CIVICRM_ROOT/CRM`).
    
    Erich's avatar
    Erich committed
    This logic is the part of CiviCRM that
    defines what it does and how it behaves
    
    Erich Schulz's avatar
    Erich Schulz committed
    (e.g. that allows people to register on events).
    
    Erich's avatar
    Erich committed
    In this directory, you will find directories for core CiviCRM functions like
    contacts, groups, profiles, deduping, importing, and the CiviCRM components
    like CiviCampaign, CiviMail, Pledges, etc.
    
    
    Erich Schulz's avatar
    Erich Schulz committed
    Each of these directories is slightly different depending on their purpose, but
    
    Erich's avatar
    Erich committed
    there are some common subdirectories: BAO, DAO, Form and Page.
    
    ### DAO
    
    Erich Schulz's avatar
    Erich Schulz committed
    The CiviCRM **data access objects** (DAOs) are PHP classes that
    ([e.g. `CRM/Pledge/DAO`](https://github.com/civicrm/civicrm-core/tree/master/CRM/Pledge/DAO))
    expose the contents
    of the database.  The release script generates each DAO automatically based
    on the matching XML file in the [data schema](#database-structure).  DAO objects tend to be instantiated in BAO classes.
    
    Erich's avatar
    Erich committed
    
    
    Erich Schulz's avatar
    Erich Schulz committed
    The DAO classes all extend the core
    [DAO base class](https://github.com/civicrm/civicrm-core/blob/master/CRM/Core/DAO.php)
    which itself is an extension of the external
    [DataObject class](https://github.com/civicrm/civicrm-packages/blob/master/DB/DataObject.php).
    These base classes provide standard CRUD (create, retrieve, update and delete)
    methods, etc. <!--fixme why the etc? what else?? -->
    
    Erich's avatar
    Erich committed
    
    
    Erich Schulz's avatar
    Erich Schulz committed
    The generated DAO object has:
    
    
    * A property for each field using the actual field name, not the unique name
    
    Erich Schulz's avatar
    Erich Schulz committed
    * A `links()` method which retrieves the links to other tables (off the foreign keys)
    * An `import()` method and an `export()` method for ?
    
    Erich's avatar
    Erich committed
    * A `fields()` method which returns an array of fields for that object keyed by the field's unique name. 
    
    * A couple of functions to define the labels for enumerated fields
    
    
    Erich's avatar
    Erich committed
    Looking at the field 'pledge.amount' we see
    
    
    ```php
      'pledge_amount' => array(
        'name' => 'amount',
        'type' => CRM_Utils_Type::T_MONEY,
        'title' => ts('Total Pledged') ,
        'required' => true,
        'import' => true,
        'where' => 'civicrm_pledge.amount',
        'headerPattern' => '',
        'dataPattern' => '',
        'export' => true,
        'bao' => 'CRM_Pledge_BAO_Pledge',
        'table_name' => 'civicrm_pledge',
        'entity' => 'Pledge',
      ),
    ```
    
    
    Erich Schulz's avatar
    Erich Schulz committed
    The key is the unique name but the name field is the field's name and the 'where' field shows the MySQL description of it. We also see the data type and whether it is available for search or export.
    
    Erich Schulz's avatar
    Erich Schulz committed
    Generally fields should be exportable unless there is a security reason or they are weird and confusing as the search builder is also driven by this setting.
    
    Erich Schulz's avatar
    Erich Schulz committed
    Fields whose option values can be calculated will also have a `pseudoconstant` section.
    
    Erich's avatar
    Erich committed
    ### BAO
    
    BAO stands for business access object
    ([example](https://github.com/civicrm/civicrm-core/blob/master/CRM/Event/BAO/Event.php)).
    BAOs map to DAOs and extend them with
    
    Erich's avatar
    Erich committed
    the business logic of CiviCRM.  The core logic of CiviCRM belongs in the
    
    Erich's avatar
    Erich committed
    BAOs, for example they have the code that creates follow up activities when an
    activity is created, or create activities and populating custom fields when a
    pledge is created.
    
    
    !!! note
    
        Historically some BAOs had both `add()` and `create()` methods. Current practice 
        is to favour a single `create()` method.
    
    Erich's avatar
    Erich committed
    ### Form
    In general each form page in CiviCRM maps to a file in one of
    the form directories.  Form files contain a class that extends CRM_Core_Form.
    This class has different methods that the core calls before display to
    check permissions, retrieve information (`preProcess`), display
    the form (`buildForm`), validate the form (`formRule`) and carry out tasks once the
    form is submitted (`postProcess`).  Forms can diplay information from the BAO
    to users and then call the BAO on submission. Generaly each form has an
    associated template (see below) which defines the form's html.
    
    
    Erich's avatar
    Erich committed
    !!! Note
        Logic in forms should support friendly user-interfaces but core application logic belongs in the BAO layer. 
        Moving logic to BAO layer facilitates unit testing and developing modernised front-end applications in the future.
    
    
    Erich's avatar
    Erich committed
    !!! tip
        Perhaps the best way to get to grips with the Forms is by experience and
        experimentation.
    
    ### Page
    If a CiviCRM screen is not a Form, it is probably a page.  Pages files contain a
    class that extend CRM_Core_Page.  Similar to the form class, Pages have methods
    that are called before the page is displayed to control access, set the title,
    etc. (`preProcess`), and when the page is displayed (`run`). Pages tend to
    take information from the BAO to be displayed to users. In general, each
    page has an associated template (see below) which is used to create the
    html of the page.
    
    ### xml
    This directory contains a menu directory which maps urls to CRM form or page
    classes and controls access to these URLs using permissions.
    
    ## Templates
    The templates directory contains all the HTML for pages and forms.  Directly
    inside the templates directory is a CRM directory.  In general, all templates
    map to a form or page class.  CiviCRM chooses a template for the form or page
    based on the class name.
    
    For example, the class CRM_Member_Form_MembershipRenewal looks for a template
    in `templates/CRM/Member/Form/MembershipRenewal.tpl`.
    
    Templates are written in smarty, a common PHP template engine.  Variables can
    be passed to smarty using the assign() method which is available to all Form
    and Page classes.
    
    Customising templates is discussed in more detail in 'Techniques'
    
    ## The API
    
    Erich Schulz's avatar
    Erich Schulz committed
    The application programming interface (API) is stored in the `/api`
    
    Erich's avatar
    Erich committed
    directory.  Best practice for using the API is discussed in more detail in
    'Techniques'
    
    ## bin scripts
    The bin directory contains a variety of scripts that can be run to carry out
    specific functions.  Some of these scripts are run on a regular basis, for
    example the CiviMail 'send' and 'process' scripts.  Others are run on a one of
    or occasional basis, e.g. update geo-coding.
    
    ## SQL
    The SQL directory is automatically generated as part of a release.  It contains
    useful files like the SQL to create the database and insert demo data. Most
    
    Erich Schulz's avatar
    Erich Schulz committed
    developers will not need to edit files in this directory.
    
    Erich's avatar
    Erich committed
    
    ## l10n
    This directory contains lots of automatically generated localisation files.
    You should not need to edit this directory directly.  You should instead use
    CiviCRM's online translation tool transifex.
    
    ## packages
    CiviCRM makes use of a lot of 3rd party packages for things like the database,
            form, javascript and pdf libraries, wysiwyg editors and so on.  You
            shouldn't need to edit these packages directory.
    
    ## Database structure
    
    
    The database structure is defined in a series of XML files
    
    Erich Schulz's avatar
    Erich Schulz committed
    ([example](https://github.com/civicrm/civicrm-core/blob/master/xml/schema/SMS/History.xml)).
    
    These files are
    
    Erich's avatar
    Erich committed
    not packaged in the releases but are available in the Github repository. They
    
    Erich Schulz's avatar
    Erich Schulz committed
    are located in
    [`/xml/schema`](https://github.com/civicrm/civicrm-core/blob/master/xml/schema).
    All the folders within the schema directory also
    have matching folders in the main
    [`/CRM`](https://github.com/civicrm/civicrm-core/blob/master/CRM).
    folder which contain the DAOs and BAOs.
    
    Erich's avatar
    Erich committed
    
    
    !!! Info
    
    Erich Schulz's avatar
    Erich Schulz committed
        A [`GenCode` script](https://github.com/civicrm/civicrm-core/blob/master/xml/GenCode.php) (which calls the
        [`CRM_Core_CodeGen_Main` class](https://github.com/civicrm/civicrm-core/blob/master/CRM/Core/CodeGen/Main.php))
        performs the magic of translating the XML files to
        the DAO PHP classes and the database table creation SQL scripts
        `civicrm.mysql` and `civicrm_data.mysql` in the
        [`/sql`](https://github.com/civicrm/civicrm-core/blob/master/sql) folder.
    
    
    Erich Schulz's avatar
    Erich Schulz committed
    Looking in [`/xml/schema/Pledge`](https://github.com/civicrm/civicrm-core/blob/master/xml/schema/Pledge)
        as an example we see 4 files:
    
    Erich Schulz's avatar
    Erich Schulz committed
    - `files.xml`
    - `Pledge.xml`
    - `PledgePayment.xml`
    - `PledgeBlock.xml`
    
    Erich's avatar
    Erich committed
    
    
    Erich Schulz's avatar
    Erich Schulz committed
    The `files.xml` is just a list of the other files. Each of the other files describes a
    table in the database, defining both table-leve and field-level metadata
    including foreign keys and indexes:
    
    Erich's avatar
    Erich committed
    
    
    Erich Schulz's avatar
    Erich Schulz committed
    ```
    <table>
      <base>CRM/SMS</base>
      <class>History</class>
      <name>civicrm_sms_history</name>
      <comment>SMS History can be linked to any object in the application.</comment>
      <add>1.4</add>
      <drop>2.0</drop>
      ... etc
    ```
    
    Erich's avatar
    Erich committed
    
    
    Erich Schulz's avatar
    Erich Schulz committed
    An example of a field definition is:
    
    Erich's avatar
    Erich committed
    
    ```
      <field>
        <name>amount</name>
        <uniqueName>pledge_amount</uniqueName>
        <title>Total Pledged</title>
        <type>decimal</type>
        <required>true</required>
        <import>true</import>
        <comment>Total pledged amount.</comment>
        <add>2.1</add>
      </field>
    ```
    
    
    <!-- fixme:
    The field 'amount' in the table 'pledge' has a unique name to distinquish it from fields in other tables (e.g. contribute) with the same field. This isn't consistent in all tables and I am trying to find out the reason / rules for this. Also, I presume 'import' means the field is exposed for .... imports?.-->
    
    We can see that the above 'pledge_amount' field was added in CiviCRM v2.1.
    
    
    Erich Schulz's avatar
    Erich Schulz committed
    Occassionally tables are dropped from the core schema so will not have associated DAOs.
    For example, the
    
    [SMS history](https://github.com/totten/civicrm-core/blob/master/xml/schema/SMS/History.xml)
    table was dropped in version 2.0, as indicated by a `<drop>2.0</drop>` field.