PHPackages                             archipro/silverstripe-smart-enum - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. archipro/silverstripe-smart-enum

ActiveSilverstripe-vendormodule[Utility &amp; Helpers](/categories/utility)

archipro/silverstripe-smart-enum
================================

Silverstripe CMS DBField backed by PHP 8.1 BackedEnums with optional scalar column storage via use\_native\_db\_enum

0.0.0(1mo ago)014.8k↑15550%BSD-3-ClausePHPPHP ^8.1CI failing

Since Jun 11Pushed 1mo agoCompare

[ Source](https://github.com/archiprocode/silverstripe-smart-enum)[ Packagist](https://packagist.org/packages/archipro/silverstripe-smart-enum)[ RSS](/packages/archipro-silverstripe-smart-enum/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (1)Dependencies (7)Versions (2)Used By (0)

Silverstripe SmartEnum DBField
==============================

[](#silverstripe-smartenum-dbfield)

Map a PHP 8.1+ `BackedEnum` to a Silverstripe `DataObject` database column. Values are derived from enum cases automatically. By default the column uses a database-native `ENUM` type (MySQL today); set `use_native_db_enum` to `false` to use a scalar column (`VARCHAR` for string-backed enums, `INT` for int-backed enums) when you need to avoid costly `ENUM` alters on large tables. This option refers to the database column type, not PHP `BackedEnum`.

CMS ModelAdmin and `DataObject` edit forms scaffold a `DropdownField` with the enum’s backing values (inherited from Silverstripe’s `DBEnum`).

Installation
------------

[](#installation)

```
composer require archipro/silverstripe-smart-enum
```

### Monorepo / path repository

[](#monorepo--path-repository)

```
"repositories": [
  {
    "type": "path",
    "url": "packages/silverstripe-smart-enum",
    "options": { "symlink": true }
  }
],
"require": {
  "archipro/silverstripe-smart-enum": "@dev"
}
```

Run `composer update archipro/silverstripe-smart-enum` and `sake dev/build` (or your usual schema build).

The module registers a `SmartEnum` Injector alias for use in `$db` field specs.

Define a SmartEnum on a DataObject
----------------------------------

[](#define-a-smartenum-on-a-dataobject)

Use the `SmartEnum` Injector alias in your `$db` array. Double-escape backslashes in the enum class name inside the field specification string:

```
use SilverStripe\ORM\DataObject;

class MyRecord extends DataObject
{
    private static $table_name = 'MyRecord';

    private static $db = [
        'Status' => 'SmartEnum("My\\\\Namespace\\\\Status", "PENDING")',
    ];
}
```

Int-backed enums work the same way; pass the int backing scalar as the default:

```
private static $db = [
    'Priority' => 'SmartEnum("My\\\\Namespace\\\\Priority", 1)',
];
```

Default value
-------------

[](#default-value)

Omit the second argument when the column should have no default. New records start with an empty value until the field is set:

```
'Status' => 'SmartEnum("My\\\\Namespace\\\\Status")',
```

Pass an explicit default as the second argument. Use the **backing scalar** of the enum case that represents the initial business state (for example the status a new record should start in):

```
'Status' => 'SmartEnum("My\\\\Namespace\\\\Status", "PENDING")',
'Priority' => 'SmartEnum("My\\\\Namespace\\\\Priority", 1)',
```

You can also pass `null` explicitly; that is equivalent to omitting the default:

```
'Status' => 'SmartEnum("My\\\\Namespace\\\\Status", null)',
```

When building the `$db` array in PHP (not a string field spec), you may pass a `BackedEnum` case instead of the scalar.

The default must match a case on the enum. Invalid scalars and enum cases from another type are rejected at field construction time.

Unlike core `DBEnum`, integer defaults are **not** treated as list indices. Pass the actual backing value (or an enum case), not a positional index.

Optional: enum class in `$db` (advanced)
----------------------------------------

[](#optional-enum-class-in-db-advanced)

By default this module only registers the `SmartEnum` Injector alias (see above). That is the **recommended** approach.

You can opt in to a different syntax that uses the backed enum FQCN directly in `$db`:

```
use My\Namespace\Priority;
use My\Namespace\Status;
use SilverStripe\ORM\DataObject;

class MyRecord extends DataObject
{
    private static array $db = [
        'Status' => Status::class,
        'Priority' => Priority::class . '(1)',
    ];
}
```

This requires wrapping the Injector config locator at application bootstrap. The decorator composes with whatever locator is already installed (other modules can decorate the chain too).

**Preferred (idempotent):**

```
use ArchiPro\Silverstripe\SmartEnum\SmartEnumServiceConfigurationLocator;

SmartEnumServiceConfigurationLocator::install();
```

**Explicit equivalent:**

```
use ArchiPro\Silverstripe\SmartEnum\SmartEnumServiceConfigurationLocator;
use SilverStripe\Core\Injector\Injector;

$injector = Injector::inst();
$injector->setConfigLocator(new SmartEnumServiceConfigurationLocator(
    $injector->getConfigLocator()
));
```

Copy [`docs/enum-class-field-spec.bootstrap.php`](docs/enum-class-field-spec.bootstrap.php) into your app (for example `app/_config/smart-enum-enum-class.php`). Do not add that file under this module’s `_config/` directory.

### Behaviour and limitations

[](#behaviour-and-limitations)

- Explicit `SmartEnum("...")` specs and YAML Injector bindings still take precedence.
- Defaults must be explicit in the field spec (`Status::class . '("PENDING")'`) or applied via the DataObject `$defaults` array at the ORM layer. This mode does **not** read `$defaults` when building the database column default.
- Per-field `use_native_db_enum` / `varchar_length` options are not available via enum-class syntax; use `SmartEnum("...", default, [options])` for those.
- Install once at bootstrap. `install()` is safe to call repeatedly; it does not double-wrap.
- If multiple decorators are used, install SmartEnum as the **outermost** layer so it runs before inner locators.

Both syntaxes can coexist when enum-class mode is enabled.

MySQL ENUM vs scalar columns
----------------------------

[](#mysql-enum-vs-scalar-columns)

`use_native_db_enum`String-backed enumInt-backed enum`true` (default)MySQL `ENUM`MySQL `ENUM` (values stored as quoted ints; coerced on read)`false``VARCHAR``INT`Use `use_native_db_enum: true` for smaller schemas with values enforced by the database. Set `use_native_db_enum` to `false` on large tables where altering an `ENUM` is slow or risky, or when you want a native `INT` column for int-backed enums.

Per-field override in the field spec options (4th argument):

```
'Status' => 'SmartEnum("My\\\\Namespace\\\\Status", "PENDING", ["use_native_db_enum" => false, "varchar_length" => 64])',
'Priority' => 'SmartEnum("My\\\\Namespace\\\\Priority", 1, ["use_native_db_enum" => false])',
```

For string-backed enums with `use_native_db_enum: false`, `varchar_length` is optional; when omitted, the length is `max(50, longest backing value length)` capped at 255.

Int-backed enums with `use_native_db_enum: true` return stringified values from MySQL. `DBSmartEnum` coerces numeric strings back to `int` at the field boundary (for example when reading via `dbObject()` or typed accessors).

### YAML / site-wide default

[](#yaml--site-wide-default)

Per-field `use_native_db_enum` must be set in the field spec options (4th argument) as shown above. To change the default for all SmartEnum fields that omit it, use static config:

```
---
Name: my-smartenum-storage
---
ArchiPro\Silverstripe\SmartEnum\DBSmartEnum:
  default_use_native_db_enum: true   # or false
```

Typed accessors (optional)
--------------------------

[](#typed-accessors-optional)

`SmartEnumDataExtension` is **not** applied globally. Add it to each `DataObject` that uses SmartEnum columns.

YAML:

```
---
Name: myrecord-smartenum
---
MyRecord:
  extensions:
    - ArchiPro\Silverstripe\SmartEnum\SmartEnumDataExtension
```

Or in PHP:

```
private static array $extensions = [
    ArchiPro\Silverstripe\SmartEnum\SmartEnumDataExtension::class,
];
```

For each `DBSmartEnum` column `Status` the extension provides:

- `getStatus(): ?BackedEnum` — `tryFrom()` on the stored scalar; `null` when empty or unknown.
- `setStatus(BackedEnum|string|int|null $value)` — accepts an enum instance or a valid backing scalar.

If the model already defines `getStatus()` / `setStatus()`, those methods take precedence over the extension.

### Property access and PHPDoc

[](#property-access-and-phpdoc)

The primary use case is property access on the `DataObject`. When the extension is applied, `$record->Status` resolves via `getStatus()` / `setStatus()` and returns a `BackedEnum` instance (or `null`). Property assignment validates the value; invalid backing scalars throw `InvalidArgumentException`.

Declare the typed property on your model for IDE and static analysis support:

```
use My\Namespace\Status;

/**
 * @property Status|null $Status
 */
class MyRecord extends DataObject
{
    // ...
}
```

`getField('Status')` still returns the raw backing scalar stored in the database record, not the enum instance.

CMS forms
---------

[](#cms-forms)

No extra configuration is required. `scaffoldFormField()` returns a `DropdownField` listing all backing values, whether or not `use_native_db_enum` is enabled.

Migrating database ENUM → scalar columns on production
------------------------------------------------------

[](#migrating-database-enum--scalar-columns-on-production)

Flipping `use_native_db_enum` from `true` to `false` on a live, large table is an operational task. `dev/build` may issue `ALTER TABLE` statements that lock or rebuild the table for a long time. Plan a manual migration and maintenance window; do not rely on a casual `dev/build` on production for column-type changes.

Running tests
-------------

[](#running-tests)

```
composer install
composer test
composer phpstan
composer lint      # PHPCS (PSR-12)
composer check     # phpstan, lint, and test in sequence
```

`composer test` requires a reachable MySQL-compatible database. Configure the connection via a project `.env` file or `SS_DATABASE_*` environment variables (for example `SS_DATABASE_SERVER`, `SS_DATABASE_USERNAME`, `SS_DATABASE_PASSWORD`, and optionally `SS_DATABASE_CHOOSE_NAME=true`). The suite fails if the database is missing or unreachable. GitHub Actions sets these automatically via [silverstripe/gha-ci](https://github.com/silverstripe/gha-ci).

License
-------

[](#license)

BSD-3-Clause

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance90

Actively maintained with recent releases

Popularity29

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity32

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

46d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1168676?v=4)[Maxime Rainville](/maintainers/maxime-rainville)[@maxime-rainville](https://github.com/maxime-rainville)

![](https://www.gravatar.com/avatar/95d114549b91352649b85d5e28f8d290eb709ba05d886f83d05fc31a7ab99d0d?d=identicon)[Boren](/maintainers/Boren)

---

Top Contributors

[![maxime-rainville](https://avatars.githubusercontent.com/u/1168676?v=4)](https://github.com/maxime-rainville "maxime-rainville (11 commits)")

---

Tags

enumsilverstripecms

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/archipro-silverstripe-smart-enum/health.svg)

```
[![Health](https://phpackages.com/badges/archipro-silverstripe-smart-enum/health.svg)](https://phpackages.com/packages/archipro-silverstripe-smart-enum)
```

###  Alternatives

[lekoala/silverstripe-cms-actions

Add actions to your models in SilverStripe

39344.8k33](/packages/lekoala-silverstripe-cms-actions)[sunnysideup/typography

Add a typography test page to your silverstripe website / application.

124.4k4](/packages/sunnysideup-typography)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
