3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2014
37 * This class delegates to the chosen DataSource to grab the data to be
40 class CRM_Contact_Import_Form_DataSource
extends CRM_Core_Form
{
44 private $_dataSourceIsValid = FALSE;
46 private $_dataSourceClassFile;
48 private $_dataSourceClass;
51 * Set variables up before form is built
56 public function preProcess() {
58 //Test database user privilege to create table(Temporary) CRM-4725
59 $errorScope = CRM_Core_TemporaryErrorScope
::ignoreException();
60 $daoTestPrivilege = new CRM_Core_DAO
;
61 $daoTestPrivilege->query("CREATE TEMPORARY TABLE import_job_permission_one(test int) ENGINE=InnoDB");
62 $daoTestPrivilege->query("CREATE TEMPORARY TABLE import_job_permission_two(test int) ENGINE=InnoDB");
63 $daoTestPrivilege->query("DROP TABLE IF EXISTS import_job_permission_one, import_job_permission_two");
66 if ($daoTestPrivilege->_lastError
) {
67 CRM_Core_Error
::fatal(ts('Database Configuration Error: Insufficient permissions. Import requires that the CiviCRM database user has permission to create temporary tables. Contact your site administrator for assistance.'));
71 $config = CRM_Core_Config
::singleton();
72 $handler = opendir($config->uploadDir
);
73 $errorFiles = array('sqlImport.errors', 'sqlImport.conflicts', 'sqlImport.duplicates', 'sqlImport.mismatch');
75 // check for post max size avoid when called twice
76 $snippet = CRM_Utils_Array
::value('snippet', $_GET, 0);
77 if (empty($snippet)) {
78 CRM_Core_Config_Defaults
::formatUnitSize(ini_get('post_max_size'), TRUE);
81 while ($file = readdir($handler)) {
82 if ($file != '.' && $file != '..' &&
83 in_array($file, $errorFiles) && !is_writable($config->uploadDir
. $file)
89 if (!empty($results)) {
90 CRM_Core_Error
::fatal(ts('<b>%1</b> file(s) in %2 directory are not writable. Listed file(s) might be used during the import to log the errors occurred during Import process. Contact your site administrator for assistance.', array(1 => implode(', ', $results), 2 => $config->uploadDir
)));
93 $this->_dataSourceIsValid
= FALSE;
94 $this->_dataSource
= CRM_Utils_Request
::retrieve(
97 CRM_Core_DAO
::$_nullObject,
103 $this->_params
= $this->controller
->exportValues($this->_name
);
104 if (!$this->_dataSource
) {
105 //considering dataSource as base criteria instead of hidden_dataSource.
106 $this->_dataSource
= CRM_Utils_Array
::value('dataSource',
108 CRM_Utils_Array
::value('dataSource',
112 $this->assign('showOnlyDataSourceFormPane', FALSE);
115 $this->assign('showOnlyDataSourceFormPane', TRUE);
118 if (strpos($this->_dataSource
, 'CRM_Import_DataSource_') === 0) {
119 $this->_dataSourceIsValid
= TRUE;
120 $this->assign('showDataSourceFormPane', TRUE);
121 $dataSourcePath = explode('_', $this->_dataSource
);
122 $templateFile = "CRM/Contact/Import/Form/" . $dataSourcePath[3] . ".tpl";
123 $this->assign('dataSourceFormTemplateFile', $templateFile);
128 * Build the form object
134 public function buildQuickForm() {
136 // If there's a dataSource in the query string, we need to load
137 // the form from the chosen DataSource class
138 if ($this->_dataSourceIsValid
) {
139 $this->_dataSourceClassFile
= str_replace('_', '/', $this->_dataSource
) . ".php";
140 require_once $this->_dataSourceClassFile
;
141 $this->_dataSourceClass
= new $this->_dataSource
;
142 $this->_dataSourceClass
->buildQuickForm( $this );
145 // Get list of data sources and display them as options
146 $dataSources = $this->_getDataSources();
148 $this->assign('urlPath', "civicrm/import");
149 $this->assign('urlPathVar', 'snippet=4');
151 $this->add('select', 'dataSource', ts('Data Source'), $dataSources, TRUE,
152 array('onchange' => 'buildDataSourceFormBlock(this.value);')
155 // duplicate handling options
156 $duplicateOptions = array();
157 $duplicateOptions[] = $this->createElement('radio',
158 NULL, NULL, ts('Skip'), CRM_Import_Parser
::DUPLICATE_SKIP
160 $duplicateOptions[] = $this->createElement('radio',
161 NULL, NULL, ts('Update'), CRM_Import_Parser
::DUPLICATE_UPDATE
163 $duplicateOptions[] = $this->createElement('radio',
164 NULL, NULL, ts('Fill'), CRM_Import_Parser
::DUPLICATE_FILL
166 $duplicateOptions[] = $this->createElement('radio',
167 NULL, NULL, ts('No Duplicate Checking'), CRM_Import_Parser
::DUPLICATE_NOCHECK
170 $this->addGroup($duplicateOptions, 'onDuplicate',
171 ts('For Duplicate Contacts')
174 $mappingArray = CRM_Core_BAO_Mapping
::getMappings(CRM_Core_OptionGroup
::getValue('mapping_type',
179 $this->assign('savedMapping', $mappingArray);
180 $this->addElement('select', 'savedMapping', ts('Mapping Option'), array('' => ts('- select -')) +
$mappingArray);
183 $js = array('onClick' => "buildSubTypes();buildDedupeRules();");
184 // contact types option
185 $contactOptions = array();
186 if (CRM_Contact_BAO_ContactType
::isActive('Individual')) {
187 $contactOptions[] = $this->createElement('radio',
188 NULL, NULL, ts('Individual'), CRM_Import_Parser
::CONTACT_INDIVIDUAL
, $js
191 if (CRM_Contact_BAO_ContactType
::isActive('Household')) {
192 $contactOptions[] = $this->createElement('radio',
193 NULL, NULL, ts('Household'), CRM_Import_Parser
::CONTACT_HOUSEHOLD
, $js
196 if (CRM_Contact_BAO_ContactType
::isActive('Organization')) {
197 $contactOptions[] = $this->createElement('radio',
198 NULL, NULL, ts('Organization'), CRM_Import_Parser
::CONTACT_ORGANIZATION
, $js
202 $this->addGroup($contactOptions, 'contactType',
206 $this->addElement('select', 'subType', ts('Subtype'));
207 $this->addElement('select', 'dedupe', ts('Dedupe Rule'));
209 CRM_Core_Form_Date
::buildAllowedDateFormats($this);
211 $config = CRM_Core_Config
::singleton();
213 if (!empty($config->geocodeMethod
)) {
215 $this->addElement('checkbox', 'doGeocodeAddress', ts('Lookup mapping info during import?'));
217 $this->assign('geoCode', $geoCode);
219 $this->addElement('text', 'fieldSeparator', ts('Import Field Separator'), array('size' => 2));
221 $this->addButtons(array(
224 'name' => ts('Continue >>'),
225 'spacing' => ' ',
230 'name' => ts('Cancel'),
237 * This virtual function is used to set the default values of
238 * various form elements
242 * @return array reference to the array of default values
248 function setDefaultValues() {
249 $config = CRM_Core_Config
::singleton();
251 'dataSource' => 'CRM_Import_DataSource_CSV',
252 'onDuplicate' => CRM_Import_Parser
::DUPLICATE_SKIP
,
253 'contactType' => CRM_Import_Parser
::CONTACT_INDIVIDUAL
,
254 'fieldSeparator' => $config->fieldSeparator
,
257 if ($loadeMapping = $this->get('loadedMapping')) {
258 $this->assign('loadedMapping', $loadeMapping);
259 $defaults['savedMapping'] = $loadeMapping;
269 private function _getDataSources() {
270 // Open the data source dir and scan it for class files
271 $config = CRM_Core_Config
::singleton();
272 $dataSourceDir = $config->importDataSourceDir
;
273 $dataSources = array();
274 if (!is_dir($dataSourceDir)) {
275 CRM_Core_Error
::fatal("Import DataSource directory $dataSourceDir does not exist");
277 if (!$dataSourceHandle = opendir($dataSourceDir)) {
278 CRM_Core_Error
::fatal("Unable to access DataSource directory $dataSourceDir");
281 while (($dataSourceFile = readdir($dataSourceHandle)) !== FALSE) {
282 $fileType = filetype($dataSourceDir . $dataSourceFile);
284 if (($fileType == 'file' ||
$fileType == 'link') &&
285 preg_match('/^(.+)\.php$/', $dataSourceFile, $matches)
287 $dataSourceClass = "CRM_Import_DataSource_" . $matches[1];
288 require_once $dataSourceDir . DIRECTORY_SEPARATOR
. $dataSourceFile;
289 $object = new $dataSourceClass;
290 $info = $object->getInfo();
291 $dataSources[$dataSourceClass] = $info['title'];
294 closedir($dataSourceHandle);
299 * Call the DataSource's postProcess method to take over
300 * and then setup some common data structures for the next step
305 public function postProcess() {
306 $this->controller
->resetPage('MapField');
308 if ($this->_dataSourceIsValid
) {
309 // Setup the params array
310 $this->_params
= $this->controller
->exportValues($this->_name
);
312 $storeParams = array(
313 'onDuplicate' => 'onDuplicate',
314 'dedupe' => 'dedupe',
315 'contactType' => 'contactType',
316 'contactSubType' => 'subType',
317 'dateFormats' => 'dateFormats',
318 'savedMapping' => 'savedMapping',
321 foreach ($storeParams as $storeName => $storeValueName) {
322 $
$storeName = $this->exportValue($storeValueName);
323 $this->set($storeName, $
$storeName);
326 $this->set('dataSource', $this->_params
['dataSource']);
327 $this->set('skipColumnHeader', CRM_Utils_Array
::value('skipColumnHeader', $this->_params
));
329 $session = CRM_Core_Session
::singleton();
330 $session->set('dateTypes', $dateFormats);
332 // Get the PEAR::DB object
333 $dao = new CRM_Core_DAO();
334 $db = $dao->getDatabaseConnection();
336 //hack to prevent multiple tables.
337 $this->_params
['import_table_name'] = $this->get('importTableName');
338 if (!$this->_params
['import_table_name']) {
339 $this->_params
['import_table_name'] = 'civicrm_import_job_' . md5(uniqid(rand(), TRUE));
342 $this->_dataSourceClass
->postProcess( $this->_params
, $db, $this );
344 // We should have the data in the DB now, parse it
345 $importTableName = $this->get('importTableName');
346 $fieldNames = $this->_prepareImportTable($db, $importTableName);
349 $parser = new CRM_Contact_Import_Parser_Contact($mapper);
350 $parser->setMaxLinesToProcess(100);
351 $parser->run($importTableName,
353 CRM_Import_Parser
::MODE_MAPFIELD
,
356 $fieldNames['status'],
357 CRM_Import_Parser
::DUPLICATE_SKIP
,
359 CRM_Contact_Import_Parser
::DEFAULT_TIMEOUT
,
364 // add all the necessary variables to the form
368 CRM_Core_Error
::fatal("Invalid DataSource on form post. This shouldn't happen!");
373 * Add a PK and status column to the import table so we can track our progress
374 * Returns the name of the primary key and status columns
377 * @param string $importTableName
382 private function _prepareImportTable($db, $importTableName) {
383 /* TODO: Add a check for an existing _status field;
384 * if it exists, create __status instead and return that
387 $statusFieldName = '_status';
388 $primaryKeyName = '_id';
390 $this->set('primaryKeyName', $primaryKeyName);
391 $this->set('statusFieldName', $statusFieldName);
393 /* Make sure the PK is always last! We rely on this later.
394 * Should probably stop doing that at some point, but it
395 * would require moving to associative arrays rather than
396 * relying on numerical order of the fields. This could in
397 * turn complicate matters for some DataSources, which
398 * would also not be good. Decisions, decisions...
401 $alterQuery = "ALTER TABLE $importTableName
402 ADD COLUMN $statusFieldName VARCHAR(32)
403 DEFAULT 'NEW' NOT NULL,
404 ADD COLUMN ${statusFieldName}Msg TEXT,
405 ADD COLUMN $primaryKeyName INT PRIMARY KEY NOT NULL
407 $db->query($alterQuery);
409 return array('status' => $statusFieldName, 'pk' => $primaryKeyName);
413 * Return a descriptive name for the page, used in wizard header
419 public function getTitle() {
420 return ts('Choose Data Source');