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