Related links
Sales & Asset management
Sales related services
Description of a part of the AM module - sales partFI - Finance Management
Framework Core functionality
- AyMINE Framework Server
- frmFrm – provided functionality
- System Rights
- System messaging
- AyMINE Business – Price calculation
- Strings and translations
- Export collection of objects
- AyMINE Framework management FAQ
- The AyMINE licence model
- AyMINE On-premise
- System events
- Mutli-client architecture
- Import collection of objects
- User sessions
- Default server methods
- Client-defined object attributes
- Common Libraries
Module - support for management
Libraries & Lincences
Mobile & Web Application
- Runtime debugging
- System console
- AyMINE Application
- In-line table edit support
- Object scripting API – object lang
- Application object structure
- Multilingual support
- View of a single object – detail
- Is using EVAL / feval method risky?
- Included library – String operations
- Cliplink
- Object API – object <g>
- API – Data object
- Object scripting API – object User
- Object view definition
- Framework support for Drag & Drop
- Common libraries
- Multiple-object update implementation
- fClip & fCliplist
- Offline persistent objects
- Mobile application
HR - Human Resources
System Management (part of framework)
Task, Project, Quality
Task & Task pattern
CMS - Content Management & Web API services
Report hierarchical objects
AyMINE report engine supports generation of the hierarchical object structure.
Typically, the children objects are of the same type as the parent objects (like subtasks under the master task). We call them genuine children. But the hierarchical reports can be used even when child objects are various (e.g. all object stored in the baseline repository.)
Generate report with genuine children
When children have the same type as parent, all objects are generated from the same report template. Report support infinite depth of children.
The template for hierarchical object structure should contain a tag where to put the children:
<body>
<h1>@name</h1>
// object report definition
@children
// optional object report part after the children section
</body>
The template contains template pattern inserted instead of @children
if children are available:
<subitems>
<h2>Children section name</h2>
<div class="subreports">
<table class="noVisible">
<tr>
<td style="width:5%;border-top:none"> </td>
<td style="width:95%;border-top: none">@subitems</td>
</tr>
</table>
</div>
</subitems>
The example creates report with children indented 5% from left
Report generation
public static function getReport(reportDesc $rep): htmlPattern
{
// Create report pattern for parent object
$rep->setTemplateName(); // creates report with default name
$pat = htmlPattern::init($rep); // create location where is stored the the parent report
// build parent report
// check if there are children
$childrenID = $tskDB->getSQLIDList("<select children>");
if ($childrenID) {
// reuse the report pattern for children
// pattern (object reportDesc) is the same for children
// but children are generated to the new report storage (object htmlPattern)
$childPat = $rep->reusePattern = null;
foreach ($childrenID as $childID) {
$rep->objID = $childID;
// all children are reported one after another to the same htmlPattern
$childPat = static::getReport($rep);
}
// complete the children generations
$childPat->finalizeReport();
// Change level of header so that they have sub-header level (from h1->h2 etc.)
$childPat->shiftHeader();
// Put all generated children reports to the parent report
$pat->fillPlaceTag('subitems', ['subitems' => $childPat->superbody]);
} else {
// If parent has no children, remove the @subitems from the pattern
$pat->fillSingle('subitems', '');
}
return $pat; // return generated report
}
Description of the steps in the method
The method creates new placement where is the report generated only if the placement is not yet created:
$pat = htmlPattern::init($rep);
$pat contain instance of with the location, but location is also referenced by the $rep->reusePattern
attribute of the reportDesc. If method getReport is called several times for several sibbling, new htmlPattern is not generated for each sibling. All siblings are generated one after another – see more in the section generate list of siblings. However,:
$childPat = $rep->reusePattern = null;
removes the reference to the htmlPattern from the reportDesc $rep
and so, when function getReport is called for 1st child, it creates new htmlPattern location for children.
Put children to the parent report
All children have generated report in the single report stored in the $childPat variable. The report is placed to the $childPat in the line
$childPat = static::getReport($rep);
because the last line of the method returns that return $pat;
.
Let' note that after the children generation, the returned htmlPattern with the children reports is also in the $rep->reusePattern
attribute, i.e. $rep->reusePattern == returned $pat
; But the $pat variable in the parent report method contain report of the parent, not the children.
The line:
$pat->fillPlaceTag('subitems', ['subitems' => $childPat->superbody]);
puts the generated report with children to the report of the $parent.
The fillPlaceTag method:
- Finds template pattern with the name from the 1st attribute (subitems in the example) in the report definition
- Fill all fields in the template pattern using the array in the second attribute. It creates from the template pattern the filled block
- Replaces the pattern placement with the same name in the $pat report with the filled block (the filled block replaces the @subitems in the example).
When object has no children report script should remove the pattern placement from the report. It is made by:
$pat->fillSingle('subitems', '');
line that replace the @subitems placement by empty string.
Generate "children" of various types
Some objects have children of various types. E.g. a project have several types of children as well as baseline in the configuration management. However, there are significant differences between both examples:
- Although project has several types of subordinated objects (like plans, requirements, tasks etc.) they are generally known because they are pre-defined by the project methodology. The report for project could make section for each object from the report management
- On the other hand, Baseline has not pre-defined objects and report cannot count with that. It should be able to report all kinds object configuration items.
This section describes how to create reports with the overview of the uknonwn list of children objects. It is made similarly with as is desribes for gunine children herinbefore, so that only differences are described here.
While gunine children uses the same report pattern as the parent object and all children siblings uses the same report pattern the arbitrary children uses their own patterns. For each child should be used the appropriate pattern.
How is the right report pattern selected
Name of the report patterns follows the same logic for all object. The pattern is called <objectName>-<patternName>
. When pattern name is not specified default
pattern name is used.
Children always use the pattern with the same name as parent object has regardless of the object name.
Example:
Configuration baseline is reported by the report ShortOverview so that, report is generated from the html template tskCMBundle__ShortOverview
.
For each configuration item is called report <objectName>__ShortOverview
, e.g. when a requirement is reported, the template tskRequirement__ShortOverview
is used.
Generate reports with ungenuine children
The following code is a part of the getReport function that generates report of various children. Children are grouped by the object type (objectName).
// get list of children object names
$setObjects = $dbo->query("SELECT distinct objectName, count(0) as objC from ...");
// go over all of them
foreach ($setObjects as $objInfo) {
// get list of childern IDs for the $objInfo->objectName object type
$objList = $tskDB->getSQLIDList(
"SELECT objectID
FROM <... table for objectName>
WHERE <... id field anme> = $rep->objID and objectName='$objInfo->objectName'
order by 1"
);
// get name of the object ($objInfo->objectName) translated to the report language ($rep->lang)
$objInfo->objTrans = langProvider::getObjName($objInfo->objectName, $rep->lang);
$objTrans = new langProvider::getObjName($objInfo->objectName, $pat->lang);
$objTrans->loadObjectLang($objInfo->objectName);
// Write header for section with objects:
$objectSuperbody .= '<h2 class="sectionHeader">' . $plural . '</h2>';
// Clear report pattern – new type of object requires new report pattern
$report = null;
try {
// Create report description for new type of objects
$childRep = new reportDesc(
$objInfo->objectName, // name of the object
null, // objectID – filed later in the cycle
$rep->lang, // report language
$rep->templateName, // copy the template name – the same name is used in all levels
$rep->format // use the same format (html / text / markdown) at all levels
);
// Generate reports for all object of the type objectName
foreach ($objList as $objID) {
$childRep->objID = $objID;
// Put the htmlPattern that is used for all children – each part is placed at the end
$childRep->reusePattern = $report;
$report = $objInfo->objectName::getReport($childRep);
}
// Complete the section for single object type but does not finalise until all children objects will be generated
$report->prepareForNext();
$report->shiftHeader();
$objectSuperbody .= $report->superbody;
if (isset($childRep->userTag) && $childRep->userTag != []) {
$objInfo->groupedMultiEnum = implode(' ', $childRep->userTag);
} else $objInfo->groupedMultiEnum = '';
$pat->fillTagToPart('objOverview', 'objOverview', $objInfo);
} catch (\Throwable $th) {
$objectSuperbody .= "<p>Error: missing object template?</p>";
}
}
Note:
Translation of the object name is loaded from the objectName counter by line:
$objInfo->objTrans = langProvider::getObjName($objInfo->objectName, $rep->lang);
The command returns singular translation, not plural. AyMINE mostly have also plural version translated and the plural is available by using calls:
$objTrans->loadObjectLang($objInfo->objectName);
$plural = $objTrans->get("$objInfo->objectName.plural"); // Warning: EXPENSIVE
However this call is rather time consuming and so not recomended for more complex scripts. If plural translation are often used, write their translation to the m_<module>Lang
file.