CRUD Generator
Github Generator URL : https://github.com/PHPCreation/frontend-components-crud-react-generator (opens in a new tab)
Unlike the other projects, this project do not depend of any other project.
It create the Generate Files for any project, just some modificatoin to do before generating and here's the link
Description
What is CRUD generator ?
A generator is a special type of function which does not return a single value, instead, it returns an iterator object with a sequence of values. In a generator function, a yield statement is used rather than a return statement. CRUD generator is new feature added typically to require multiple, repetitive operations that we have to repeat each time we define a new resource. To realise this feature, we used Node CLI, for more information about Node CLI there is documentation Node CLI in the Tech section.
CRUD generator architecture
Explain architecture
As we can see throw the architecture there are many parts in the project, for the generated files, it all exist in config/generateFiles file and to create that we needed other save attribut from the API such as Fields and finally we have 4 major parts that create the CRUD generator :
Explain Code details
Ticket Template
To generate CRUD template special for each entity we have to make functions for each different bloc
that containes specific attributs and logic that defined in config-template.tsx.
For example :
// Base FQCN
const fqcn_bui: IFQCN_BUI = {
Bundle: [bundle],
Unit: [unit],
Interface: 'base'
};
To specific the variables to modify we have to put it between [ ... ].
In the previeus part of code each entity have unique [bundle] and [unit], so the function in ticket-template :
/**
* AddFQCN
* @param {*} entityName
* @param {*} outputPath
*/
function AddFQCN (entityName,outputPath) {
console.log('Start : add FQCN ',start);
let simpleName = entitySimpleName(entityName)
const bundle = 'ticketCrud';
modifyFile(outputPath, '[bundle]', '\''+bundle+'\'');
modifyFile(outputPath, '[unit]', '\''+simpleName+'\'');
console.log('End : add FQCN',end);
console.log('Execution : ', (end - start)*1000);
}
Result exapmle :
/*
* FQCN
*/
// Base FQCN
const fqcn_bui: IFQCN_BUI = {
Bundle: 'ticketCrud',
Unit: 'Ticket',
Interface: 'base'
};
Functions.js
In functions.js (that exist in ./utils/) we define the re-uses functions that can be declared in different template functions, for example :
function modifyFile (filePath, modifyRegex, modifyString ) {
const fileContent = fs.readFileSync(filePath, 'utf8');
const fileContentReplaced = fileContent.replace(modifyRegex, modifyString);
recreateNewRawFile (filePath, fileContentReplaced)
}
function readJsonFile (filePath) {
let jsonObj;
console.log(filePath);
const fileContent = fs.readFileSync(filePath, 'utf8');
jsonObj = JSON.parse(fileContent);
return jsonObj;
}
Ticket API
To get the DATA form the API ressources, there is an async functions that manage the MetaData endpoint and with different requests. The next example explain how to get the data and stock the fields in files :
async function apiTicketRequest(baseUrl, apiUrlEndpoint, serialisation, requiredField, apiMetode = 'get') {
let resMetadataEntity = '';
const token = fs.readFileSync('./config/token.txt', 'utf8');
if (serialisation != undefined) {
resMetadataEntity = await axios({
method: apiMetode,
url: baseUrl + apiUrlEndpoint + serialisation,
headers: {
Authorization: token
}
});
} else if (requiredField != undefined) {
resMetadataEntity = await axios({
method: apiMetode,
url: baseUrl + apiUrlEndpoint + requiredField,
headers: {
Authorization: token
}
});
} else {
resMetadataEntity = await axios({
method: apiMetode,
url: baseUrl + apiUrlEndpoint,
headers: {
Authorization: token
}
});
}
return resMetadataEntity;
}
Ticket Process
To manage the functions of ticket template we created in ticket-template and DATA we got from ticket-api
we organise the process in ticket-process to be more easier to controle CRUD generator.
The next Code explain how get the Data for each entity (with comments for more explaination):
async function MetaDataEntity (baseUrl,entityName,fieldsPath,serializationPath,showFieldsPath,listingFieldsPath,requiredFieldsPath) {
console.log('Start : Meta Data Entity ',start);
// Use data from API
let fieldsMetadata = await MetaDataEntityList(baseUrl,entityName);
let resourceName = await ResourceNameList(baseUrl,entityName);
// let serializationGroup = await SerializationGroup(baseUrl,entityName);
//decomment ca si tu as besoin des fields de listinf et show
let showField = await SerializationShowFields(baseUrl,entityName);
let listingField = await SerializationListingFields(baseUrl,entityName);
let requiredField = await RequiredFields(baseUrl,entityName)
// save data
recreateStringFile (fieldsPath,fieldsMetadata);
// recreateStringFile (serializationPath,serializationGroup);
//decomment ca si tu as besoin des fields de listinf et show
recreateStringFile (showFieldsPath,showField);
recreateStringFile (listingFieldsPath,listingField);
recreateStringFile (requiredFieldsPath,requiredField);
// create template
let simpleName = entitySimpleName(entityName);
const templatePath = './config/config-template.tsx'
let docPath = recreateFolder(simpleName);
let outputPath = `${docPath}/index.tsx`;
CreateConfigFromTemplate (templatePath,outputPath);
replacefields (simpleName,fieldsPath,showFieldsPath,listingFieldsPath,requiredFieldsPath,resourceName,outputPath);
console.log('Fields saved');
console.log('End : Meta Data Entity ',end);
console.log('Execution : ', (end - start)*1000);
}
Other example containes the ordre of functions to fill the variable blocs :
function replacefields (entityName,fieldsPath,showFieldsPath,listingFieldsPath,requiredFieldsPath,resourceName,outputPath) {
HeaderInformation(outputPath)
AddFQCN(entityName,outputPath)
AddResource(resourceName,outputPath)
let showFields = readJsonFile(showFieldsPath)
let listingFields = readJsonFile(listingFieldsPath)
let requiredField = readJsonFile(requiredFieldsPath)
let allFields = readJsonFile(fieldsPath)
let filtredFormFields = limitedFormObj(requiredField)
let requiredselectedField = limitedselectedObj(requiredField)
AddFieldsExport(listingFields,outputPath)
AddFieldsAll(listingFields,outputPath)
AddSelectedList(requiredselectedField,outputPath)
AddFormModalInputs(filtredFormFields,outputPath)
AddMainColumns(listingFields,outputPath)
AddFormInputs(allFields,outputPath)
AddFilterFields(requiredselectedField,resourceName,outputPath)
AddSideBoxs(showFields,outputPath)
AddDisplayFields(showFields,outputPath)
AddqField(entityName,outputPath)
}
index.js
Finally in index.js as explained in the tech part of the documentation it is the executable file
that generate all the CRUD files and initialize the flags.
Example of executable function :
if (input.includes('token')) {
RegenerateToken(baseUrl,devUsername,devPassword)
}
To execute this function make sure to be in the correcte path and run : ./index.js token
Example of initializing the flags :
let baseUrl = flags.baseUrl;
let devUsername = flags.devUsername;
let devPassword = flags.devPassword;
Manual Modification of Generator
Before generating new files you have to change :
- Verify config-template is tsx not txt (in ./)
- Flags are in CLI and we have to change the base URL flag and bundleCrud flag with the correct ones (in ./utils/cli.js)
- In ticket-process check your 'replacefields' which list you have to pass in each part of the template (in ./)
Manual Modification of Generated files
Modification to do when you put the the generated files in project to use it :
- Delete empty
type
in main columns . - For foriegn key change 'title" in main columns with le correcte name of the entity, example :
title: 'status',
=>title: 'ticket_statuses',
. - For FormInputItem change
targetResourceAsync: 'impact',
if its foriegn key totargetResourceAsync: 'ticket_impacts',
. - For FormInputItem change
prefixOnSubmit: '/api/v1/impact/',
if its foriegn key toprefixOnSubmit: '/api/v1/ticket_impacts/',
. - In filter attributs if its foriegn key change
targetResourceAsync:'impact',
totargetResourceAsync:'ticket_impacts',
. - In sideBoxes change the subresource to the correcte entity name (exp :
impact
toticket_impacts
) and add fields you want to show (id exist by default). - In displayFields if link of IRI isn't right fix entity name example :
{ key: 'impact.id' , path: 'impact.impact', entity: 'impact', type: 'iri' },
to :{ key: 'impact.id' , path: 'impact.impact', entity: 'ticket_impacts', type: 'iri' },