Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

Polymorphic has_many with CSV Bulk Uploader


Go to End


848 Views

Avatar
mlascarides

Community Member, 1 Post

8 April 2016 at 12:16pm

Hello,

I'm working on a little internal CMS project using Silverstripe and I'm hitting a small bug. Wondering if it's an issue or if it's something I've overlooked.

I have a StaticText model that manages an arbitrary number of bits of text (essays, description, copyright statements, etc) as a has_many on either a Publication or Format model. This is working just fine.

I am using ModelAdmin (https://docs.silverstripe.org/en/3.3/developer_guides/customising_the_admin_interface/modeladmin/) to manage the interface. I'm also using CsvBulkLoader to import existing data from CSV. This is where I run into some problems.

The CSV import is working, and even gets as far as setting the ID number of the right polymorphic association (ie, StaticTextOfID has the right ID for Format on Format-related StaticTexts, and has the right ID for Publication on Publication-related StaticTexts). However, all of the values for the polymorphic class name in the db are set to "File".

The Silverstripe ORM creates the polymorphic "…OfClass" field as an Enum and includes all classes it knows about. The first on the list is "File", and since the Enum type does not allow nil values, it seems like that "File" value is coming from a blank value defaulting to the first one on the list. SO the only missing bit here is getting the CSVBulkUploader to set the Class of the polymorphic relation.

Bonus question: The other thing I am not sure how to handle is how I can make a dropdown select in ModelAdmin of all possible has_manys in the polymorphic relationship, ie, if I create a new StaticText, see all Formats and Publications together in one dropdown? Might not be possible, but thought I'd ask.

code follows:

ModelAdmin setup:

class PPAdmin extends ModelAdmin {

    private static $managed_models = array(
        'Format',
        'Publication',
        'StaticText'
    );

	private static $model_importers = array(
      'Format' 			=> 'CsvBulkLoader',
      'Publication' 	=> 'PublicationCsvBulkLoader',
      'StaticText' 		=> 'StaticTextCsvBulkLoader',
   );

    private static $url_segment = 'pp';

    private static $menu_title = 'PP Content';
}

Publication model:

class Publication extends DataObject {

    private static $db = array(
        'Title' 			=> 'Varchar(255)',
        'Code' 				=> 'Varchar(255)',
        'Region' 			=> "Enum('National,Northland,Auckland,Waikato,Bay of Plenty,Gisborne,Taranaki,Manawatu,Hawke\'s Bay,Wellington,Nelson,Marlborough,West Coast,Canterbury,Otago,Samoa')",
        'TitleAlternate' 	=> 'Varchar(255)',
        'Publish'           => "Enum('classic,staging,beta,everywhere')"
    );

    private static $has_many = array(
      'StaticTexts' => 'StaticText.StaticTextOf'
    );

    private static $has_one = array(
      'Format' => 'Format'
    );

    public function getCMSFields() {
        $fields = parent::getCMSFields();

        $formatList = Format::get()->map()->toArray();
        $formatSelect = DropdownField::create('FormatID', 'Format')->setSource($formatList);

        $fields->replaceField('FormatID', $formatSelect);

        return $fields;
    }

    private static $defaults = array(
        "Region" => 'National',
        "Publish" => 'everywhere',
    );

    private static $summary_fields = array(
      'Title',
      'Code',
      'Region',
      'Publish'
   );

StaticText model:

class StaticText extends DataObject {

    private static $db = array(
        'Language' 			=> "Enum('en,mi')",
        'Code' 				=> "Enum('Acknowledgement,Essay,Description,Copyright,Content-acknowledgement,ShortText,LongText')",
        'Content'           => 'Text',
        'StartYear'         => 'Int',
        'EndYear'           => 'Int',
        'Append'            => "Enum('Yes,No')",
        'Status'            => "Enum('Unconfirmed,Needs Translation,Confirmed,Needs Editing')",
        'Publish'           => "Enum('classic,staging,beta,everywhere')"
    );

	private static $has_one = array(
        'StaticTextOf' => 'DataObject'
    );

    public function getCMSFields() {
        $fields = parent::getCMSFields();
        $item_field = DropdownField::create('StaticTextOf');
        $fields->addFieldToTab('Root.Main', $item_field);
        return $fields;
    }

    private static $defaults = array(
        "Language" => 'en',
        "Append" => 'No',
        "Status" => 'Unconfirmed',
        "Publish" => 'everywhere',
    );

    private static $summary_fields = array(
        'Language',
        'Code',
        'Status',
        'Publish'
    );

STaticTextUploader:

class StaticTextCsvBulkLoader extends CsvBulkLoader {
   public $relationCallbacks = array(
      'StaticTextOf' => array(
         'relationname' => 'StaticTextOf',
         'callback' => 'getItemByTitle'
      )
   );
   public static function getItemByTitle(&$obj, $val, $record) {
   		$parts = split('---', $val, 2);
   		if ($parts[0] == 'Format') {
   			$item = Format::get()->filter('Title', $parts[1])->First();		
   		} else {
   			$item = Publication::get()->filter('Title', $parts[1])->First();		
   		}
   		return $item;
   }
}