CRM-12274
[civicrm-core.git] / CRM / Utils / Migrate / ExportJSON.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
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. |
13 | |
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. |
18 | |
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 +--------------------------------------------------------------------+
26*/
27
28/**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2013
32 * $Id$
33 *
34 */
35class CRM_Utils_Migrate_ExportJSON {
36 CONST CHUNK_SIZE = 128;
37
38 protected $_contactIDs;
39
40 protected $_allContactIDs;
41
42 protected $_values;
43
44 protected $_discoverContacts = FALSE;
45
46 protected $_renameGroups = 1;
47
48 protected $_renameTags = 1;
49
50 protected $_sitePrefix = 'Site 1'; function __construct(&$params) {
51 foreach ($params as $name => $value) {
52 $varName = '_' . $name;
53 $this->$varName = $value;
54 }
55 }
56
57 /**
58 * Split a large array of contactIDs into more manageable smaller chunks
59 */
60 function &splitContactIDs(&$contactIDs) {
61 // contactIDs could be a real large array, so we split it up into
62 // smaller chunks and then general xml for each chunk
63 $chunks = array();
64 $current = 0;
65 $chunks[$current] = array();
66 $count = 0;
67
68 foreach ($contactIDs as $k => $v) {
69 $chunks[$current][$k] = $v;
70 $count++;
71
72 if ($count == self::CHUNK_SIZE) {
73 $current++;
74 $chunks[$current] = array();
75 $count = 0;
76 }
77 }
78
79 if (empty($chunks[$current])) {
80 unset($chunks[$current]);
81 }
82
83 return $chunks;
84 }
85
86 /**
87 * Given a set of contact IDs get the values
88 */
89 function getValues(&$contactIDs, &$additionalContactIDs) {
90
91 $this->contact($contactIDs);
92 $this->address($contactIDs);
93 $this->phone($contactIDs);
94 $this->email($contactIDs);
95 $this->im($contactIDs);
96 $this->website($contactIDs);
97 $this->note($contactIDs);
98
99 $this->group($contactIDs);
100 $this->groupContact($contactIDs);
101 $this->savedSearch($contactIDs);
102
103 $this->tag($contactIDs);
104 $this->entityTag($contactIDs);
105
106 $this->relationship($contactIDs, $additionalContactIDs);
107 $this->activity($contactIDs, $additionalContactIDs);
108 }
109
110 function metaData() {
111 $optionGroupVars = array(
112 'prefix_id' => 'individual_prefix',
113 'suffix_id' => 'individual_suffix',
114 'gender_id' => 'gender',
115 'mobile_provider' => 'mobile_provider',
116 'phone_type' => 'phone_type',
117 'activity_type' => 'activity_type',
118 'status_id' => 'activity_status_id',
119 'priority_id' => 'activity_priority_id',
120 'medium_id' => 'encounter_medium',
121 'email_greeting' => 'email_greeting',
122 'postal_greeting' => 'postal_greeting',
123 'addressee_id' => 'addressee',
124 );
125 $this->optionGroup($optionGroupVars);
126
127 $auxilaryTables = array(
128 'civicrm_location_type' => 'CRM_Core_DAO_LocationType',
129 'civicrm_relationship_type' => 'CRM_Contact_DAO_RelationshipType',
130 );
131 $this->auxTable($auxilaryTables);
132 }
133
134 function auxTable($tables) {
135 foreach ($tables as $tableName => $daoName) {
136 $fields = &$this->dbFields($daoName, TRUE);
137
138 $sql = "SELECT * from $tableName";
139 $this->sql($sql, $tableName, $fields);
140 }
141 }
142
143 function optionGroup($optionGroupVars) {
144 $names = array_values($optionGroupVars);
145 $str = array();
146 foreach ($names as $name) {
147 $str[] = "'$name'";
148 }
149 $nameString = implode(",", $str);
150
151 $sql = "
152SELECT *
153FROM civicrm_option_group
154WHERE name IN ( $nameString )
155";
156 $fields = &$this->dbFields('CRM_Core_DAO_OptionGroup', TRUE);
157 $this->sql($sql, 'civicrm_option_group', $fields);
158
159 $sql = "
160SELECT v.*
161FROM civicrm_option_value v
162INNER JOIN civicrm_option_group g ON v.option_group_id = g.id
163WHERE g.name IN ( $nameString )
164";
165 $fields = &$this->dbFields('CRM_Core_DAO_OptionValue', TRUE);
166 $this->sql($sql, 'civicrm_option_value', $fields);
167 }
168
169 function table(&$ids,
170 $tableName,
171 &$fields,
172 $whereField,
173 $additionalWhereCond = NULL
174 ) {
175 if (empty($ids)) {
176 return;
177 }
178
179 $idString = implode(',', $ids);
180
181 $sql = "
182SELECT *
183 FROM $tableName
184 WHERE $whereField IN ( $idString )
185";
186
187 if ($additionalWhereCond) {
188 $sql .= " AND $additionalWhereCond";
189 }
190
191 $this->sql($sql, $tableName, $fields);
192 }
193
194 function sql($sql, $tableName, &$fields) {
195 $dao = &CRM_Core_DAO::executeQuery($sql);
196
197 while ($dao->fetch()) {
198 $value = array();
199 foreach ($fields as $name) {
200 if (empty($dao->$name)) {
201 $value[$name] = NULL;
202 }
203 else {
204 $value[$name] = $dao->$name;
205 }
206 }
207 $this->appendValue($dao->id, $tableName, $value);
208 }
209 $dao->free();
210 }
211
212 function contact(&$contactIDs) {
213 $fields = &$this->dbFields('CRM_Contact_DAO_Contact', TRUE);
214 $this->table($contactIDs, 'civicrm_contact', $fields, 'id', NULL);
215 }
216
217 function note(&$contactIDs) {
218 $fields = &$this->dbFields('CRM_Core_DAO_Note', TRUE);
219 $this->table($contactIDs, 'civicrm_note', $fields, 'entity_id', "entity_table = 'civicrm_contact'");
220 }
221
222 function phone(&$contactIDs) {
223 $fields = &$this->dbFields('CRM_Core_DAO_Phone', TRUE);
224 $this->table($contactIDs, 'civicrm_phone', $fields, 'contact_id', NULL);
225 }
226
227 function email(&$contactIDs) {
228 $fields = &$this->dbFields('CRM_Core_DAO_Email', TRUE);
229 $this->table($contactIDs, 'civicrm_email', $fields, 'contact_id', NULL);
230 }
231
232 function im(&$contactIDs) {
233 $fields = &$this->dbFields('CRM_Core_DAO_IM', TRUE);
234 $this->table($contactIDs, 'civicrm_im', $fields, 'contact_id', NULL);
235 }
236
237 function website(&$contactIDs) {
238 $fields = &$this->dbFields('CRM_Core_DAO_Website', TRUE);
239 $this->table($contactIDs, 'civicrm_website', $fields, 'contact_id', NULL);
240 }
241
242 function address(&$contactIDs) {
243 $fields = &$this->dbFields('CRM_Core_DAO_Email', TRUE);
244 $this->table($contactIDs, 'civicrm_address', $fields, 'contact_id', NULL);
245 }
246
247 function groupContact(&$contactIDs) {
248 $fields = &$this->dbFields('CRM_Contact_DAO_GroupContact', TRUE);
249 $this->table($contactIDs, 'civicrm_group_contact', $fields, 'contact_id', NULL);
250 }
251
252 // TODO - support group inheritance
253 // Parent child group ids are encoded in a text string
254 function group(&$contactIDs) {
255 // handle groups only once
256 static $_groupsHandled = array();
257
258 $ids = implode(',', $contactIDs);
259
260 $sql = "
261SELECT DISTINCT group_id
262FROM civicrm_group_contact
263WHERE contact_id IN ( $ids )
264";
265 $dao = CRM_Core_DAO::executeQuery($sql);
266 $groupIDs = array();
267 while ($dao->fetch()) {
268 if (!isset($_groupsHandled[$dao->group_id])) {
269 $groupIDs[] = $dao->group_id;
270 $_groupsHandled[$dao->group_id] = 1;
271 }
272 }
273
274 $fields = &$this->dbFields('CRM_Contact_DAO_Group', TRUE);
275 $this->table($groupIDs, 'civicrm_group', $fields, 'id');
276
277 $this->savedSearch($groupIDs);
278 }
279
280 // TODO - support search builder and custom saved searches
281 function savedSearch(&$groupIDs) {
282 if (empty($groupIDs)) {
283 return;
284 }
285
286 $idString = implode(",", $groupIDs);
287 $sql = "
288SELECT s.*
289FROM civicrm_saved_search s
290INNER JOIN civicrm_group g on g.saved_search_id = s.id
291WHERE g.id IN ( $idString )
292";
293
294 $fields = &$this->dbFields('CRM_Contact_DAO_SavedSearch', TRUE);
295 $this->sql($sql, 'civicrm_saved_search', $fields);
296 }
297
298 function entityTag(&$contactIDs) {
299 $fields = &$this->dbFields('CRM_Core_DAO_EntityTag', TRUE);
300 $this->table($contactIDs, 'civicrm_entity_tag', $fields, 'entity_id', "entity_table = 'civicrm_contact'");
301 }
302
303 function tag(&$contactIDs) {
304 // handle tags only once
305 static $_tagsHandled = array();
306
307 $ids = implode(',', $contactIDs);
308
309 $sql = "
310SELECT DISTINCT tag_id
311FROM civicrm_entity_tag
312WHERE entity_id IN ( $ids )
313AND entity_table = 'civicrm_contact'
314";
315 $dao = CRM_Core_DAO::executeQuery($sql);
316 $tagIDs = array();
317 while ($dao->fetch()) {
318 if (!isset($_tagsHandled[$dao->tag_id])) {
319 $tagIDs[] = $dao->tag_id;
320 $_tagsHandled[$dao->tag_id] = 1;
321 }
322 }
323
324 $fields = &$this->dbFields('CRM_Core_DAO_Tag', TRUE);
325 $this->table($tagIDs, 'civicrm_tag', $fields, 'id');
326 }
327
328 function relationship(&$contactIDs, &$additionalContacts) {
329 // handle relationships only once
330 static $_relationshipsHandled = array();
331
332 $ids = implode(',', $contactIDs);
333
334 $sql = "(
335 SELECT r.*
336 FROM civicrm_relationship r
337 WHERE r.contact_id_a IN ( $ids )
338) UNION (
339 SELECT r.*
340 FROM civicrm_relationship r
341 WHERE r.contact_id_b IN ( $ids )
342)
343";
344
345 $fields = $this->dbFields('CRM_Contact_DAO_Relationship', TRUE);
346 $dao = &CRM_Core_DAO::executeQuery($sql);
347 while ($dao->fetch()) {
348 if (isset($_relationshipsHandled[$dao->id])) {
349 continue;
350 }
351 $_relationshipsHandled[$dao->id] = $dao->id;
352
353 $relationship = array();
354 foreach ($fields as $fld) {
355 if (empty($dao->$fld)) {
356 $relationship[$fld] = NULL;
357 }
358 else {
359 $relationship[$fld] = $dao->$fld;
360 }
361 }
362 $this->appendValue($dao->id, 'civicrm_relationship', $relationship);
363
364 $this->addAdditionalContacts(array(
365 $dao->contact_id_a,
366 $dao->contact_id_b,
367 ),
368 $additionalContacts
369 );
370 }
371 $dao->free();
372 }
373
374 function activity(&$contactIDs, &$additionalContacts) {
375 static $_activitiesHandled = array();
376
377 $ids = implode(',', $contactIDs);
378
379 $sql = "(
380 SELECT a.*
381 FROM civicrm_activity a
382 INNER JOIN civicrm_activity_assignment aa ON aa.activity_id = a.id
383 WHERE aa.assignee_contact_id IN ( $ids )
384 AND ( a.activity_type_id != 3 AND a.activity_type_id != 20 )
385) UNION (
386 SELECT a.*
387 FROM civicrm_activity a
388 INNER JOIN civicrm_activity_target at ON at.activity_id = a.id
389 WHERE at.target_contact_id IN ( $ids )
390 AND ( a.activity_type_id != 3 AND a.activity_type_id != 20 )
391)
392";
393
394 $fields = &$this->dbFields('CRM_Activity_DAO_Activity', TRUE);
395
396 $activityIDs = array();
397 $dao = &CRM_Core_DAO::executeQuery($sql);
398 while ($dao->fetch()) {
399 if (isset($_activitiesHandled[$dao->id])) {
400 continue;
401 }
402 $_activitiesHandled[$dao->id] = $dao->id;
403 $activityIDs[] = $dao->id;
404
405 $activity = array();
406 foreach ($fields as $fld) {
407 if (empty($dao->$fld)) {
408 $activity[$fld] = NULL;
409 }
410 else {
411 $activity[$fld] = $dao->$fld;
412 }
413 }
414
415 $this->appendValue($dao->id, 'civicrm_activity', $activity);
416 $this->addAdditionalContacts(array($dao->source_contact_id),
417 $additionalContacts
418 );
419 }
420 $dao->free();
421
422 if (empty($activityIDs)) {
423 return;
424 }
425
426 $activityIDString = implode(",", $activityIDs);
427
428 // now get all assignee contact ids and target contact ids for this activity
429 $sql = "SELECT * FROM civicrm_activity_assignment WHERE activity_id IN ($activityIDString)";
430 $aaDAO = &CRM_Core_DAO::executeQuery($sql);
431 $activityContacts = array();
432 while ($aaDAO->fetch()) {
433 $activityAssignee = array(
434 'id' => $aaDAO->id,
435 'assignee_contact_id' => $aaDAO->assignee_contact_id,
436 'activity_id' => $aaDAO->activity_id,
437 );
438 $this->appendValue($aaDAO->id, 'civicrm_activity_assignment', $activityAssignee);
439 $activityContacts[] = $aaDAO->assignee_contact_id;
440 }
441 $aaDAO->free();
442
443 $sql = "SELECT * FROM civicrm_activity_target WHERE activity_id IN ($activityIDString)";
444 $atDAO = &CRM_Core_DAO::executeQuery($sql);
445 while ($atDAO->fetch()) {
446 $activityTarget = array(
447 'id' => $atDAO->id,
448 'target_contact_id' => $atDAO->target_contact_id,
449 'activity_id' => $atDAO->activity_id,
450 );
451 $this->appendValue($atDAO->id, 'civicrm_activity_target', $activityTarget);
452 $activityContacts[] = $atDAO->target_contact_id;
453 }
454 $atDAO->free();
455
456 $this->addAdditionalContacts($activityContacts, $additionalContacts);
457 }
458
459 function appendValue($id, $name, $value) {
460 if (empty($value)) {
461 return;
462 }
463
464 if (!isset($this->_values[$name])) {
465 $this->_values[$name] = array();
466 $this->_values[$name][] = array_keys($value);
467 }
468 $this->_values[$name][] = array_values($value);
469 }
470
471 function dbFields($daoName, $onlyKeys = FALSE) {
472 static $_fieldsRetrieved = array();
473
474 if (!isset($_fieldsRetrieved[$daoName])) {
475 $_fieldsRetrieved[$daoName] = array();
476 $daoFile = str_replace('_',
477 DIRECTORY_SEPARATOR,
478 $daoName
479 ) . '.php';
480 include_once ($daoFile);
481
482 $daoFields = &$daoName::fields();
483
484 foreach ($daoFields as $key => & $value) {
485 $_fieldsRetrieved[$daoName][$value['name']] = array(
486 'uniqueName' => $key,
487 'type' => $value['type'],
488 'title' => CRM_Utils_Array::value('title', $value, NULL),
489 );
490 }
491 }
492
493 if ($onlyKeys) {
494 return array_keys($_fieldsRetrieved[$daoName]);
495 }
496 else {
497 return $_fieldsRetrieved[$daoName];
498 }
499 }
500
501 function addAdditionalContacts($contactIDs, &$additionalContacts) {
502 if (!$this->_discoverContacts) {
503 return;
504 }
505
506 foreach ($contactIDs as $cid) {
507 if ($cid &&
508 !isset($this->_allContactIDs[$cid]) &&
509 !isset($additionalContacts[$cid])
510 ) {
511 $additionalContacts[$cid] = $cid;
512 }
513 }
514 }
515
516 function export(&$contactIDs) {
517 $chunks = &$this->splitContactIDs($contactIDs);
518
519 $additionalContactIDs = array();
520
521 foreach ($chunks as $chunk) {
522 $this->getValues($chunk, $additionalContactIDs);
523 }
524
525 if (!empty($additionalContactIDs)) {
526 $this->_allContactIDs = $this->_allContactIDs + $additionalContactIDs;
527 $this->export($additionalContactIDs);
528 }
529 }
530
531 function run($fileName,
532 $lastExportTime = NULL,
533 $discoverContacts = FALSE
534 ) {
535 $this->_discoverContacts = $discoverContacts;
536
537 if (!$lastExportTime) {
538 $sql = "
539SELECT id
540FROM civicrm_contact
541";
542 }
543 else {
544 $sql = "(
545SELECT DISTINCT entity_id
546FROM civicrm_log
547WHERE entity_table = 'civicrm_contact'
548AND modified_date >= $lastExportTime
549) UNION (
550SELECT DISTINCT contact_id
551FROM civicrm_subscription_history
552WHERE date >= $lastExportTime
553)
554";
555 }
556
557
558 $dao = &CRM_Core_DAO::executeQuery($sql);
559
560 $contactIDs = array();
561 while ($dao->fetch()) {
562 $contactIDs[$dao->id] = $dao->id;
563 }
564
565 $this->_allContactIDs = $contactIDs;
566 $this->_values = array();
567
568 $this->metaData();
569
570 $this->export($contactIDs);
571
572 $json = json_encode($this->_values, JSON_NUMERIC_CHECK);
573 file_put_contents($fileName,
574 $json
575 );
576
577 // print_r( json_decode( $json ) );
578 }
579}
580