Save current selection of a DropdownField populated by an Enum

Silverstripe Version:
SS 4.9

Question:

I wanted to understand how the variable type Enum works and if you can save the value from the Dropdown directly in the admin panel without adding a Varchar field in addition to the Enum (which I don’t show in the end of the day). I’ve seen discussion saying it was deprecated and that the data would be split in different objects, so I’m kinda confused if I should use it or not, and how.

This code works, basically I just have Dropdowns populated with Strings to choose which one to save from the back end and from a form in the front end. I already have both, but I can’t save the value in the back end without having the combination Enum + Varchar (it would go back to default value if I used only Enum like in SS3), and therefore not sure if I’m going in the right direction.

By the way, when doing Dev/Build with Enum, it throw an error, I have to first create the variable as another type like Int or Varchar, then once the table is created in the DB, I can switch to Enum and it works.

Details of your query go here


<?php

namespace App\Hub; 

use SilverStripe\ORM\DataObject;
use SilverStripe\Security\Permission;
use SilverStripe\Security\Member;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TabSet;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\TextareaField;
use SilverStripe\Forms\DropdownField;

class PostObject extends DataObject {
        
    private static $db = [
        'Title' => 'Varchar',
        'PostType' => 'Enum(["void","YouTube","Vimeo","Instagram","Image","Video"])',
        'Type' => 'Varchar(20)',
        'EmbedCode' => 'Varchar',
        'IsActive' => 'Boolean(1)'
    ];

    private static $defaults = [
        'PostType' => 'void'
    ];

    private static $has_one = [
        'Member' => Member::class 
    ];

    public function getCMSFields(){        
        $fields = FieldList::create(TabSet::create('Root'));
        //$fields = parent::getCMSFields();   
        $fields->addFieldsToTab('Root.Main', [
            TextField::create('Title'),
            DropdownField::create( 'Type', 'Post Type', singleton('App\Hub\PostObject')->dbObject('PostType')->enumValues() )
        ]);

        return $fields;
    } 
} 

So, the first thing to know is what the build error is saying.

You can save directly into the enum column without the need for saving the value in a varchar (which pretty much defeats the whole point of using an enum in the first place)

That’s what I was thinking, will do a test tomorrow and check the error message when building the database. I just know whenever I click save, it goes back to the default value. Thanks for the quick reply!

I tried with a TestDB field as Enum with the same Strings and it gives me this error related to the DB connection. Which is odd as it works for any other data type outside of Enum.

Building database unlabelledgirls using SilverStripe\ORM\Connect\MySQL 5.7.26

[Emergency] Uncaught SilverStripe\ORM\Connect\DatabaseException: Couldn’t run query: ALTER TABLE “App_Hub_PostObject” ADD “TestDB” enum() character set utf8mb4 collate utf8mb4_unicode_ci, CHANGE “PostType” “PostType” enum(’’) character set utf8mb4 collate utf8mb4_unicode_ci You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘) character set utf8mb4 collate utf8mb4_unicode_ci, CHANGE “PostType” “PostType”’ at line 1

GET /dev/build

Line 64 in /Applications/MAMP/htdocs/unlabelledgirls/vendor/silverstripe/framework/src/ORM/Connect/DBConnector.php

Source
55 if (!empty($sql)) {
56 $formatter = new SQLFormatter();
57 $formattedSQL = $formatter->formatPlain($sql);
58 $msg = “Couldn’t run query:\n\n{$formattedSQL}\n\n{$msg}”;
59 }
60
61 if ($errorLevel === E_USER_ERROR) {
62 // Treating errors as exceptions better allows for responding to errors
63 // in code, such as credential checking during installation
64 throw new DatabaseException($msg, 0, null, $sql, $parameters);
65 } else {
66 user_error($msg, $errorLevel);
67 }
68 }
69
70 /**

Trace

  • SilverStripe\ORM\Connect\DBConnector->databaseError(Couldn’t run query: ALTER TABLE “App_Hub_PostObject” ADD “TestDB” enum() character set utf8mb4 collate utf8mb4_unicode_ci, CHANGE “PostType” “PostType” enum(’’) character set utf8mb4 collate utf8mb4_unicode_ci You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘) character set utf8mb4 collate utf8mb4_unicode_ci, CHANGE “PostType” “PostType”’ at line 1, 256, ALTER TABLE “App_Hub_PostObject” ADD “TestDB” enum() character set utf8mb4 collate utf8mb4_unicode_ci, CHANGE “PostType” “PostType” enum(’’) character set utf8mb4 collate utf8mb4_unicode_ci)
    MySQLiConnector.php:181
  • SilverStripe\ORM\Connect\MySQLiConnector->query(ALTER TABLE “App_Hub_PostObject” ADD “TestDB” enum() character set utf8mb4 collate utf8mb4_unicode_ci, CHANGE “PostType” “PostType” enum(’’) character set utf8mb4 collate utf8mb4_unicode_ci, 256)
    Database.php:159
  • SilverStripe\ORM\Connect\Database->SilverStripe\ORM\Connect{closure}(ALTER TABLE “App_Hub_PostObject” ADD “TestDB” enum() character set utf8mb4 collate utf8mb4_unicode_ci, CHANGE “PostType” “PostType” enum(’’) character set utf8mb4 collate utf8mb4_unicode_ci)
    Database.php:258
  • SilverStripe\ORM\Connect\Database->benchmarkQuery(ALTER TABLE “App_Hub_PostObject” ADD “TestDB” enum() character set utf8mb4 collate utf8mb4_unicode_ci, CHANGE “PostType” “PostType” enum(’’) character set utf8mb4 collate utf8mb4_unicode_ci, Closure)
    Database.php:160
  • SilverStripe\ORM\Connect\Database->query(ALTER TABLE “App_Hub_PostObject” ADD “TestDB” enum() character set utf8mb4 collate utf8mb4_unicode_ci, CHANGE “PostType” “PostType” enum(’’) character set utf8mb4 collate utf8mb4_unicode_ci, 256)
    MySQLDatabase.php:396
  • SilverStripe\ORM\Connect\MySQLDatabase->query(ALTER TABLE “App_Hub_PostObject” ADD “TestDB” enum() character set utf8mb4 collate utf8mb4_unicode_ci, CHANGE “PostType” “PostType” enum(’’) character set utf8mb4 collate utf8mb4_unicode_ci, 256)
    DBSchemaManager.php:123
  • SilverStripe\ORM\Connect\DBSchemaManager->query(ALTER TABLE “App_Hub_PostObject” ADD “TestDB” enum() character set utf8mb4 collate utf8mb4_unicode_ci, CHANGE “PostType” “PostType” enum(’’) character set utf8mb4 collate utf8mb4_unicode_ci)
    MySQLSchemaManager.php:111
  • SilverStripe\ORM\Connect\MySQLSchemaManager->alterTable(App_Hub_PostObject, Array, Array, Array, Array, , )
    DBSchemaManager.php:187
  • SilverStripe\ORM\Connect\DBSchemaManager->schemaUpdate(Closure)
    DatabaseAdmin.php:344
  • SilverStripe\ORM\DatabaseAdmin->doBuild(, 1)
    DatabaseAdmin.php:152
  • SilverStripe\ORM\DatabaseAdmin->build()
    DatabaseAdmin.php:124

I think there is a bug or regression in ClassInfo::parse_class_spec. In the meantime, to workaround this issue, you can use string notation or explicit array notation, e.g.:

// String notation
'PostType' => 'Enum("void,YouTube,Vimeo,Instagram,Image,Video")',
// Explicit array notation
'PostType' => 'Enum(array("void","YouTube","Vimeo","Instagram","Image","Video"))',

Relevant link to the issue on GitHub.

Thanks a lot for the tip, it works like a charm!