Path: blob/master/src/applications/fact/chart/PhabricatorChartFunction.php
12256 views
<?php12abstract class PhabricatorChartFunction3extends Phobject {45private $argumentParser;6private $functionLabel;78final public function getFunctionKey() {9return $this->getPhobjectClassConstant('FUNCTIONKEY', 32);10}1112final public static function getAllFunctions() {13return id(new PhutilClassMapQuery())14->setAncestorClass(__CLASS__)15->setUniqueMethod('getFunctionKey')16->execute();17}1819final public function setArguments(array $arguments) {20$parser = $this->getArgumentParser();21$parser->setRawArguments($arguments);2223$specs = $this->newArguments();2425if (!is_array($specs)) {26throw new Exception(27pht(28'Expected "newArguments()" in class "%s" to return a list of '.29'argument specifications, got %s.',30get_class($this),31phutil_describe_type($specs)));32}3334assert_instances_of($specs, 'PhabricatorChartFunctionArgument');3536foreach ($specs as $spec) {37$parser->addArgument($spec);38}3940$parser->setHaveAllArguments(true);41$parser->parseArguments();4243return $this;44}4546public function setFunctionLabel(PhabricatorChartFunctionLabel $label) {47$this->functionLabel = $label;48return $this;49}5051public function getFunctionLabel() {52if (!$this->functionLabel) {53$this->functionLabel = id(new PhabricatorChartFunctionLabel())54->setName(pht('Unlabeled Function'))55->setColor('rgba(255, 0, 0, 1)')56->setFillColor('rgba(255, 0, 0, 0.15)');57}5859return $this->functionLabel;60}6162final public function getKey() {63return $this->getFunctionLabel()->getKey();64}6566final public static function newFromDictionary(array $map) {67PhutilTypeSpec::checkMap(68$map,69array(70'function' => 'string',71'arguments' => 'list<wild>',72));7374$functions = self::getAllFunctions();7576$function_name = $map['function'];77if (!isset($functions[$function_name])) {78throw new Exception(79pht(80'Attempting to build function "%s" from dictionary, but that '.81'function is unknown. Known functions are: %s.',82$function_name,83implode(', ', array_keys($functions))));84}8586$function = id(clone $functions[$function_name])87->setArguments($map['arguments']);8889return $function;90}9192public function getSubfunctions() {93$result = array();94$result[] = $this;9596foreach ($this->getFunctionArguments() as $argument) {97foreach ($argument->getSubfunctions() as $subfunction) {98$result[] = $subfunction;99}100}101102return $result;103}104105public function getFunctionArguments() {106$results = array();107108$parser = $this->getArgumentParser();109foreach ($parser->getAllArguments() as $argument) {110if ($argument->getType() !== 'function') {111continue;112}113114$name = $argument->getName();115$value = $this->getArgument($name);116117if (!is_array($value)) {118$results[] = $value;119} else {120foreach ($value as $arg_value) {121$results[] = $arg_value;122}123}124}125126return $results;127}128129public function newDatapoints(PhabricatorChartDataQuery $query) {130$xv = $this->newInputValues($query);131132if ($xv === null) {133$xv = $this->newDefaultInputValues($query);134}135136$xv = $query->selectInputValues($xv);137138$n = count($xv);139$yv = $this->evaluateFunction($xv);140141$points = array();142for ($ii = 0; $ii < $n; $ii++) {143$y = $yv[$ii];144145if ($y === null) {146continue;147}148149$points[] = array(150'x' => $xv[$ii],151'y' => $y,152);153}154155return $points;156}157158abstract protected function newArguments();159160final protected function newArgument() {161return new PhabricatorChartFunctionArgument();162}163164final protected function getArgument($key) {165return $this->getArgumentParser()->getArgumentValue($key);166}167168final protected function getArgumentParser() {169if (!$this->argumentParser) {170$parser = id(new PhabricatorChartFunctionArgumentParser())171->setFunction($this);172173$this->argumentParser = $parser;174}175return $this->argumentParser;176}177178abstract public function evaluateFunction(array $xv);179abstract public function getDataRefs(array $xv);180abstract public function loadRefs(array $refs);181182public function getDomain() {183return null;184}185186public function newInputValues(PhabricatorChartDataQuery $query) {187return null;188}189190public function loadData() {191return;192}193194protected function newDefaultInputValues(PhabricatorChartDataQuery $query) {195$x_min = $query->getMinimumValue();196$x_max = $query->getMaximumValue();197$limit = $query->getLimit();198199return $this->newLinearSteps($x_min, $x_max, $limit);200}201202protected function newLinearSteps($src, $dst, $count) {203$count = (int)$count;204$src = (int)$src;205$dst = (int)$dst;206207if ($count === 0) {208throw new Exception(209pht('Can not generate zero linear steps between two values!'));210}211212if ($src === $dst) {213return array($src);214}215216if ($count === 1) {217return array($src);218}219220$is_reversed = ($src > $dst);221if ($is_reversed) {222$min = (double)$dst;223$max = (double)$src;224} else {225$min = (double)$src;226$max = (double)$dst;227}228229$step = (double)($max - $min) / (double)($count - 1);230231$steps = array();232for ($cursor = $min; $cursor <= $max; $cursor += $step) {233$x = (int)round($cursor);234235if (isset($steps[$x])) {236continue;237}238239$steps[$x] = $x;240}241242$steps = array_values($steps);243244if ($is_reversed) {245$steps = array_reverse($steps);246}247248return $steps;249}250}251252253