array( 'title', 'salutation' ), 'FirstName' => array( 'firstname', 'christianname', 'givenname' ), 'Surname' => array( 'lastname','surname', 'familyname' ), 'Email' => array( 'email', 'emailaddress' ), 'Address' => array( 'address' ), 'PhoneNumber' => array('phone','phonenumber'), 'JobTitle' => array( 'jobtitle' ), 'Organisation' => array( 'organisation', 'organization' ), 'EmailType' => array( 'htmlorplaintext', 'emailtype' ) ); static $custom_set_fields = array(); public static function setCustomField( $getMapCode, $fieldName ) { self::$custom_set_fields[] = array( 'Code' => $getMapCode, 'Field' => $fieldName ); } function __construct( $name, $title, $memberGroup, $memberClass = 'Member', $form = null ) { $this->memberGroup = $memberGroup; $this->memberClass = $memberClass; parent::__construct( $name, $title, null, $form ); } function Field() { $frameURL = Director::absoluteBaseURL() . 'admin/newsletter/displayfilefield/' . $this->typeID; return ""; } function setTypeID( $id ) { $this->typeID = $id; } function CustomSetFields() { $fields = new FieldSet(); foreach( self::$custom_set_fields as $customField ) { eval( '$map = ' . $customField['Code'] .';' ); $noneMap = array( 0 => '(Not set)' ); $map = $noneMap + $map; $fields->push( new DropdownField( 'Set['.$customField['Field'].']', $customField['Field'], $map ) ); } return $fields; } /** * Returns HTML to be displayed inside the IFrame */ static function fileupload() { } /** * Returns the table of results to be displayed in the table of * details loaded from the file */ function displaytable() { // Check that a file was uploaded $tempFile = fopen( $_FILES['ImportFile']['tmp_name'], 'r' ); // display some error if the file cannot be opened $this->clientFileName = $_FILES['ImportFile']['name']; while( ( $row = fgetcsv( $tempFile ) ) !== false ) { if( !$this->tableColumns ) { $this->parseTableHeader( $row ); } else { $newRow = array(); $newSessionTableRow = array(); foreach( $row as $cell ) { $newRow[] = $this->parseCSVCell( $cell ); $newSessionTableRow[] = $cell; } $cells = new DataObjectSet( $newRow ); $table[] = $cells->customise( array( 'Cells' => $cells ) ); $sessionTable[] = $newSessionTableRow; } } fclose( $tempFile ); $this->table = new DataObjectSet( $table ); Session::set("ImportFile.{$_REQUEST['ID']}", $sessionTable); return $this->renderWith( 'Newsletter_RecipientImportField_Table' ); } /** * Determines what type each column is */ function parseTableHeader( $columns ) { $columnSource = array_combine( array_keys( self::$column_types ), array_keys( self::$column_types ) ); $columnSource = array_merge( array( 'Unknown' => 'Unknown' ), $columnSource ); $colCount = 0; foreach( $columns as $cell ) { $columnType = $this->getColumnType( $this->parseCSVCell( $cell )->Value() ); $this->tableColumns[] = new DropdownField( 'ImportFileColumns[' . (string)( $colCount++ ) . ']', '', $columnSource, $columnType ); } } function parseCSVCell( $cell ) { return new RecipientImportField_Cell( $cell ); } function getColumnType( $cell ) { $cell = strtolower( $cell ); $escapedValue = preg_replace( '/[^a-z]/', '', $cell ); foreach( self::$column_types as $type => $aliases ) { if( in_array( $escapedValue, $aliases ) ) return $type; } return 'Unknown'; } function setController( $controller ) { $this->controller = $controller; } /** * Set of table column headers */ function ColumnHeaders() { return new DataObjectSet( $this->tableColumns ); } function Rows() { return $this->table; } function FileName() { return $this->clientFileName; } function TypeID() { return $this->typeID; } } class RecipientImportField_Cell extends ViewableData { protected $value; function __construct( $value ) { $this->value = $value; } function Value() { return $this->value; } } class RecipientImportField_UploadForm extends Form { function import( $data, $form ) { $id = $data['ID']; $mailType = DataObject::get_one("NewsletterType", "ID = $id"); if($mailType->GroupID) $group = DataObject::get_one("Group", "ID = $mailType->GroupID"); $recipientField = new RecipientImportField("ImportFile","Import from file", $group ); $recipientField->setTypeID( $id ); // if the file is not valid, then return an error if( empty( $_FILES ) || empty( $_FILES['ImportFile'] ) || $_FILES['ImportFile']['size'] == 0 ) return $this->customise( array( 'ID' => $id, "UploadForm" => $this->controller->UploadForm( $id ), 'ErrorMessage' => 'Please choose a CSV file to import' ) )->renderWith('Newsletter_RecipientImportField'); elseif( !$this->isValidCSV( $_FILES['ImportFile'] ) ) { /*if( file_exists( $_FILES['ImportFile']['tmp_name'] ) ) unlink( $_FILES['ImportFile']['tmp_name'] ); unset( $_FILES['ImportFile'] );*/ return $this->customise( array( 'ID' => $id, "UploadForm" => $this->controller->UploadForm( $id ), 'ErrorMessage' => 'The selected file was not a CSV file' ) )->renderWith('Newsletter_RecipientImportField'); } else return $recipientField->displaytable(); } function isValidCSV( $file ) { return preg_match( '/.*\.csv$/', $file['name'] ) > 0; } function confirm( $data, $form ) { $id = $data['ID']; $mailType = DataObject::get_one("NewsletterType", "ID = $id"); if($mailType->GroupID) $group = DataObject::get_one("Group", "ID = $mailType->GroupID"); return $this->importMembers( $id, $group, $data['ImportFileColumns'], $data['Set'] ); } function cancel( $data, $form ) { $newForm = $this->controller->UploadForm( $data['ID'] ); return $newForm->forTemplate(); } function action_import( $data, $form ) { return $this->import( $data, $form ); } function action_confirm( $data, $form ) { return $this->confirm( $data, $form ); } function action_cancel( $data, $form ) { return $this->cancel( $data, $form ); } /** * Import members from the uploaded file */ protected function importMembers( $id, $group, $cols, $setFields, $primaryColType = 'Email' ) { $startTime = time(); $importData = Session::set("ImportFile.{$id}"); $validColumns = array_keys( RecipientImportField::$column_types ); $columnMap = array_flip( $cols ); // Debug::show($columnMap); // locate the primary column's index $primaryColumn = /*array_search( $primaryColType, $validColumns );*/ $columnMap[$primaryColType]; // changed fields $changedFields = array(); // intersect the list of valid columns with the column map to find the columns we need $importColumns = array_intersect( $validColumns, $cols ); // statistics $newMembers = 0; $changedMembers = 0; $skippedMembers = 0; // the class that the imported members will become $newMemberClass = Object::getCustomClass( 'Member' ); // for each row, add a new member or overwrite an existing member foreach( $importData as $newMemberRow ) { // skip rows with an empty value for the primary column if( empty( $newMemberRow[$primaryColumn] ) ) { $skippedMembers++; continue; } // remember to check if the user has unsubscribed $trackChanges = true; // TODO: Write DataObject::update $member = $this->findMember( $newMemberRow[$primaryColumn] ); if( !$member ) { $newMembers++; $trackChanges = false; $member = Object::create("Member"); } else { // skip this member if the are unsubscribed if( $member->Unsubscribed ) { $skippedMembers++; continue; } if( $member->class != $newMemberClass ) $member->setClassName( $newMemberClass ); $changedMembers++; } // add each of the valid columns foreach( $importColumns as $datum ) { // perform any required conversions $newValue = trim( $newMemberRow[$columnMap[$datum]] ); $oldValue = trim( $member->$datum ); // Debug::message( "$datum@{$columnMap[$datum]}" ); // track the modifications to the member data if( $trackChanges && $newValue != $oldValue && $datum != $primaryColumn ) { $changedFields[] = array( $newMemberRow[$primaryColumn], "$datum:\n$oldValue", "$datum:\n$newValue" ); $numChangedFields++; } $member->$datum = $newValue; } // set any set fields if( $setFields ) foreach( $setFields as $fieldName => $fieldValue ) $member->$fieldName = $fieldValue; // add member to group $member->write(); $member->Groups()->add( $group->ID ); } $numChangedFields = count( $changedFields ); $this->notifyChanges( $changedFields ); // TODO Refresh window $customData = array( 'ID' => $id, "UploadForm" => $this->controller->UploadForm( $id ), 'ImportMessage' => 'Imported new members', 'NewMembers' => (string)$newMembers, 'ChangedMembers' => (string)$changedMembers, 'ChangedFields' => (string)$numChangedFields, 'SkippedRecords' => (string)$skippedMembers, 'Time' => time() - $startTime ); return $this->customise( $customData )->renderWith('Newsletter_RecipientImportField'); } function findMember( $email ) { $email = addslashes( $email ); return DataObject::get_one( 'Member', "`Email`='$email'" ); } function notifyChanges( $changes ) { $email = new Email( Email::getAdminEmail(), Email::getAdminEmail(), 'Changed Fields' ); $body = ""; foreach( $changes as $change ) { $body .= "-------------------------------\n"; $body .= implode( ' ', $change ) . "\n"; } $email->setBody( $body ); $email->send(); } } ?>