Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a custom CSV importer for SilverStripe

I'm working on building a custom import control for a SilverStripe site because the CSV files that are going to be used are unfortunately not properly formatted CSV files and cannot be improved (we have to work with what we're given, basically). The files contain semi-color separated data, and each line is one entry:

"[ID]";"[First Name]";"[Middle Initial]";"[Last Name]";"[Title]";"[University/College]";"[Specialty]";"[Graduation Date]"

Any of those values could be empty (i.e. An entry may not have the middle initial or it may not have the speciality listed). These fields are then just marked as a single space within a pair of double quotes:

"[ID]";"[First Name]";" ";"[Last Name]";"[Title]";"[University/College]";" ";"[Graduation Date]"

It's also important to note that the CSV files do not have headers, and it is unlikely that they will be able to have them. I have read about the CSVBulkLoader class for SilverStripe, but it seems that, without headers, it is difficult to make use of it. Plus, there is the issue with empty fields like I mentioned.

Is it possible to set up a file that breaks the data in the CSV files at the semi-colon? This way I could get each value on one line and I could map them to their fields in the SilverStripe Admin Model.

Here is an admin model I am working on at the moment:

<?php
class PhysicianEducationAdmin extends ModelAdmin {

    private static $managed_models = array('PhysicianEducation');
    private static $url_segment = 'physicianeducation';
    private static $menu_title = 'Physician Education Info';

}

<?php

class PhysicianEducation extends DataObject {

    private static $db = array(
        'ProviderID' => 'varchar',
        'FirstName' => 'varchar(250)',
        'MiddleName' => 'varchar(250)',
        'LastName' => 'varchar(250)',
        'Title' => 'varchar(10)',
        'Institution' => 'varchar(550)',
        'Education' => 'varchar(250)',
        'Specialty' => 'varchar(250)',
        'EndDate' => 'Date',
    );

    public static $summary_fields = array(
        'ProviderID' => 'Provider ID',
        'FirstName' => 'First Name',
        'MiddleName' => 'Middle Initial',
        'LastName' => 'Last Name',
        'Title' => 'Title',
        'Institution' => 'Institution',
        'Education' => 'Education',
        'Specialty' => 'Speciality',
        'EndDate' => 'End Date',
    );

}
like image 211
Dejsa Cocan Avatar asked Nov 21 '25 02:11

Dejsa Cocan


2 Answers

You should be able to use the fgetcsv() function http://php.net/manual/en/function.fgetcsv.php.

It allows you to specify the delimiter (for you ';'), and the enclosure (for you '"'), which is the default.

like image 103
Chris Avatar answered Nov 23 '25 21:11

Chris


Silverstripe includes a CSVParser class that can be used for this. You can pass the delimiter in as the second parameter on the constructor. Since the file doesn't have a header row, you can provide it with one using the provideHeaderRow function. CSVParser implements the Iterator interface, so you can loop over the object within a loop:

$physicians = CSVParser::create('myfile.csv', ';');
$physicians->provideHeaderRow(array(...));

foreach($physicians as $physician) {
  $pe = PhysicianEducation::create()->update($physician);
  $pe->write();
}

You will need to add some validation to your DataObject (perhaps doing some checks in onBeforeWrite, or making a subclass of Validator) to prevent invalid records (such as empty fields) from being created.

like image 40
cryptopay Avatar answered Nov 23 '25 21:11

cryptopay



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!