650 lines
17 KiB
PHP
650 lines
17 KiB
PHP
<?php
|
|
/*
|
|
+--------------------------------------------------------------------+
|
|
| CiviCRM version 4.7 |
|
|
+--------------------------------------------------------------------+
|
|
| Copyright CiviCRM LLC (c) 2004-2017 |
|
|
+--------------------------------------------------------------------+
|
|
| This file is a part of CiviCRM. |
|
|
| |
|
|
| CiviCRM is free software; you can copy, modify, and distribute it |
|
|
| under the terms of the GNU Affero General Public License |
|
|
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
|
|
| |
|
|
| CiviCRM is distributed in the hope that it will be useful, but |
|
|
| WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
|
| See the GNU Affero General Public License for more details. |
|
|
| |
|
|
| You should have received a copy of the GNU Affero General Public |
|
|
| License and the CiviCRM Licensing Exception along |
|
|
| with this program; if not, contact CiviCRM LLC |
|
|
| at info[AT]civicrm[DOT]org. If you have questions about the |
|
|
| GNU Affero General Public License or the licensing of CiviCRM, |
|
|
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
|
|
+--------------------------------------------------------------------+
|
|
*/
|
|
|
|
/**
|
|
*
|
|
* @package CRM
|
|
* @copyright CiviCRM LLC (c) 2004-2017
|
|
*/
|
|
class CRM_Utils_Migrate_ExportJSON {
|
|
const CHUNK_SIZE = 128;
|
|
|
|
protected $_contactIDs;
|
|
|
|
protected $_allContactIDs;
|
|
|
|
protected $_values;
|
|
|
|
protected $_discoverContacts = FALSE;
|
|
|
|
protected $_renameGroups = 1;
|
|
|
|
protected $_renameTags = 1;
|
|
|
|
protected $_sitePrefix = 'Site 1';
|
|
|
|
/**
|
|
* @param array $params
|
|
*/
|
|
public function __construct(&$params) {
|
|
foreach ($params as $name => $value) {
|
|
$varName = '_' . $name;
|
|
$this->$varName = $value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Split a large array of contactIDs into more manageable smaller chunks.
|
|
*
|
|
* @param array $contactIDs
|
|
*
|
|
* @return array
|
|
*/
|
|
public function &splitContactIDs(&$contactIDs) {
|
|
// contactIDs could be a real large array, so we split it up into
|
|
// smaller chunks and then general xml for each chunk
|
|
$chunks = array();
|
|
$current = 0;
|
|
$chunks[$current] = array();
|
|
$count = 0;
|
|
|
|
foreach ($contactIDs as $k => $v) {
|
|
$chunks[$current][$k] = $v;
|
|
$count++;
|
|
|
|
if ($count == self::CHUNK_SIZE) {
|
|
$current++;
|
|
$chunks[$current] = array();
|
|
$count = 0;
|
|
}
|
|
}
|
|
|
|
if (empty($chunks[$current])) {
|
|
unset($chunks[$current]);
|
|
}
|
|
|
|
return $chunks;
|
|
}
|
|
|
|
/**
|
|
* Given a set of contact IDs get the values.
|
|
*
|
|
* @param array $contactIDs
|
|
* @param array $additionalContactIDs
|
|
*/
|
|
public function getValues(&$contactIDs, &$additionalContactIDs) {
|
|
|
|
$this->contact($contactIDs);
|
|
$this->address($contactIDs);
|
|
$this->phone($contactIDs);
|
|
$this->email($contactIDs);
|
|
$this->im($contactIDs);
|
|
$this->website($contactIDs);
|
|
$this->note($contactIDs);
|
|
|
|
$this->group($contactIDs);
|
|
$this->groupContact($contactIDs);
|
|
$this->savedSearch($contactIDs);
|
|
|
|
$this->tag($contactIDs);
|
|
$this->entityTag($contactIDs);
|
|
|
|
$this->relationship($contactIDs, $additionalContactIDs);
|
|
$this->activity($contactIDs, $additionalContactIDs);
|
|
}
|
|
|
|
public function metaData() {
|
|
$optionGroupVars = array(
|
|
'prefix_id' => 'individual_prefix',
|
|
'suffix_id' => 'individual_suffix',
|
|
'gender_id' => 'gender',
|
|
'mobile_provider' => 'mobile_provider',
|
|
'phone_type' => 'phone_type',
|
|
'activity_type' => 'activity_type',
|
|
'status_id' => 'activity_status_id',
|
|
'priority_id' => 'activity_priority_id',
|
|
'medium_id' => 'encounter_medium',
|
|
'communication_style_id' => 'communication_style',
|
|
'email_greeting' => 'email_greeting',
|
|
'postal_greeting' => 'postal_greeting',
|
|
'addressee_id' => 'addressee',
|
|
);
|
|
$this->optionGroup($optionGroupVars);
|
|
|
|
$auxilaryTables = array(
|
|
'civicrm_location_type' => 'CRM_Core_DAO_LocationType',
|
|
'civicrm_relationship_type' => 'CRM_Contact_DAO_RelationshipType',
|
|
);
|
|
$this->auxTable($auxilaryTables);
|
|
}
|
|
|
|
/**
|
|
* @param $tables
|
|
*/
|
|
public function auxTable($tables) {
|
|
foreach ($tables as $tableName => $daoName) {
|
|
$fields = &$this->dbFields($daoName, TRUE);
|
|
|
|
$sql = "SELECT * from $tableName";
|
|
$this->sql($sql, $tableName, $fields);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param $optionGroupVars
|
|
*/
|
|
public function optionGroup($optionGroupVars) {
|
|
$names = array_values($optionGroupVars);
|
|
$str = array();
|
|
foreach ($names as $name) {
|
|
$str[] = "'$name'";
|
|
}
|
|
$nameString = implode(",", $str);
|
|
|
|
$sql = "
|
|
SELECT *
|
|
FROM civicrm_option_group
|
|
WHERE name IN ( $nameString )
|
|
";
|
|
$fields = &$this->dbFields('CRM_Core_DAO_OptionGroup', TRUE);
|
|
$this->sql($sql, 'civicrm_option_group', $fields);
|
|
|
|
$sql = "
|
|
SELECT v.*
|
|
FROM civicrm_option_value v
|
|
INNER JOIN civicrm_option_group g ON v.option_group_id = g.id
|
|
WHERE g.name IN ( $nameString )
|
|
";
|
|
$fields = &$this->dbFields('CRM_Core_DAO_OptionValue', TRUE);
|
|
$this->sql($sql, 'civicrm_option_value', $fields);
|
|
}
|
|
|
|
/**
|
|
* @param $ids
|
|
* @param string $tableName
|
|
* @param $fields
|
|
* @param $whereField
|
|
* @param null $additionalWhereCond
|
|
*/
|
|
public function table(
|
|
&$ids,
|
|
$tableName,
|
|
&$fields,
|
|
$whereField,
|
|
$additionalWhereCond = NULL
|
|
) {
|
|
if (empty($ids)) {
|
|
return;
|
|
}
|
|
|
|
$idString = implode(',', $ids);
|
|
|
|
$sql = "
|
|
SELECT *
|
|
FROM $tableName
|
|
WHERE $whereField IN ( $idString )
|
|
";
|
|
|
|
if ($additionalWhereCond) {
|
|
$sql .= " AND $additionalWhereCond";
|
|
}
|
|
|
|
$this->sql($sql, $tableName, $fields);
|
|
}
|
|
|
|
/**
|
|
* @param $sql
|
|
* @param string $tableName
|
|
* @param $fields
|
|
*/
|
|
public function sql($sql, $tableName, &$fields) {
|
|
$dao = &CRM_Core_DAO::executeQuery($sql);
|
|
|
|
while ($dao->fetch()) {
|
|
$value = array();
|
|
foreach ($fields as $name) {
|
|
if (empty($dao->$name)) {
|
|
$value[$name] = NULL;
|
|
}
|
|
else {
|
|
$value[$name] = $dao->$name;
|
|
}
|
|
}
|
|
$this->appendValue($dao->id, $tableName, $value);
|
|
}
|
|
$dao->free();
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
*/
|
|
public function contact(&$contactIDs) {
|
|
$fields = &$this->dbFields('CRM_Contact_DAO_Contact', TRUE);
|
|
$this->table($contactIDs, 'civicrm_contact', $fields, 'id', NULL);
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
*/
|
|
public function note(&$contactIDs) {
|
|
$fields = &$this->dbFields('CRM_Core_DAO_Note', TRUE);
|
|
$this->table($contactIDs, 'civicrm_note', $fields, 'entity_id', "entity_table = 'civicrm_contact'");
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
*/
|
|
public function phone(&$contactIDs) {
|
|
$fields = &$this->dbFields('CRM_Core_DAO_Phone', TRUE);
|
|
$this->table($contactIDs, 'civicrm_phone', $fields, 'contact_id', NULL);
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
*/
|
|
public function email(&$contactIDs) {
|
|
$fields = &$this->dbFields('CRM_Core_DAO_Email', TRUE);
|
|
$this->table($contactIDs, 'civicrm_email', $fields, 'contact_id', NULL);
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
*/
|
|
public function im(&$contactIDs) {
|
|
$fields = &$this->dbFields('CRM_Core_DAO_IM', TRUE);
|
|
$this->table($contactIDs, 'civicrm_im', $fields, 'contact_id', NULL);
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
*/
|
|
public function website(&$contactIDs) {
|
|
$fields = &$this->dbFields('CRM_Core_DAO_Website', TRUE);
|
|
$this->table($contactIDs, 'civicrm_website', $fields, 'contact_id', NULL);
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
*/
|
|
public function address(&$contactIDs) {
|
|
$fields = &$this->dbFields('CRM_Core_DAO_Email', TRUE);
|
|
$this->table($contactIDs, 'civicrm_address', $fields, 'contact_id', NULL);
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
*/
|
|
public function groupContact(&$contactIDs) {
|
|
$fields = &$this->dbFields('CRM_Contact_DAO_GroupContact', TRUE);
|
|
$this->table($contactIDs, 'civicrm_group_contact', $fields, 'contact_id', NULL);
|
|
}
|
|
|
|
/**
|
|
* @todo support group inheritance
|
|
*
|
|
* Parent child group ids are encoded in a text string
|
|
*
|
|
* @param $contactIDs
|
|
*/
|
|
public function group(&$contactIDs) {
|
|
// handle groups only once
|
|
static $_groupsHandled = array();
|
|
|
|
$ids = implode(',', $contactIDs);
|
|
|
|
$sql = "
|
|
SELECT DISTINCT group_id
|
|
FROM civicrm_group_contact
|
|
WHERE contact_id IN ( $ids )
|
|
";
|
|
$dao = CRM_Core_DAO::executeQuery($sql);
|
|
$groupIDs = array();
|
|
while ($dao->fetch()) {
|
|
if (!isset($_groupsHandled[$dao->group_id])) {
|
|
$groupIDs[] = $dao->group_id;
|
|
$_groupsHandled[$dao->group_id] = 1;
|
|
}
|
|
}
|
|
|
|
$fields = &$this->dbFields('CRM_Contact_DAO_Group', TRUE);
|
|
$this->table($groupIDs, 'civicrm_group', $fields, 'id');
|
|
|
|
$this->savedSearch($groupIDs);
|
|
}
|
|
|
|
/**
|
|
* @todo support search builder and custom saved searches
|
|
* @param $groupIDs
|
|
*/
|
|
public function savedSearch(&$groupIDs) {
|
|
if (empty($groupIDs)) {
|
|
return;
|
|
}
|
|
|
|
$idString = implode(",", $groupIDs);
|
|
$sql = "
|
|
SELECT s.*
|
|
FROM civicrm_saved_search s
|
|
INNER JOIN civicrm_group g on g.saved_search_id = s.id
|
|
WHERE g.id IN ( $idString )
|
|
";
|
|
|
|
$fields = &$this->dbFields('CRM_Contact_DAO_SavedSearch', TRUE);
|
|
$this->sql($sql, 'civicrm_saved_search', $fields);
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
*/
|
|
public function entityTag(&$contactIDs) {
|
|
$fields = &$this->dbFields('CRM_Core_DAO_EntityTag', TRUE);
|
|
$this->table($contactIDs, 'civicrm_entity_tag', $fields, 'entity_id', "entity_table = 'civicrm_contact'");
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
*/
|
|
public function tag(&$contactIDs) {
|
|
// handle tags only once
|
|
static $_tagsHandled = array();
|
|
|
|
$ids = implode(',', $contactIDs);
|
|
|
|
$sql = "
|
|
SELECT DISTINCT tag_id
|
|
FROM civicrm_entity_tag
|
|
WHERE entity_id IN ( $ids )
|
|
AND entity_table = 'civicrm_contact'
|
|
";
|
|
$dao = CRM_Core_DAO::executeQuery($sql);
|
|
$tagIDs = array();
|
|
while ($dao->fetch()) {
|
|
if (!isset($_tagsHandled[$dao->tag_id])) {
|
|
$tagIDs[] = $dao->tag_id;
|
|
$_tagsHandled[$dao->tag_id] = 1;
|
|
}
|
|
}
|
|
|
|
$fields = &$this->dbFields('CRM_Core_DAO_Tag', TRUE);
|
|
$this->table($tagIDs, 'civicrm_tag', $fields, 'id');
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
* @param $additionalContacts
|
|
*/
|
|
public function relationship(&$contactIDs, &$additionalContacts) {
|
|
// handle relationships only once
|
|
static $_relationshipsHandled = array();
|
|
|
|
$ids = implode(',', $contactIDs);
|
|
|
|
$sql = "(
|
|
SELECT r.*
|
|
FROM civicrm_relationship r
|
|
WHERE r.contact_id_a IN ( $ids )
|
|
) UNION (
|
|
SELECT r.*
|
|
FROM civicrm_relationship r
|
|
WHERE r.contact_id_b IN ( $ids )
|
|
)
|
|
";
|
|
|
|
$fields = $this->dbFields('CRM_Contact_DAO_Relationship', TRUE);
|
|
$dao = &CRM_Core_DAO::executeQuery($sql);
|
|
while ($dao->fetch()) {
|
|
if (isset($_relationshipsHandled[$dao->id])) {
|
|
continue;
|
|
}
|
|
$_relationshipsHandled[$dao->id] = $dao->id;
|
|
|
|
$relationship = array();
|
|
foreach ($fields as $fld) {
|
|
if (empty($dao->$fld)) {
|
|
$relationship[$fld] = NULL;
|
|
}
|
|
else {
|
|
$relationship[$fld] = $dao->$fld;
|
|
}
|
|
}
|
|
$this->appendValue($dao->id, 'civicrm_relationship', $relationship);
|
|
|
|
$this->addAdditionalContacts(array(
|
|
$dao->contact_id_a,
|
|
$dao->contact_id_b,
|
|
),
|
|
$additionalContacts
|
|
);
|
|
}
|
|
$dao->free();
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
* @param $additionalContacts
|
|
*/
|
|
public function activity(&$contactIDs, &$additionalContacts) {
|
|
static $_activitiesHandled = array();
|
|
$activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
|
|
$assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
|
|
$targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
|
|
$ids = implode(',', $contactIDs);
|
|
|
|
// query framing returning all contacts in valid activity
|
|
$sql = "
|
|
SELECT a.*, ac.id as acID, ac.activity_id, ac.contact_id, ac.record_type_id
|
|
FROM civicrm_activity a
|
|
INNER JOIN civicrm_activity_contact ac ON ac.activity_id = a.id
|
|
WHERE ac.contact_id IN ( $ids )
|
|
AND (a.activity_type_id != 3 AND a.activity_type_id != 20)
|
|
";
|
|
|
|
$fields = &$this->dbFields('CRM_Activity_DAO_Activity', TRUE);
|
|
|
|
$dao = &CRM_Core_DAO::executeQuery($sql);
|
|
while ($dao->fetch()) {
|
|
// adding source, target and assignee contacts in additional contacts array
|
|
$this->addAdditionalContacts(array($dao->contact_id),
|
|
$additionalContacts
|
|
);
|
|
|
|
// append values of activity contacts
|
|
$activityContacts = array(
|
|
'id' => $dao->acID,
|
|
'contact_id' => $dao->contact_id,
|
|
'activity_id' => $dao->activity_id,
|
|
'record_type_id' => $dao->record_type_id,
|
|
);
|
|
$this->appendValue($dao->acID, 'civicrm_activity_contact', $activityContacts);
|
|
|
|
if (isset($_activitiesHandled[$dao->id])) {
|
|
continue;
|
|
}
|
|
$_activitiesHandled[$dao->id] = $dao->id;
|
|
|
|
$activity = array();
|
|
foreach ($fields as $fld) {
|
|
if (empty($dao->$fld)) {
|
|
$activity[$fld] = NULL;
|
|
}
|
|
else {
|
|
$activity[$fld] = $dao->$fld;
|
|
}
|
|
}
|
|
|
|
// append activity value
|
|
$this->appendValue($dao->id, 'civicrm_activity', $activity);
|
|
}
|
|
$dao->free();
|
|
}
|
|
|
|
/**
|
|
* @param int $id
|
|
* @param string $name
|
|
* @param $value
|
|
*/
|
|
public function appendValue($id, $name, $value) {
|
|
if (empty($value)) {
|
|
return;
|
|
}
|
|
|
|
if (!isset($this->_values[$name])) {
|
|
$this->_values[$name] = array();
|
|
$this->_values[$name][] = array_keys($value);
|
|
}
|
|
$this->_values[$name][] = array_values($value);
|
|
}
|
|
|
|
/**
|
|
* @param string $daoName
|
|
* @param bool $onlyKeys
|
|
*
|
|
* @return array
|
|
*/
|
|
public function dbFields($daoName, $onlyKeys = FALSE) {
|
|
static $_fieldsRetrieved = array();
|
|
|
|
if (!isset($_fieldsRetrieved[$daoName])) {
|
|
$_fieldsRetrieved[$daoName] = array();
|
|
$daoFile = str_replace('_',
|
|
DIRECTORY_SEPARATOR,
|
|
$daoName
|
|
) . '.php';
|
|
include_once $daoFile;
|
|
|
|
$daoFields = &$daoName::fields();
|
|
|
|
foreach ($daoFields as $key => & $value) {
|
|
$_fieldsRetrieved[$daoName][$value['name']] = array(
|
|
'uniqueName' => $key,
|
|
'type' => $value['type'],
|
|
'title' => CRM_Utils_Array::value('title', $value, NULL),
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($onlyKeys) {
|
|
return array_keys($_fieldsRetrieved[$daoName]);
|
|
}
|
|
else {
|
|
return $_fieldsRetrieved[$daoName];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
* @param $additionalContacts
|
|
*/
|
|
public function addAdditionalContacts($contactIDs, &$additionalContacts) {
|
|
if (!$this->_discoverContacts) {
|
|
return;
|
|
}
|
|
|
|
foreach ($contactIDs as $cid) {
|
|
if ($cid &&
|
|
!isset($this->_allContactIDs[$cid]) &&
|
|
!isset($additionalContacts[$cid])
|
|
) {
|
|
$additionalContacts[$cid] = $cid;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param $contactIDs
|
|
*/
|
|
public function export(&$contactIDs) {
|
|
$chunks = &$this->splitContactIDs($contactIDs);
|
|
|
|
$additionalContactIDs = array();
|
|
|
|
foreach ($chunks as $chunk) {
|
|
$this->getValues($chunk, $additionalContactIDs);
|
|
}
|
|
|
|
if (!empty($additionalContactIDs)) {
|
|
$this->_allContactIDs = $this->_allContactIDs + $additionalContactIDs;
|
|
$this->export($additionalContactIDs);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $fileName
|
|
* @param null $lastExportTime
|
|
* @param bool $discoverContacts
|
|
*/
|
|
public function run(
|
|
$fileName,
|
|
$lastExportTime = NULL,
|
|
$discoverContacts = FALSE
|
|
) {
|
|
$this->_discoverContacts = $discoverContacts;
|
|
|
|
if (!$lastExportTime) {
|
|
$sql = "
|
|
SELECT id
|
|
FROM civicrm_contact
|
|
";
|
|
}
|
|
else {
|
|
$sql = "(
|
|
SELECT DISTINCT entity_id
|
|
FROM civicrm_log
|
|
WHERE entity_table = 'civicrm_contact'
|
|
AND modified_date >= $lastExportTime
|
|
) UNION (
|
|
SELECT DISTINCT contact_id
|
|
FROM civicrm_subscription_history
|
|
WHERE date >= $lastExportTime
|
|
)
|
|
";
|
|
}
|
|
|
|
$dao = &CRM_Core_DAO::executeQuery($sql);
|
|
|
|
$contactIDs = array();
|
|
while ($dao->fetch()) {
|
|
$contactIDs[$dao->id] = $dao->id;
|
|
}
|
|
|
|
$this->_allContactIDs = $contactIDs;
|
|
$this->_values = array();
|
|
|
|
$this->metaData();
|
|
|
|
$this->export($contactIDs);
|
|
|
|
$json = json_encode($this->_values, JSON_NUMERIC_CHECK);
|
|
file_put_contents($fileName,
|
|
$json
|
|
);
|
|
|
|
// print_r( json_decode( $json ) );
|
|
}
|
|
|
|
}
|