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