Skip to content

Commit 8c6eb63

Browse files
committed
PHP Namespaces support (#271)
* added namespace helper referred to types using dynamic namespaces generated the same output for single namespace V1 * fix broken test by updating the parameter and the path generation logic * make base class reference dynamic * found a bug: is_a doesn't refer to GraphList instead of List update param references to full names * update complex type references * test base for PHP * add PHP beta tests, and couple of fixes in Complex type * refactor common code, and make namespace building parameter based * update command line instructions to reflect php.namespacePrefix change
1 parent ac55a14 commit 8c6eb63

File tree

117 files changed

+8793
-115
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+8793
-115
lines changed

GraphODataTemplateWriter.Test/TypeHelperTests.cs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,45 @@ public void Namespace_Should_PascalCase_For_CSharp()
111111

112112
Assert.AreEqual(namespaceName, "Microsoft.Graph");
113113
}
114-
}
114+
115+
[TestMethod]
116+
public void PHPMainNamespace_Generated_For_V1()
117+
{
118+
var testNamespace = "microsoft.graph";
119+
const string expectedPHPNamespace = "Microsoft\\Graph";
120+
121+
var actualPHPNamespace = TypeHelperPHP.GetPHPNamespace(testNamespace);
122+
Assert.AreEqual(expectedPHPNamespace, actualPHPNamespace);
123+
}
124+
125+
[TestMethod]
126+
public void PHPMainNamespace_Generated_For_Beta()
127+
{
128+
var testNamespace = "microsoft.graph";
129+
const string expectedPHPNamespace = "Beta\\Microsoft\\Graph";
130+
131+
var actualPHPNamespace = TypeHelperPHP.GetPHPNamespace(testNamespace, "Beta");
132+
Assert.AreEqual(expectedPHPNamespace, actualPHPNamespace);
133+
}
134+
135+
[TestMethod]
136+
public void PHPSubNamespace_Generated_For_V1()
137+
{
138+
var testNamespace = "microsoft.graph.callRecords";
139+
const string expectedPHPNamespace = "Microsoft\\Graph\\CallRecords";
140+
141+
var actualPHPNamespace = TypeHelperPHP.GetPHPNamespace(testNamespace);
142+
Assert.AreEqual(expectedPHPNamespace, actualPHPNamespace);
143+
}
144+
145+
[TestMethod]
146+
public void PHPSubNamespace_Generated_For_Beta()
147+
{
148+
var testNamespace = "microsoft.graph.callRecords";
149+
const string expectedPHPNamespace = "Beta\\Microsoft\\Graph\\CallRecords";
150+
151+
var actualPHPNamespace = TypeHelperPHP.GetPHPNamespace(testNamespace, "Beta");
152+
Assert.AreEqual(expectedPHPNamespace, actualPHPNamespace);
153+
}
154+
}
115155
}

Templates/PHP/Model/ComplexType.php.tt

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,12 @@ CodeWriterPHP writer = (CodeWriterPHP) host.CodeWriter;
88
TemplateWriterSettings settings = ConfigurationService.Settings;
99
OdcmClass complex = (OdcmClass)host.CurrentType;
1010
String complexName = complex.Name.SanitizeEntityName();
11-
string targetNamespace = @"Microsoft\Graph\Model";
12-
String complexBaseName = "";
13-
if (complex.Base != null)
14-
complexBaseName = complex.Base.Name.SanitizeEntityName();
15-
16-
// TemplateWriterSettings.Properties are set at the Typewriter command line. Check the command line
17-
// documentation for more information on how the TemplateWriterSettings.Properties is used.
18-
if (settings.Properties.ContainsKey("php.namespace"))
11+
String targetNamespace = TypeHelperPHP.GetPHPNamespace(complex, settings);
12+
String complexBaseName = TypeHelperPHP.GetBaseTypeFullName(complex.Base, targetNamespace, settings);
13+
if (complexBaseName.Contains("\\"))
1914
{
20-
targetNamespace = settings.Properties["php.namespace"];
21-
}
15+
complexBaseName = "\\" + complexBaseName;
16+
}
2217

2318
#>
2419
<#=writer.WriteHeader(writer.GetDocBlock(complexName.ToCheckedCase()))#>
@@ -27,11 +22,12 @@ namespace <#=targetNamespace#>;
2722
<#
2823
if (complex.Base != null) {
2924
#>
30-
class <#=complexName.ToCheckedCase()#> extends <#=complexBaseName.ToCheckedCase()#>
25+
class <#=complexName.ToCheckedCase()#> extends <#=complexBaseName#>
3126
<#
3227
} else {
28+
var entityTypeFullName = TypeHelperPHP.GetPHPEntityTypeReference(targetNamespace, settings);
3329
#>
34-
class <#=complexName.ToCheckedCase()#> extends Entity
30+
class <#=complexName.ToCheckedCase()#> extends <#=entityTypeFullName#>
3531
<#
3632
}
3733
#>
@@ -55,6 +51,18 @@ if (complex.IsBaseAbstractAndReferencedAsPropertyType() && !complex.IsAbstract)
5551
}
5652
foreach(var property in complex.Properties.Where(prop => prop.Type.GetTypeString() != "bytes")){
5753
var propertyName = property.Name.SanitizePropertyName(complexName);
54+
var camelCasePropertyName = property.Name.ToCamelize();
55+
var propertyTypeString = property.Type.GetTypeString();
56+
var propertyNamespace = TypeHelperPHP.GetPHPNamespace(property.Type, settings);
57+
58+
// Check whether this type is a generated model type or a PHP type
59+
var fullPropertyTypeName = propertyTypeString[0] == '\\' || propertyTypeString.IsPHPPrimitiveType()
60+
? propertyTypeString
61+
: string.Join("\\", propertyNamespace, propertyTypeString.SanitizeEntityName().ToCheckedCase());
62+
63+
var propertyTypeReference = propertyNamespace == targetNamespace && !propertyTypeString.IsPHPPrimitiveType()
64+
? propertyTypeString.SanitizeEntityName().ToCheckedCase()
65+
: fullPropertyTypeName;
5866
if (!property.Type.IsComplex()) {
5967
#>
6068
/**
@@ -64,7 +72,7 @@ foreach(var property in complex.Properties.Where(prop => prop.Type.GetTypeString
6472
* <#=property.GetSanitizedLongDescription()#>
6573
<# } #>
6674
*
67-
* @return <#=property.Type.GetTypeString()#> The <#=propertyName#>
75+
* @return <#=propertyTypeReference#> The <#=propertyName#>
6876
*/
6977
public function get<#=propertyName.ToCheckedCase()#>()
7078
{
@@ -92,7 +100,7 @@ foreach(var property in complex.Properties.Where(prop => prop.Type.GetTypeString
92100
* <#=property.GetSanitizedLongDescription()#>
93101
<# } #>
94102
*
95-
* @param <#=property.Type.GetTypeString()#> $val The value of the <#=propertyName#>
103+
* @param <#=propertyTypeReference#> $val The value of the <#=propertyName#>
96104
*
97105
* @return <#=complexName.ToCheckedCase()#>
98106
*/
@@ -123,26 +131,20 @@ foreach(var property in complex.Properties.Where(prop => prop.Type.GetTypeString
123131
* <#=property.GetSanitizedLongDescription()#>
124132
<# } #>
125133
*
126-
* @return <#=property.Type.GetTypeString().SanitizeEntityName().ToCheckedCase()#> The <#=propertyName#>
134+
* @return <#=propertyTypeReference#> The <#=propertyName#>
127135
*/
128136
public function get<#=propertyName.ToCheckedCase()#>()
129137
{
130138
if (array_key_exists("<#=property.Name.ToCamelize()#>", $this->_propDict)) {
131-
<#
132-
// Check whether this type is a generated model type or a PHP type
133-
if (property.Type.GetTypeString()[0] == '\\') { #>
134-
if (is_a($this->_propDict["<#=property.Name.ToCamelize()#>"], "<#=property.Type.GetTypeString()#>")) {
135-
<# } else { #>
136-
if (is_a($this->_propDict["<#=property.Name.ToCamelize()#>"], "<#=targetNamespace#>\<#=property.Type.GetTypeString()#>")) {
137-
<# } #>
138-
return $this->_propDict["<#=property.Name.ToCamelize()#>"];
139+
if (is_a($this->_propDict["<#=camelCasePropertyName#>"], "<#=fullPropertyTypeName#>")) {
140+
return $this->_propDict["<#=camelCasePropertyName#>"];
139141
} else {
140-
<# if (property.Type.GetTypeString() == "\\GuzzleHttp\\Psr7\\Stream") { #>
141-
$this->_propDict["<#=property.Name.ToCamelize()#>"] = \GuzzleHttp\Psr7\stream_for($this->_propDict["<#=property.Name.ToCamelize()#>"]);
142-
return $this->_propDict["<#=property.Name.ToCamelize()#>"];
142+
<# if (propertyTypeString == "\\GuzzleHttp\\Psr7\\Stream") { #>
143+
$this->_propDict["<#=camelCasePropertyName#>"] = \GuzzleHttp\Psr7\stream_for($this->_propDict["<#=camelCasePropertyName#>"]);
144+
return $this->_propDict["<#=camelCasePropertyName#>"];
143145
<# } else { #>
144-
$this->_propDict["<#=property.Name.ToCamelize()#>"] = new <#=property.Type.GetTypeString().SanitizeEntityName().ToCheckedCase()#>($this->_propDict["<#=property.Name.ToCamelize()#>"]);
145-
return $this->_propDict["<#=property.Name.ToCamelize()#>"];
146+
$this->_propDict["<#=camelCasePropertyName#>"] = new <#=propertyTypeReference#>($this->_propDict["<#=camelCasePropertyName#>"]);
147+
return $this->_propDict["<#=camelCasePropertyName#>"];
146148
<# } #>
147149
}
148150
}
@@ -156,7 +158,7 @@ if (property.Type.GetTypeString()[0] == '\\') { #>
156158
* <#=property.GetSanitizedLongDescription()#>
157159
<# } #>
158160
*
159-
* @param <#=property.Type.GetTypeString()#> $val The value to assign to the <#=property.Name#>
161+
* @param <#=propertyTypeReference#> $val The value to assign to the <#=property.Name#>
160162
*
161163
* @return <#=complexName.ToCheckedCase()#> The <#=complexName.ToCheckedCase()#>
162164
*/

Templates/PHP/Model/EntityType.php.tt

Lines changed: 57 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,33 @@ CodeWriterPHP writer = (CodeWriterPHP) host.CodeWriter;
88
OdcmClass entity = host.CurrentType.AsOdcmClass();
99
TemplateWriterSettings settings = ConfigurationService.Settings;
1010
String entityName = entity.Name.SanitizeEntityName();
11-
string targetNamespace = @"Microsoft\Graph\Model";
12-
String entityBaseName = "";
13-
14-
if (entity.Base != null)
15-
entityBaseName = entity.Base.Name.SanitizeEntityName();
16-
17-
// TemplateWriterSettings.Properties are set at the Typewriter command line. Check the command line
18-
// documentation for more information on how the TemplateWriterSettings.Properties is used.
19-
if (settings.Properties.ContainsKey("php.namespace"))
11+
String entityCheckedCase = entity.Name.ToCheckedCase();
12+
String targetNamespace = TypeHelperPHP.GetPHPNamespace(entity, settings);
13+
String entityBaseName = TypeHelperPHP.GetBaseTypeFullName(entity.Base, targetNamespace, settings);
14+
if (entityBaseName.Contains("\\"))
2015
{
21-
targetNamespace = settings.Properties["php.namespace"];
22-
}
16+
entityBaseName = "\\" + entityBaseName;
17+
}
2318

2419
#>
2520
<#=writer.WriteHeader(writer.GetDocBlock(entityName.ToCheckedCase()))#>
2621
namespace <#=targetNamespace#>;
2722

2823
<#=writer.GetClassBlock(entityName.ToCheckedCase().ToString(), "Model")#>
2924
<#
30-
if (entity.Name.ToCheckedCase() == "Entity") {
25+
if (entityCheckedCase == "Entity") {
3126
#>
32-
class <#=entity.Name.ToCheckedCase()#> implements \JsonSerializable
27+
class <#=entityCheckedCase#> implements \JsonSerializable
3328
<#
3429
} else {
3530
#>
36-
class <#=entityName.ToCheckedCase()#> extends <#=entityBaseName.ToCheckedCase() #>
31+
class <#=entityName.ToCheckedCase()#> extends <#=entityBaseName#>
3732
<#
3833
}
3934
#>
4035
{
4136
<#
42-
if (entity.Name.ToCheckedCase() == "Entity") {
37+
if (entityCheckedCase == "Entity") {
4338
#>
4439
/**
4540
* The array of properties available
@@ -50,7 +45,7 @@ if (entity.Name.ToCheckedCase() == "Entity") {
5045
protected $_propDict;
5146

5247
/**
53-
* Construct a new <#=entity.Name.ToCheckedCase()#>
48+
* Construct a new <#=entityCheckedCase#>
5449
*
5550
* @param array $propDict A list of properties to set
5651
*/
@@ -72,7 +67,19 @@ if (entity.Name.ToCheckedCase() == "Entity") {
7267
<#
7368
}
7469
foreach(var property in entity.Properties.Where(prop => prop.Type.GetTypeString() != "bytes")){
75-
String propertyName = property.Name.SanitizePropertyName(entityName).ToCamelize();
70+
String propertyName = property.Name.SanitizePropertyName(entityName).ToCamelize();
71+
var camelCasePropertyName = property.Name.ToCamelize();
72+
var propertyTypeString = property.Type.GetTypeString();
73+
var propertyNamespace = TypeHelperPHP.GetPHPNamespace(property.Type, settings);
74+
75+
// Check whether this type is a generated model type or a PHP type
76+
var fullPropertyTypeName = propertyTypeString[0] == '\\' || propertyTypeString.IsPHPPrimitiveType()
77+
? propertyTypeString
78+
: string.Join("\\", propertyNamespace, propertyTypeString.SanitizeEntityName().ToCheckedCase());
79+
80+
var propertyTypeReference = propertyNamespace == targetNamespace && !propertyTypeString.IsPHPPrimitiveType()
81+
? propertyTypeString.SanitizeEntityName().ToCheckedCase()
82+
: fullPropertyTypeName;
7683
if (property.Type.IsComplex()) {
7784
if (property.IsCollection()) {
7885
#>
@@ -88,8 +95,8 @@ foreach(var property in entity.Properties.Where(prop => prop.Type.GetTypeString(
8895
*/
8996
public function get<#=propertyName.ToCheckedCase()#>()
9097
{
91-
if (array_key_exists("<#=property.Name.ToCamelize()#>", $this->_propDict)) {
92-
return $this->_propDict["<#=property.Name.ToCamelize()#>"];
98+
if (array_key_exists("<#=camelCasePropertyName#>", $this->_propDict)) {
99+
return $this->_propDict["<#=camelCasePropertyName#>"];
93100
} else {
94101
return null;
95102
}
@@ -102,13 +109,13 @@ foreach(var property in entity.Properties.Where(prop => prop.Type.GetTypeString(
102109
* <#=property.GetSanitizedLongDescription()#>
103110
<# } #>
104111
*
105-
* @param <#=property.Type.GetTypeString().SanitizeEntityName().ToCheckedCase()#> $val The <#=propertyName#>
112+
* @param <#=propertyTypeReference#> $val The <#=propertyName#>
106113
*
107-
* @return <#=entity.Name.ToCheckedCase()#>
114+
* @return <#=entityCheckedCase#>
108115
*/
109116
public function set<#=propertyName.ToCheckedCase()#>($val)
110117
{
111-
$this->_propDict["<#=property.Name.ToCamelize()#>"] = $val;
118+
$this->_propDict["<#=camelCasePropertyName#>"] = $val;
112119
return $this;
113120
}
114121

@@ -122,26 +129,20 @@ foreach(var property in entity.Properties.Where(prop => prop.Type.GetTypeString(
122129
* <#=property.GetSanitizedLongDescription()#>
123130
<# } #>
124131
*
125-
* @return <#=property.Type.GetTypeString().SanitizeEntityName().ToCheckedCase()#> The <#=propertyName#>
132+
* @return <#=propertyTypeReference#> The <#=propertyName#>
126133
*/
127134
public function get<#=propertyName.ToCheckedCase()#>()
128135
{
129-
if (array_key_exists("<#=property.Name.ToCamelize()#>", $this->_propDict)) {
130-
<#
131-
// Check whether this type is a generated model type or a PHP type
132-
if (property.Type.GetTypeString()[0] == '\\') { #>
133-
if (is_a($this->_propDict["<#=property.Name.ToCamelize()#>"], "<#=property.Type.GetTypeString()#>")) {
134-
<# } else { #>
135-
if (is_a($this->_propDict["<#=property.Name.ToCamelize()#>"], "<#=targetNamespace#>\<#=property.Type.GetTypeString()#>")) {
136-
<# } #>
137-
return $this->_propDict["<#=property.Name.ToCamelize()#>"];
136+
if (array_key_exists("<#=camelCasePropertyName#>", $this->_propDict)) {
137+
if (is_a($this->_propDict["<#=camelCasePropertyName#>"], "<#=fullPropertyTypeName#>")) {
138+
return $this->_propDict["<#=camelCasePropertyName#>"];
138139
} else {
139-
<# if (property.Type.GetTypeString() == "\\GuzzleHttp\\Psr7\\Stream") { #>
140-
$this->_propDict["<#=property.Name.ToCamelize()#>"] = \GuzzleHttp\Psr7\stream_for($this->_propDict["<#=property.Name.ToCamelize()#>"]);
141-
return $this->_propDict["<#=property.Name.ToCamelize()#>"];
140+
<# if (propertyTypeString == "\\GuzzleHttp\\Psr7\\Stream") { #>
141+
$this->_propDict["<#=camelCasePropertyName#>"] = \GuzzleHttp\Psr7\stream_for($this->_propDict["<#=camelCasePropertyName#>"]);
142+
return $this->_propDict["<#=camelCasePropertyName#>"];
142143
<# } else { #>
143-
$this->_propDict["<#=property.Name.ToCamelize()#>"] = new <#=property.Type.GetTypeString().SanitizeEntityName().ToCheckedCase()#>($this->_propDict["<#=property.Name.ToCamelize()#>"]);
144-
return $this->_propDict["<#=property.Name.ToCamelize()#>"];
144+
$this->_propDict["<#=camelCasePropertyName#>"] = new <#=propertyTypeReference#>($this->_propDict["<#=camelCasePropertyName#>"]);
145+
return $this->_propDict["<#=camelCasePropertyName#>"];
145146
<# } #>
146147
}
147148
}
@@ -155,18 +156,18 @@ if (property.Type.GetTypeString()[0] == '\\') { #>
155156
* <#=property.GetSanitizedLongDescription()#>
156157
<# } #>
157158
*
158-
* @param <#=property.Type.GetTypeString().SanitizeEntityName().ToCheckedCase()#> $val The <#=propertyName#>
159+
* @param <#=propertyTypeReference#> $val The <#=propertyName#>
159160
*
160-
* @return <#=entity.Name.ToCheckedCase()#>
161+
* @return <#=entityCheckedCase#>
161162
*/
162163
public function set<#=propertyName.ToCheckedCase()#>($val)
163164
{
164-
<# if (property.Type.GetTypeString() == "bool") { #>
165-
$this->_propDict["<#=property.Name.ToCamelize()#>"] = boolval($val);
166-
<# } else if (property.Type.GetTypeString() == "int") { #>
167-
$this->_propDict["<#=property.Name.ToCamelize()#>"] = intval($val);
165+
<# if (propertyTypeString == "bool") { #>
166+
$this->_propDict["<#=camelCasePropertyName#>"] = boolval($val);
167+
<# } else if (propertyTypeString == "int") { #>
168+
$this->_propDict["<#=camelCasePropertyName#>"] = intval($val);
168169
<# } else { #>
169-
$this->_propDict["<#=property.Name.ToCamelize()#>"] = $val;
170+
$this->_propDict["<#=camelCasePropertyName#>"] = $val;
170171
<# } #>
171172
return $this;
172173
}
@@ -182,19 +183,19 @@ if (property.Type.GetTypeString()[0] == '\\') { #>
182183
* <#=property.GetSanitizedLongDescription()#>
183184
<# } #>
184185
*
185-
* @return <#=property.Type.GetTypeString()#> The <#=propertyName#>
186+
* @return <#=propertyTypeReference#> The <#=propertyName#>
186187
*/
187188
public function get<#=propertyName.ToCheckedCase()#>()
188189
{
189-
if (array_key_exists("<#=property.Name.ToCamelize()#>", $this->_propDict)) {
190+
if (array_key_exists("<#=camelCasePropertyName#>", $this->_propDict)) {
190191
<#
191-
if (property.Type.GetTypeString() == "\\DateTime") {
192+
if (propertyTypeString == "\\DateTime") {
192193
#>
193-
return new \DateTime($this->_propDict["<#=property.Name.ToCamelize()#>"]);
194+
return new \DateTime($this->_propDict["<#=camelCasePropertyName#>"]);
194195
<#
195196
} else {
196197
#>
197-
return $this->_propDict["<#=property.Name.ToCamelize()#>"];
198+
return $this->_propDict["<#=camelCasePropertyName#>"];
198199
<#
199200
}
200201
#>
@@ -210,23 +211,23 @@ if (property.Type.GetTypeString()[0] == '\\') { #>
210211
* <#=property.GetSanitizedLongDescription()#>
211212
<# } #>
212213
*
213-
* @param <#=property.Type.GetTypeString()#> $val The <#=propertyName#>
214+
* @param <#=propertyTypeReference#> $val The <#=propertyName#>
214215
*
215-
* @return <#=entity.Name.ToCheckedCase()#>
216+
* @return <#=entityCheckedCase#>
216217
*/
217218
public function set<#=propertyName.ToCheckedCase()#>($val)
218219
{
219220
<#
220-
if (property.Type.GetTypeString() == "\\DateTime") {
221+
if (propertyTypeString == "\\DateTime") {
221222
#>
222-
$this->_propDict["<#=property.Name.ToCamelize()#>"]
223+
$this->_propDict["<#=camelCasePropertyName#>"]
223224
= $val->format(\DateTime::ISO8601) . "Z";
224225
<#
225226
} else {
226227
#>
227-
<# if (property.Type.GetTypeString() == "bool") { #>
228+
<# if (propertyTypeString == "bool") { #>
228229
$this->_propDict["<#=property.Name#>"] = boolval($val);
229-
<# } else if (property.Type.GetTypeString() == "int") { #>
230+
<# } else if (propertyTypeString == "int") { #>
230231
$this->_propDict["<#=property.Name#>"] = intval($val);
231232
<# } else { #>
232233
$this->_propDict["<#=property.Name#>"] = $val;
@@ -240,7 +241,7 @@ if (property.Type.GetTypeString()[0] == '\\') { #>
240241
<#
241242
}
242243
}
243-
if (entity.Name.ToCheckedCase() == "Entity") {
244+
if (entityCheckedCase == "Entity") {
244245
#>
245246
/**
246247
* Gets the ODataType

0 commit comments

Comments
 (0)