Skip to content

Commit 2ba6185

Browse files
committed
Support for typed arrays
1 parent 9e50ff9 commit 2ba6185

File tree

8 files changed

+168
-27
lines changed

8 files changed

+168
-27
lines changed

Tests/DefinitionTest.php

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public function testGetSet() : void
3030
$this->assertEquals($boolean, $fixture->boolean);
3131
$this->assertIsBool($fixture->boolean);
3232

33-
$array = [1, 2, 3];
33+
$array = ['String', '2', 'Another string'];
3434
$fixture->array = $array;
3535
$this->assertEquals($array, $fixture->array);
3636
$this->assertIsArray($fixture->array);
@@ -62,14 +62,14 @@ public function testGetSet() : void
6262

6363
$json = $fixture->getJSON();
6464
$expectedJSON ='{
65-
"class": {},
65+
"class": [],
6666
"integer": 123,
6767
"string": "A long string",
6868
"boolean": true,
6969
"array": [
70-
1,
71-
2,
72-
3
70+
"String",
71+
"2",
72+
"Another string"
7373
],
7474
"float": 1.23,
7575
"enum": "primary_email",
@@ -123,6 +123,30 @@ public function testBadArrayType() : void
123123
$fixture->array = 0;
124124
}
125125

126+
public function testBadArrayTypes() : void
127+
{
128+
$fixture = new \Tests\Fixtures\TypeTest();
129+
$this->expectException(\PHPFUI\ConstantContact\Exception\InvalidType::class);
130+
$fixture->classArray = [
131+
new \Tests\Fixtures\ClassTest(),
132+
new \Tests\Fixtures\ClassTest(),
133+
new \Tests\Fixtures\TypeTest(),
134+
];
135+
}
136+
137+
public function testBadArrayOfTypeSize() : void
138+
{
139+
$fixture = new \Tests\Fixtures\TypeTest();
140+
$this->expectException(\PHPFUI\ConstantContact\Exception\InvalidValue::class);
141+
$fixture->classArraySize = [
142+
new \Tests\Fixtures\ClassTest(),
143+
new \Tests\Fixtures\ClassTest(),
144+
new \Tests\Fixtures\ClassTest(),
145+
new \Tests\Fixtures\ClassTest(),
146+
new \Tests\Fixtures\ClassTest(),
147+
];
148+
}
149+
126150
public function testBadClassType() : void
127151
{
128152
$fixture = new \Tests\Fixtures\TypeTest();

Tests/Fixtures/ClassTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Tests\Fixtures;
44

5-
class ClassTest
5+
class ClassTest extends \PHPFUI\ConstantContact\Definition\Base
66
{
77

88
}

Tests/Fixtures/TypeTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class TypeTest extends \PHPFUI\ConstantContact\Definition\Base
1515
'ucEnum' => ['DRAFT', 'SCHEDULED', 'EXECUTING', 'DONE', 'ERROR', 'REMOVED'],
1616
'intEnum' => [1, 2, 3, 4, 5],
1717
'class' => 'Tests\\Fixtures\\ClassTest',
18+
'classArray' => 'array[\\Tests\\Fixtures\\ClassTest]',
19+
'classArraySize' => 'array[\\Tests\\Fixtures\\ClassTest][3]',
1820
];
1921

2022
protected static array $minLength = [

Tools/Generator.php

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,7 @@ public function generateDefinition(string $class, array $properties) : void
116116
}
117117
if (isset($details['$ref']))
118118
{
119-
$parts = \explode('/', str_replace('_', '', $details['$ref']));
120-
$type = str_replace('\\', '\\\\', $this->definitionNamespace . '\\' . \array_pop($parts));
119+
$type = $this->getTypeNameFromRef($details['$ref']);
121120
}
122121
else
123122
{
@@ -127,7 +126,7 @@ public function generateDefinition(string $class, array $properties) : void
127126
{
128127
$namespace = $this->definitionNamespace;
129128
$baseName = $this->getUniqueClassName($namespace, $this->getClassName($name));
130-
$type = str_replace('\\', '\\\\', $namespace . '\\' . $baseName);
129+
$type = '\\' . $namespace . '\\' . $baseName;
131130
$this->generateDefinition($baseName, $details);
132131
}
133132

@@ -146,21 +145,44 @@ public function generateDefinition(string $class, array $properties) : void
146145
}
147146
elseif ($type == 'date')
148147
{
149-
$type = 'PHPFUI\\ConstantContact\\Date';
148+
$type = '\PHPFUI\ConstantContact\Date';
150149
}
151150
elseif ($type == 'boolean')
152151
{
153152
$type = 'bool';
154153
}
155154
elseif ($type == 'uuid')
156155
{
157-
$type = 'PHPFUI\\ConstantContact\\UUID';
156+
$type = '\PHPFUI\ConstantContact\UUID';
158157
}
159158
if (isset($details['enum']))
160159
{
161160
$originalType = $type;
162161
$type = $details['enum'];
163162
}
163+
164+
if (isset($details['items']))
165+
{
166+
$items = $details['items'];
167+
$itemType = '';
168+
if (isset($items['$ref']))
169+
{
170+
$itemType = $this->getTypeNameFromRef($items['$ref']);
171+
}
172+
elseif (isset($items['type']) && ($items['format'] ?? '') == 'uuid')
173+
{
174+
$itemType = '\PHPFUI\ConstantContact\UUID';
175+
}
176+
if ('array' == $type && $itemType)
177+
{
178+
$type = 'array[' . $itemType . ']';
179+
if ($details['maxItems'] ?? false)
180+
{
181+
$type .= '[' . $details['maxItems'] . ']';
182+
}
183+
}
184+
}
185+
164186
}
165187
$fields[$name] = $type;
166188

@@ -206,8 +228,7 @@ private function writeClass(string $namespace, string $class, string $apiPath, a
206228
{
207229
if (isset($parameter['schema']))
208230
{
209-
$parts = \explode('/', $parameter['schema']['$ref']);
210-
$type = '\\' . $this->definitionNamespace . '\\' . \array_pop($parts);
231+
$type = $this->getTypeNameFromRef($parameter['schema']['$ref']);
211232
}
212233
else
213234
{
@@ -313,7 +334,7 @@ public function ~method~(~parameters~) : ~returnType~
313334
$php = <<<'PHP'
314335
<?php
315336
316-
// Generated file. Do not edit by hand. Use generate.php in project root.
337+
// Generated file. Do not edit by hand. Use update.php in project root.
317338
318339
namespace PHPFUI\ConstantContact\~namespace~;
319340
@@ -422,6 +443,8 @@ private function generateFromTemplate(string $name, array $properties, array $do
422443
$template = <<<PHP
423444
<?php
424445
446+
// Generated file. Do not edit by hand. Use update.php in project root.
447+
425448
namespace {$this->definitionNamespace};
426449
427450
/**
@@ -490,4 +513,11 @@ class ~class~ extends {$backSlash}{$this->definitionNamespace}\Base
490513
throw new \Exception("Error writing file {$path}");
491514
}
492515
}
516+
517+
private function getTypeNameFromRef(string $ref) : string
518+
{
519+
$parts = \explode('/', str_replace('_', '', $ref));
520+
return '\\' . $this->definitionNamespace . '\\' . \array_pop($parts);
521+
}
522+
493523
}

src/ConstantContact/Base.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,19 @@ public function __construct(protected \PHPFUI\ConstantContact\Client $client, pr
1010

1111
public function success() : bool
1212
{
13-
return 200 == $this->client->getLastErrorNumber();
13+
$status = $this->client->getStatusCode();
14+
15+
return $status >= 200 && $status < 300;
16+
}
17+
18+
public function getStatusCode() : int
19+
{
20+
return $this->client->getStatusCode();
1421
}
1522

16-
public function getResponseCode() : int
23+
public function getLastError() : string
1724
{
18-
return $this->client->getLastErrorNumber();
25+
return $this->client->getLastError();
1926
}
2027

2128
public function getResponseText() : string

src/ConstantContact/Client.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public function getLastError() : string
9797
return $this->lastError;
9898
}
9999

100-
public function getStatusCode() : int
100+
public function getStatusCode() : int
101101
{
102102
return $this->statusCode;
103103
}

src/ConstantContact/Definition/Base.php

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,25 @@ abstract class Base
2222
'array' => true,
2323
];
2424

25-
public function __construct()
25+
public function __construct(array $initialValues = [])
2626
{
2727
foreach (static::$fields as $field => $type)
2828
{
29-
if (! \is_array($type) && ! isset(self::$scalars[$type]))
29+
if (isset($initialValues[$field]))
3030
{
31-
$this->data[$field] = new $type();
31+
$this->setFields[$field] = true;
32+
$this->data[$field] = $initialValues[$field];
33+
}
34+
elseif (! \is_array($type) && ! isset(self::$scalars[$type]))
35+
{
36+
if (str_starts_with($type, 'array'))
37+
{
38+
$this->data[$field] = [];
39+
}
40+
else
41+
{
42+
$this->data[$field] = new $type();
43+
}
3244
}
3345
}
3446
}
@@ -56,6 +68,7 @@ public function __set(string $field, $value)
5668
{
5769
throw new \PHPFUI\ConstantContact\Exception\InvalidField(static::class . "::{$field} is not a valid field");
5870
}
71+
5972
$type = \get_debug_type($value);
6073

6174
if (\is_array($expectedType))
@@ -65,9 +78,42 @@ public function __set(string $field, $value)
6578
throw new \PHPFUI\ConstantContact\Exception\InvalidValue(static::class . "::{$field} is {$value} but must be one of " . \implode(', ', $expectedType));
6679
}
6780
}
68-
elseif ($expectedType != $type)
81+
else
6982
{
70-
throw new \PHPFUI\ConstantContact\Exception\InvalidType(static::class . "::{$field} is of type {$type} but should be type {$expectedType}");
83+
$expectedType = trim($expectedType, '\\');
84+
if ($type == 'array' && str_starts_with($expectedType, 'array'))
85+
{
86+
$arrayStart = strpos($expectedType, '[');
87+
if ($arrayStart)
88+
{
89+
$arrayEnd = strpos($expectedType, ']');
90+
if (strlen($expectedType) > $arrayEnd + 1)
91+
{
92+
$maxSize = (int)trim(substr($expectedType, $arrayEnd), '[]');
93+
if (count($value) > $maxSize)
94+
{
95+
throw new \PHPFUI\ConstantContact\Exception\InvalidValue(static::class . "::{$field} array has a limit of {$maxSize} values");
96+
}
97+
}
98+
$expectedType = trim(substr($expectedType, $arrayStart + 2, $arrayEnd - $arrayStart - 2), '\\');
99+
}
100+
else
101+
{
102+
$expectedType = 'string';
103+
}
104+
foreach ($value as $index => $element)
105+
{
106+
$elementType = \get_debug_type($element);
107+
if ($expectedType != $elementType)
108+
{
109+
throw new \PHPFUI\ConstantContact\Exception\InvalidType(static::class . "::{$field} should be an array[{$expectedType}] but index {$index} is of type {$elementType}");
110+
}
111+
}
112+
}
113+
elseif ($expectedType != $type)
114+
{
115+
throw new \PHPFUI\ConstantContact\Exception\InvalidType(static::class . "::{$field} is of type {$type} but should be type {$expectedType}");
116+
}
71117
}
72118

73119
if (isset(static::$minLength[$field]))
@@ -114,9 +160,32 @@ public function getData() : array
114160
{
115161
if ($value instanceof self)
116162
{
117-
$value = $value->getData();
163+
$result[$field] = $value->getData();
164+
}
165+
elseif (is_array($value))
166+
{
167+
if (! count($value))
168+
{
169+
continue;
170+
}
171+
$result[$field] = [];
172+
foreach ($value as $item)
173+
{
174+
if ($item instanceof self)
175+
{
176+
$item = $item->getData();
177+
}
178+
elseif (is_object($item))
179+
{
180+
$item = (string)$item;
181+
}
182+
$result[$field][] = $item;
183+
}
184+
}
185+
else
186+
{
187+
$result[$field] = is_object($value) ? (string)$value : $value;
118188
}
119-
$result[$field] = $value;
120189
}
121190
}
122191

@@ -136,3 +205,4 @@ public function getfields() : array
136205
return static::$fields;
137206
}
138207
}
208+

update.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<?php
22

3-
exec('/usr/bin/php8.0 composer.phar self-update');
4-
exec('/usr/bin/php8.0 composer.phar update');
3+
$php = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ? 'php' : '/usr/bin/php8.0';
4+
5+
exec($php . ' composer.phar self-update');
6+
exec($php . ' composer.phar update');
57

68
include 'vendor/autoload.php';
79

@@ -27,6 +29,12 @@
2729
$generator->makeClasses($yaml['basePath'], $yaml['paths']);
2830
$generator->makeDefinitions($yaml['definitions']);
2931

32+
// don't update git if running under Windows
33+
if ('php' == $php)
34+
{
35+
exit;
36+
}
37+
3038
// Stage all changed files
3139
$repo->run('add', ['.']);
3240

0 commit comments

Comments
 (0)