INFRA-132 - CRM/Contact - phpcbf
[civicrm-core.git] / CRM / Contact / Import / ImportJob.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
39de6fd5 4 | CiviCRM version 4.6 |
6a488035 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
6a488035
TO
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 2009. |
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
06b69b18 31 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
32 * $Id$
33 *
34 */
35
36/**
37 * This class acts like a psuedo-BAO for transient import job tables
38 */
719a6fec 39class CRM_Contact_Import_ImportJob {
6a488035
TO
40
41 protected $_tableName;
42 protected $_primaryKeyName;
43 protected $_statusFieldName;
44
45 protected $_doGeocodeAddress;
46 protected $_invalidRowCount;
47 protected $_conflictRowCount;
48 protected $_onDuplicate;
49 protected $_dedupe;
50 protected $_newGroupName;
51 protected $_newGroupDesc;
52 protected $_groups;
53 protected $_allGroups;
54 protected $_newTagName;
55 protected $_newTagDesc;
56 protected $_tag;
57 protected $_allTags;
58
59 protected $_mapper;
60 protected $_mapperKeys;
61 protected $_mapperLocTypes;
62 protected $_mapperPhoneTypes;
63 protected $_mapperImProviders;
64 protected $_mapperWebsiteTypes;
65 protected $_mapperRelated;
66 protected $_mapperRelatedContactType;
67 protected $_mapperRelatedContactDetails;
68 protected $_mapperRelatedContactLocType;
69 protected $_mapperRelatedContactPhoneType;
70 protected $_mapperRelatedContactImProvider;
71 protected $_mapperRelatedContactWebsiteType;
72 protected $_mapFields;
73
74 protected $_parser;
75
86538308
EM
76 /**
77 * @param null $tableName
78 * @param null $createSql
79 * @param bool $createTable
80 *
81 * @throws Exception
82 */
6a488035
TO
83 public function __construct($tableName = NULL, $createSql = NULL, $createTable = FALSE) {
84 $dao = new CRM_Core_DAO();
85 $db = $dao->getDatabaseConnection();
86
87 if ($createTable) {
88 if (!$createSql) {
89 CRM_Core_Error::fatal('Either an existing table name or an SQL query to build one are required');
90 }
91
92 // FIXME: we should regen this table's name if it exists rather than drop it
93 if (!$tableName) {
94 $tableName = 'civicrm_import_job_' . md5(uniqid(rand(), TRUE));
95 }
96 $db->query("DROP TABLE IF EXISTS $tableName");
97 $db->query("CREATE TABLE $tableName ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci $createSql");
98 }
99
100 if (!$tableName) {
101 CRM_Core_Error::fatal('Import Table is required.');
102 }
103
104 $this->_tableName = $tableName;
105
106 //initialize the properties.
107 $properties = array(
108 'mapperKeys',
109 'mapperRelated',
110 'mapperLocTypes',
111 'mapperPhoneTypes',
112 'mapperImProviders',
113 'mapperWebsiteTypes',
114 'mapperRelatedContactType',
115 'mapperRelatedContactDetails',
116 'mapperRelatedContactLocType',
117 'mapperRelatedContactPhoneType',
118 'mapperRelatedContactImProvider',
119 'mapperRelatedContactWebsiteType',
120 );
ce80b209
TO
121 foreach ($properties as $property) { $this->{"_$property"} = array();
122 }
6a488035
TO
123 }
124
86538308
EM
125 /**
126 * @return null|string
127 */
6a488035
TO
128 public function getTableName() {
129 return $this->_tableName;
130 }
131
86538308
EM
132 /**
133 * @param bool $dropIfComplete
134 *
135 * @return bool
136 * @throws Exception
137 */
6a488035
TO
138 public function isComplete($dropIfComplete = TRUE) {
139 if (!$this->_statusFieldName) {
140 CRM_Core_Error::fatal("Could not get name of the import status field");
141 }
142 $query = "SELECT * FROM $this->_tableName
143 WHERE $this->_statusFieldName = 'NEW' LIMIT 1";
144 $result = CRM_Core_DAO::executeQuery($query);
145 if ($result->fetch()) {
146 return FALSE;
147 }
148 if ($dropIfComplete) {
149 $query = "DROP TABLE $this->_tableName";
150 CRM_Core_DAO::executeQuery($query);
151 }
152 return TRUE;
153 }
154
86538308 155 /**
c490a46a 156 * @param array $params
86538308 157 */
6a488035
TO
158 public function setJobParams(&$params) {
159 foreach ($params as $param => $value) {
0e6e8724
DL
160 $fldName = "_$param";
161 $this->$fldName = $value;
6a488035
TO
162 }
163 }
164
86538308 165 /**
c490a46a 166 * @param CRM_Core_Form $form
86538308
EM
167 * @param int $timeout
168 */
6a488035
TO
169 public function runImport(&$form, $timeout = 55) {
170 $mapper = $this->_mapper;
171 $mapperFields = array();
b4f964d9 172 $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
e7e657f0 173 $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
cbf48754 174 $websiteTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id');
b2b0530a 175 $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
6a488035
TO
176
177 //initialize mapper perperty value.
178 $mapperPeroperties = array(
179 'mapperRelated' => 'mapperRelatedVal',
180 'mapperLocTypes' => 'mapperLocTypesVal',
181 'mapperPhoneTypes' => 'mapperPhoneTypesVal',
182 'mapperImProviders' => 'mapperImProvidersVal',
183 'mapperWebsiteTypes' => 'mapperWebsiteTypesVal',
184 'mapperRelatedContactType' => 'mapperRelatedContactTypeVal',
185 'mapperRelatedContactDetails' => 'mapperRelatedContactDetailsVal',
186 'mapperRelatedContactLocType' => 'mapperRelatedContactLocTypeVal',
187 'mapperRelatedContactPhoneType' => 'mapperRelatedContactPhoneTypeVal',
188 'mapperRelatedContactImProvider' => 'mapperRelatedContactImProviderVal',
189 'mapperRelatedContactWebsiteType' => 'mapperRelatedContactWebsiteTypeVal',
190 );
191
192 foreach ($mapper as $key => $value) {
193 //set respective mapper value to null.
ce80b209
TO
194 foreach (array_values($mapperPeroperties) as $perpertyVal) { $$perpertyVal = NULL;
195 }
6a488035 196
6a488035 197 $fldName = CRM_Utils_Array::value(0, $mapper[$key]);
4ba3ef8e 198 $header = array($this->_mapFields[$fldName]);
6a488035
TO
199 $selOne = CRM_Utils_Array::value(1, $mapper[$key]);
200 $selTwo = CRM_Utils_Array::value(2, $mapper[$key]);
201 $selThree = CRM_Utils_Array::value(3, $mapper[$key]);
202 $this->_mapperKeys[$key] = $fldName;
203
204 //need to differentiate non location elements.
205 if ($selOne && is_numeric($selOne)) {
206 if ($fldName == 'url') {
207 $header[] = $websiteTypes[$selOne];
208 $mapperWebsiteTypesVal = $selOne;
209 }
210 else {
211 $header[] = $locationTypes[$selOne];
212 $mapperLocTypesVal = $selOne;
213 if ($selTwo && is_numeric($selTwo)) {
214 if ($fldName == 'phone') {
215 $header[] = $phoneTypes[$selTwo];
216 $mapperPhoneTypesVal = $selTwo;
217 }
218 elseif ($fldName == 'im') {
219 $header[] = $imProviders[$selTwo];
220 $mapperImProvidersVal = $selTwo;
221 }
222 }
223 }
224 }
225
226 $fldNameParts = explode('_', $fldName, 3);
227 $id = $fldNameParts[0];
228 $first = isset($fldNameParts[1]) ? $fldNameParts[1] : NULL;
229 $second = isset($fldNameParts[2]) ? $fldNameParts[2] : NULL;
230 if (($first == 'a' && $second == 'b') ||
231 ($first == 'b' && $second == 'a')
232 ) {
233
234 $header[] = ucwords(str_replace("_", " ", $selOne));
235
236 $relationType = new CRM_Contact_DAO_RelationshipType();
237 $relationType->id = $id;
238 $relationType->find(TRUE);
239 $mapperRelatedContactTypeVal = $relationType->{"contact_type_$second"};
240
241 $mapperRelatedVal = $fldName;
242 if ($selOne) {
243 $mapperRelatedContactDetailsVal = $selOne;
244 if ($selTwo) {
245 if ($selOne == 'url') {
246 $header[] = $websiteTypes[$selTwo];
247 $mapperRelatedContactWebsiteTypeVal = $selTwo;
248 }
249 else {
250 $header[] = $locationTypes[$selTwo];
251 $mapperRelatedContactLocTypeVal = $selTwo;
252 if ($selThree) {
253 if ($selOne == 'phone') {
254 $header[] = $phoneTypes[$selThree];
255 $mapperRelatedContactPhoneTypeVal = $selThree;
256 }
257 elseif ($selOne == 'im') {
258 $header[] = $imProviders[$selThree];
259 $mapperRelatedContactImProviderVal = $selThree;
260 }
261 }
262 }
263 }
264 }
265 }
266 $mapperFields[] = implode(' - ', $header);
267
268 //set the respective mapper param array values.
269 foreach ($mapperPeroperties as $mapperProKey => $mapperProVal) {
270 $this->{"_$mapperProKey"}[$key] = $$mapperProVal;
271 }
272 }
273
719a6fec 274 $this->_parser = new CRM_Contact_Import_Parser_Contact(
6a488035
TO
275 $this->_mapperKeys,
276 $this->_mapperLocTypes,
277 $this->_mapperPhoneTypes,
278 $this->_mapperImProviders,
279 $this->_mapperRelated,
280 $this->_mapperRelatedContactType,
281 $this->_mapperRelatedContactDetails,
282 $this->_mapperRelatedContactLocType,
283 $this->_mapperRelatedContactPhoneType,
284 $this->_mapperRelatedContactImProvider,
285 $this->_mapperWebsiteTypes,
286 $this->_mapperRelatedContactWebsiteType
287 );
288
289 $this->_parser->run($this->_tableName, $mapperFields,
a05662ef 290 CRM_Import_Parser::MODE_IMPORT,
6a488035
TO
291 $this->_contactType,
292 $this->_primaryKeyName,
293 $this->_statusFieldName,
294 $this->_onDuplicate,
295 $this->_statusID,
296 $this->_totalRowCount,
297 $this->_doGeocodeAddress,
719a6fec 298 CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
6a488035
TO
299 $this->_contactSubType,
300 $this->_dedupe
301 );
302
303 $contactIds = $this->_parser->getImportedContacts();
304
305 //get the related contactIds. CRM-2926
306 $relatedContactIds = $this->_parser->getRelatedImportedContacts();
307 if ($relatedContactIds) {
308 $contactIds = array_merge($contactIds, $relatedContactIds);
309 if ($form) {
310 $form->set('relatedCount', count($relatedContactIds));
311 }
312 }
313
314 if ($this->_newGroupName || count($this->_groups)) {
315 $groupAdditions = $this->_addImportedContactsToNewGroup($contactIds,
316 $this->_newGroupName,
317 $this->_newGroupDesc
318 );
319 if ($form) {
320 $form->set('groupAdditions', $groupAdditions);
321 }
322 }
323
324 if ($this->_newTagName || count($this->_tag)) {
325 $tagAdditions = $this->_tagImportedContactsWithNewTag($contactIds,
326 $this->_newTagName,
327 $this->_newTagDesc
328 );
329 if ($form) {
330 $form->set('tagAdditions', $tagAdditions);
331 }
332 }
333 }
334
86538308
EM
335 /**
336 * @param $form
337 */
6a488035 338 public function setFormVariables($form) {
a05662ef 339 $this->_parser->set($form, CRM_Import_Parser::MODE_IMPORT);
6a488035
TO
340 }
341
86538308
EM
342 /**
343 * @param $contactIds
100fef9d 344 * @param string $newGroupName
86538308
EM
345 * @param $newGroupDesc
346 *
347 * @return array|bool
348 */
6a488035
TO
349 private function _addImportedContactsToNewGroup($contactIds,
350 $newGroupName, $newGroupDesc
351 ) {
352
353 $newGroupId = NULL;
354
355 if ($newGroupName) {
356 /* Create a new group */
357
358 $gParams = array(
359 'title' => $newGroupName,
360 'description' => $newGroupDesc,
361 'is_active' => TRUE,
362 );
363 $group = CRM_Contact_BAO_Group::create($gParams);
364 $this->_groups[] = $newGroupId = $group->id;
365 }
366
367 if (is_array($this->_groups)) {
368 $groupAdditions = array();
369 foreach ($this->_groups as $groupId) {
370 $addCount = CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $groupId);
371 $totalCount = $addCount[1];
372 if ($groupId == $newGroupId) {
373 $name = $newGroupName;
374 $new = TRUE;
375 }
376 else {
377 $name = $this->_allGroups[$groupId];
378 $new = FALSE;
379 }
380 $groupAdditions[] = array(
381 'url' => CRM_Utils_System::url('civicrm/group/search',
382 'reset=1&force=1&context=smog&gid=' . $groupId
383 ),
384 'name' => $name,
385 'added' => $totalCount,
386 'notAdded' => $addCount[2],
387 'new' => $new,
388 );
389 }
390 return $groupAdditions;
391 }
392 return FALSE;
393 }
394
86538308
EM
395 /**
396 * @param $contactIds
100fef9d 397 * @param string $newTagName
86538308
EM
398 * @param $newTagDesc
399 *
400 * @return array|bool
401 */
6a488035
TO
402 private function _tagImportedContactsWithNewTag($contactIds,
403 $newTagName, $newTagDesc
404 ) {
405
406 $newTagId = NULL;
407 if ($newTagName) {
408 /* Create a new Tag */
409
410 $tagParams = array(
411 'name' => $newTagName,
412 'title' => $newTagName,
413 'description' => $newTagDesc,
414 'is_selectable' => TRUE,
415 'used_for' => 'civicrm_contact',
416 );
417 $id = array();
418 $addedTag = CRM_Core_BAO_Tag::add($tagParams, $id);
419 $this->_tag[$addedTag->id] = 1;
420 }
421 //add Tag to Import
422
423 if (is_array($this->_tag)) {
424 $tagAdditions = array();
425 foreach ($this->_tag as $tagId => $val) {
426 $addTagCount = CRM_Core_BAO_EntityTag::addEntitiesToTag($contactIds, $tagId);
427 $totalTagCount = $addTagCount[1];
428 if (isset($addedTag) && $tagId == $addedTag->id) {
429 $tagName = $newTagName;
430 $new = TRUE;
431 }
432 else {
433 $tagName = $this->_allTags[$tagId];
434 $new = FALSE;
435 }
436 $tagAdditions[] = array(
437 'url' => CRM_Utils_System::url('civicrm/contact/search',
438 'reset=1&force=1&context=smog&id=' . $tagId
439 ),
440 'name' => $tagName,
441 'added' => $totalTagCount,
442 'notAdded' => $addTagCount[2],
443 'new' => $new,
444 );
445 }
446 return $tagAdditions;
447 }
448 return FALSE;
449 }
450
86538308
EM
451 /**
452 * @return array
453 */
6a488035
TO
454 public static function getIncompleteImportTables() {
455 $dao = new CRM_Core_DAO();
456 $database = $dao->database();
457 $query = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA
458 WHERE TABLE_SCHEMA = ? AND
459 TABLE_NAME LIKE 'civicrm_import_job_%'
460 ORDER BY TABLE_NAME";
461 $result = CRM_Core_DAO::executeQuery($query, array($database));
462 $incompleteImportTables = array();
463 while ($importTable = $result->fetch()) {
464 if (!$this->isComplete($importTable)) {
465 $incompleteImportTables[] = $importTable;
466 }
467 }
468 return $incompleteImportTables;
469 }
470}