- Provide displayable 'field values' for all field types (list, numeric, entity, image, url, ...)
- Offer these values in multiple formats: DB value, HTML, markdown (for narratives), plaintext (e.g. for a mobile app).
- Support normalized/denormalized data sources, given the original Item: plain field values from the table, images that require metadata, app data and entity fields that do lookups elsewhere, and ideally functions or collections that might be computed on the fly (see: UserExpressionFieldDef).
- Other concerns: Help text, directory crosslinks.
- get_field_replacement_value() – Does what it was designed to do, but it's no longer possible to add new features to the function, due to its complexity.
- Field Components – Nicely split out by field type, but they're tied to the existing page types. Currently these support some of what get_field_replacement_value() does, but things like directory crosslinks and non-HTML output aren't covered, so we can't switch wholesale.
In either case below, field values could probably be accessed in one of three ways. All are already partially supported, but don't do enough of what get_field_replacement_value() does to be really rolled out, yet:
$def = /* some field definition */;
// Case 1 - Field Component
$value = Field::create($def)->getValue($item);
// Case 2 - Field (Definition)
$value = $def->getValue($item);
// Case 3 - Item
$warue = $item->getValue($def->db_name);
Add onto the existing FieldComponent classes to support features they're missing (directory crosslinks, non-HTML output formats). Classes:
- Field.php
- FieldCombo.php
- FieldComboRaw.php
- FieldDate.php
- FieldEdit.php
- FieldEditCurrency.php
- FieldList.php
- FieldEntity.php
- ...and 10-15 more
Pros
- This is easier, architecturally, and would avoid the need for a parallel class structure to what we already have.
Cons
- The Component classes may start to get overcommitted, since they already support things like differentiating DD vs SBS page formatting, edit page support, and edit validation.
Extend the FieldDef class (perhaps this should be renamed to just "Field") into subclasses related to the different data_type and control_type cases. Examples:
Either internally, or by delegation to something like a Decorator, each subclass would be responsible for providing its value in each format we need to support: DB value, plaintext, HTML, and markdown.
Additional decorators or has-a components provide functionality that isn't really specific to any field type, like crosslinks and help text.
Internally, each field might have a data source (say, FieldValueSource) instance responsible for taking the original item array and returning the DB value of the current field. In most cases that's a simple return $item[$field];
, but I'm wondering if we want to allow room for multi-step data sources that could handle things like: entity field attributes ($school->get('state.population')
), values derived at runtime from other fields or user input (see: calculators), or maybe normalized price fields or something.
Overview:
Pros
- Doesn't add responsibilities to Component subclasses (and hopefully takes some responsibilities away).
- Can be extended to support new field types in the future.
Cons
- This would create a class structure that is a bit redundant compared to the descendants of the Field Components.
- It's unclear where the line is between a 'format' like HTML and a view-specific use, like SBS HTML vs DD HTML. Does it make sense to support HTML at all, outside of the Component subclasses?
The reason for the weird
FieldValueSource
thing is really Calculators, currently they're already extending the FieldDef classes into subclasses that support different sources, but that class heirarchy will need to go away if we subclass based on data type. Shouldn't be too difficult though.The formatters idea is interesting. I think there should be defaults, i.e. a FieldDef by itself already has enough info to create a human-readable date, but using a Formatter or Decorator in combination with FieldDefs could be nice. I've got an initial commit on master, for gatekeeping purposes. Future commits will probably be on a branch. In any case GFRV's responsibilities need to be split into different classes of some sort, so i'll just chip away at that for now.