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