dev/core#945 - fix use of $this error in static method
[civicrm-core.git] / CRM / Contact / Import / ImportJob.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
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 and the CiviCRM Licensing Exception. |
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-2019
32 */
33
34 /**
35 * This class acts like a psuedo-BAO for transient import job tables.
36 */
37 class CRM_Contact_Import_ImportJob {
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;
50 protected $_newGroupType;
51 protected $_groups;
52 protected $_allGroups;
53 protected $_newTagName;
54 protected $_newTagDesc;
55 protected $_tag;
56 protected $_allTags;
57
58 protected $_mapper;
59 protected $_mapperKeys = array();
60 protected $_mapFields;
61
62 protected $_parser;
63
64 /**
65 * @param null $tableName
66 * @param null $createSql
67 * @param bool $createTable
68 *
69 * @throws Exception
70 */
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;
93 }
94
95 /**
96 * @return null|string
97 */
98 public function getTableName() {
99 return $this->_tableName;
100 }
101
102 /**
103 * @param bool $dropIfComplete
104 *
105 * @return bool
106 * @throws Exception
107 */
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
125 /**
126 * @param array $params
127 */
128 public function setJobParams(&$params) {
129 foreach ($params as $param => $value) {
130 $fldName = "_$param";
131 $this->$fldName = $value;
132 }
133 }
134
135 /**
136 * @param CRM_Core_Form $form
137 * @param int $timeout
138 */
139 public function runImport(&$form, $timeout = 55) {
140 $mapper = $this->_mapper;
141 $mapperFields = array();
142 $parserParameters = CRM_Contact_Import_Parser_Contact::getParameterForParser(count($mapper));
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');
146 $locationTypes = array('Primary' => ts('Primary')) + CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
147
148 foreach ($mapper as $key => $value) {
149
150 $fldName = CRM_Utils_Array::value(0, $mapper[$key]);
151 $header = array($this->_mapFields[$fldName]);
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.
158 // @todo merge this with duplicate code on MapField class.
159 if ($selOne && (is_numeric($selOne) || $selOne === 'Primary')) {
160 if ($fldName == 'url') {
161 $header[] = $websiteTypes[$selOne];
162 $parserParameters['mapperWebsiteType'][$key] = $selOne;
163 }
164 else {
165 $header[] = $locationTypes[$selOne];
166 $parserParameters['mapperLocType'][$key] = $selOne;
167 if ($selTwo && is_numeric($selTwo)) {
168 if ($fldName == 'phone') {
169 $header[] = $phoneTypes[$selTwo];
170 $parserParameters['mapperPhoneType'][$key] = $selTwo;
171 }
172 elseif ($fldName == 'im') {
173 $header[] = $imProviders[$selTwo];
174 $parserParameters['mapperImProvider'][$key] = $selTwo;
175 }
176 }
177 }
178 }
179
180 $fldNameParts = explode('_', $fldName, 3);
181 $id = $fldNameParts[0];
182 $first = isset($fldNameParts[1]) ? $fldNameParts[1] : NULL;
183 $second = isset($fldNameParts[2]) ? $fldNameParts[2] : NULL;
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);
193 $parserParameters['relatedContactType'][$key] = $relationType->{"contact_type_$second"};
194
195 $parserParameters['mapperRelated'][$key] = $fldName;
196 if ($selOne) {
197 $parserParameters['relatedContactDetails'][$key] = $selOne;
198 if ($selTwo) {
199 if ($selOne == 'url') {
200 $header[] = $websiteTypes[$selTwo];
201 $parserParameters[$key]['relatedContactWebsiteType'][$key] = $selTwo;
202 }
203 else {
204 $header[] = $locationTypes[$selTwo];
205 $parserParameters['relatedContactLocType'][$key] = $selTwo;
206 if ($selThree) {
207 if ($selOne == 'phone') {
208 $header[] = $phoneTypes[$selThree];
209 $parserParameters['relatedContactPhoneType'][$key] = $selThree;
210 }
211 elseif ($selOne == 'im') {
212 $header[] = $imProviders[$selThree];
213 $parserParameters['relatedContactImProvider'][$key] = $selThree;
214 }
215 }
216 }
217 }
218 }
219 }
220 $mapperFields[] = implode(' - ', $header);
221 }
222
223 $this->_parser = new CRM_Contact_Import_Parser_Contact(
224 $this->_mapperKeys,
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']
236 );
237
238 $this->_parser->run($this->_tableName, $mapperFields,
239 CRM_Import_Parser::MODE_IMPORT,
240 $this->_contactType,
241 $this->_primaryKeyName,
242 $this->_statusFieldName,
243 $this->_onDuplicate,
244 $this->_statusID,
245 $this->_totalRowCount,
246 $this->_doGeocodeAddress,
247 CRM_Contact_Import_Parser::DEFAULT_TIMEOUT,
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,
266 $this->_newGroupDesc,
267 $this->_newGroupType
268 );
269 if ($form) {
270 $form->set('groupAdditions', $groupAdditions);
271 }
272 }
273
274 if ($this->_newTagName || !empty($this->_tag)) {
275 $tagAdditions = $this->_tagImportedContactsWithNewTag($contactIds,
276 $this->_newTagName,
277 $this->_newTagDesc
278 );
279 if ($form) {
280 $form->set('tagAdditions', $tagAdditions);
281 }
282 }
283 }
284
285 /**
286 * @param $form
287 */
288 public function setFormVariables($form) {
289 $this->_parser->set($form, CRM_Import_Parser::MODE_IMPORT);
290 }
291
292 /**
293 * Add imported contacts.
294 *
295 * @param array $contactIds
296 * @param string $newGroupName
297 * @param string $newGroupDesc
298 * @param string $newGroupType
299 *
300 * @return array|bool
301 */
302 private function _addImportedContactsToNewGroup(
303 $contactIds,
304 $newGroupName, $newGroupDesc, $newGroupType
305 ) {
306
307 $newGroupId = NULL;
308
309 if ($newGroupName) {
310 /* Create a new group */
311 $newGroupType = isset($newGroupType) ? $newGroupType : array();
312 $gParams = array(
313 'title' => $newGroupName,
314 'description' => $newGroupDesc,
315 'group_type' => $newGroupType,
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
350 /**
351 * @param $contactIds
352 * @param string $newTagName
353 * @param $newTagDesc
354 *
355 * @return array|bool
356 */
357 private function _tagImportedContactsWithNewTag(
358 $contactIds,
359 $newTagName, $newTagDesc
360 ) {
361
362 $newTagId = NULL;
363 if ($newTagName) {
364 /* Create a new Tag */
365
366 $tagParams = array(
367 'name' => $newTagName,
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) {
381 $addTagCount = CRM_Core_BAO_EntityTag::addEntitiesToTag($contactIds, $tagId, 'civicrm_contact', FALSE);
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
406 /**
407 * @return array
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 (!self::isComplete($importTable)) {
420 $incompleteImportTables[] = $importTable;
421 }
422 }
423 return $incompleteImportTables;
424 }
425
426 }