You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 11 Next »

Background

This document is intended to provide guidance to anyone writing code against COmanage Registry PE (v5.0.0 or later), including plugin developers. It describes various facilities developed for COmanage specifically, to help make it easier to write DRY code.

Prerequisites

Before continuing, be sure to be familiar with the following:

  1. PHP, and in particular newer PHP features such as
    1. Traits
    2. Named Arguments
  2. CakePHP v4 and the MVC design pattern
  3. The Registry Data Model (and the Technical Manual in general)

PHP 8

Registry PE is targeting PHP 8+. In particular:

  1. Function calls should be typed, including the return type.

Adding New Models

Data Model and Functional Design

Before writing any code, start by proposing changes to the existing data model (which may include defining new tables that will map to the new models added to the application). Build a proposed functional design around the data model changes. For code that will be contributed to the project, review these designs with the development group before beginning any meaningful coding, since code that does not align with the project's direction will not be accepted.

schema.json

Schema management is handled by Doctrine DBAL, using a Registry specific JSON schema file processed by DatabaseCommand. The format of the schema file is fairly self documenting, but note the following:

  • The columnLibrary provides default definitions for commonly used attributes. These defaults will be used when the table defines a column name with the same name as the library definition. All library values are inherited by default, it is then only necessary to explicitly define the ones that should be changed.
  • Index names must be explicitly specified (as opposed to autogenerated) so that if the index definition changes DBAL can recompute the index. (This is much more efficient than the previous ADOdb based system, which rebuilt all indexes on the table any time the table was changed in any way.)
    • In general, do not define unique constraints on indexes, as they will conflict with Changelog Behavior. Uniqueness can be enforced using Application 
      Rules.
  • Cake's Timestamp fields will be automatically inserted, unless timestamps is set to false in the table definition.
  • Fields for Changelog Behavior will be automatically inserted, unless changelog is set to false in the table definition.
  • For attributes that can be created via Registry Pipelines, setting sourced to true will insert the necessary foreign key and index.
  • For Multi-Valued Entity Attributes (MVEAs), setting mvea to a list of parent tables will insert the necessary foreign keys and indexes.

Note that since JSON files inexplicably can't have comments, the key comment is reserved in all contexts except the list of column definitions to be used for comments.

Application Rules

"Implicit logic" must be documented in the form of Application Rules.

Application Rules are typically enforced using Cake's Application Rules, which are applied to a table using the table's buildRules() function. By convention, COmanage rules are named ruleSomethingOrOther(), and are defined in the table they apply to. Rules common to multiple tables should be implemented in RulesTrait. Global rules that apply to all tables are implemented in the RuleBuilderEventListener.

Application Rules must be labeled in a comment adjacent to the code that enforces them using the form AR-Model-#, that is the string "AR-", the camel cased singular model name, a dash, and the number of the rule for that model (for example: AR-ApiUser-3). Global rules are referred to as General Model Rules, and are labeled AR-GMR-#.

In general, Application Rules are not configurable.

Transmogrification

For migration of Registry tables from v4 to v5, appropriate support for migrating existing data must be added to TransmogrificationCommand.

Each table must be added to $tables in the same order as schema.json (ie: to correctly sequence the population of primary keys). By default, fields are mapped 1-1 unless configured via fieldMap. (The displayField is used when Transmogrification is running.)

In some cases, a custom mapping function is required to calculate the target table value. In some of these cases, results from an earlier table should be cached so later mapping actions can quickly find earlier values. This is accomplished with the cache entry.

If a table was not previously Changelog enabled but is Changelog enabled in v5, the key addChangelog must be set to true.

Boolean fields must currently be explicitly identified in the booleans entry.

Logging

XXX

Testing

XXX

Documentation

  • Application Rules must be documented as described above.
  • Functional documentation should be added to the Technical Manual.
  • The Data Model must be updated.
  • The REST API documentation must be updated, if needed.

Leveraging DRY Patterns

Registry builds various utilities on top of the Cake framework.

Authorization (RegistryAuth Component)

XXX

Behaviors

Changelog Behavior

XXX

Log Behavior

XXX

Enumerations

XXX

Localizations

When localizing text strings, use the table name and/or field name as is whenever possible.

Traits

Common code used to be placed in AppModel, which led to a large and complicated pile of code. In general, common functionality is now implemented using traits.

AutoViewVars Trait

XXX

PrimaryLink Trait

The Primary Link of a table is the foreign key to the most significant parent object, typically co_id or person_id. The Primary Link is used to automatically determine permissions, generate links, and other similar purposes.

Redirect Goals

After adding or editing an entity, different models may have different user experiences for where to go next. The selection of a redirect target can be controlled by setting a Redirect Goal. Currently supported Redirect Goals are

  • index: Redirect to the index for the model, filtered by the Primary Link
  • primaryLink: Redirect to the Primary Link entity
  • self: Re-render the same form

Models

Determining the Current CO

In general, model code should obtain the current CO via parameters passed to the functions it implements, either directly (when there is no other parameter that implies a CO) or indirectly (when another parameter, such as $personId, can be used to calculate the CO). The function findCoForRecord (implemented in PrimaryLinkTrait) can be helpful.

In rare cases, it may be necessary to determine the CO by other means, for example in order to adjust validation rules based on the current CO. Models can setAcceptsCoId on their table (again via PrimaryLinkTrait), and AppController will then provide the CO to the table as part of setCO. Note this currently works only for the primary table of the request and its immediate relations.

Validation and Application Rules

XXX

Views

columns.inc

Appending a Custom String

It is possible to append a custom string (such as "Primary Link") to a field in the index view on a per-record basis using the append directive. The value is a function implemented on the entity. For example,

templates/Names/columns.inc
$indexColumns = [
  'type_id' => [
    'type' => 'fk',
    'append' => 'primaryLabel'
  ]
]

when rendering the field type for the index of names, $name→primaryLink(): string will be called and the returned string will be appended with a comma to the string for the current value of the type foreign key. The result will be something like "Official, Primary Name".

fields.inc and FieldHelper

XXX

Custom Display Fields

By default, the display field used for a model is whatever is set using Cake's setDisplayField. However, tables can implement model-specific display logic by implementing generateDisplayField($entity): string.

  • No labels