3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2019
33 class CRM_Utils_Migrate_ExportJSON
{
34 const CHUNK_SIZE
= 128;
36 protected $_contactIDs;
38 protected $_allContactIDs;
42 protected $_discoverContacts = FALSE;
44 protected $_renameGroups = 1;
46 protected $_renameTags = 1;
48 protected $_sitePrefix = 'Site 1';
51 * @param array $params
53 public function __construct(&$params) {
54 foreach ($params as $name => $value) {
55 $varName = '_' . $name;
56 $this->$varName = $value;
61 * Split a large array of contactIDs into more manageable smaller chunks.
63 * @param array $contactIDs
67 public function &splitContactIDs(&$contactIDs) {
68 // contactIDs could be a real large array, so we split it up into
69 // smaller chunks and then general xml for each chunk
72 $chunks[$current] = [];
75 foreach ($contactIDs as $k => $v) {
76 $chunks[$current][$k] = $v;
79 if ($count == self
::CHUNK_SIZE
) {
81 $chunks[$current] = [];
86 if (empty($chunks[$current])) {
87 unset($chunks[$current]);
94 * Given a set of contact IDs get the values.
96 * @param array $contactIDs
97 * @param array $additionalContactIDs
99 public function getValues(&$contactIDs, &$additionalContactIDs) {
101 $this->contact($contactIDs);
102 $this->address($contactIDs);
103 $this->phone($contactIDs);
104 $this->email($contactIDs);
105 $this->im($contactIDs);
106 $this->website($contactIDs);
107 $this->note($contactIDs);
109 $this->group($contactIDs);
110 $this->groupContact($contactIDs);
111 $this->savedSearch($contactIDs);
113 $this->tag($contactIDs);
114 $this->entityTag($contactIDs);
116 $this->relationship($contactIDs, $additionalContactIDs);
117 $this->activity($contactIDs, $additionalContactIDs);
120 public function metaData() {
122 'prefix_id' => 'individual_prefix',
123 'suffix_id' => 'individual_suffix',
124 'gender_id' => 'gender',
125 'mobile_provider' => 'mobile_provider',
126 'phone_type' => 'phone_type',
127 'activity_type' => 'activity_type',
128 'status_id' => 'activity_status_id',
129 'priority_id' => 'activity_priority_id',
130 'medium_id' => 'encounter_medium',
131 'communication_style_id' => 'communication_style',
132 'email_greeting' => 'email_greeting',
133 'postal_greeting' => 'postal_greeting',
134 'addressee_id' => 'addressee',
136 $this->optionGroup($optionGroupVars);
139 'civicrm_location_type' => 'CRM_Core_DAO_LocationType',
140 'civicrm_relationship_type' => 'CRM_Contact_DAO_RelationshipType',
142 $this->auxTable($auxilaryTables);
148 public function auxTable($tables) {
149 foreach ($tables as $tableName => $daoName) {
150 $fields = &$this->dbFields($daoName, TRUE);
152 $sql = "SELECT * from $tableName";
153 $this->sql($sql, $tableName, $fields);
158 * @param $optionGroupVars
160 public function optionGroup($optionGroupVars) {
161 $names = array_values($optionGroupVars);
163 foreach ($names as $name) {
166 $nameString = implode(",", $str);
170 FROM civicrm_option_group
171 WHERE name IN ( $nameString )
173 $fields = &$this->dbFields('CRM_Core_DAO_OptionGroup', TRUE);
174 $this->sql($sql, 'civicrm_option_group', $fields);
178 FROM civicrm_option_value v
179 INNER JOIN civicrm_option_group g ON v.option_group_id = g.id
180 WHERE g.name IN ( $nameString )
182 $fields = &$this->dbFields('CRM_Core_DAO_OptionValue', TRUE);
183 $this->sql($sql, 'civicrm_option_value', $fields);
188 * @param string $tableName
191 * @param null $additionalWhereCond
193 public function table(
198 $additionalWhereCond = NULL
204 $idString = implode(',', $ids);
209 WHERE $whereField IN ( $idString )
212 if ($additionalWhereCond) {
213 $sql .= " AND $additionalWhereCond";
216 $this->sql($sql, $tableName, $fields);
221 * @param string $tableName
224 public function sql($sql, $tableName, &$fields) {
225 $dao = &CRM_Core_DAO
::executeQuery($sql);
227 while ($dao->fetch()) {
229 foreach ($fields as $name) {
230 if (empty($dao->$name)) {
231 $value[$name] = NULL;
234 $value[$name] = $dao->$name;
237 $this->appendValue($dao->id
, $tableName, $value);
244 public function contact(&$contactIDs) {
245 $fields = &$this->dbFields('CRM_Contact_DAO_Contact', TRUE);
246 $this->table($contactIDs, 'civicrm_contact', $fields, 'id', NULL);
252 public function note(&$contactIDs) {
253 $fields = &$this->dbFields('CRM_Core_DAO_Note', TRUE);
254 $this->table($contactIDs, 'civicrm_note', $fields, 'entity_id', "entity_table = 'civicrm_contact'");
260 public function phone(&$contactIDs) {
261 $fields = &$this->dbFields('CRM_Core_DAO_Phone', TRUE);
262 $this->table($contactIDs, 'civicrm_phone', $fields, 'contact_id', NULL);
268 public function email(&$contactIDs) {
269 $fields = &$this->dbFields('CRM_Core_DAO_Email', TRUE);
270 $this->table($contactIDs, 'civicrm_email', $fields, 'contact_id', NULL);
276 public function im(&$contactIDs) {
277 $fields = &$this->dbFields('CRM_Core_DAO_IM', TRUE);
278 $this->table($contactIDs, 'civicrm_im', $fields, 'contact_id', NULL);
284 public function website(&$contactIDs) {
285 $fields = &$this->dbFields('CRM_Core_DAO_Website', TRUE);
286 $this->table($contactIDs, 'civicrm_website', $fields, 'contact_id', NULL);
292 public function address(&$contactIDs) {
293 $fields = &$this->dbFields('CRM_Core_DAO_Email', TRUE);
294 $this->table($contactIDs, 'civicrm_address', $fields, 'contact_id', NULL);
300 public function groupContact(&$contactIDs) {
301 $fields = &$this->dbFields('CRM_Contact_DAO_GroupContact', TRUE);
302 $this->table($contactIDs, 'civicrm_group_contact', $fields, 'contact_id', NULL);
306 * @todo support group inheritance
308 * Parent child group ids are encoded in a text string
312 public function group(&$contactIDs) {
313 // handle groups only once
314 static $_groupsHandled = [];
316 $ids = implode(',', $contactIDs);
319 SELECT DISTINCT group_id
320 FROM civicrm_group_contact
321 WHERE contact_id IN ( $ids )
323 $dao = CRM_Core_DAO
::executeQuery($sql);
325 while ($dao->fetch()) {
326 if (!isset($_groupsHandled[$dao->group_id
])) {
327 $groupIDs[] = $dao->group_id
;
328 $_groupsHandled[$dao->group_id
] = 1;
332 $fields = &$this->dbFields('CRM_Contact_DAO_Group', TRUE);
333 $this->table($groupIDs, 'civicrm_group', $fields, 'id');
335 $this->savedSearch($groupIDs);
339 * @todo support search builder and custom saved searches
342 public function savedSearch(&$groupIDs) {
343 if (empty($groupIDs)) {
347 $idString = implode(",", $groupIDs);
350 FROM civicrm_saved_search s
351 INNER JOIN civicrm_group g on g.saved_search_id = s.id
352 WHERE g.id IN ( $idString )
355 $fields = &$this->dbFields('CRM_Contact_DAO_SavedSearch', TRUE);
356 $this->sql($sql, 'civicrm_saved_search', $fields);
362 public function entityTag(&$contactIDs) {
363 $fields = &$this->dbFields('CRM_Core_DAO_EntityTag', TRUE);
364 $this->table($contactIDs, 'civicrm_entity_tag', $fields, 'entity_id', "entity_table = 'civicrm_contact'");
370 public function tag(&$contactIDs) {
371 // handle tags only once
372 static $_tagsHandled = [];
374 $ids = implode(',', $contactIDs);
377 SELECT DISTINCT tag_id
378 FROM civicrm_entity_tag
379 WHERE entity_id IN ( $ids )
380 AND entity_table = 'civicrm_contact'
382 $dao = CRM_Core_DAO
::executeQuery($sql);
384 while ($dao->fetch()) {
385 if (!isset($_tagsHandled[$dao->tag_id
])) {
386 $tagIDs[] = $dao->tag_id
;
387 $_tagsHandled[$dao->tag_id
] = 1;
391 $fields = &$this->dbFields('CRM_Core_DAO_Tag', TRUE);
392 $this->table($tagIDs, 'civicrm_tag', $fields, 'id');
397 * @param $additionalContacts
399 public function relationship(&$contactIDs, &$additionalContacts) {
400 // handle relationships only once
401 static $_relationshipsHandled = [];
403 $ids = implode(',', $contactIDs);
407 FROM civicrm_relationship r
408 WHERE r.contact_id_a IN ( $ids )
411 FROM civicrm_relationship r
412 WHERE r.contact_id_b IN ( $ids )
416 $fields = $this->dbFields('CRM_Contact_DAO_Relationship', TRUE);
417 $dao = &CRM_Core_DAO
::executeQuery($sql);
418 while ($dao->fetch()) {
419 if (isset($_relationshipsHandled[$dao->id
])) {
422 $_relationshipsHandled[$dao->id
] = $dao->id
;
425 foreach ($fields as $fld) {
426 if (empty($dao->$fld)) {
427 $relationship[$fld] = NULL;
430 $relationship[$fld] = $dao->$fld;
433 $this->appendValue($dao->id
, 'civicrm_relationship', $relationship);
435 $this->addAdditionalContacts([
446 * @param $additionalContacts
448 public function activity(&$contactIDs, &$additionalContacts) {
449 static $_activitiesHandled = [];
450 $activityContacts = CRM_Activity_BAO_ActivityContact
::buildOptions('record_type_id', 'validate');
451 $assigneeID = CRM_Utils_Array
::key('Activity Assignees', $activityContacts);
452 $targetID = CRM_Utils_Array
::key('Activity Targets', $activityContacts);
453 $ids = implode(',', $contactIDs);
455 // query framing returning all contacts in valid activity
457 SELECT a.*, ac.id as acID, ac.activity_id, ac.contact_id, ac.record_type_id
458 FROM civicrm_activity a
459 INNER JOIN civicrm_activity_contact ac ON ac.activity_id = a.id
460 WHERE ac.contact_id IN ( $ids )
461 AND (a.activity_type_id != 3 AND a.activity_type_id != 20)
464 $fields = &$this->dbFields('CRM_Activity_DAO_Activity', TRUE);
466 $dao = &CRM_Core_DAO
::executeQuery($sql);
467 while ($dao->fetch()) {
468 // adding source, target and assignee contacts in additional contacts array
469 $this->addAdditionalContacts([$dao->contact_id
],
473 // append values of activity contacts
474 $activityContacts = [
476 'contact_id' => $dao->contact_id
,
477 'activity_id' => $dao->activity_id
,
478 'record_type_id' => $dao->record_type_id
,
480 $this->appendValue($dao->acID
, 'civicrm_activity_contact', $activityContacts);
482 if (isset($_activitiesHandled[$dao->id
])) {
485 $_activitiesHandled[$dao->id
] = $dao->id
;
488 foreach ($fields as $fld) {
489 if (empty($dao->$fld)) {
490 $activity[$fld] = NULL;
493 $activity[$fld] = $dao->$fld;
497 // append activity value
498 $this->appendValue($dao->id
, 'civicrm_activity', $activity);
504 * @param string $name
507 public function appendValue($id, $name, $value) {
512 if (!isset($this->_values
[$name])) {
513 $this->_values
[$name] = [];
514 $this->_values
[$name][] = array_keys($value);
516 $this->_values
[$name][] = array_values($value);
520 * @param string $daoName
521 * @param bool $onlyKeys
525 public function dbFields($daoName, $onlyKeys = FALSE) {
526 static $_fieldsRetrieved = [];
528 if (!isset($_fieldsRetrieved[$daoName])) {
529 $_fieldsRetrieved[$daoName] = [];
530 $daoFile = str_replace('_',
534 include_once $daoFile;
536 $daoFields = &$daoName::fields();
538 foreach ($daoFields as $key => & $value) {
539 $_fieldsRetrieved[$daoName][$value['name']] = [
540 'uniqueName' => $key,
541 'type' => $value['type'],
542 'title' => CRM_Utils_Array
::value('title', $value, NULL),
548 return array_keys($_fieldsRetrieved[$daoName]);
551 return $_fieldsRetrieved[$daoName];
557 * @param $additionalContacts
559 public function addAdditionalContacts($contactIDs, &$additionalContacts) {
560 if (!$this->_discoverContacts
) {
564 foreach ($contactIDs as $cid) {
566 !isset($this->_allContactIDs
[$cid]) &&
567 !isset($additionalContacts[$cid])
569 $additionalContacts[$cid] = $cid;
577 public function export(&$contactIDs) {
578 $chunks = &$this->splitContactIDs($contactIDs);
580 $additionalContactIDs = [];
582 foreach ($chunks as $chunk) {
583 $this->getValues($chunk, $additionalContactIDs);
586 if (!empty($additionalContactIDs)) {
587 $this->_allContactIDs
= $this->_allContactIDs +
$additionalContactIDs;
588 $this->export($additionalContactIDs);
593 * @param string $fileName
594 * @param null $lastExportTime
595 * @param bool $discoverContacts
599 $lastExportTime = NULL,
600 $discoverContacts = FALSE
602 $this->_discoverContacts
= $discoverContacts;
604 if (!$lastExportTime) {
612 SELECT DISTINCT entity_id
614 WHERE entity_table = 'civicrm_contact'
615 AND modified_date >= $lastExportTime
617 SELECT DISTINCT contact_id
618 FROM civicrm_subscription_history
619 WHERE date >= $lastExportTime
624 $dao = &CRM_Core_DAO
::executeQuery($sql);
627 while ($dao->fetch()) {
628 $contactIDs[$dao->id
] = $dao->id
;
631 $this->_allContactIDs
= $contactIDs;
636 $this->export($contactIDs);
638 $json = json_encode($this->_values
, JSON_NUMERIC_CHECK
);
639 file_put_contents($fileName,
643 // print_r( json_decode( $json ) );