Path: blob/master/src/applications/fact/chart/PhabricatorComposeChartFunction.php
12256 views
<?php12final class PhabricatorComposeChartFunction3extends PhabricatorHigherOrderChartFunction {45const FUNCTIONKEY = 'compose';67protected function newArguments() {8return array(9$this->newArgument()10->setName('f')11->setType('function')12->setRepeatable(true),13);14}1516public function evaluateFunction(array $xv) {17$original_positions = array_keys($xv);18$remaining_positions = $original_positions;19foreach ($this->getFunctionArguments() as $function) {20$xv = $function->evaluateFunction($xv);2122// If a function evaluates to "null" at some positions, we want to return23// "null" at those positions and stop evaluating the function.2425// We also want to pass "evaluateFunction()" a natural list containing26// only values it should evaluate: keys should not be important and we27// should not pass "null". This simplifies implementation of functions.2829// To do this, first create a map from original input positions to30// function return values.31$xv = array_combine($remaining_positions, $xv);3233// If a function evaluated to "null" at any position where we evaluated34// it, the result will be "null". We remove the position from the35// vector so we stop evaluating it.36foreach ($xv as $x => $y) {37if ($y !== null) {38continue;39}4041unset($xv[$x]);42}4344// Store the remaining original input positions for the next round, then45// throw away the array keys so we're passing the next function a natural46// list with only non-"null" values.47$remaining_positions = array_keys($xv);48$xv = array_values($xv);4950// If we have no more inputs to evaluate, we can bail out early rather51// than passing empty vectors to functions for evaluation.52if (!$xv) {53break;54}55}565758$yv = array();59$xv = array_combine($remaining_positions, $xv);60foreach ($original_positions as $position) {61if (isset($xv[$position])) {62$y = $xv[$position];63} else {64$y = null;65}66$yv[$position] = $y;67}6869return $yv;70}7172public function getDataRefs(array $xv) {73// TODO: This is not entirely correct. The correct implementation would74// map "x -> y" at each stage of composition and pull and aggregate all75// the datapoint refs. In practice, we currently never compose functions76// with a data function somewhere in the middle, so just grabbing the first77// result is close enough.7879// In the future, we may: notably, "x -> shift(-1 month) -> ..." to80// generate a month-over-month overlay is a sensible operation which will81// source data from the middle of a function composition.8283foreach ($this->getFunctionArguments() as $function) {84return $function->getDataRefs($xv);85}8687return array();88}8990}919293