Skip to content

Commit 750de6d

Browse files
committed
More typing
1 parent 12db529 commit 750de6d

File tree

9 files changed

+122
-48
lines changed

9 files changed

+122
-48
lines changed

lib/MC/Google/Visualization.php

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,32 @@
2222
*
2323
* @see \Tests\VisualizationTest
2424
*
25-
* @phpstan-type FieldSpec array{callback?:callable,field?:string,extra?:array,fields?:string[],sort_field?:string,type?:string,join?:string}
25+
* @phpstan-type FieldSpec array{
26+
* type: string,
27+
* field?: string,
28+
* fields?: string[],
29+
* callback?: callable,
30+
* extra?: mixed[],
31+
* sort_field?: string,
32+
* join?: string
33+
* }
34+
* @phpstan-type QueryParsed array{
35+
* select?: array<string|string[]>,
36+
* from?: string,
37+
* where?: null|array<array{type: string, value: string}>,
38+
* groupby?: string[],
39+
* pivot?: string[],
40+
* orderby?: string[],
41+
* limit?: string,
42+
* offset?: string,
43+
* label?: string
44+
* }
45+
* @phpstan-type Entity array{
46+
* table: string,
47+
* fields: array<string, FieldSpec>,
48+
* joins: string[],
49+
* where?: string
50+
* }
2651
*/
2752
class Visualization
2853
{
@@ -37,7 +62,7 @@ class Visualization
3762
/**
3863
* The entity schema that defines which tables are exposed to visualization clients, along with their fields, joins, and callbacks.
3964
*
40-
* @var array
65+
* @var array<string, Entity>
4166
*/
4267
protected $entities = [];
4368

@@ -60,7 +85,7 @@ class Visualization
6085
/**
6186
* If a format string is not provided by the query, these will be used to format values by default.
6287
*
63-
* @var array
88+
* @var array<string, string>
6489
*/
6590
protected $defaultFormat = [
6691
'date' => 'm/d/Y',
@@ -156,8 +181,8 @@ public function setDefaultFormat(string $type, string $format): void
156181
* Handle the entire request, pulling the query from the $_GET variables and printing the results directly
157182
* if not specified otherwise.
158183
*
159-
* @param bool $echo print response and set header
160-
* @param null|array $queryParams query parameters
184+
* @param bool $echo print response and set header
185+
* @param null|array{tq:string, tqx:string, responseHandler?:string} $queryParams query parameters
161186
*
162187
* @return string the javascript response
163188
*
@@ -199,22 +224,22 @@ public function handleRequest(bool $echo = true, ?array $queryParams = null): st
199224
/**
200225
* Handle a specific query. Use this if you want to gather the query parameters yourself instead of using handleRequest().
201226
*
202-
* @param string $query the visualization query to parse and execute
203-
* @param array $params all extra params sent along with the query - must include at least "reqId" key
227+
* @param string $query the visualization query to parse and execute
228+
* @param array<string, float|int|string> $params all extra params sent along with the query - must include at least "reqId" key
204229
*
205230
* @return string the javascript response
206231
*/
207232
public function handleQuery(string $query, array $params): string
208233
{
209-
$reqId = null;
234+
$reqId = -1;
210235
$response = '';
211236

212237
try {
213238
if (!$this->db instanceof PDO) {
214239
throw new Visualization_Error('You must pass a PDO connection to the MC Google Visualization Server if you want to let the server handle the entire request');
215240
}
216241

217-
$reqId = $params['reqId'];
242+
$reqId = (int) $params['reqId'];
218243
$queryParsed = $this->parseQuery($query);
219244
$meta = $this->generateMetadata($queryParsed);
220245
$sql = $this->generateSQL($meta);
@@ -236,13 +261,13 @@ public function handleQuery(string $query, array $params): string
236261

237262
$response .= $this->getSuccessClose();
238263
} catch (Visualization_Error $visualizationError) {
239-
$response .= $this->handleError($reqId, $visualizationError->getMessage(), $params['responseHandler'], $visualizationError->type, $visualizationError->summary);
264+
$response .= $this->handleError($reqId, $visualizationError->getMessage(), (string) $params['responseHandler'], $visualizationError->type, $visualizationError->summary);
240265
} catch (PDOException $pdoException) {
241-
$response .= $this->handleError($reqId, $pdoException->getMessage(), $params['responseHandler'], 'invalid_query', 'Invalid Query - PDO exception');
266+
$response .= $this->handleError($reqId, $pdoException->getMessage(), (string) $params['responseHandler'], 'invalid_query', 'Invalid Query - PDO exception');
242267
} catch (ParseError $parseError) {
243-
$response .= $this->handleError($reqId, $parseError->getMessage(), $params['responseHandler'], 'invalid_query', 'Invalid Query - Parse Error');
268+
$response .= $this->handleError($reqId, $parseError->getMessage(), (string) $params['responseHandler'], 'invalid_query', 'Invalid Query - Parse Error');
244269
} catch (Exception $exception) {
245-
$response .= $this->handleError($reqId, $exception->getMessage(), $params['responseHandler']);
270+
$response .= $this->handleError($reqId, $exception->getMessage(), (string) $params['responseHandler']);
246271
}
247272

248273
return $response;
@@ -251,9 +276,11 @@ public function handleQuery(string $query, array $params): string
251276
/**
252277
* Given the results of parseQuery(), introspect against the entity definitions provided and return the metadata array used to generate the SQL.
253278
*
254-
* @param array $query the visualization query broken up into sections
279+
* @param array<string, mixed> $query the visualization query broken up into sections
255280
*
256-
* @return array the metadata array from merging the query with the entity table definitions
281+
* @phpstan-param QueryParsed $query
282+
*
283+
* @return array<string, mixed> the metadata array from merging the query with the entity table definitions
257284
*
258285
* @throws Visualization_QueryError
259286
* @throws Visualization_Error
@@ -704,7 +731,9 @@ public function getGrammar(): Def
704731
*
705732
* @param string $str the query string to parse
706733
*
707-
* @return array the parsed query as an array, keyed by each part of the query (select, from, where, groupby, pivot, orderby, limit, offset, label, format, options
734+
* @return array<string, mixed> the parsed query as an array, keyed by each part of the query (select, from, where, groupby, pivot, orderby, limit, offset, label, format, options
735+
*
736+
* @phpstan-return QueryParsed
708737
*
709738
* @throws ParseError
710739
* @throws Visualization_QueryError
@@ -727,8 +756,10 @@ public function parseQuery(string $str): array
727756
break;
728757

729758
case 'from':
730-
$vals = $token->getValues();
731-
$query['from'] = $vals[1];
759+
$from = $token->getValues();
760+
$from = $from[1];
761+
assert(null !== $from);
762+
$query['from'] = $from;
732763

733764
break;
734765

@@ -744,7 +775,7 @@ public function parseQuery(string $str): array
744775
$groupby = $token->getValues();
745776
array_shift($groupby);
746777
array_shift($groupby);
747-
$query['groupby'] = $groupby;
778+
$query['groupby'] = array_filter($groupby);
748779

749780
break;
750781

@@ -754,7 +785,7 @@ public function parseQuery(string $str): array
754785
}
755786
$pivot = $token->getValues();
756787
array_shift($pivot);
757-
$query['pivot'] = $pivot;
788+
$query['pivot'] = array_filter($pivot);
758789

759790
break;
760791

@@ -784,13 +815,15 @@ public function parseQuery(string $str): array
784815
case 'limit':
785816
$limit = $token->getValues();
786817
$limit = $limit[1];
818+
assert(null !== $limit);
787819
$query['limit'] = $limit;
788820

789821
break;
790822

791823
case 'offset':
792824
$offset = $token->getValues();
793825
$offset = $offset[1];
826+
assert(null !== $offset);
794827
$query['offset'] = $offset;
795828

796829
break;
@@ -803,6 +836,7 @@ public function parseQuery(string $str): array
803836
$count = count($labels);
804837
for ($i = 0; $i < $count; $i += 2) {
805838
$field = $labels[$i];
839+
assert(null !== $labels[$i + 1]);
806840
$label = trim($labels[$i + 1], '\'"');
807841
$queryLabels[$field] = $label;
808842
}
@@ -818,6 +852,7 @@ public function parseQuery(string $str): array
818852
$count = count($formats);
819853
for ($i = 0; $i < $count; $i += 2) {
820854
$field = $formats[$i];
855+
assert(null !== $formats[$i + 1]);
821856
$queryFormats[$field] = trim($formats[$i + 1], '\'"');
822857
}
823858
$query['formats'] = $queryFormats;
@@ -1290,15 +1325,18 @@ protected function getFieldSQL(string $name, array $spec, bool $alias = false, s
12901325
/**
12911326
* Recursively process the dependant fields for callback entity fields.
12921327
*
1293-
* @param array $field the spec array for the field to add (must have a "callback" key)
1294-
* @param array $entity the spec array for the entity to pull other fields from
1295-
* @param array $meta the query metadata array to append the results
1328+
* @param array $fieldSpec the spec array for the field to add (must have a "callback" key)
1329+
* @param array $entity the spec array for the entity to pull other fields from
1330+
* @param array $meta the query metadata array to append the results
1331+
*
1332+
* @phpstan-param FieldSpec $fieldSpec
1333+
* @phpstan-param Entity $entity
12961334
*
12971335
* @throws Visualization_Error
12981336
*/
1299-
protected function addDependantCallbackFields(array $field, array $entity, array &$meta): void
1337+
protected function addDependantCallbackFields(array $fieldSpec, array $entity, array &$meta): void
13001338
{
1301-
foreach ($field['fields'] as $dependant) {
1339+
foreach ($fieldSpec['fields'] ?? [] as $dependant) {
13021340
if (!isset($entity['fields'][$dependant])) {
13031341
throw new Visualization_Error('Unknown callback required field "'.$dependant.'"');
13041342
}
@@ -1335,6 +1373,7 @@ protected function parseFieldTokens(Token $token, array &$fields = null): void
13351373
if ($token->hasChildren()) {
13361374
if ('function' === $token->name) {
13371375
$field = $token->getValues();
1376+
assert(null !== $field[0]);
13381377
$field[0] = strtolower($field[0]);
13391378
$fields[] = $field;
13401379
} else {
@@ -1350,8 +1389,8 @@ protected function parseFieldTokens(Token $token, array &$fields = null): void
13501389
/**
13511390
* Helper method for the query parser to recursively scan and flatten the where clause's conditions.
13521391
*
1353-
* @param Token $token the token or token group to parse
1354-
* @param null|array $where the collector array of tokens that make up the where clause
1392+
* @param Token $token the token or token group to parse
1393+
* @param null|array<array{type: string, value: string}> $where the collector array of tokens that make up the where clause
13551394
*/
13561395
protected function parseWhereTokens(Token $token, array &$where = null): void
13571396
{

lib/MC/Parser.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,17 @@ class Parser
3232
/**
3333
* Return a Set with the function arguments as the subexpressions.
3434
*/
35-
public function set(): Set
35+
public function set(Def ...$args): Set
3636
{
37-
return new Set(func_get_args());
37+
return new Set($args);
3838
}
3939

4040
/**
4141
* Return a OneOf with the function arguments as the possible expressions.
4242
*/
43-
public function oneOf(): OneOf
43+
public function oneOf(Def ...$args): OneOf
4444
{
45-
return new OneOf(func_get_args());
45+
return new OneOf($args);
4646
}
4747

4848
/**

lib/MC/Parser/Def.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function parse(string $str): Token
2828
$str = ltrim($str);
2929

3030
[$loc, $tok] = $this->parsePart($str, 0);
31-
if ($loc !== strlen($str)) {
31+
if ((null === $tok) || ($loc !== strlen($str))) {
3232
throw new ParseError('An error occurred: "'.substr($str, $loc).'"', $str, $loc);
3333
}
3434

@@ -38,7 +38,7 @@ public function parse(string $str): Token
3838
/**
3939
* Parse a string, cleaning up whitespace when we're done.
4040
*
41-
* @return array A two-item array of the string location where parsing stopped, and the MC_Token instance that matches the grammar conditions
41+
* @return array{int, null|Token} A two-item array of the string location where parsing stopped and the MC_Token instance that matches the grammar conditions
4242
*
4343
* @throws ParseError
4444
*/
@@ -61,7 +61,7 @@ public function parsePart(string $str, int $loc): array
6161
* @param string $str the string to parse
6262
* @param int $loc the index to start parsing
6363
*
64-
* @return array A two-item array of the string location where parsing stopped, and the MC_Token instance that matches the grammar conditions
64+
* @return array{int, null|Token} A two-item array of the string location where parsing stopped, and the Token instance that matches the grammar conditions
6565
*
6666
* @throws ParseError
6767
*/
@@ -103,11 +103,9 @@ public function suppress(): self
103103
/**
104104
* Return a token instance, copying over this Def's name and flagging suppression.
105105
*
106-
* @param mixed $value
107-
*
108106
* @return null|Token the new token, or null if the token should be suppressed
109107
*/
110-
public function token($value): ?Token
108+
public function token(?string $value): ?Token
111109
{
112110
if ($this->suppress) {
113111
return null;

lib/MC/Parser/Def/OneOf.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ class OneOf extends Def
1515
/** @var Def[] */
1616
public $exprs = [];
1717

18+
/**
19+
* @param Def[] $exprs
20+
*/
1821
public function __construct(array $exprs = [])
1922
{
2023
$this->exprs = $exprs;

lib/MC/Parser/Def/Set.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
*/
1212
class Set extends Def
1313
{
14-
/** @var array */
14+
/** @var Def[] */
1515
public $exprs = [];
1616

1717
/**
18-
* Set constructor.
18+
* @param Def[] $exprs
1919
*/
2020
public function __construct(array $exprs = [])
2121
{
@@ -31,7 +31,7 @@ public function _parse(string $str, int $loc): array
3131
$res = $this->tokenGroup();
3232
foreach ($this->exprs as $expr) {
3333
[$loc, $toks] = $expr->parsePart($str, $loc);
34-
if ((null !== $toks) && (!is_array($toks) || (count($toks) > 0))) {
34+
if (null !== $toks) {
3535
$res->append($toks);
3636
}
3737
}

lib/MC/Parser/Token.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,29 @@ class Token
1212
/** @var null|string */
1313
public $name;
1414

15-
/** @var mixed */
15+
/** @var null|string */
1616
public $value;
1717

1818
/**
1919
* Token constructor.
20-
*
21-
* @param mixed $value
2220
*/
23-
public function __construct($value, ?string $name)
21+
public function __construct(?string $value, ?string $name)
2422
{
2523
$this->value = $value;
2624
$this->name = $name;
2725
}
2826

27+
/**
28+
* @return array<null|string>
29+
*/
2930
public function getValues(): array
3031
{
3132
return [$this->value];
3233
}
3334

35+
/**
36+
* @return array<array{null|string, null|string}>
37+
*/
3438
public function getNameValues(): array
3539
{
3640
return [[$this->name, $this->value]];

lib/MC/Parser/Token/Group.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,7 @@ class Group extends Token implements Countable
1414
/** @var Token[] */
1515
public $subtoks = [];
1616

17-
/**
18-
* @param null|string $name
19-
*/
20-
public function __construct($name)
17+
public function __construct(?string $name)
2118
{
2219
parent::__construct(null, $name);
2320
}
@@ -43,6 +40,9 @@ public function count(): int
4340
return count($this->subtoks);
4441
}
4542

43+
/**
44+
* @return array<null|string>
45+
*/
4646
public function getValues(): array
4747
{
4848
$values = [];
@@ -53,6 +53,9 @@ public function getValues(): array
5353
return $values;
5454
}
5555

56+
/**
57+
* @return array<array{null|string, null|string}>
58+
*/
5659
public function getNameValues(): array
5760
{
5861
$values = [];

0 commit comments

Comments
 (0)