@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
