Merge pull request #23227 from eileenmcnaughton/inbetween_4
[civicrm-core.git] / CRM / Contact / Import / ImportJob.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
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 |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 /**
19 * This class acts like a psuedo-BAO for transient import job tables.
20 */
21 class CRM_Contact_Import_ImportJob {
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;
34 protected $_newGroupType;
35 protected $_groups;
36 protected $_allGroups;
37 protected $_newTagName;
38 protected $_newTagDesc;
39 protected $_tag;
40 protected $_allTags;
41
42 protected $_mapper;
43 protected $_mapperKeys = [];
44 protected $_mapFields;
45
46 protected $_parser;
47
48 /**
49 * @param string|null $tableName
50 * @param string|null $createSql
51 * @param bool $createTable
52 *
53 * @throws \CRM_Core_Exception
54 */
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) {
61 throw new CRM_Core_Exception(ts('Either an existing table name or an SQL query to build one are required'));
62 }
63 if ($tableName) {
64 // Drop previous table if passed in and create new one.
65 $db->query("DROP TABLE IF EXISTS $tableName");
66 }
67 $table = CRM_Utils_SQL_TempTable::build()->setDurable();
68 $tableName = $table->getName();
69 $table->createWithQuery($createSql);
70 }
71
72 if (!$tableName) {
73 throw new CRM_Core_Exception(ts('Import Table is required.'));
74 }
75
76 $this->_tableName = $tableName;
77 }
78
79 /**
80 * @return null|string
81 */
82 public function getTableName() {
83 return $this->_tableName;
84 }
85
86 /**
87 * @param bool $dropIfComplete
88 *
89 * @return bool
90 * @throws Exception
91 */
92 public function isComplete($dropIfComplete = TRUE) {
93 if (!$this->_statusFieldName) {
94 throw new CRM_Core_Exception("Could not get name of the import status field");
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
109 /**
110 * @param array $params
111 */
112 public function setJobParams(&$params) {
113 foreach ($params as $param => $value) {
114 $fldName = "_$param";
115 $this->$fldName = $value;
116 }
117 }
118
119 /**
120 * @param CRM_Core_Form $form
121 * @param int $timeout
122 */
123 public function runImport(&$form, $timeout = 55) {
124 $mapper = $this->_mapper;
125 $mapperFields = [];
126 $parserParameters = CRM_Contact_Import_Parser_Contact::getParameterForParser(count($mapper));
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');
130 $locationTypes = array('Primary' => ts('Primary')) + CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
131
132 foreach ($mapper as $key => $value) {
133
134 $fldName = $mapper[$key][0] ?? NULL;
135 $header = array($this->_mapFields[$fldName]);
136 $selOne = $mapper[$key][1] ?? NULL;
137 $selTwo = $mapper[$key][2] ?? NULL;
138 $selThree = $mapper[$key][3] ?? NULL;
139 $this->_mapperKeys[$key] = $fldName;
140
141 //need to differentiate non location elements.
142 // @todo merge this with duplicate code on MapField class.
143 if ($selOne && (is_numeric($selOne) || $selOne === 'Primary')) {
144 if ($fldName === 'url') {
145 $header[] = $websiteTypes[$selOne];
146 $parserParameters['mapperWebsiteType'][$key] = $selOne;
147 }
148 else {
149 $header[] = $locationTypes[$selOne];
150 $parserParameters['mapperLocType'][$key] = $selOne;
151 if ($selTwo && is_numeric($selTwo)) {
152 if ($fldName === 'phone' || $fldName === 'phone_ext') {
153 $header[] = $phoneTypes[$selTwo];
154 $parserParameters['mapperPhoneType'][$key] = $selTwo;
155 }
156 elseif ($fldName === 'im') {
157 $header[] = $imProviders[$selTwo];
158 $parserParameters['mapperImProvider'][$key] = $selTwo;
159 }
160 }
161 }
162 }
163
164 $fldNameParts = explode('_', $fldName, 3);
165 $id = $fldNameParts[0];
166 $first = $fldNameParts[1] ?? NULL;
167 $second = $fldNameParts[2] ?? NULL;
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);
177 $parserParameters['relatedContactType'][$key] = $relationType->{"contact_type_$second"};
178
179 $parserParameters['mapperRelated'][$key] = $fldName;
180 if ($selOne) {
181 $parserParameters['relatedContactDetails'][$key] = $selOne;
182 if ($selTwo) {
183 if ($selOne == 'url') {
184 $header[] = $websiteTypes[$selTwo];
185 $parserParameters[$key]['relatedContactWebsiteType'][$key] = $selTwo;
186 }
187 else {
188 $header[] = $locationTypes[$selTwo];
189 $parserParameters['relatedContactLocType'][$key] = $selTwo;
190 if ($selThree) {
191 if ($selOne == 'phone' || $selOne == 'phone_ext') {
192 $header[] = $phoneTypes[$selThree];
193 $parserParameters['relatedContactPhoneType'][$key] = $selThree;
194 }
195 elseif ($selOne == 'im') {
196 $header[] = $imProviders[$selThree];
197 $parserParameters['relatedContactImProvider'][$key] = $selThree;
198 }
199 }
200 }
201 }
202 }
203 }
204 $mapperFields[] = implode(' - ', $header);
205 }
206
207 $this->_parser = new CRM_Contact_Import_Parser_Contact(
208 $this->_mapperKeys,
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']
220 );
221
222 $this->_parser->run($this->_tableName, $mapperFields,
223 CRM_Import_Parser::MODE_IMPORT,
224 $this->_contactType,
225 $this->_primaryKeyName,
226 $this->_statusFieldName,
227 $this->_onDuplicate,
228 $this->_statusID,
229 $this->_totalRowCount,
230 $this->_doGeocodeAddress,
231 CRM_Contact_Import_Parser_Contact::DEFAULT_TIMEOUT,
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,
250 $this->_newGroupDesc,
251 $this->_newGroupType
252 );
253 if ($form) {
254 $form->set('groupAdditions', $groupAdditions);
255 }
256 }
257
258 if ($this->_newTagName || !empty($this->_tag)) {
259 $tagAdditions = $this->_tagImportedContactsWithNewTag($contactIds,
260 $this->_newTagName,
261 $this->_newTagDesc
262 );
263 if ($form) {
264 $form->set('tagAdditions', $tagAdditions);
265 }
266 }
267 }
268
269 /**
270 * @param $form
271 */
272 public function setFormVariables($form) {
273 $this->_parser->set($form, CRM_Import_Parser::MODE_IMPORT);
274 }
275
276 /**
277 * Add imported contacts.
278 *
279 * @param array $contactIds
280 * @param string $newGroupName
281 * @param string $newGroupDesc
282 * @param string $newGroupType
283 *
284 * @return array|bool
285 */
286 private function _addImportedContactsToNewGroup(
287 $contactIds,
288 $newGroupName, $newGroupDesc, $newGroupType
289 ) {
290
291 $newGroupId = NULL;
292
293 if ($newGroupName) {
294 /* Create a new group */
295 $newGroupType = $newGroupType ?? [];
296 $gParams = array(
297 'title' => $newGroupName,
298 'description' => $newGroupDesc,
299 'group_type' => $newGroupType,
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)) {
307 $groupAdditions = [];
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
334 /**
335 * @param $contactIds
336 * @param string $newTagName
337 * @param $newTagDesc
338 *
339 * @return array|bool
340 * @throws \CRM_Core_Exception
341 */
342 private function _tagImportedContactsWithNewTag(
343 $contactIds,
344 $newTagName, $newTagDesc
345 ) {
346
347 $newTagId = NULL;
348 if ($newTagName) {
349 /* Create a new Tag */
350
351 $tagParams = array(
352 'name' => $newTagName,
353 'description' => $newTagDesc,
354 'is_selectable' => TRUE,
355 'used_for' => 'civicrm_contact',
356 );
357 $addedTag = CRM_Core_BAO_Tag::add($tagParams);
358 $this->_tag[$addedTag->id] = 1;
359 }
360 //add Tag to Import
361
362 if (is_array($this->_tag)) {
363 $tagAdditions = [];
364 foreach ($this->_tag as $tagId => $val) {
365 $addTagCount = CRM_Core_BAO_EntityTag::addEntitiesToTag($contactIds, $tagId, 'civicrm_contact', FALSE);
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
390 }