Update docs - Add more discussion of change-sets (alterAlngular) and philosophy
authorTim Otten <totten@civicrm.org>
Tue, 18 Sep 2018 09:20:33 +0000 (02:20 -0700)
committerCiviCRM <info@civicrm.org>
Wed, 16 Sep 2020 02:13:16 +0000 (19:13 -0700)
ext/afform/README.md
ext/afform/docs/alter.md [new file with mode: 0644]
ext/afform/docs/philosophy.md [new file with mode: 0644]

index bbe9cb53c47b117a10b1b02f348b6a0c382ed233..e8c115e2ad688852bad630d78af802c05fe48fe0 100644 (file)
@@ -1,6 +1,6 @@
 # org.civicrm.afform (Early Proof of Concept)
 
-![Screenshot](/images/screenshot.png)
+<!-- ![Screenshot](/images/screenshot.png) -->
 
 The Affable Administrative Angular Form Framework (`afform`) is a system for administering AngularJS-based forms
 in CiviCRM which:
@@ -8,7 +8,7 @@ in CiviCRM which:
 1. Allows developers to declaratively define a canonical, baseline form using AngularJS.
 2. Allows administrators (or administrative tools) to use the CRUD API to customize the forms.
 3. Allows developers (or administrators/tools) to embed these forms in other CiviCRM-AngularJS apps.
-4. (WIP; pending upstream support) Allow developers to apply [change sets](https://docs.civicrm.org/dev/en/latest/framework/angular/changeset/).
+4. Allows developers to apply change-sets via hook. (*WIP; pending upstream support*)
 
 This extension is a proof-of-concept.  It aims to demonstrate the core model/concept -- however, there are 
 [known issues and additional components](docs/roadmap.md) to address, and some documentation will be easier to approach
@@ -49,5 +49,7 @@ cv en afform
 * [Writing Forms: Afform as basic AngularJS templates](docs/writing.md) (With example: *Contact Record*)
 * [Embedding Forms: Afform as reusable building-block](docs/embed.md) (With example: *Contact Record*)
 * [Form CRUD: Updating forms via programmatic API](docs/crud.md)
+* [Form Hooks: Updating forms via declarative selector](docs/alter.md) (*WIP; pending upstream support*)
 * [Full AngularJS: Integrating between Afform and vanilla AngularJS](docs/angular.md)
 * [Roadmap and Known Issues](docs/roadmap.md)
+* [Philosophy, Beliefs, Assumptions](docs/philosophy.md)
diff --git a/ext/afform/docs/alter.md b/ext/afform/docs/alter.md
new file mode 100644 (file)
index 0000000..295f584
--- /dev/null
@@ -0,0 +1,58 @@
+# Form Hooks: Updating forms via declarative selector
+
+> __WIP__ This describes functionality that is intended but not actual.  It
+> first requires writing a modest patch to civicrm-core so that HTML
+> documents managed by afform can go through `hook_civicrm_alterAngular`.
+
+Form hooks offer a different style of customization than [Form CRUD](docs/crud.md).  In the CRUD style, you use
+an API to save an updated form -- which stores the exact form (as designed by the user). In the hook style, you
+wait until a form is being displayed; and, as part of the rendering process, you filter the results.
+
+## Example
+
+In this example, we use `hook_civicrm_alterAngular` to apply a filter to the file `~/crmMailing/BlockSummary.html` --
+the filter selects an element by CSS class (`crm-group`) and then appends a new field to the bottom of that element:
+
+```php
+function mailwords_civicrm_alterAngular(\Civi\Angular\Manager $angular) {
+  $changeSet = \Civi\Angular\ChangeSet::create('inject_mailwords')
+    // ->requires('crmMailing', 'mailwords')
+    ->alterHtml('~/crmMailing/BlockSummary.html',
+      function (phpQueryObject $doc) {
+        $doc->find('.crm-group')->append('
+        <div crm-ui-field="{name: \'subform.mailwords\', title: ts(\'Keywords\')}">
+          <input crm-ui-id="subform.mailwords" class="crm-form-text" name="mailwords" ng-model="mailing.template_options.keywords">
+        </div>
+      ');
+      });
+  $angular->add($changeSet);
+}
+```
+
+## Comparison: CRUD vs Hook
+
+Similarities:
+
+* Both styles have safe and unsafe use-cases.
+* The safety generally depends on the specific components being used.
+    * Ex: If you add a new `crm-ui-field` (via either style), that could be safe/maintainable (if `crm-ui-field` is supported, stable, widely used) or it could be risky/hard-to-maintain
+      (if `crm-ui-field` is undocumented and rarely used).
+* In either style, there are legitimate scenarios for someone to reference a safe or risky component.  
+* In either style, it is difficult for a person to keep track of whether the referenced components are safe or risky. The lists of components will be long and will change over time. We'd rather have tooling to keep track of this.
+* Provided you abide by the code-style of the example, it is possible for the framework to build a list of all CRUD'd forms and all change-sets. In turn, it's possibile to loop through them, audit them, and warn about anything which appears unsafe.
+
+Differences:
+
+* CRUD is concrete. It saves what you tell it to save, and it doesn't do anything else. This makes it more suitable as the conceptual model for users' GUI editor. The good and bad consequences of CRUD are limited to the specific things you manipulated.
+* Change-sets are abstract. They can change many components (e.g. converting every `<h1>` to a `<div class="my-header-1">`). The good and bad consequences of change-sets can apply across a wider range of things.
+* CRUD locks-in your changes and preferences. If there's an upgrade, your form should remain safely as it was before (provided the form relied on safe components).
+* Change-sets are adaptable. If there's an upgrade or edit to the underlying, the change-set will be used on top of the latest revision. If the change-set is revised, then the latest change-set will be used without needing to edit the forms individually..
+
+I expect future people will develop better insight on the trade-offs; for an initial first-read, my expectations are that:
+
+* CRUD is more appropriate when an *administrator* is changing a *policy decision* (such as the relative position of two elements).
+* Change-sets are more appropriate when a *developer* is changing an *implementation detail* (such as the CSS classes used to style all calendar widgets).
+
+## See also
+
+https://docs.civicrm.org/dev/en/latest/framework/angular/changeset/
diff --git a/ext/afform/docs/philosophy.md b/ext/afform/docs/philosophy.md
new file mode 100644 (file)
index 0000000..d6b0744
--- /dev/null
@@ -0,0 +1,79 @@
+# Philosophy, Beliefs, Assumptions
+
+Afform is generally grounded in a few beliefs..
+
+## Leap by extension
+
+Afform represents a major conceptual change in how core forms are developed.  It is incubated as an extension that can
+be enabled or disabled to taste.  The aim is for oother extension using `afform` can incrementally override/replace
+particular forms in core.
+
+## Features and user-experiences evolve in funny workflows
+
+If we could sit down and define one true, correct version of a "Donation" form, then our lives as Civi devlopers would
+be easy: draw a mockup, write code, ship, and retire.  But we can't -- because Civi users and integrators engage with
+the system creatively.  They aim to optimize conversion-rates, to integrate with donor journerys, to question how each
+detail makes sense in their situation, etc.  That means switching between open-ended donation amounts, sliders, radios,
+etc; revising the language and layout; maybe adding an informational question or newsletter opt-in.
+
+I believe that features and user-experiences evolve in funny workflows -- because the actual stories behind major
+improvements have not fit into a single mold.  A main ambition of `afform` is to allow multiple workflows in developing
+a common type of deliverable (*the forms*).  Thus, the architecture anticipates scenarios for developers defining forms
+concretely; for users defining forms concretely; for using GUIs or text-editors or IDEs or SCMs; for using
+cross-cutting hooks and selectors.  Compatibility with multiple workflows is a primary feature of the design.
+
+This is *not* an argument for maximal customization or maximal decentralization.  As participants in an ecosystem, we
+must still communicate and exercise judgment about the best way to approach each problem.  But there are legitimate
+instances for each workflow; given that each will be sought, we want them to be safe and somewhat consistent.
+
+What distinguishes `afform` from the original form architecture (Civi's combination of HTML_Quickform, Smarty and
+Profiles)?  Each of those workflows has been given some consideration upfront with the aim of providing a *consistent,
+unified model* -- so that the same data-structure can be pushed through any of those common workflows.
+
+## Incremental and measurable strictness
+
+JavaScript, PHP, and HTML are forgiving, loosely-typed systems.  This can be viewed as a strength (wrt to learnability
+and prototyping), and it can be viewed as a weakness (allowing a number of common mistakes to go unidentified until a
+user runs into them).
+
+Personally, I think that strongly-typed languages are better for large, multi-person projects -- providing a fallback
+to protect against some common mistakes that arise people don't fully communicate or understand a change.  However,
+adopting a strongly-typed system is a major change, and it's not perfect, and I can respect the arguments in favor of
+loosely-typed systems.
+
+A compromise is to phase-in some static analysis incrementally.  For `afform`, this means that the main deliverables
+(HTML documents+changesets) should be encoded in an inspectable form -- it must be possible for the system to enumerate
+all documents+changesets and audit them (i.e.  identifying which form elements -- CSS classes and Angular directives --
+are officially supported or unsupported).  This, in turn, means that we can provide warnings and scores to identify
+which customizations are more maintainable or more experimental/suspect.
+
+## Don't reinvent the wheel; do use a wheel that fits
+
+The general philosophy and architecture in `afform` could be used with almost any form system that has a clear
+component hierarchy (such as AngularJS's HTML notation, Symfony Form's object graph, or Drupal Form API's array-trees).
+
+It specifically uses AngularJS.  Why?  In order of descending importance:
+
+* It can work across a wide range of existing deployment environments (D7, D8, WordPress, Backdrop, Joomla, Standalone).
+* It already exists.
+* I have experience with it.
+* The main Angular tutorials aimed at generalist web developers are reasonably slick.
+* The connection between the code you write and what's displayed in the browser is fairly concrete.
+
+It's by no means a perfect wheel.  Other wheels have strengths, too.  I checked the top-line requirement and grabbed
+the closest wheel that fit.
+
+## Fidelity to upstream
+
+The upstream AngularJS project canonically represents a form as an HTML file on disk; thus, `afform` does the same.
+The upstream project uses `ng-if` for a conditional element; thus, an `afform` instance should do the same.  The
+upstream project uses "directives" for composable building blocks; and `afform`, the same.
+
+This convention (a) helps to reduce bike-shedding, (b) helps us get some benefit out of re-using an existing wheel, and
+(c) practices what we preach with regard to "consistency" across the various workflows.
+
+## Generally comparable platform requirements
+
+If you can install CiviCRM on a server today, then you should be able to install `afform` and a personalized mix of
+extensions which build on it.  This means that the main workflows facilitated by `afform` can require PHP (and even
+MySQL), but they can't require (say) Redis or Ruby or NodeJS.