Skip to content

Instantly share code, notes, and snippets.

@donmccurdy
Created August 29, 2014 21:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save donmccurdy/1a87e66e78df92cae1d9 to your computer and use it in GitHub Desktop.
Save donmccurdy/1a87e66e78df92cae1d9 to your computer and use it in GitHub Desktop.
GFRV

get_field_replacement_value() → ???

Requirements

  • 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.

Current Implementation

  • 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);

Idea #1 - Component-based Fields

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.

Idea #2 - FieldDef-based Fields

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:

field-subclasses

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:

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?
@dylanwenzlau
Copy link

I think we need a better fundamental separation of field types other than the existing component organization. For example, every single field should be able to be a "list" field, for the most part. And dropdown is exclusively a display characteristic that could also be applied to just about any field type (we need to rename combo to dropdown, btw).

I'm leaning toward a more raw approach that is further from HTML than components, and of course having zero attachment to any particular page type. Components could be the display portion maybe, responsible for page-specific HTML? Although at the same time, there should be a little bit of centralized HTML for all display locations.

@schnerd
Copy link

schnerd commented Sep 1, 2014

I'd generally agree with Dylan... the formatting of field values should mostly be separate from our Component architecture, but components would still be responsible for wrapping those values in any page-specific HTML. That might take longer that just building off the current component structure, but it seems like a better long-term solution.

I like the idea of using decorators/formatters from #2–hard to say whether we need a full-fledged subclasses of FieldDef with FieldValueSource, or if we could just get away with a strategy-ish design pattern where we pass around instances of classes that implement some Formatter interface:

Dates:

<?php // Gist doesn't highlight PHP unless you put an opening php tag lolz

$item->get('start_date'); // 2014-03-04 00:00:00

$formatter = new DateFieldFormatter('F j, Y');
$item->get('start_date', $formatter); // March 4, 2014

$formatter = new DateFieldFormatter(DateFieldFormatter:TIME_AGO);
$item->get('start_date', $formatter); // 3 months ago

or Smart ratings:

<?php
$item->get('expert_rating'); // 3.5

// Formatter that just multiplies by 20 for rating
$formatter = new NormalizedRatingFormatter();
$item->get('expert_rating', $formatter); // 70

$formatter = new SmartRatingSVGFormatter(90);
$item->get('expert_rating', $formatter); // <svg width="90" ...

I'm certainly not sure if that's a good solution, just trying to throw some other ideas out there. It may also be worth thinking about what simple_tag_replace might look like, since I'd imagine it's one of the most prominent paths into GFRV.

Sitting down together and bouncing ideas around for an hour might be useful (I'm gone this week but definitely don't wait for me if y'all are ready to get started).

@donmccurdy
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment