Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
fee14197 | 4 | | CiviCRM version 5 | |
6a488035 | 5 | +--------------------------------------------------------------------+ |
6b83d5bd | 6 | | Copyright CiviCRM LLC (c) 2004-2019 | |
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 | | |
c73475ea | 12 | | Version 3, 19 November 2009 and the CiviCRM Licensing Exception. | |
6a488035 TO |
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 | +--------------------------------------------------------------------+ | |
d25dd0ee | 26 | */ |
6a488035 TO |
27 | |
28 | /** | |
29 | * | |
30 | * @package CRM | |
6b83d5bd | 31 | * @copyright CiviCRM LLC (c) 2004-2019 |
6a488035 TO |
32 | */ |
33 | ||
34 | /** | |
616eac7e | 35 | * This class acts like a psuedo-BAO for transient import job tables. |
6a488035 | 36 | */ |
719a6fec | 37 | class CRM_Contact_Import_ImportJob { |
6a488035 TO |
38 | |
39 | protected $_tableName; | |
40 | protected $_primaryKeyName; | |
41 | protected $_statusFieldName; | |
42 | ||
43 | protected $_doGeocodeAddress; | |
44 | protected $_invalidRowCount; | |
45 | protected $_conflictRowCount; | |
46 | protected $_onDuplicate; | |
47 | protected $_dedupe; | |
48 | protected $_newGroupName; | |
49 | protected $_newGroupDesc; | |
5a552b87 | 50 | protected $_newGroupType; |
6a488035 TO |
51 | protected $_groups; |
52 | protected $_allGroups; | |
53 | protected $_newTagName; | |
54 | protected $_newTagDesc; | |
55 | protected $_tag; | |
56 | protected $_allTags; | |
57 | ||
58 | protected $_mapper; | |
1881b7b0 | 59 | protected $_mapperKeys = array(); |
6a488035 TO |
60 | protected $_mapFields; |
61 | ||
62 | protected $_parser; | |
63 | ||
86538308 EM |
64 | /** |
65 | * @param null $tableName | |
66 | * @param null $createSql | |
67 | * @param bool $createTable | |
68 | * | |
69 | * @throws Exception | |
70 | */ | |
6a488035 TO |
71 | public function __construct($tableName = NULL, $createSql = NULL, $createTable = FALSE) { |
72 | $dao = new CRM_Core_DAO(); | |
73 | $db = $dao->getDatabaseConnection(); | |
74 | ||
75 | if ($createTable) { | |
76 | if (!$createSql) { | |
77 | CRM_Core_Error::fatal('Either an existing table name or an SQL query to build one are required'); | |
78 | } | |
79 | ||
80 | // FIXME: we should regen this table's name if it exists rather than drop it | |
81 | if (!$tableName) { | |
82 | $tableName = 'civicrm_import_job_' . md5(uniqid(rand(), TRUE)); | |
83 | } | |
84 | $db->query("DROP TABLE IF EXISTS $tableName"); | |
85 | $db->query("CREATE TABLE $tableName ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci $createSql"); | |
86 | } | |
87 | ||
88 | if (!$tableName) { | |
89 | CRM_Core_Error::fatal('Import Table is required.'); | |
90 | } | |
91 | ||
92 | $this->_tableName = $tableName; | |
6a488035 TO |
93 | } |
94 | ||
86538308 EM |
95 | /** |
96 | * @return null|string | |
97 | */ | |
6a488035 TO |
98 | public function getTableName() { |
99 | return $this->_tableName; | |
100 | } | |
101 | ||
86538308 EM |
102 | /** |
103 | * @param bool $dropIfComplete | |
104 | * | |
105 | * @return bool | |
106 | * @throws Exception | |
107 | */ | |
6a488035 TO |
108 | public function isComplete($dropIfComplete = TRUE) { |
109 | if (!$this->_statusFieldName) { | |
110 | CRM_Core_Error::fatal("Could not get name of the import status field"); | |
111 | } | |
112 | $query = "SELECT * FROM $this->_tableName | |
113 | WHERE $this->_statusFieldName = 'NEW' LIMIT 1"; | |
114 | $result = CRM_Core_DAO::executeQuery($query); | |
115 | if ($result->fetch()) { | |
116 | return FALSE; | |
117 | } | |
118 | if ($dropIfComplete) { | |
119 | $query = "DROP TABLE $this->_tableName"; | |
120 | CRM_Core_DAO::executeQuery($query); | |
121 | } | |
122 | return TRUE; | |
123 | } | |
124 | ||
86538308 | 125 | /** |
c490a46a | 126 | * @param array $params |
86538308 | 127 | */ |
6a488035 TO |
128 | public function setJobParams(&$params) { |
129 | foreach ($params as $param => $value) { | |
0e6e8724 DL |
130 | $fldName = "_$param"; |
131 | $this->$fldName = $value; | |
6a488035 TO |
132 | } |
133 | } | |
134 | ||
86538308 | 135 | /** |
c490a46a | 136 | * @param CRM_Core_Form $form |
86538308 EM |
137 | * @param int $timeout |
138 | */ | |
6a488035 | 139 | public function runImport(&$form, $timeout = 55) { |
353ffa53 | 140 | $mapper = $this->_mapper; |
6ebecfea | 141 | $mapperFields = array(); |
1881b7b0 | 142 | $parserParameters = CRM_Contact_Import_Parser_Contact::getParameterForParser(count($mapper)); |
353ffa53 TO |
143 | $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id'); |
144 | $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id'); | |
145 | $websiteTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id'); | |
28557f54 | 146 | $locationTypes = array('Primary' => ts('Primary')) + CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id'); |
6a488035 | 147 | |
6a488035 | 148 | foreach ($mapper as $key => $value) { |
6a488035 | 149 | |
6a488035 | 150 | $fldName = CRM_Utils_Array::value(0, $mapper[$key]); |
4ba3ef8e | 151 | $header = array($this->_mapFields[$fldName]); |
6a488035 TO |
152 | $selOne = CRM_Utils_Array::value(1, $mapper[$key]); |
153 | $selTwo = CRM_Utils_Array::value(2, $mapper[$key]); | |
154 | $selThree = CRM_Utils_Array::value(3, $mapper[$key]); | |
155 | $this->_mapperKeys[$key] = $fldName; | |
156 | ||
157 | //need to differentiate non location elements. | |
6ebecfea | 158 | // @todo merge this with duplicate code on MapField class. |
159 | if ($selOne && (is_numeric($selOne) || $selOne === 'Primary')) { | |
6a488035 TO |
160 | if ($fldName == 'url') { |
161 | $header[] = $websiteTypes[$selOne]; | |
1881b7b0 | 162 | $parserParameters['mapperWebsiteType'][$key] = $selOne; |
6a488035 TO |
163 | } |
164 | else { | |
165 | $header[] = $locationTypes[$selOne]; | |
1881b7b0 | 166 | $parserParameters['mapperLocType'][$key] = $selOne; |
6a488035 TO |
167 | if ($selTwo && is_numeric($selTwo)) { |
168 | if ($fldName == 'phone') { | |
169 | $header[] = $phoneTypes[$selTwo]; | |
1881b7b0 | 170 | $parserParameters['mapperPhoneType'][$key] = $selTwo; |
6a488035 TO |
171 | } |
172 | elseif ($fldName == 'im') { | |
173 | $header[] = $imProviders[$selTwo]; | |
1881b7b0 | 174 | $parserParameters['mapperImProvider'][$key] = $selTwo; |
6a488035 TO |
175 | } |
176 | } | |
177 | } | |
178 | } | |
179 | ||
180 | $fldNameParts = explode('_', $fldName, 3); | |
353ffa53 TO |
181 | $id = $fldNameParts[0]; |
182 | $first = isset($fldNameParts[1]) ? $fldNameParts[1] : NULL; | |
183 | $second = isset($fldNameParts[2]) ? $fldNameParts[2] : NULL; | |
6a488035 TO |
184 | if (($first == 'a' && $second == 'b') || |
185 | ($first == 'b' && $second == 'a') | |
186 | ) { | |
187 | ||
188 | $header[] = ucwords(str_replace("_", " ", $selOne)); | |
189 | ||
190 | $relationType = new CRM_Contact_DAO_RelationshipType(); | |
191 | $relationType->id = $id; | |
192 | $relationType->find(TRUE); | |
1881b7b0 | 193 | $parserParameters['relatedContactType'][$key] = $relationType->{"contact_type_$second"}; |
6a488035 | 194 | |
1881b7b0 | 195 | $parserParameters['mapperRelated'][$key] = $fldName; |
6a488035 | 196 | if ($selOne) { |
1881b7b0 | 197 | $parserParameters['relatedContactDetails'][$key] = $selOne; |
6a488035 TO |
198 | if ($selTwo) { |
199 | if ($selOne == 'url') { | |
200 | $header[] = $websiteTypes[$selTwo]; | |
1881b7b0 | 201 | $parserParameters[$key]['relatedContactWebsiteType'][$key] = $selTwo; |
6a488035 TO |
202 | } |
203 | else { | |
204 | $header[] = $locationTypes[$selTwo]; | |
1881b7b0 | 205 | $parserParameters['relatedContactLocType'][$key] = $selTwo; |
6a488035 TO |
206 | if ($selThree) { |
207 | if ($selOne == 'phone') { | |
208 | $header[] = $phoneTypes[$selThree]; | |
1881b7b0 | 209 | $parserParameters['relatedContactPhoneType'][$key] = $selThree; |
6a488035 TO |
210 | } |
211 | elseif ($selOne == 'im') { | |
212 | $header[] = $imProviders[$selThree]; | |
1881b7b0 | 213 | $parserParameters['relatedContactImProvider'][$key] = $selThree; |
6a488035 TO |
214 | } |
215 | } | |
216 | } | |
217 | } | |
218 | } | |
219 | } | |
220 | $mapperFields[] = implode(' - ', $header); | |
6a488035 TO |
221 | } |
222 | ||
719a6fec | 223 | $this->_parser = new CRM_Contact_Import_Parser_Contact( |
6a488035 | 224 | $this->_mapperKeys, |
1881b7b0 | 225 | $parserParameters['mapperLocType'], |
226 | $parserParameters['mapperPhoneType'], | |
227 | $parserParameters['mapperImProvider'], | |
228 | $parserParameters['mapperRelated'], | |
229 | $parserParameters['relatedContactType'], | |
230 | $parserParameters['relatedContactDetails'], | |
231 | $parserParameters['relatedContactLocType'], | |
232 | $parserParameters['relatedContactPhoneType'], | |
233 | $parserParameters['relatedContactImProvider'], | |
234 | $parserParameters['mapperWebsiteType'], | |
235 | $parserParameters['relatedContactWebsiteType'] | |
6a488035 TO |
236 | ); |
237 | ||
238 | $this->_parser->run($this->_tableName, $mapperFields, | |
a05662ef | 239 | CRM_Import_Parser::MODE_IMPORT, |
6a488035 TO |
240 | $this->_contactType, |
241 | $this->_primaryKeyName, | |
242 | $this->_statusFieldName, | |
243 | $this->_onDuplicate, | |
244 | $this->_statusID, | |
245 | $this->_totalRowCount, | |
246 | $this->_doGeocodeAddress, | |
719a6fec | 247 | CRM_Contact_Import_Parser::DEFAULT_TIMEOUT, |
6a488035 TO |
248 | $this->_contactSubType, |
249 | $this->_dedupe | |
250 | ); | |
251 | ||
252 | $contactIds = $this->_parser->getImportedContacts(); | |
253 | ||
254 | //get the related contactIds. CRM-2926 | |
255 | $relatedContactIds = $this->_parser->getRelatedImportedContacts(); | |
256 | if ($relatedContactIds) { | |
257 | $contactIds = array_merge($contactIds, $relatedContactIds); | |
258 | if ($form) { | |
259 | $form->set('relatedCount', count($relatedContactIds)); | |
260 | } | |
261 | } | |
262 | ||
263 | if ($this->_newGroupName || count($this->_groups)) { | |
264 | $groupAdditions = $this->_addImportedContactsToNewGroup($contactIds, | |
265 | $this->_newGroupName, | |
5a552b87 SL |
266 | $this->_newGroupDesc, |
267 | $this->_newGroupType | |
6a488035 TO |
268 | ); |
269 | if ($form) { | |
270 | $form->set('groupAdditions', $groupAdditions); | |
271 | } | |
272 | } | |
273 | ||
f547eb3a | 274 | if ($this->_newTagName || !empty($this->_tag)) { |
6a488035 TO |
275 | $tagAdditions = $this->_tagImportedContactsWithNewTag($contactIds, |
276 | $this->_newTagName, | |
277 | $this->_newTagDesc | |
278 | ); | |
279 | if ($form) { | |
280 | $form->set('tagAdditions', $tagAdditions); | |
281 | } | |
282 | } | |
283 | } | |
284 | ||
86538308 EM |
285 | /** |
286 | * @param $form | |
287 | */ | |
6a488035 | 288 | public function setFormVariables($form) { |
a05662ef | 289 | $this->_parser->set($form, CRM_Import_Parser::MODE_IMPORT); |
6a488035 TO |
290 | } |
291 | ||
86538308 | 292 | /** |
dbb0d30b | 293 | * Add imported contacts. |
294 | * | |
295 | * @param array $contactIds | |
100fef9d | 296 | * @param string $newGroupName |
dbb0d30b | 297 | * @param string $newGroupDesc |
298 | * @param string $newGroupType | |
86538308 EM |
299 | * |
300 | * @return array|bool | |
301 | */ | |
51ccfbbe TO |
302 | private function _addImportedContactsToNewGroup( |
303 | $contactIds, | |
5a552b87 | 304 | $newGroupName, $newGroupDesc, $newGroupType |
6a488035 TO |
305 | ) { |
306 | ||
307 | $newGroupId = NULL; | |
308 | ||
309 | if ($newGroupName) { | |
310 | /* Create a new group */ | |
81477fb3 | 311 | $newGroupType = isset($newGroupType) ? $newGroupType : array(); |
6a488035 TO |
312 | $gParams = array( |
313 | 'title' => $newGroupName, | |
314 | 'description' => $newGroupDesc, | |
5a552b87 | 315 | 'group_type' => $newGroupType, |
6a488035 TO |
316 | 'is_active' => TRUE, |
317 | ); | |
318 | $group = CRM_Contact_BAO_Group::create($gParams); | |
319 | $this->_groups[] = $newGroupId = $group->id; | |
320 | } | |
321 | ||
322 | if (is_array($this->_groups)) { | |
323 | $groupAdditions = array(); | |
324 | foreach ($this->_groups as $groupId) { | |
325 | $addCount = CRM_Contact_BAO_GroupContact::addContactsToGroup($contactIds, $groupId); | |
326 | $totalCount = $addCount[1]; | |
327 | if ($groupId == $newGroupId) { | |
328 | $name = $newGroupName; | |
329 | $new = TRUE; | |
330 | } | |
331 | else { | |
332 | $name = $this->_allGroups[$groupId]; | |
333 | $new = FALSE; | |
334 | } | |
335 | $groupAdditions[] = array( | |
336 | 'url' => CRM_Utils_System::url('civicrm/group/search', | |
337 | 'reset=1&force=1&context=smog&gid=' . $groupId | |
338 | ), | |
339 | 'name' => $name, | |
340 | 'added' => $totalCount, | |
341 | 'notAdded' => $addCount[2], | |
342 | 'new' => $new, | |
343 | ); | |
344 | } | |
345 | return $groupAdditions; | |
346 | } | |
347 | return FALSE; | |
348 | } | |
349 | ||
86538308 EM |
350 | /** |
351 | * @param $contactIds | |
100fef9d | 352 | * @param string $newTagName |
86538308 EM |
353 | * @param $newTagDesc |
354 | * | |
355 | * @return array|bool | |
356 | */ | |
51ccfbbe TO |
357 | private function _tagImportedContactsWithNewTag( |
358 | $contactIds, | |
6a488035 TO |
359 | $newTagName, $newTagDesc |
360 | ) { | |
361 | ||
362 | $newTagId = NULL; | |
363 | if ($newTagName) { | |
364 | /* Create a new Tag */ | |
365 | ||
366 | $tagParams = array( | |
367 | 'name' => $newTagName, | |
6a488035 TO |
368 | 'description' => $newTagDesc, |
369 | 'is_selectable' => TRUE, | |
370 | 'used_for' => 'civicrm_contact', | |
371 | ); | |
372 | $id = array(); | |
373 | $addedTag = CRM_Core_BAO_Tag::add($tagParams, $id); | |
374 | $this->_tag[$addedTag->id] = 1; | |
375 | } | |
376 | //add Tag to Import | |
377 | ||
378 | if (is_array($this->_tag)) { | |
379 | $tagAdditions = array(); | |
380 | foreach ($this->_tag as $tagId => $val) { | |
424616b8 | 381 | $addTagCount = CRM_Core_BAO_EntityTag::addEntitiesToTag($contactIds, $tagId, 'civicrm_contact', FALSE); |
6a488035 TO |
382 | $totalTagCount = $addTagCount[1]; |
383 | if (isset($addedTag) && $tagId == $addedTag->id) { | |
384 | $tagName = $newTagName; | |
385 | $new = TRUE; | |
386 | } | |
387 | else { | |
388 | $tagName = $this->_allTags[$tagId]; | |
389 | $new = FALSE; | |
390 | } | |
391 | $tagAdditions[] = array( | |
392 | 'url' => CRM_Utils_System::url('civicrm/contact/search', | |
393 | 'reset=1&force=1&context=smog&id=' . $tagId | |
394 | ), | |
395 | 'name' => $tagName, | |
396 | 'added' => $totalTagCount, | |
397 | 'notAdded' => $addTagCount[2], | |
398 | 'new' => $new, | |
399 | ); | |
400 | } | |
401 | return $tagAdditions; | |
402 | } | |
403 | return FALSE; | |
404 | } | |
405 | ||
86538308 EM |
406 | /** |
407 | * @return array | |
408 | */ | |
6a488035 | 409 | public static function getIncompleteImportTables() { |
353ffa53 | 410 | $dao = new CRM_Core_DAO(); |
6a488035 | 411 | $database = $dao->database(); |
353ffa53 | 412 | $query = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA |
6a488035 TO |
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()) { | |
b3870992 | 419 | if (!self::isComplete($importTable)) { |
6a488035 TO |
420 | $incompleteImportTables[] = $importTable; |
421 | } | |
422 | } | |
423 | return $incompleteImportTables; | |
424 | } | |
96025800 | 425 | |
6a488035 | 426 | } |