silverstripe-framework/docs/en/02_Developer_Guides/11_Integration/00_CSV_Import.md
Damian Mooyman 88fdc75456 Merge remote-tracking branch 'composer/3.1' into 3
Conflicts:
	.editorconfig
	docs/en/00_Getting_Started/00_Server_Requirements.md
	docs/en/00_Getting_Started/01_Installation/04_Other_installation_Options/Windows_IIS7.md
	docs/en/00_Getting_Started/01_Installation/04_Other_installation_Options/Windows_Platform_Installer.md
	docs/en/00_Getting_Started/04_Directory_Structure.md
	docs/en/00_Getting_Started/index.md
	docs/en/01_Tutorials/01_Building_A_Basic_Site.md
	docs/en/01_Tutorials/02_Extending_A_Basic_Site.md
	docs/en/01_Tutorials/03_Forms.md
	docs/en/01_Tutorials/04_Site_Search.md
	docs/en/01_Tutorials/05_Dataobject_Relationship_Management.md
	docs/en/01_Tutorials/index.md
	docs/en/02_Developer_Guides/00_Model/01_Data_Model_and_ORM.md
	docs/en/02_Developer_Guides/00_Model/11_Scaffolding.md
	docs/en/02_Developer_Guides/01_Templates/06_Themes.md
	docs/en/02_Developer_Guides/03_Forms/How_Tos/Simple_Contact_Form.md
	docs/en/02_Developer_Guides/05_Extending/05_Injector.md
	docs/en/02_Developer_Guides/09_Security/04_Secure_Coding.md
	docs/en/02_Developer_Guides/10_Email/index.md
	docs/en/02_Developer_Guides/11_Integration/01_RestfulService.md
	docs/en/02_Developer_Guides/12_Search/01_Searchcontext.md
	docs/en/02_Developer_Guides/14_Files/index.md
	docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/03_CMS_Layout.md
	docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/06_Javascript_Development.md
	docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Customise_CMS_Tree.md
	docs/en/02_Developer_Guides/15_Customising_the_Admin_Interface/How_Tos/Customise_Site_Reports.md
	docs/en/02_Developer_Guides/18_Cookies_And_Sessions/01_Cookies.md
	docs/en/04_Changelogs/3.1.9.md
	docs/en/05_Contributing/00_Issues_and_Bugs.md
	docs/en/05_Contributing/02_Release_Process.md
	docs/en/05_Contributing/03_Documentation.md
	filesystem/File.php
	filesystem/GD.php
	model/DataDifferencer.php
	model/Versioned.php
	security/BasicAuth.php
	security/Member.php
	tests/filesystem/FileTest.php
	tests/forms/uploadfield/UploadFieldTest.php
	tests/model/VersionedTest.php
	tests/security/BasicAuthTest.php
2015-01-15 18:52:46 +13:00

202 lines
5.8 KiB
Markdown

# Import CSV data
## Introduction
CSV import can be easily achieved through PHP's built-in `fgetcsv()` method,
but this method doesn't know anything about your datamodel. In SilverStripe,
this can be handled through the a specialized CSV importer class that can
be customized to fit your data.
## The CsvBulkLoader class
The [api:CsvBulkLoader] class facilitate complex CSV-imports by defining column-mappings and custom converters.
It uses PHP's built-in `fgetcsv()` function to process CSV input, and accepts a file handle as an input.
Feature overview:
* Custom column mapping
* Auto-detection of CSV-header rows
* Duplicate detection based on custom criteria
* Automatic generation of relations based on one or more columns in the CSV-Data
* Definition of custom import methods (e.g. for date conversion or combining multiple columns)
* Optional deletion of existing records if they're not present in the CSV-file
* Results grouped by "imported", "updated" and "deleted"
## Usage
You can use the CsvBulkLoader without subclassing or other customizations, if the column names
in your CSV file match `$db` properties in your dataobject. E.g. a simple import for the
`[api:Member]` class could have this data in a file:
FirstName,LastName,Email
Donald,Duck,donald@disney.com
Daisy,Duck,daisy@disney.com
The loader would be triggered through the `load()` method:
:::php
$loader = new CsvBulkLoader('Member');
$result = $loader->load('<my-file-path>');
By the way, you can import `[api:Member]` and `[api:Group]` data through `http://localhost/admin/security`
interface out of the box.
## Import through ModelAdmin
The simplest way to use [api:CsvBulkLoader] is through a [api:ModelAdmin] interface - you get an upload form out of the box.
:::php
<?php
class PlayerAdmin extends ModelAdmin {
private static $managed_models = array(
'Player'
);
private static $model_importers = array(
'Player' => 'PlayerCsvBulkLoader',
);
private static $url_segment = 'players';
}
?>
The new admin interface will be available under `http://localhost/admin/players`, the import form is located
below the search form on the left.
## Import through a custom controller
You can have more customized logic and interface feedback through a custom controller.
Let's create a simple upload form (which is used for `MyDataObject` instances).
You'll need to add a route to your controller to make it accessible via URL
(see [director](/reference/director)).
:::php
<?php
class MyController extends Controller {
private static $allowed_actions = array('Form');
protected $template = "BlankPage";
public function Link($action = null) {
return Controller::join_links('MyController', $action);
}
public function Form() {
$form = new Form(
$this,
'Form',
new FieldList(
new FileField('CsvFile', false)
),
new FieldList(
new FormAction('doUpload', 'Upload')
),
new RequiredFields()
);
return $form;
}
public function doUpload($data, $form) {
$loader = new CsvBulkLoader('MyDataObject');
$results = $loader->load($_FILES['CsvFile']['tmp_name']);
$messages = array();
if($results->CreatedCount()) $messages[] = sprintf('Imported %d items', $results->CreatedCount());
if($results->UpdatedCount()) $messages[] = sprintf('Updated %d items', $results->UpdatedCount());
if($results->DeletedCount()) $messages[] = sprintf('Deleted %d items', $results->DeletedCount());
if(!$messages) $messages[] = 'No changes';
$form->sessionMessage(implode(', ', $messages), 'good');
return $this->redirectBack();
}
}
Note: This interface is not secured, consider using [api:Permission::check()] to limit the controller to users
with certain access rights.
## Column mapping and relation import
We're going to use our knowledge from the previous example to import a more sophisticated CSV file.
Sample CSV Content
"Number","Name","Birthday","Team"
11,"John Doe",1982-05-12,"FC Bayern"
12,"Jane Johnson", 1982-05-12,"FC Bayern"
13,"Jimmy Dole",,"Schalke 04"
Datamodel for Player
:::php
<?php
class Player extends DataObject {
private static $db = array(
'PlayerNumber' => 'Int',
'FirstName' => 'Text',
'LastName' => 'Text',
'Birthday' => 'Date',
);
private static $has_one = array(
'Team' => 'FootballTeam'
);
}
?>
Datamodel for FootballTeam:
:::php
<?php
class FootballTeam extends DataObject {
private static $db = array(
'Title' => 'Text',
);
private static $has_many = array(
'Players' => 'Player'
);
}
?>
Sample implementation of a custom loader. Assumes a CSV-file in a certain format (see below).
* Converts property names
* Splits a combined "Name" fields from the CSV-data into `FirstName` and `Lastname` by a custom importer method
* Avoids duplicate imports by a custom `$duplicateChecks` definition
* Creates `Team` relations automatically based on the `Gruppe` column in the CSV data
:::php
<?php
class PlayerCsvBulkLoader extends CsvBulkLoader {
public $columnMap = array(
'Number' => 'PlayerNumber',
'Name' => '->importFirstAndLastName',
'Birthday' => 'Birthday',
'Team' => 'Team.Title',
);
public $duplicateChecks = array(
'Number' => 'PlayerNumber'
);
public $relationCallbacks = array(
'Team.Title' => array(
'relationname' => 'Team',
'callback' => 'getTeamByTitle'
)
);
public static function importFirstAndLastName(&$obj, $val, $record) {
$parts = explode(' ', $val);
if(count($parts) != 2) return false;
$obj->FirstName = $parts[0];
$obj->LastName = $parts[1];
}
public static function getTeamByTitle(&$obj, $val, $record) {
return FootballTeam::get()->filter('Title', $val)->First();
}
}
?>
## Related
* [api:CsvParser]
* [api:ModelAdmin]