| Version | Date | Notes | By |
|---|---|---|---|
| 0.1 | 2018-10-23 | Initial release | ROB |
This system allows for an artifact to define a coding structute and for a using artifact to use / store the code generated by the coding structure, incrementing it according to whatever rules the structure defined. In time it might replace the various specific code generating methods independently implemented in the various modules.
In the backend there are two traits that must be used in order to form this definer / user artifact pair, the DefinesGenericCode and the UsesGenericCode (For example the OccurrenceType model implements the DefinesGenericCode and the Occurrence model implements the UsesGenericCode).
Moving to the frontend, the way to display the generic code defining interface is by using the following compose:
<compose if.bind="generic_code_params" view-model="wemake-modules/administration/generic-code-definitions/single-definition-form-component/index" model.bind="generic_code_params"></compose>
and defining the following object (compose's model) in the viewModel:
this.generic_code_params = {
// Object containing / storing code definitions
definition: this.model.generic_code_definitions[0],
// label (this component collectively behaves as if it were part of a form)
label: {
name: 'form.field.code',
required: true
},
// This is an array of fields (of the using artifact) allowed to influence the generation of the code
// NOTE: this may be moved to the backend in the future.
allowed_usage_fields: [
{
id: 'year',
name: this.appContainer.i18n.tr('form.field.year')
},
{
id: 'origin_acronym',
name: this.appContainer.i18n.tr('form.field.origin-acronym')
},
{
id: 'company_organization_acronym',
name: this.appContainer.i18n.tr('form.field.company-organization-acronym')
}
]
};
In the backend, the code definitions will be stored, associated to the defining artifact like so:
// This function converts frontend to local class representations of the generic code
$definingArtifact->convertFromAssociativeArrayToWorkingCollection($frontendGenericCodeDefinitions);
// this function converts the local class representations of the generic code into a single json object
// The json object is stored in the defining artifact, in the 'generic_code_definitions' field by default
$definingArtifact->storeGenericCodeDefinitions();
As you can see from the code above, the defining artifact will require a new text field in the database to store the generic code definition json. It is recomended to use the default generic_code_definitions but this is possible to change by adding the code bellow to the defining artifact model:
/**
* @var String - define the field where the definitions json will be stored.
*/
private $genericCodeDefinitionsField = 'generic_code_definitions';
In the frontend, the following special field must be included so as to display a preview / editable version of the code that will be attributed to that using artifact:
// Add this field to form schema of using artifact create or edit form
this.code_preview = {
type: 'gcs-using-artifact-code-preview',
key: '__code_preview',
label: 'form.field.code-preview',
size: 6,
options: [],
required: false,
// the code definition that applies goes here
definition: null,
// the object instance that stores the values goes here
incrementor_values: null,
// the object instance that serves to detect if there where changes made
// by the user or by the backend goes here
incrementor_values_dirty_check: null
};
The idea of dirty checking is important to the way the generic code generator works. In certain cases, certain code parts may be editable by the user, but also depend on (be generated by) changes in the using artifact's fields. If the user edits a code part, then changes in the other fields should stop changing that part of the code (e.g.: is dirty).
In the backend, store the code parts, incrementors and user made changes using this code (in a controller or builder).
$definingArtifactModel->storeIncrementorsInArtifact($usingArtifactModel, 'code', $incrementorValuesData);
It is also possible to generate the code as one single string using the function:
$codeString = $definingArtifact->getFullSugestionCode(UsingArtifact::class, 'code', $variableWithFrontendChangesToCode)
You may validate the information sent by the frontend like so:
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
/* Code */
// Generic code system validations
$genericCodeValidations = $definingArtifact->generateGenericCodeRequestRules(UsingArtifact::class, 'code');
// Merge both rule sets.
$rules = collect($rules)
->merge($genericCodeValidations)
->toArray();
/* ... */
return $rules;
}
/**
* Set custom attributes for validator errors.
*
* @return array
*/
public function attributes()
{
/* Code */
// Generic code system attributes
$genericCodeAttributes = $definingArtifact->generateGenericCodeRequestAttributes(UsingArtifact::class, 'code');
// Merge both attribute sets
$attributes = collect($attributes)
->merge($genericCodeAttributes)
->toArray();
/* ... */
return $attributes;
}
CRITICAL
The fact that code portions of the using artifact can be edited (either directly or through using artifact's fields) by the user means that the code must be rebuilt by using a series of observers on both the fields we expect to change and the code parts themselves to see if they change / are changed and a backend endpoint to retrieve the new valid code part configuration, means that there is a lot of specific / repeated code in this area.
That makes this part of the process the "weakest link" and this should be changed as fast as possible (see how it has been implemented in occurrences).