webform_civicrm-8.x-5.0-beta3/src/ContactComponent.php

src/ContactComponent.php
<?php

namespace Drupal\webform_civicrm;

use Drupal\Core\Render\Markup;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Xss;

/**
 * Class ContactComponent
 *
 * CiviCRM contact webform component.
 */
class ContactComponent implements ContactComponentInterface {

  /**
   * UtilsInterface object
   */
  protected $utils;

  public function __construct(UtilsInterface $utils) {
    $this->utils = $utils;
  }

  /**
   * Implements _webform_display_component().
   */
  function _webform_display_civicrm_contact($component, $value, $format = 'html') {
    $display = empty($value[0]) ? '' : $this->utils->wf_crm_display_name($value[0]);
    if ($format == 'html' && $display && user_access('access CiviCRM')) {
      $display = l($display, 'civicrm/contact/view', [
        'alias' => TRUE,
        'query' => [
          'reset' => 1,
          'cid' => $value[0],
        ],
      ]);
    }
    return [
      '#title' => $component['name'],
      '#weight' => $component['weight'],
      '#theme' => 'display_civicrm_contact',
      '#theme_wrappers' => $format == 'html' ? ['webform_element'] : ['webform_element_text'],
      '#field_prefix' => '',
      '#field_suffix' => '',
      '#format' => $format,
      '#value' => $display,
      '#translatable' => ['title'],
    ];
  }

  /**
   * Implements _webform_table_component().
   */
  function _webform_table_civicrm_contact($component, $value) {
    return empty($value[0]) ? '' : Html::escape($this->utils->wf_crm_display_name($value[0]));
  }

  /**
   * Implements _webform_csv_headers_component().
   */
  function _webform_csv_headers_civicrm_contact($component, $export_options) {
    $header = [];
    $header[0] = '';
    $header[1] = '';
    $header[2] = $component['name'];
    return $header;
  }

  /**
   * Implements _webform_csv_data_component().
   */
  function _webform_csv_data_civicrm_contact($component, $export_options, $value) {
    return empty($value[0]) ? '' : $this->utils->wf_crm_display_name($value[0]);
  }

  /**
   * Returns a list of contacts based on component settings.
   *
   * @param \Drupal\webform\WebformInterface $node
   *   Node object
   * @param array $element
   *   Webform element
   * @param array $params
   *   Contact get params (filters)
   * @param array $contacts
   *   Existing contact data
   * @param string $str
   *   Search string (used during autocomplete)
   *
   * @return array
   */
  function wf_crm_contact_search($node, $element, $params, $contacts, $str = NULL) {
  //  TODO in Drupal8 now node is a webform - maybe we could check here if it has  CiviCRM handler
  //  if (empty($node->webform_civicrm)) {
  //    return array();
  //  }
    $limit = $str ? 12 : 500;
    $ret = [];
    $display_fields = array_values($element['#results_display']);
    $fieldMappings = [
      'current_employer' => ['employer_id', 'display_name'],
      'email' => ['email', 'email'],
      'phone' => ['phone', 'phone'],
      'city' => ['address', 'city'],
      'state_province' => ['address', 'state_province_id:label'],
      'country' => ['address', 'country_id:label'],
      'county' => ['address', 'county_id:label'],
      'postal_code' => ['address', 'postal_code'],
      'street_address' => ['address', 'street_address']
    ];
    $joinedTables = [];
    foreach ($fieldMappings as $field => $type) {
      if ($key = array_search($field, $display_fields)) {
        unset($display_fields[$key]);
        [$table, $fieldName]= $type;
        $display_fields[] = "{$table}.{$fieldName}";
        if (empty($joinedTables[$table]) && in_array($table, ['email', 'phone', 'address'])) {
          $joinedTables[$table] = TRUE;
          $params['join'][] = [ucfirst($table) . " AS {$table}", 'LEFT', ["{$table}.is_primary", '=', 1]];
        }
      }
    }
    $sort_field = 'sort_name';
    // Search and sort based on the selected display field
    if (!in_array('display_name', $display_fields)) {
      $sort_field = $display_fields[0];
    }
    $params += [
      'limit' => $limit,
      'orderBy' => [
        $sort_field => 'ASC',
      ],
      'select' => $display_fields,
    ];
    if (!empty($params['relationship']['contact'])) {
      $c = $params['relationship']['contact'];
      $relations = NULL;
      if (!empty($contacts[$c]['id'])) {
        $relations = $this->wf_crm_find_relations($contacts[$c]['id'], wf_crm_aval($params['relationship'], 'types'));
        $params['where'][] = ['id', 'IN', $relations];
      }
      if (!$relations) {
        return $ret;
      }
    }
    unset($params['relationship']);
    if ($str) {
      $searchFields = [];
      foreach ($display_fields as $fld) {
        $searchFields[] = [$fld, 'CONTAINS', $str];
      }
      $params['where'][] = ['OR', $searchFields];
    }
    $result = $this->utils->wf_civicrm_api4('Contact', 'get', $params);
    // Autocomplete results
    if ($str) {
      foreach ($result as $contact) {
        if ($name = $this->wf_crm_format_contact($contact, $display_fields)) {
          $ret[] = ['id' => $contact['id'], 'name' => $name];
        }
      }
      if (count($ret) < $limit && $element['#allow_create']) {
        // HTML hack to get prompt to show up different than search results
        $ret[] = ['id' => "-$str", 'name' => Xss::filter($element['#none_prompt'])];
      }
    }
    // Select results
    else {
      if (!empty($element['#allow_create'])) {
        $ret['-'] = Xss::filter($element['#none_prompt']);
      }
      foreach ($result as $contact) {
        // Select lists will be escaped by FAPI
        if ($name = $this->wf_crm_format_contact($contact, $display_fields, FALSE)) {
          $ret[$contact['id']] = $name;
        }
      }
      // If we get exactly $limit results, there are probably more - warn that the list is truncated
      if (wf_crm_aval($result, 'rowCount') >= $limit) {
        \Drupal::logger('webform_civicrm')->warning(
          'Maximum contacts exceeded, list truncated on the webform "@title". The webform_civicrm "@field" field cannot display more than @limit contacts because it is a select list. Recommend switching to autocomplete widget in element settings.',
          ['@limit' => $limit, '@field' => $element['#title'], '@title' => $node->label()]);
        if ($node->access('update') && \Drupal::currentUser()->hasPermission('access CiviCRM')) {
          $warning_message = Markup::create('<strong>' . t('Maximum contacts exceeded, list truncated.') .'</strong><br>' .
          t('The field "@field" cannot show more than @limit contacts because it is a select list. Recommend switching to autocomplete widget.', ['@limit' => $limit, '@field' => $element['#title']]));
          \Drupal::messenger()->addMessage($warning_message);
        }
      }
    }
    return $ret;
  }

  /**
   * Load contact name if user has permission. Else return FALSE.
   *
   * @param $component
   *   Webform component of type 'civicrm_contact'
   * @param $filters
   *   Contact get params
   * @param $cid
   *   Contact id
   *
   * @return bool|string
   */
  function wf_crm_contact_access($component, $filters, $cid) {
    // Create new contact doesn't require lookup
    $cid = (string) $cid;
    $component['#form_key'] = $component['#form_key'] ?? $component['#webform_key'];
    list(, $c, ) = explode('_', $component['#form_key'], 3);
    if (!empty($component['#none_prompt']) && !empty($component['#allow_create']) && $cid && strpos($cid, '-') === 0) {
      return Html::escape($component['#none_prompt']);
    }
    if (!is_numeric($cid)) {
      return FALSE;
    }
    // Remove unnecessary param as api v4 does not accept them.
    unset($filters['relationship']);
    $filters['where'][] = ['id', '=', $cid];
    $filters['where'][] = ['is_deleted', '=', 0];
    // A contact always has permission to view self
    if ($cid == $this->utils->wf_crm_user_cid()) {
      $filters['checkPermissions'] = FALSE;
    }
    // If checksum is included in the URL, bypass the permission.
    $checksumValid = $this->utils->checksumUserAccess($c, $cid);
    if (!empty($filters['checkPermissions']) && $checksumValid) {
      $filters['checkPermissions'] = FALSE;
    }
    // Fetch contact name with filters applied
    $result = $this->utils->wf_civicrm_api4('Contact', 'get', $filters)[0] ?? [];
    return $this->wf_crm_format_contact($result, /*$component['#extra']['results_display']*/ ['display_name']);
  }

  /**
   * Display a contact based on chosen fields
   *
   * @param array $contact
   * @param array $display_fields
   * @param bool $escape
   * @return bool|string
   */
  function wf_crm_format_contact($contact, $display_fields, $escape = TRUE) {
    if (!$contact) {
      return FALSE;
    }
    $display = [];
    foreach ($display_fields as $field) {
      if ($field && !empty($contact[$field])) {
        $display[] = $escape ? Html::escape($contact[$field]) : $contact[$field];
      }
    }
    return implode(' :: ', $display);
  }

  /**
   * Get a contact's relations of certain types
   *
   * @param int cid
   *   Contact id
   * @param array types
   *   Array of relationship_type_ids
   * @param bool $current
   *   Limit to current & enabled relations?
   *
   * @return array
   */
  function wf_crm_find_relations($cid, $types = [], $current = TRUE) {
    $found = $allowed = $type_ids = [];
    $cid = (int) $cid;
    static $employer_type = 0;
    if ($cid) {
      if (!$employer_type && $current) {
        $employer_type = \CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_relationship_type WHERE name_a_b = 'Employee of'");
      }
      foreach ($types as $t) {
        list($type, $a) = explode('_', $t);
        // Put current employer first in the list
        if ($type == $employer_type && $current) {
          $search_key = $a == 'b' ? 'id' : 'employer_id';
          $employer = $this->utils->wf_civicrm_api4('Contact', 'get', [
            'where' => [
              [$search_key, '=', $cid],
            ],
          ])->first()[$a == 'b' ? 'employer_id' : 'id'] ?? NULL;
          if ($employer) {
            $found[$employer] = $employer;
          }
        }
        $type_ids[] = $type;
        if ($a == 'a' || $a == 'r') {
          $allowed[] = $type . '_a';
        }
        if ($a == 'b' || $a == 'r') {
          $allowed[] = $type . '_b';
        }
      }
      $params = [
        'return' => ['contact_id_a', 'contact_id_b', 'relationship_type_id', 'end_date'],
        'contact_id_a' => $cid,
        'contact_id_b' => $cid,
        'options' => ['or' => [['contact_id_a', 'contact_id_b']]],
      ];
      if ($type_ids) {
        $params['relationship_type_id'] = ['IN' => $type_ids];
      }
      if ($current) {
        $params['is_active'] = 1;
      }
      foreach ($this->utils->wf_crm_apivalues('relationship', 'get', $params) as $relationship) {
        $a = $relationship['contact_id_a'] == $cid ? 'b' : 'a';
        if (!$current || empty($relationship['end_date']) || strtotime($relationship['end_date']) > time()) {
          if (!$allowed || in_array($relationship['relationship_type_id'] . '_' . $a, $allowed)) {
            $c = $relationship["contact_id_$a"];
            $found[$c] = $c;
          }
        }
      }
    }
    return $found;
  }

  /**
   * Format filters for the contact get api
   *
   * @param \Drupal\webform\WebformInterface $node
   *   Webform node object
   * @param array $component
   *   Webform component of type 'civicrm_contact'
   *
   * @return array
   *   Api params
   */
  function wf_crm_search_filters($node, array $component) {
    /** @var \Drupal\webform\Plugin\WebformElementManagerInterface $element_manager */
    $element_manager = \Drupal::service('plugin.manager.webform.element');
    $contact_element = $element_manager->getElementInstance($component);
    $contactFilters = [
      'contact_type',
      'contact_sub_type',
      'tag',
      'group',
      'relationship' => [
        'contact',
        'types',
      ],
    ];
    $params = [
      'checkPermissions' => $contact_element->getElementProperty($component, 'check_permissions')
    ];
    $params['where'][] = ['is_deleted', '=', 0];
    foreach ($contactFilters as $key => $filter) {
      // Add Relationship filter
      if ($key === 'relationship') {
        foreach ($filter as $val) {
          $filterVal = $contact_element->getElementProperty($component, "filter_relationship_{$val}");
          $this->wf_crm_search_filterArray($filterVal);
          if ($filterVal) {
            $params['relationship'][$val] = $filterVal;
          }
        }
      }
      else {
        $filterVal = $contact_element->getElementProperty($component, $filter);
        $this->wf_crm_search_filterArray($filterVal);
        if ($filterVal) {
          switch ($filter) {
            case 'group':
            case 'tag':
              $filter .= 's';
              $op = 'IN';
              break;

            case 'contact_sub_type':
              $op = 'CONTAINS';
              break;

            default:
              $op = '=';
          }
          $params['where'][] = [$filter, $op, $filterVal];
        }
      }
    }
    return $params;
  }

  /**
   * Remove blank values in the array.
   */
  function wf_crm_search_filterArray(&$filterVal) {
    if (is_array($filterVal)) {
      $filterVal = array_filter($filterVal);
    }
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc