Answers.Body: <p>And this is an example of a function to create an Activity type</p>
  
  <pre><code>  /**
     * Function to create activity type
     *
     * @param array $params
     * @return array
     * @throws Exception when params invalid
     * @throws Exception when error from API create
     * @access public
     * @static
     */
    public static function createActivityType($params) {
      $activityTypeData = array();
      $params['option_group_id'] = self::getOptionGroupIdWithName('activity_type');
      if (!isset($params['name']) || empty($params['name'])) {
        throw new Exception('When trying to create an Activity Type name is a mandatory parameter and can not be empty');
      }
      if (empty($params['label']) || !isset($params['label'])) {
        $params['label'] = self::buildLabelFromName($params['name']);
      }
      if (!isset($params['is_active'])) {
        $params['is_active'] = 1;
      }
      if (self::getActivityTypeWithName($params['name']) == FALSE) {
        try {
          $activityType = civicrm_api3('OptionValue', 'Create', $params);
          $activityTypeData = $activityType['values'][$activityType['id']];
        } catch (CiviCRM_API3_Exception $ex) {
          throw new Exception('Could not create activity type with name ' . $params['name']
            . ', error from API OptionValue Create: ' . $ex-&gt;getMessage());
        }
      }
      return $activityTypeData;
    }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-04-06T20:32:59.060Z
Answers.Text: Where would this function be placed/integrated?
Answers.UserDisplayName: Vito Mantese
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-06-09T10:00:07.713Z
Answers.LastActivityDate: 2015-06-09T10:00:07.713Z
Answers.UserDisplayName: ErikH - CiviCooP
Answers.Body: <p>You first create the activity type in your code. 
  Then you create the custom group with extends = Activity, where you then have to set the activity type you want to link the data too in the param 'extends_entity_column_value', something like this:</p>
  
  <pre><code> if ($customGroupParams['extends'] == 'Activity') {
        $extendsActivity = CRM_Streetimport_Utils::getActivityTypeWithName($customGroupData['extends_entity_column_value']);
        $customGroupParams['extends_entity_column_value'] = CRM_Core_DAO::VALUE_SEPARATOR.$extendsActivity['value'];
   }
  </code></pre>
  
  <p>and then you can add your custom fields. Does that answer your question?</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-06-09T07:50:43.780Z
Answers.LastActivityDate: 2015-06-09T07:50:43.780Z
Answers.UserDisplayName: ErikH - CiviCooP
Answers.Body: <p>I've done this with the API. Pretty much everything you create in CiviCRM has a machine name field. This can be used as a known identifier, whereas the numerical Id fields cannot be known across different installations.</p>
  
  <p>I made a helper which significantly shortened my install code:</p>
  
  <pre><code>/**
   * Helper function for creating data structures.
   *
   * @param string $entity - name of the API entity.
   * @param Array $params_min parameters to use for search.
   * @param Array $params_extra these plus $params_min are used if a create call
   *              is needed.
   */
  function pelf_get_or_create($entity, $params_min, $params_extra) {
    $params_min += ['sequential' =&gt; 1];
    $result = civicrm_api3($entity, 'get', $params_min);
    if (!$result['count']) {
      // Couldn't find it, create it now.
      $result = civicrm_api3($entity, 'create', $params_extra + $params_min);
    }
    return $result['values'][0];
  }
  </code></pre>
  
  <p>Then the install can do things like:</p>
  
  <pre><code>  // Ensure we have the activity type set up for Prospects.
    $my_activity_type = pelf_get_or_create('OptionValue', [
      'option_group_id' =&gt; "activity_type",
      'name' =&gt; "my_unique_activity",
    ],
    [ 'label' =&gt; 'Something suitable']);
  
    // Ensure we have the custom field group we need for prospects.
    $customgroup = pelf_get_or_create('CustomGroup', [
      'name' =&gt; "another_unique_name",
      'extends' =&gt; "Activity",
      'extends_entity_column_value' =&gt; $my_activity_type['value'],
    ],
    ['title' =&gt; 'Some custom Details']);
  
    // Add a field.
    $my_field_1 = pelf_get_or_create('CustomField', [
        'name' =&gt; "another_name_for_field",
        'custom_group_id' =&gt; $customgroup['id'],
        'data_type' =&gt; "String",
        'html_type' =&gt; "Text",
        'is_required' =&gt; "1",
        'default_value' =&gt; "0",
      ],
      ['label' =&gt; 'Explain it']);
  </code></pre>
  
  <p>Nb. I had to create a select field, too. This was a pain because you have to create the option group for its options, then all its options, then finally create the field itself, passing the id of the option group to the field create. I omitted it here because it's basically more of the same.</p>
  
  <p>Anyway, with that code in my install hook, I can then easily fetch them in other code in my extension by using the names as lookups. AFAICS the name field is a machine-only field - there's usually a 'label' or 'title' field that is used by the UI.</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2016-03-21T18:50:24.833Z
Answers.LastActivityDate: 2016-03-21T18:50:24.833Z
Answers.UserDisplayName: artfulrobot
Body: <p>I want to extend my extension with a custom Activity type that has it's own custom fields. The Activity type is not part of a case.</p>
  
  <p>I can not find in civix help and in <a href="http://wiki.civicrm.org/confluence/display/CRMDOC/Create+an+Extension" rel="nofollow">http://wiki.civicrm.org/confluence/display/CRMDOC/Create+an+Extension</a> how to do that.</p>
  
  <p>Who knows?</p>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2016-03-21T10:39:09.317Z
Comments.Text: Did you do this? And if you did, how did you later refer to the `activity_type_id`s created - by lookup by name/label or did you store the ID somewhere? I'm needing to do the same. Thanks.
Comments.UserDisplayName: artfulrobot
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2016-04-08T17:53:02.123Z
Comments.Text: Also interested. I think a detailed example would be a useful tool. I can help make one once I understand it myself.
Comments.UserDisplayName: Vito Mantese
Tags: <extension><activities><best-practice>
Title: How do I add a custom Activity with custom fields to an extension?
ThreadText: # How do I add a custom Activity with custom fields to an extension?
  
  (Asked by: username_0 on 2015-06-09)
  
  I want to extend my extension with a custom Activity type that has it's own custom fields. The Activity type is not part of a case.
  
  I can not find in civix help and in <http://wiki.civicrm.org/confluence/display/CRMDOC/Create+an+Extension> how to do that.
  
  Who knows?
  
  **Tags:** extension, activities, best-practice
  
  > **Comments:**
  > **username_1**: Did you do this? And if you did, how did you later refer to the `activity_type_id`s created - by lookup by name/label or did you store the ID somewhere? I'm needing to do the same. Thanks.  
  > **username_2**: Also interested. I think a detailed example would be a useful tool. I can help make one once I understand it myself.  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_3 on 2015-06-09. Score: 5
  
  And this is an example of a function to create an Activity type
  
  ```
    /**
     * Function to create activity type
     *
     * @param array $params
     * @return array
     * @throws Exception when params invalid
     * @throws Exception when error from API create
     * @access public
     * @static
     */
    public static function createActivityType($params) {
      $activityTypeData = array();
      $params['option_group_id'] = self::getOptionGroupIdWithName('activity_type');
      if (!isset($params['name']) || empty($params['name'])) {
        throw new Exception('When trying to create an Activity Type name is a mandatory parameter and can not be empty');
      }
      if (empty($params['label']) || !isset($params['label'])) {
        $params['label'] = self::buildLabelFromName($params['name']);
      }
      if (!isset($params['is_active'])) {
        $params['is_active'] = 1;
      }
      if (self::getActivityTypeWithName($params['name']) == FALSE) {
        try {
          $activityType = civicrm_api3('OptionValue', 'Create', $params);
          $activityTypeData = $activityType['values'][$activityType['id']];
        } catch (CiviCRM_API3_Exception $ex) {
          throw new Exception('Could not create activity type with name ' . $params['name']
            . ', error from API OptionValue Create: ' . $ex->getMessage());
        }
      }
      return $activityTypeData;
    }
  
  ```
  
  > **Comments:**
  > **username_2**: Where would this function be placed/integrated?  
  
  ---
  
  ### Answer by username_3 on 2015-06-09. Score: 3
  
  You first create the activity type in your code.
  Then you create the custom group with extends = Activity, where you then have to set the activity type you want to link the data too in the param 'extends\_entity\_column\_value', something like this:
  
  ```
   if ($customGroupParams['extends'] == 'Activity') {
        $extendsActivity = CRM_Streetimport_Utils::getActivityTypeWithName($customGroupData['extends_entity_column_value']);
        $customGroupParams['extends_entity_column_value'] = CRM_Core_DAO::VALUE_SEPARATOR.$extendsActivity['value'];
   }
  
  ```
  
  and then you can add your custom fields. Does that answer your question?
  
  
  ---
  
  ### Answer by username_1 on 2016-03-21. Score: 1
  
  I've done this with the API. Pretty much everything you create in CiviCRM has a machine name field. This can be used as a known identifier, whereas the numerical Id fields cannot be known across different installations.
  
  I made a helper which significantly shortened my install code:
  
  ```
  /**
   * Helper function for creating data structures.
   *
   * @param string $entity - name of the API entity.
   * @param Array $params_min parameters to use for search.
   * @param Array $params_extra these plus $params_min are used if a create call
   *              is needed.
   */
  function pelf_get_or_create($entity, $params_min, $params_extra) {
    $params_min += ['sequential' => 1];
    $result = civicrm_api3($entity, 'get', $params_min);
    if (!$result['count']) {
      // Couldn't find it, create it now.
      $result = civicrm_api3($entity, 'create', $params_extra + $params_min);
    }
    return $result['values'][0];
  }
  
  ```
  
  Then the install can do things like:
  
  ```
    // Ensure we have the activity type set up for Prospects.
    $my_activity_type = pelf_get_or_create('OptionValue', [
      'option_group_id' => "activity_type",
      'name' => "my_unique_activity",
    ],
    [ 'label' => 'Something suitable']);
  
    // Ensure we have the custom field group we need for prospects.
    $customgroup = pelf_get_or_create('CustomGroup', [
      'name' => "another_unique_name",
      'extends' => "Activity",
      'extends_entity_column_value' => $my_activity_type['value'],
    ],
    ['title' => 'Some custom Details']);
  
    // Add a field.
    $my_field_1 = pelf_get_or_create('CustomField', [
        'name' => "another_name_for_field",
        'custom_group_id' => $customgroup['id'],
        'data_type' => "String",
        'html_type' => "Text",
        'is_required' => "1",
        'default_value' => "0",
      ],
      ['label' => 'Explain it']);
  
  ```
  
  Nb. I had to create a select field, too. This was a pain because you have to create the option group for its options, then all its options, then finally create the field itself, passing the id of the option group to the field create. I omitted it here because it's basically more of the same.
  
  Anyway, with that code in my install hook, I can then easily fetch them in other code in my extension by using the names as lookups. AFAICS the name field is a machine-only field - there's usually a 'label' or 'title' field that is used by the UI.
  
  
  ---
  
  