@startuml participant Controller participant ExportManager as em participant SelectedExport as se participant Formatter as f collections aggregators as aa collections filters as ff activate Controller Controller -> em: ExportManager::generate(string 'export_alias', Centers[], $data, $formatterdata) activate em note left $data contains the data from the export form (export form + aggregators form + filters forms) end note em -> se: Export::initiateQuery($modifiers, $acl, $data) activate se note left $modifiers contains the selected modifiers and their data. Usually you can ignore this. $acl contains the list of selected centers. The export must check that the user has the right to compute the export for this center $data the data from the export form (if the export build a form with `buildForm` function end note create Query as q se -> q: the export will create a query se -> em: return the query deactivate se alt The query is a "native sql query" note over em, se When the export create a native query, there aren't any filters or aggregators which can alter the query. We immediatly get the results from the query. end note else "The query is a query builder" note over em, se As the query is a query builder, filters and formatters will be able to alter the query. end note loop for each filter selected by user em -> ff: FilterInterface::alterQuery(query, $data) activate ff note over em, ff The filter will alter query, adding his own clause (i.e. WHERE clause). It is his responsability to avoid removing clauses added by other filters / aggregators. The ExportManager will also transmit the $data filled by the user (if the filter has a form) to each filter / aggregator. end note ff -> q: append some clauses deactivate ff end loop for each aggregator selected by user note over em, aa As of filter, aggregators will append their own clauses in the query (usually GROUP BY clause). end note em -> aa: AggregatorInterface::alterQuery(query, data) activate aa aa -> q: append some clauses deactivate aa end end alt note over se The query is now ready. We will fetch the results from databases. The Export is responsible for getting the results end note em -> se: Export::getResult(query, $data) activate se se -> q: getResult() activate q q -> se: return result destroy q se -> em: return result deactivate se em -> f: FormatterInterface::getResponse() activate f note over f, ff The formatter will ask the export, and each aggregators the keys they are responsible for. Then, for each of those keys, he will ask to each participant (Export or aggregator) a Closure, which will render the value in results into a human readable string. end note f -> se: getQueryKeys activate se se -> f: return string[] loop for each keys the export is responsible for f -> se: ExportInterface::getLabel() create "closure for key export" as closuree se -> closuree: create a closure se -> f: return closure end loop for each aggregator f -> aa: getQueryKeys() activate aa aa -> f: return string[] deactivate aa loop for each keys the aggregator is responsible for f -> aa: getLabel() activate aa create "closure for key aggregators" as closureg aa -> closureg: create a closure aa -> f: return closure deactivate aa end end loop over results note over f, closureg Each row in result will be transformed in a human readable format by the closure. The human readable string will be appended by the Formatter in his response (a Spreadsheet, CSV file, ...) end note f -> closuree: call activate closuree closuree -> f: return a human readable format for this value deactivate closuree f -> closureg: call activate closureg closureg -> f: return a human readable format for the value deactivate g f -> f: append the result in his response end f -> em: return a Response deactivate f em -> Controller: return a Response deactivate em deactivate Controller @enduml