3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
17 class CRM_Utils_Migrate_ExportJSON
{
18 const CHUNK_SIZE
= 128;
20 protected $_contactIDs;
22 protected $_allContactIDs;
26 protected $_discoverContacts = FALSE;
28 protected $_renameGroups = 1;
30 protected $_renameTags = 1;
32 protected $_sitePrefix = 'Site 1';
35 * @param array $params
37 public function __construct(&$params) {
38 foreach ($params as $name => $value) {
39 $varName = '_' . $name;
40 $this->$varName = $value;
45 * Split a large array of contactIDs into more manageable smaller chunks.
47 * @param array $contactIDs
51 public function &splitContactIDs(&$contactIDs) {
52 // contactIDs could be a real large array, so we split it up into
53 // smaller chunks and then general xml for each chunk
56 $chunks[$current] = [];
59 foreach ($contactIDs as $k => $v) {
60 $chunks[$current][$k] = $v;
63 if ($count == self
::CHUNK_SIZE
) {
65 $chunks[$current] = [];
70 if (empty($chunks[$current])) {
71 unset($chunks[$current]);
78 * Given a set of contact IDs get the values.
80 * @param array $contactIDs
81 * @param array $additionalContactIDs
83 public function getValues(&$contactIDs, &$additionalContactIDs) {
85 $this->contact($contactIDs);
86 $this->address($contactIDs);
87 $this->phone($contactIDs);
88 $this->email($contactIDs);
89 $this->im($contactIDs);
90 $this->website($contactIDs);
91 $this->note($contactIDs);
93 $this->group($contactIDs);
94 $this->groupContact($contactIDs);
95 $this->savedSearch($contactIDs);
97 $this->tag($contactIDs);
98 $this->entityTag($contactIDs);
100 $this->relationship($contactIDs, $additionalContactIDs);
101 $this->activity($contactIDs, $additionalContactIDs);
104 public function metaData() {
106 'prefix_id' => 'individual_prefix',
107 'suffix_id' => 'individual_suffix',
108 'gender_id' => 'gender',
109 'mobile_provider' => 'mobile_provider',
110 'phone_type' => 'phone_type',
111 'activity_type' => 'activity_type',
112 'status_id' => 'activity_status_id',
113 'priority_id' => 'activity_priority_id',
114 'medium_id' => 'encounter_medium',
115 'communication_style_id' => 'communication_style',
116 'email_greeting' => 'email_greeting',
117 'postal_greeting' => 'postal_greeting',
118 'addressee_id' => 'addressee',
120 $this->optionGroup($optionGroupVars);
123 'civicrm_location_type' => 'CRM_Core_DAO_LocationType',
124 'civicrm_relationship_type' => 'CRM_Contact_DAO_RelationshipType',
126 $this->auxTable($auxilaryTables);
132 public function auxTable($tables) {
133 foreach ($tables as $tableName => $daoName) {
134 $fields = &$this->dbFields($daoName, TRUE);
136 $sql = "SELECT * from $tableName";
137 $this->sql($sql, $tableName, $fields);
142 * @param $optionGroupVars
144 public function optionGroup($optionGroupVars) {
145 $names = array_values($optionGroupVars);
147 foreach ($names as $name) {
150 $nameString = implode(",", $str);
154 FROM civicrm_option_group
155 WHERE name IN ( $nameString )
157 $fields = &$this->dbFields('CRM_Core_DAO_OptionGroup', TRUE);
158 $this->sql($sql, 'civicrm_option_group', $fields);
162 FROM civicrm_option_value v
163 INNER JOIN civicrm_option_group g ON v.option_group_id = g.id
164 WHERE g.name IN ( $nameString )
166 $fields = &$this->dbFields('CRM_Core_DAO_OptionValue', TRUE);
167 $this->sql($sql, 'civicrm_option_value', $fields);
172 * @param string $tableName
175 * @param null $additionalWhereCond
177 public function table(
182 $additionalWhereCond = NULL
188 $idString = implode(',', $ids);
193 WHERE $whereField IN ( $idString )
196 if ($additionalWhereCond) {
197 $sql .= " AND $additionalWhereCond";
200 $this->sql($sql, $tableName, $fields);
205 * @param string $tableName
208 public function sql($sql, $tableName, &$fields) {
209 $dao = &CRM_Core_DAO
::executeQuery($sql);
211 while ($dao->fetch()) {
213 foreach ($fields as $name) {
214 if (empty($dao->$name)) {
215 $value[$name] = NULL;
218 $value[$name] = $dao->$name;
221 $this->appendValue($dao->id
, $tableName, $value);
228 public function contact(&$contactIDs) {
229 $fields = &$this->dbFields('CRM_Contact_DAO_Contact', TRUE);
230 $this->table($contactIDs, 'civicrm_contact', $fields, 'id', NULL);
236 public function note(&$contactIDs) {
237 $fields = &$this->dbFields('CRM_Core_DAO_Note', TRUE);
238 $this->table($contactIDs, 'civicrm_note', $fields, 'entity_id', "entity_table = 'civicrm_contact'");
244 public function phone(&$contactIDs) {
245 $fields = &$this->dbFields('CRM_Core_DAO_Phone', TRUE);
246 $this->table($contactIDs, 'civicrm_phone', $fields, 'contact_id', NULL);
252 public function email(&$contactIDs) {
253 $fields = &$this->dbFields('CRM_Core_DAO_Email', TRUE);
254 $this->table($contactIDs, 'civicrm_email', $fields, 'contact_id', NULL);
260 public function im(&$contactIDs) {
261 $fields = &$this->dbFields('CRM_Core_DAO_IM', TRUE);
262 $this->table($contactIDs, 'civicrm_im', $fields, 'contact_id', NULL);
268 public function website(&$contactIDs) {
269 $fields = &$this->dbFields('CRM_Core_DAO_Website', TRUE);
270 $this->table($contactIDs, 'civicrm_website', $fields, 'contact_id', NULL);
276 public function address(&$contactIDs) {
277 $fields = &$this->dbFields('CRM_Core_DAO_Email', TRUE);
278 $this->table($contactIDs, 'civicrm_address', $fields, 'contact_id', NULL);
284 public function groupContact(&$contactIDs) {
285 $fields = &$this->dbFields('CRM_Contact_DAO_GroupContact', TRUE);
286 $this->table($contactIDs, 'civicrm_group_contact', $fields, 'contact_id', NULL);
290 * @todo support group inheritance
292 * Parent child group ids are encoded in a text string
296 public function group(&$contactIDs) {
297 // handle groups only once
298 static $_groupsHandled = [];
300 $ids = implode(',', $contactIDs);
303 SELECT DISTINCT group_id
304 FROM civicrm_group_contact
305 WHERE contact_id IN ( $ids )
307 $dao = CRM_Core_DAO
::executeQuery($sql);
309 while ($dao->fetch()) {
310 if (!isset($_groupsHandled[$dao->group_id
])) {
311 $groupIDs[] = $dao->group_id
;
312 $_groupsHandled[$dao->group_id
] = 1;
316 $fields = &$this->dbFields('CRM_Contact_DAO_Group', TRUE);
317 $this->table($groupIDs, 'civicrm_group', $fields, 'id');
319 $this->savedSearch($groupIDs);
323 * @todo support search builder and custom saved searches
326 public function savedSearch(&$groupIDs) {
327 if (empty($groupIDs)) {
331 $idString = implode(",", $groupIDs);
334 FROM civicrm_saved_search s
335 INNER JOIN civicrm_group g on g.saved_search_id = s.id
336 WHERE g.id IN ( $idString )
339 $fields = &$this->dbFields('CRM_Contact_DAO_SavedSearch', TRUE);
340 $this->sql($sql, 'civicrm_saved_search', $fields);
346 public function entityTag(&$contactIDs) {
347 $fields = &$this->dbFields('CRM_Core_DAO_EntityTag', TRUE);
348 $this->table($contactIDs, 'civicrm_entity_tag', $fields, 'entity_id', "entity_table = 'civicrm_contact'");
354 public function tag(&$contactIDs) {
355 // handle tags only once
356 static $_tagsHandled = [];
358 $ids = implode(',', $contactIDs);
361 SELECT DISTINCT tag_id
362 FROM civicrm_entity_tag
363 WHERE entity_id IN ( $ids )
364 AND entity_table = 'civicrm_contact'
366 $dao = CRM_Core_DAO
::executeQuery($sql);
368 while ($dao->fetch()) {
369 if (!isset($_tagsHandled[$dao->tag_id
])) {
370 $tagIDs[] = $dao->tag_id
;
371 $_tagsHandled[$dao->tag_id
] = 1;
375 $fields = &$this->dbFields('CRM_Core_DAO_Tag', TRUE);
376 $this->table($tagIDs, 'civicrm_tag', $fields, 'id');
381 * @param $additionalContacts
383 public function relationship(&$contactIDs, &$additionalContacts) {
384 // handle relationships only once
385 static $_relationshipsHandled = [];
387 $ids = implode(',', $contactIDs);
391 FROM civicrm_relationship r
392 WHERE r.contact_id_a IN ( $ids )
395 FROM civicrm_relationship r
396 WHERE r.contact_id_b IN ( $ids )
400 $fields = $this->dbFields('CRM_Contact_DAO_Relationship', TRUE);
401 $dao = &CRM_Core_DAO
::executeQuery($sql);
402 while ($dao->fetch()) {
403 if (isset($_relationshipsHandled[$dao->id
])) {
406 $_relationshipsHandled[$dao->id
] = $dao->id
;
409 foreach ($fields as $fld) {
410 if (empty($dao->$fld)) {
411 $relationship[$fld] = NULL;
414 $relationship[$fld] = $dao->$fld;
417 $this->appendValue($dao->id
, 'civicrm_relationship', $relationship);
419 $this->addAdditionalContacts([
430 * @param $additionalContacts
432 public function activity(&$contactIDs, &$additionalContacts) {
433 static $_activitiesHandled = [];
434 $activityContacts = CRM_Activity_BAO_ActivityContact
::buildOptions('record_type_id', 'validate');
435 $assigneeID = CRM_Utils_Array
::key('Activity Assignees', $activityContacts);
436 $targetID = CRM_Utils_Array
::key('Activity Targets', $activityContacts);
437 $ids = implode(',', $contactIDs);
439 // query framing returning all contacts in valid activity
441 SELECT a.*, ac.id as acID, ac.activity_id, ac.contact_id, ac.record_type_id
442 FROM civicrm_activity a
443 INNER JOIN civicrm_activity_contact ac ON ac.activity_id = a.id
444 WHERE ac.contact_id IN ( $ids )
445 AND (a.activity_type_id != 3 AND a.activity_type_id != 20)
448 $fields = &$this->dbFields('CRM_Activity_DAO_Activity', TRUE);
450 $dao = &CRM_Core_DAO
::executeQuery($sql);
451 while ($dao->fetch()) {
452 // adding source, target and assignee contacts in additional contacts array
453 $this->addAdditionalContacts([$dao->contact_id
],
457 // append values of activity contacts
458 $activityContacts = [
460 'contact_id' => $dao->contact_id
,
461 'activity_id' => $dao->activity_id
,
462 'record_type_id' => $dao->record_type_id
,
464 $this->appendValue($dao->acID
, 'civicrm_activity_contact', $activityContacts);
466 if (isset($_activitiesHandled[$dao->id
])) {
469 $_activitiesHandled[$dao->id
] = $dao->id
;
472 foreach ($fields as $fld) {
473 if (empty($dao->$fld)) {
474 $activity[$fld] = NULL;
477 $activity[$fld] = $dao->$fld;
481 // append activity value
482 $this->appendValue($dao->id
, 'civicrm_activity', $activity);
488 * @param string $name
491 public function appendValue($id, $name, $value) {
496 if (!isset($this->_values
[$name])) {
497 $this->_values
[$name] = [];
498 $this->_values
[$name][] = array_keys($value);
500 $this->_values
[$name][] = array_values($value);
504 * @param string $daoName
505 * @param bool $onlyKeys
509 public function dbFields($daoName, $onlyKeys = FALSE) {
510 static $_fieldsRetrieved = [];
512 if (!isset($_fieldsRetrieved[$daoName])) {
513 $_fieldsRetrieved[$daoName] = [];
514 $daoFile = str_replace('_',
518 include_once $daoFile;
520 $daoFields = &$daoName::fields();
522 foreach ($daoFields as $key => & $value) {
523 $_fieldsRetrieved[$daoName][$value['name']] = [
524 'uniqueName' => $key,
525 'type' => $value['type'],
526 'title' => $value['title'] ??
NULL,
532 return array_keys($_fieldsRetrieved[$daoName]);
535 return $_fieldsRetrieved[$daoName];
541 * @param $additionalContacts
543 public function addAdditionalContacts($contactIDs, &$additionalContacts) {
544 if (!$this->_discoverContacts
) {
548 foreach ($contactIDs as $cid) {
550 !isset($this->_allContactIDs
[$cid]) &&
551 !isset($additionalContacts[$cid])
553 $additionalContacts[$cid] = $cid;
561 public function export(&$contactIDs) {
562 $chunks = &$this->splitContactIDs($contactIDs);
564 $additionalContactIDs = [];
566 foreach ($chunks as $chunk) {
567 $this->getValues($chunk, $additionalContactIDs);
570 if (!empty($additionalContactIDs)) {
571 $this->_allContactIDs
= $this->_allContactIDs +
$additionalContactIDs;
572 $this->export($additionalContactIDs);
577 * @param string $fileName
578 * @param null $lastExportTime
579 * @param bool $discoverContacts
583 $lastExportTime = NULL,
584 $discoverContacts = FALSE
586 $this->_discoverContacts
= $discoverContacts;
588 if (!$lastExportTime) {
596 SELECT DISTINCT entity_id
598 WHERE entity_table = 'civicrm_contact'
599 AND modified_date >= $lastExportTime
601 SELECT DISTINCT contact_id
602 FROM civicrm_subscription_history
603 WHERE date >= $lastExportTime
608 $dao = &CRM_Core_DAO
::executeQuery($sql);
611 while ($dao->fetch()) {
612 $contactIDs[$dao->id
] = $dao->id
;
615 $this->_allContactIDs
= $contactIDs;
620 $this->export($contactIDs);
622 $json = json_encode($this->_values
, JSON_NUMERIC_CHECK
);
623 file_put_contents($fileName,
627 // print_r( json_decode( $json ) );