diff --git a/examples/test_spec/twilio_response_v1.yaml b/examples/test_spec/twilio_response_v1.yaml index 3188edba5..7411ebb9f 100644 --- a/examples/test_spec/twilio_response_v1.yaml +++ b/examples/test_spec/twilio_response_v1.yaml @@ -1,3 +1,407 @@ # This spec tests followings # 1. All types of response body(json) -# 2. Tests paginated response. \ No newline at end of file +# 2. Tests different response structures for each CRUDF operation +# 3. Create - returns created object with metadata +# 4. Read - returns full object with nested details +# 5. Update - returns updated fields with audit info +# 6. Delete - returns deletion confirmation status +# 7. Find/List - returns paginated array with meta + +info: + contact: + email: support@twilio.com + name: Twilio Support + url: https://support.twilio.com + description: This is the public Twilio REST API. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: https://www.twilio.com/legal/tos + title: Twilio - RESPONSE BODY TEST + version: 1.11.0 + x-twilio: + apiStandards: v1.0 +openapi: 3.0.1 + +components: + securitySchemes: + accountSid_authToken: + scheme: basic + type: http + schemas: + # Schema for Create response - includes creation metadata + WidgetCreateResponse: + type: object + properties: + sid: + type: string + description: Unique identifier for the widget + name: + type: string + description: Name of the widget + description: + type: string + description: Description of the widget + date_created: + type: string + format: date-time + description: Timestamp when the widget was created + created_by: + type: string + description: Account SID of the creator + url: + type: string + format: uri + description: URL to fetch this widget + + # Schema for Read response - includes full details with nested objects + WidgetFetchResponse: + type: object + properties: + sid: + type: string + description: Unique identifier for the widget + name: + type: string + description: Name of the widget + description: + type: string + description: Description of the widget + status: + type: string + enum: + - active + - inactive + - archived + description: Current status of the widget + configuration: + type: object + properties: + enabled: + type: boolean + max_capacity: + type: integer + timeout_seconds: + type: integer + retry_policy: + type: object + properties: + max_retries: + type: integer + backoff_multiplier: + type: number + description: Configuration settings for the widget + tags: + type: array + items: + type: string + description: Tags associated with the widget + date_created: + type: string + format: date-time + date_updated: + type: string + format: date-time + url: + type: string + format: uri + + # Schema for Update response - returns updated fields with audit trail + WidgetUpdateResponse: + type: object + properties: + sid: + type: string + description: Unique identifier for the widget + updated_fields: + type: array + items: + type: string + description: List of fields that were updated + previous_values: + type: object + additionalProperties: true + description: Previous values of updated fields + current_values: + type: object + additionalProperties: true + description: Current values of updated fields + date_updated: + type: string + format: date-time + updated_by: + type: string + description: Account SID of the updater + revision: + type: integer + description: Revision number after update + + # Schema for Delete response - returns deletion confirmation + WidgetDeleteResponse: + type: object + properties: + sid: + type: string + description: Unique identifier of the deleted widget + deleted: + type: boolean + description: Whether the deletion was successful + deleted_at: + type: string + format: date-time + description: Timestamp when the widget was deleted + deleted_by: + type: string + description: Account SID of the deleter + message: + type: string + description: Human-readable confirmation message + archive_url: + type: string + format: uri + description: URL to access archived version if available + + # Schema for List item - simplified version for listing + WidgetListResponse: + type: object + properties: + sid: + type: string + name: + type: string + status: + type: string + enum: + - active + - inactive + - archived + date_created: + type: string + format: date-time + url: + type: string + format: uri + +paths: + # CREATE - POST /v1/Widgets + /v1/Widgets: + servers: + - url: https://response.twilio.com + post: + operationId: CreateWidget + description: Create a new Widget resource + security: + - accountSid_authToken: [] + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + title: CreateWidgetRequest + required: + - Name + properties: + Name: + type: string + description: Name of the widget + Description: + type: string + description: Description of the widget + Status: + type: string + enum: + - active + - inactive + description: Initial status of the widget + responses: + '201': + description: Widget created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetCreateResponse' + + # FIND/LIST - GET /v1/Widgets + get: + operationId: ListWidget + description: Retrieve a list of all Widgets with pagination + security: + - accountSid_authToken: [] + parameters: + - name: Status + in: query + description: Filter by widget status + required: false + schema: + type: string + enum: + - active + - inactive + - archived + - name: PageSize + in: query + description: Maximum number of items to return in a single response + required: false + schema: + type: integer + minimum: 1 + maximum: 1000 + - name: PageToken + in: query + description: Token for pagination + required: false + schema: + type: string + responses: + '200': + description: List of widgets retrieved successfully + content: + application/json: + schema: + type: object + properties: + widgets: + type: array + items: + $ref: '#/components/schemas/WidgetListResponse' + meta: + type: object + required: + - key + - pageSize + properties: + key: + type: string + description: The key of the list property contains the actual data items + example: "services" + pageSize: + type: integer + description: The actual number of items returned in this response + example: 20 + previousToken: + type: string + description: Token to fetch the previous page of results + example: "eyJwYWdlIjowLCJxdWVyeSI6ImJvb2tzIn0=" + nextToken: + type: string + description: Token to fetch the next page of results + example: "eyJwYWdlIjoyLCJxdWVyeSI6ImJvb2tzIn0=" + + # READ, UPDATE, DELETE - /v1/Widgets/{Sid} + /v1/Widgets/{Sid}: + servers: + - url: https://response.twilio.com + + # READ - GET /v1/Widgets/{Sid} + get: + operationId: FetchWidget + description: Fetch a specific Widget by its SID + security: + - accountSid_authToken: [] + parameters: + - name: Sid + in: path + description: The unique identifier of the Widget + required: true + schema: + type: string + minLength: 34 + maxLength: 34 + pattern: '^WG[0-9a-fA-F]{32}$' + - name: IncludeConfiguration + in: query + description: Whether to include configuration details + required: false + schema: + type: boolean + default: true + responses: + '200': + description: Widget retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetFetchResponse' + + # UPDATE - POST /v1/Widgets/{Sid} + post: + operationId: UpdateWidget + description: Update a specific Widget by its SID + security: + - accountSid_authToken: [] + parameters: + - name: Sid + in: path + description: The unique identifier of the Widget + required: true + schema: + type: string + minLength: 34 + maxLength: 34 + pattern: '^WG[0-9a-fA-F]{32}$' + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + title: UpdateWidgetRequest + properties: + Name: + type: string + description: Updated name of the widget + Description: + type: string + description: Updated description of the widget + Status: + type: string + enum: + - active + - inactive + - archived + description: Updated status of the widget + ConfigurationEnabled: + type: boolean + description: Whether widget configuration is enabled + ConfigurationMaxCapacity: + type: integer + description: Maximum capacity setting + responses: + '200': + description: Widget updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetUpdateResponse' + + # DELETE - DELETE /v1/Widgets/{Sid} + delete: + operationId: DeleteWidget + description: Delete a specific Widget by its SID + security: + - accountSid_authToken: [] + parameters: + - name: Sid + in: path + description: The unique identifier of the Widget + required: true + schema: + type: string + minLength: 34 + maxLength: 34 + pattern: '^WG[0-9a-fA-F]{32}$' + - name: Archive + in: query + description: Whether to archive instead of permanently delete + required: false + schema: + type: boolean + default: false + responses: + '200': + description: Widget deleted successfully + content: + application/json: + schema: + $ref: '#/components/schemas/WidgetDeleteResponse' diff --git a/src/main/java/com/twilio/oai/TwilioPhpGenerator.java b/src/main/java/com/twilio/oai/TwilioPhpGenerator.java index 48f46b890..f247e407b 100644 --- a/src/main/java/com/twilio/oai/TwilioPhpGenerator.java +++ b/src/main/java/com/twilio/oai/TwilioPhpGenerator.java @@ -134,9 +134,27 @@ public OperationsMap postProcessOperationsWithModels(final OperationsMap objs, L final List opList = directoryStructureService.processOperations(results); PhpApiResources apiResources = processCodegenOperations(opList); results.put("resources", apiResources); + + // Generate dynamic instance class files (one per response model) + generateDynamicInstanceFiles(apiResources, results); + return results; } + private void generateDynamicInstanceFiles(PhpApiResources apiResources, OperationsMap objs) { + // Build base context with all properties needed by the template + Map baseContext = new HashMap<>(); + baseContext.putAll(additionalProperties); + baseContext.put("resources", apiResources); + // domainName and version are already in additionalProperties (set by TwilioCodegenAdapter) + + // Get output directory for API files + String outputDir = apiFileFolder(); + + // Generate the dynamic files + phpApiActionTemplate.generateDynamicFiles(baseContext, outputDir); + } + @Override public String getName() { return EnumConstants.Generator.TWILIO_PHP.getValue(); @@ -162,14 +180,26 @@ private PhpApiResources processCodegenOperations(List opList) CodegenModelResolver codegenModelResolver = new CodegenModelResolver(conventionMapper, modelFormatMap, Arrays.asList(EnumConstants.JavaDataTypes.values())); PhpPropertyResolver phpPropertyResolver = new PhpPropertyResolver(conventionMapper); - return new PhpApiResourceBuilder(phpApiActionTemplate, opList, this.allModels, twilioCodegen.getToggles(JSON_INGRESS), phpPropertyResolver) - .addVersionLessTemplates(openAPI, directoryStructureService) + + // Create the builder and configure it + PhpApiResourceBuilder builder = new PhpApiResourceBuilder(phpApiActionTemplate, opList, this.allModels, twilioCodegen.getToggles(JSON_INGRESS), phpPropertyResolver); + builder.addVersionLessTemplates(openAPI, directoryStructureService) .updateAdditionalProps(directoryStructureService) .updateOperations(phpParameterResolver) .updateResponseModel(phpPropertyResolver, codegenModelResolver) .updateTemplate() .updateApiPath() - .setImports(directoryStructureService) - .build(); + .setImports(directoryStructureService); + + // Build the apiResource + PhpApiResources apiResources = builder.build(); + + // Register dynamic templates with the full apiResource if there are multiple response models + // This must be done after build() so the apiResource has all properties set + if (builder.hasMultipleResponseModels()) { + phpApiActionTemplate.addDynamicTemplates(PhpApiActionTemplate.TEMPLATE_TYPE_INSTANCE_CLASS, apiResources); + } + + return apiResources; } } diff --git a/src/main/java/com/twilio/oai/api/ApiResourceBuilder.java b/src/main/java/com/twilio/oai/api/ApiResourceBuilder.java index 355268a87..3c05468d5 100644 --- a/src/main/java/com/twilio/oai/api/ApiResourceBuilder.java +++ b/src/main/java/com/twilio/oai/api/ApiResourceBuilder.java @@ -30,6 +30,7 @@ public abstract class ApiResourceBuilder implements IApiResourceBuilder { protected final Map modelTree = new TreeMap<>(); protected final List requiredPathParams = new ArrayList<>(); protected Set apiResponseModels = new LinkedHashSet<>(); + protected Set responseInstanceModels = new LinkedHashSet<>(); protected final Map metaAPIProperties = new HashMap<>(); protected final List listOperations = new ArrayList<>(); protected final List instanceOperations = new ArrayList<>(); diff --git a/src/main/java/com/twilio/oai/api/ApiResources.java b/src/main/java/com/twilio/oai/api/ApiResources.java index f6aec5194..0b982ef67 100644 --- a/src/main/java/com/twilio/oai/api/ApiResources.java +++ b/src/main/java/com/twilio/oai/api/ApiResources.java @@ -18,6 +18,7 @@ public class ApiResources { String recordKey; String version; List responseModels; + Set responseInstanceModels; List requiredPathParams; List apiOperations; Map metaProperties; @@ -41,5 +42,6 @@ public ApiResources(ApiResourceBuilder apiResourceBuilder) { if (ResourceCacheContext.get() != null && ResourceCacheContext.get().isV1()) { isApiV1 = true; } + responseInstanceModels = apiResourceBuilder.responseInstanceModels; } } diff --git a/src/main/java/com/twilio/oai/api/PhpApiResourceBuilder.java b/src/main/java/com/twilio/oai/api/PhpApiResourceBuilder.java index 06fc152ba..6245538a8 100644 --- a/src/main/java/com/twilio/oai/api/PhpApiResourceBuilder.java +++ b/src/main/java/com/twilio/oai/api/PhpApiResourceBuilder.java @@ -2,6 +2,7 @@ import com.twilio.oai.*; import com.twilio.oai.common.EnumConstants; +import com.twilio.oai.java.cache.ResourceCacheContext; import com.twilio.oai.resolver.IConventionMapper; import com.twilio.oai.resolver.LanguageConventionResolver; import com.twilio.oai.resolver.Resolver; @@ -58,7 +59,16 @@ public PhpApiResourceBuilder updateTemplate() { template.add(PhpApiActionTemplate.TEMPLATE_TYPE_OPTIONS); template.add(PhpApiActionTemplate.TEMPLATE_TYPE_PAGE); template.add(PhpApiActionTemplate.TEMPLATE_TYPE_LIST); - template.add(PhpApiActionTemplate.TEMPLATE_TYPE_INSTANCE); + + // Only add regular instance template when there's 1 or fewer response models + // OR when isApiV1 is false (dynamic templates only work with API V1 standard) + // When there are multiple distinct response models AND isApiV1 is true, dynamic templates will be + // added after build() in the generator with the full apiResource + boolean isApiV1 = ResourceCacheContext.get() != null && ResourceCacheContext.get().isV1(); + if (!isApiV1 || responseInstanceModels == null || responseInstanceModels.size() <= 1) { + template.add(PhpApiActionTemplate.TEMPLATE_TYPE_INSTANCE); + } + // if any operation in current op list(CRUDF) has application/json request body type if (!nestedModels.isEmpty()) template.add(PhpApiActionTemplate.TEMPLATE_TYPE_MODELS); @@ -66,6 +76,16 @@ public PhpApiResourceBuilder updateTemplate() { return this; } + /** + * Returns true if this builder has multiple distinct response models that require + * separate instance class files AND isApiV1 is true. + * Dynamic instance templates are only generated for API V1 standard specs. + */ + public boolean hasMultipleResponseModels() { + boolean isApiV1 = ResourceCacheContext.get() != null && ResourceCacheContext.get().isV1(); + return isApiV1 && responseInstanceModels != null && responseInstanceModels.size() > 1; + } + @Override public PhpApiResources build() { return new PhpApiResources(this); @@ -378,6 +398,7 @@ private static Set extractConditionalParams(CodegenOperation operation) @Override public ApiResourceBuilder updateResponseModel(Resolver codegenPropertyResolver) { List responseModels = new ArrayList<>(); + Set responseInstanceModels = new HashSet<>(); codegenOperationList.forEach(codegenOperation -> { codegenOperation.responses .stream() @@ -392,8 +413,10 @@ public ApiResourceBuilder updateResponseModel(Resolver codegenP item.vars.forEach(e -> codegenPropertyResolver.resolve(e, this)); item.allVars.forEach(e -> codegenPropertyResolver.resolve(e, this)); responseModels.add(item); + responseInstanceModels.add(item); }); }); + this.responseInstanceModels = responseInstanceModels; this.apiResponseModels = getDistinctResponseModel(responseModels); return this; } diff --git a/src/main/java/com/twilio/oai/template/AbstractApiActionTemplate.java b/src/main/java/com/twilio/oai/template/AbstractApiActionTemplate.java index 7864629e6..e9549c5f3 100644 --- a/src/main/java/com/twilio/oai/template/AbstractApiActionTemplate.java +++ b/src/main/java/com/twilio/oai/template/AbstractApiActionTemplate.java @@ -1,12 +1,16 @@ package com.twilio.oai.template; -import java.io.File; -import java.util.List; -import java.util.Map; - +import com.samskivert.mustache.Mustache; +import com.samskivert.mustache.Template; import org.openapitools.codegen.CodegenConfig; +import org.openapitools.codegen.CodegenModel; import org.openapitools.codegen.SupportingFile; +import java.io.*; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.*; + public abstract class AbstractApiActionTemplate implements IApiActionTemplate { public static final String API_TEMPLATE = "api"; public static final String NESTED_MODELS = "nested_models"; @@ -15,6 +19,22 @@ public abstract class AbstractApiActionTemplate implements IApiActionTemplate { private final Map> templates = mapping(); protected final CodegenConfig codegen; + // Store dynamic template data + protected final Map dynamicTemplates = new LinkedHashMap<>(); + + // Inner class to hold dynamic template configuration + protected static class DynamicTemplateData { + String templateFile; + String fileSuffix; + Object apiResource; // The full apiResource object (e.g., PhpApiResources) + + DynamicTemplateData(String templateFile, String fileSuffix, Object apiResource) { + this.templateFile = templateFile; + this.fileSuffix = fileSuffix; + this.apiResource = apiResource; + } + } + protected AbstractApiActionTemplate(CodegenConfig defaultCodegen) { this.codegen = initialise(defaultCodegen); } @@ -33,6 +53,7 @@ public void clean() { for (final List entry : templates.values()) { codegen.apiTemplateFiles().remove(entry.get(0)); } + dynamicTemplates.clear(); } @Override @@ -41,6 +62,152 @@ public void add(String template) { codegen.apiTemplateFiles().put(templateStrings.get(0), templateStrings.get(1)); } + @Override + public void addDynamicTemplates(String templateType, Object apiResource) { + List templateStrings = templates.get(templateType); + if (templateStrings != null && apiResource != null) { + // Check if apiResource has responseInstanceModels with more than 1 model + Set models = getResponseInstanceModels(apiResource); + if (models != null && models.size() > 1) { + dynamicTemplates.put(templateType, new DynamicTemplateData( + templateStrings.get(0), // template file + templateStrings.get(1), // file suffix + apiResource + )); + } + } + } + + @Override + public void generateDynamicFiles(Map baseContext, String outputDir) { + for (Map.Entry entry : dynamicTemplates.entrySet()) { + DynamicTemplateData data = entry.getValue(); + + // Extract responseInstanceModels from apiResource + Set models = getResponseInstanceModels(data.apiResource); + if (models == null || models.isEmpty()) { + continue; + } + + for (CodegenModel model : models) { + try { + // Build context with apiResource as "resources" + // The template uses {{#resources}} wrapper, so we need to provide the apiResource + // but with responseInstanceModels containing only the current model + Map context = new HashMap<>(baseContext); + + // Create a wrapper that provides all apiResource properties + // but overrides responseInstanceModels with just the current model + Map resourcesMap = new HashMap<>(); + copyObjectProperties(data.apiResource, resourcesMap); + // Override responseInstanceModels with single model + resourcesMap.put("responseInstanceModels", Collections.singleton(model)); + context.put("resources", resourcesMap); + + // Read and compile template + String templateContent = readResourceTemplate(data.templateFile); + Template template = Mustache.compiler() + .withLoader(name -> new StringReader(readResourceTemplate(name + ".mustache"))) + .defaultValue("") + .compile(templateContent); + + // Render + String rendered = template.execute(context); + + // Write file: {outputDir}/{ModelClassname}{suffix} + String filename = outputDir + File.separator + model.classname + data.fileSuffix; + writeFile(filename, rendered); + + System.out.println("Generated dynamic file: " + filename); + + } catch (Exception e) { + System.err.println("Error generating dynamic file for " + model.classname + ": " + e.getMessage()); + e.printStackTrace(); + } + } + } + } + + /** + * Extracts responseInstanceModels from an apiResource object using reflection. + */ + @SuppressWarnings("unchecked") + private Set getResponseInstanceModels(Object apiResource) { + if (apiResource == null) return null; + + try { + Field field = findField(apiResource.getClass(), "responseInstanceModels"); + if (field != null) { + field.setAccessible(true); + Object value = field.get(apiResource); + if (value instanceof Set) { + return (Set) value; + } + } + } catch (Exception e) { + // Ignore and return null + } + return null; + } + + /** + * Finds a field by name in the class hierarchy. + */ + private Field findField(Class clazz, String fieldName) { + while (clazz != null) { + try { + return clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + clazz = clazz.getSuperclass(); + } + } + return null; + } + + /** + * Copies all properties from an object to a map for mustache rendering. + * Uses reflection to access fields from the object and its superclasses. + */ + private void copyObjectProperties(Object source, Map targetMap) { + if (source == null) return; + + Class clazz = source.getClass(); + while (clazz != null) { + for (Field field : clazz.getDeclaredFields()) { + try { + field.setAccessible(true); + Object value = field.get(source); + if (value != null) { + targetMap.put(field.getName(), value); + } + } catch (IllegalAccessException e) { + // Skip inaccessible fields + } + } + clazz = clazz.getSuperclass(); + } + } + + protected String readResourceTemplate(String templatePath) { + String fullPath = codegen.templateDir() + "/" + templatePath; + try (InputStream is = getClass().getClassLoader().getResourceAsStream(fullPath)) { + if (is == null) { + throw new RuntimeException("Template not found: " + fullPath); + } + return new String(is.readAllBytes(), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Cannot read template: " + fullPath, e); + } + } + + protected void writeFile(String filename, String content) throws IOException { + File file = new File(filename); + file.getParentFile().mkdirs(); + try (FileWriter writer = new FileWriter(file, StandardCharsets.UTF_8)) { + writer.write(content); + } + } + @Override public void addSupportVersion() { final List templateStrings = templates.get(VERSION_TEMPLATE); diff --git a/src/main/java/com/twilio/oai/template/IApiActionTemplate.java b/src/main/java/com/twilio/oai/template/IApiActionTemplate.java index c9a3d4f3a..c42f12149 100644 --- a/src/main/java/com/twilio/oai/template/IApiActionTemplate.java +++ b/src/main/java/com/twilio/oai/template/IApiActionTemplate.java @@ -1,7 +1,15 @@ package com.twilio.oai.template; +import java.util.Map; + public interface IApiActionTemplate { void clean(); void add(String template); void addSupportVersion(); + + // Method for registering dynamic templates that generate multiple files from apiResource + void addDynamicTemplates(String templateType, Object apiResource); + + // Method to generate the dynamic files + void generateDynamicFiles(Map baseContext, String outputDir); } diff --git a/src/main/java/com/twilio/oai/template/PhpApiActionTemplate.java b/src/main/java/com/twilio/oai/template/PhpApiActionTemplate.java index d5b99fc73..173bac738 100644 --- a/src/main/java/com/twilio/oai/template/PhpApiActionTemplate.java +++ b/src/main/java/com/twilio/oai/template/PhpApiActionTemplate.java @@ -1,6 +1,7 @@ package com.twilio.oai.template; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -13,6 +14,8 @@ public class PhpApiActionTemplate extends AbstractApiActionTemplate { public static final String TEMPLATE_TYPE_INSTANCE = "instance"; public static final String TEMPLATE_TYPE_MODELS = "models"; public static final String TEMPLATE_TYPE_PAGE = "page"; + // New template type for individual instance classes (one file per response model) + public static final String TEMPLATE_TYPE_INSTANCE_CLASS = "instanceClass"; public PhpApiActionTemplate(final CodegenConfig defaultCodegen) { super(defaultCodegen); @@ -20,19 +23,16 @@ public PhpApiActionTemplate(final CodegenConfig defaultCodegen) { @Override protected Map> mapping() { - return Map.of(TEMPLATE_TYPE_LIST, - Arrays.asList(TEMPLATE_TYPE_LIST + ".mustache", "List.php"), - TEMPLATE_TYPE_CONTEXT, - Arrays.asList(TEMPLATE_TYPE_CONTEXT + ".mustache", "Context.php"), - TEMPLATE_TYPE_INSTANCE, - Arrays.asList(TEMPLATE_TYPE_INSTANCE + ".mustache", "Instance.php"), - TEMPLATE_TYPE_OPTIONS, - Arrays.asList(TEMPLATE_TYPE_OPTIONS + ".mustache", "Options.php"), - TEMPLATE_TYPE_MODELS, - Arrays.asList(TEMPLATE_TYPE_MODELS + ".mustache", "Models.php"), - TEMPLATE_TYPE_PAGE, - Arrays.asList(TEMPLATE_TYPE_PAGE + ".mustache", "Page.php"), - VERSION_TEMPLATE, - Arrays.asList(VERSION_TEMPLATE + ".mustache", ".php")); + Map> map = new HashMap<>(); + map.put(TEMPLATE_TYPE_LIST, Arrays.asList(TEMPLATE_TYPE_LIST + ".mustache", "List.php")); + map.put(TEMPLATE_TYPE_CONTEXT, Arrays.asList(TEMPLATE_TYPE_CONTEXT + ".mustache", "Context.php")); + map.put(TEMPLATE_TYPE_INSTANCE, Arrays.asList(TEMPLATE_TYPE_INSTANCE + ".mustache", "Instance.php")); + map.put(TEMPLATE_TYPE_OPTIONS, Arrays.asList(TEMPLATE_TYPE_OPTIONS + ".mustache", "Options.php")); + map.put(TEMPLATE_TYPE_MODELS, Arrays.asList(TEMPLATE_TYPE_MODELS + ".mustache", "Models.php")); + map.put(TEMPLATE_TYPE_PAGE, Arrays.asList(TEMPLATE_TYPE_PAGE + ".mustache", "Page.php")); + map.put(VERSION_TEMPLATE, Arrays.asList(VERSION_TEMPLATE + ".mustache", ".php")); + // Dynamic template for generating individual instance class files + map.put(TEMPLATE_TYPE_INSTANCE_CLASS, Arrays.asList("instanceClass.mustache", "Instance.php")); + return map; } } diff --git a/src/main/resources/twilio-php/contextMethod.mustache b/src/main/resources/twilio-php/contextMethod.mustache index efae75c64..e3cf40d27 100644 --- a/src/main/resources/twilio-php/contextMethod.mustache +++ b/src/main/resources/twilio-php/contextMethod.mustache @@ -140,7 +140,7 @@ {{^vendorExtensions.x-is-delete-operation}} $payload = $this->version->{{#lambda.camelcase}}{{vendorExtensions.x-name}}{{/lambda.camelcase}}('{{httpMethod}}', $this->uri{{#queryParams.0}}, $params{{/queryParams.0}}{{^queryParams}}, []{{/queryParams}}{{#formParams.0}}, $data{{/formParams.0}}{{^formParams}}{{#bodyParams.0}}, $data{{/bodyParams.0}}{{^bodyParams}}, []{{/bodyParams}}{{/formParams}}, $headers); - return new {{apiName}}Instance( + return new {{^isApiV1}}{{apiName}}{{/isApiV1}}{{#isApiV1}}{{returnBaseType}}{{/isApiV1}}Instance( $this->version, $payload{{#optionalParams}}{{#isPathParam}}, $this->solution['{{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}']{{/isPathParam}}{{/optionalParams}}{{#requiredParams}}{{#isPathParam}}, diff --git a/src/main/resources/twilio-php/instance.mustache b/src/main/resources/twilio-php/instance.mustache index 0d8b3a55c..c56bcb0c2 100644 --- a/src/main/resources/twilio-php/instance.mustache +++ b/src/main/resources/twilio-php/instance.mustache @@ -7,6 +7,7 @@ namespace Twilio\Rest\{{domainName}}\{{version}}{{namespaceSubPart}}; {{>imports}} +{{^isApiV1}} {{#responseModels.0}} /** {{#responseModels}} @@ -33,8 +34,7 @@ class {{apiName}}Instance extends InstanceResource */ public function __construct(Version $version, array $payload{{#requiredPathParams}}{{#vendorExtensions.x-is-parent-param}}, {{{dataType}}} ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}{{/vendorExtensions.x-is-parent-param}}{{^vendorExtensions.x-is-parent-param}}, ?{{{dataType}}} ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}} = null{{/vendorExtensions.x-is-parent-param}}{{/requiredPathParams}}) { - {{^isApiV1}}parent::__construct($version);{{/isApiV1}}{{#isApiV1}}$apiV1Version = new ApiV1Version($version->getDomain(), $version->version); - parent::__construct($apiV1Version);{{/isApiV1}} + parent::__construct($version); {{#responseModels.0}} // Marshaled Properties @@ -129,5 +129,9 @@ class {{apiName}}Instance extends InstanceResource return '[Twilio.{{domainName}}.{{version}}.{{apiName}}Instance{{#metaProperties.x-is-context-operation}} ' . \implode(' ', $context) . '{{/metaProperties.x-is-context-operation}}]'; } } +{{/isApiV1}} +{{#isApiV1}} +{{>instanceClasses}} +{{/isApiV1}} {{/resources}} diff --git a/src/main/resources/twilio-php/instanceClass.mustache b/src/main/resources/twilio-php/instanceClass.mustache new file mode 100644 index 000000000..92d802968 --- /dev/null +++ b/src/main/resources/twilio-php/instanceClass.mustache @@ -0,0 +1,130 @@ +{{#resources}} +{{#isApiV1}} +licenseInfo}} + +namespace Twilio\Rest\{{domainName}}\{{version}}{{namespaceSubPart}}; + +{{>imports}} + +{{#responseInstanceModels}} +/** +{{#vars}} * @property {{{dataType}}} ${{#lambda.customcamelcase}}{{baseName}}{{/lambda.customcamelcase}} +{{/vars}} */ +class {{classname}}Instance extends InstanceResource +{ +{{#metaProperties.contextImportProperties}} + protected $_{{#lambda.camelcase}}{{mountName}}{{/lambda.camelcase}}; + {{#-last}} + + {{/-last}} +{{/metaProperties.contextImportProperties}} + /** + * Initialize the {{classname}}Instance + * + * @param Version $version Version that contains the resource + * @param mixed[] $payload The response payload + {{#requiredPathParams}} + * @param {{{dataType}}} ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}{{#description}} {{{description}}}{{/description}} + {{/requiredPathParams}} + */ + public function __construct(Version $version, array $payload{{#requiredPathParams}}{{#vendorExtensions.x-is-parent-param}}, {{{dataType}}} ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}{{/vendorExtensions.x-is-parent-param}}{{^vendorExtensions.x-is-parent-param}}, ?{{{dataType}}} ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}} = null{{/vendorExtensions.x-is-parent-param}}{{/requiredPathParams}}) + { + {{^isApiV1}}parent::__construct($version);{{/isApiV1}}{{#isApiV1}}$apiV1Version = new ApiV1Version($version->getDomain(), $version->version); + parent::__construct($apiV1Version);{{/isApiV1}} + + // Marshaled Properties + $this->properties = [ + {{#vars}} + {{^vendorExtensions.x-deserialize}} + '{{#lambda.customcamelcase}}{{baseName}}{{/lambda.customcamelcase}}' => Values::array_get($payload, '{{name}}'), + {{/vendorExtensions.x-deserialize}} + {{#vendorExtensions.x-deserialize}} + '{{#lambda.customcamelcase}}{{baseName}}{{/lambda.customcamelcase}}' => {{.}}(Values::array_get($payload, '{{name}}')), + {{/vendorExtensions.x-deserialize}} + {{/vars}} + ]; + + $this->solution = [{{#requiredPathParams}}{{#vendorExtensions.x-is-parent-param}}'{{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}' => ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}, {{/vendorExtensions.x-is-parent-param}}{{^vendorExtensions.x-is-parent-param}}'{{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}' => ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}} ?: $this->properties['{{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}'], {{/vendorExtensions.x-is-parent-param}}{{/requiredPathParams}}]; + } + +{{#metaProperties.x-is-context-operation}} + /** + * Generate an instance context for the instance, the context is capable of + * performing various actions. All instance actions are proxied to the context + * + * @return {{apiName}}Context Context for this {{apiName}}Instance + */ + protected function proxy(): {{apiName}}Context + { + if (!$this->context) { + $this->context = new {{apiName}}Context( + $this->version{{#requiredPathParams.0}},{{/requiredPathParams.0}} + {{#requiredPathParams}} + $this->solution['{{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}']{{^-last}},{{/-last}} + {{/requiredPathParams}} + ); + } + + return $this->context; + } + +{{/metaProperties.x-is-context-operation}} +{{#apiOperations}} +{{#vendorExtensions.instanceOperation}}{{>method}} + return $this->proxy()->{{#lambda.camelcase}}{{vendorExtensions.x-name}}{{/lambda.camelcase}}({{#requiredParams}}{{^isPathParam}}${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}{{^-last}}, {{/-last}}{{/isPathParam}}{{/requiredParams}}{{#vendorExtensions.hasRequiredNonPathParams}}{{#vendorExtensions.hasOptionalQueryParams}}, {{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{#vendorExtensions.hasOptionalFormParams}}, {{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalFormParams}}{{#vendorExtensions.hasOptionalHeaderParams}}, {{/vendorExtensions.hasOptionalHeaderParams}}{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{/vendorExtensions.hasRequiredNonPathParams}}{{#vendorExtensions.hasOptionalQueryParams}}$options{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{#vendorExtensions.hasOptionalFormParams}}$options{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalFormParams}}{{#vendorExtensions.hasOptionalHeaderParams}}$options{{/vendorExtensions.hasOptionalHeaderParams}}{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}); + } + +{{/vendorExtensions.instanceOperation}} +{{/apiOperations}} +{{#metaProperties.contextImportProperties}} + /** + * Access the {{#lambda.camelcase}}{{mountName}}{{/lambda.camelcase}} + */ + protected function get{{#lambda.titlecase}}{{mountName}}{{/lambda.titlecase}}(): {{filename}}List + { + return $this->proxy()->{{#lambda.camelcase}}{{mountName}}{{/lambda.camelcase}}; + } + +{{/metaProperties.contextImportProperties}} + /** + * Magic getter to access properties + * + * @param string $name Property to access + * @return mixed The requested property + * @throws TwilioException For unknown properties + */ + public function __get(string $name) + { + if (\array_key_exists($name, $this->properties)) { + return $this->properties[$name]; + } + + if (\property_exists($this, '_' . $name)) { + $method = 'get' . \ucfirst($name); + return $this->$method(); + } + + throw new TwilioException('Unknown property: ' . $name); + } + + /** + * Provide a friendly representation + * + * @return string Machine friendly representation + */ + public function __toString(): string + { + {{#metaProperties.x-is-context-operation}} + $context = []; + foreach ($this->solution as $key => $value) { + $context[] = "$key=$value"; + } + {{/metaProperties.x-is-context-operation}} + return '[Twilio.{{domainName}}.{{version}}.{{classname}}Instance{{#metaProperties.x-is-context-operation}} ' . \implode(' ', $context) . '{{/metaProperties.x-is-context-operation}}]'; + } +} +{{/responseInstanceModels}} +{{/isApiV1}} +{{/resources}} diff --git a/src/main/resources/twilio-php/instanceClasses.mustache b/src/main/resources/twilio-php/instanceClasses.mustache new file mode 100644 index 000000000..51b37a946 --- /dev/null +++ b/src/main/resources/twilio-php/instanceClasses.mustache @@ -0,0 +1,120 @@ +{{#isApiV1}} +{{#responseInstanceModels}} +{{#vars}}/** + * @property {{{dataType}}} ${{#lambda.customcamelcase}}{{baseName}}{{/lambda.customcamelcase}} + */{{/vars}} +class {{classname}}Instance extends InstanceResource +{ +{{#metaProperties.contextImportProperties}} + protected $_{{#lambda.camelcase}}{{mountName}}{{/lambda.camelcase}}; + {{#-last}} + + {{/-last}} +{{/metaProperties.contextImportProperties}} + /** + * Initialize the {{classname}}Instance + * + * @param Version $version Version that contains the resource + * @param mixed[] $payload The response payload + {{#requiredPathParams}} + * @param {{{dataType}}} ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}{{#description}} {{{description}}}{{/description}} + {{/requiredPathParams}} + */ + public function __construct(Version $version, array $payload{{#requiredPathParams}}{{#vendorExtensions.x-is-parent-param}}, {{{dataType}}} ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}{{/vendorExtensions.x-is-parent-param}}{{^vendorExtensions.x-is-parent-param}}, ?{{{dataType}}} ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}} = null{{/vendorExtensions.x-is-parent-param}}{{/requiredPathParams}}) + { + {{^isApiV1}}parent::__construct($version);{{/isApiV1}}{{#isApiV1}}$apiV1Version = new ApiV1Version($version->getDomain(), $version->version); + parent::__construct($apiV1Version);{{/isApiV1}} + + // Marshaled Properties + $this->properties = [ + {{#vars}} + {{^vendorExtensions.x-deserialize}} + '{{#lambda.customcamelcase}}{{baseName}}{{/lambda.customcamelcase}}' => Values::array_get($payload, '{{name}}'), + {{/vendorExtensions.x-deserialize}} + {{#vendorExtensions.x-deserialize}} + '{{#lambda.customcamelcase}}{{baseName}}{{/lambda.customcamelcase}}' => {{.}}(Values::array_get($payload, '{{name}}')), + {{/vendorExtensions.x-deserialize}} + {{/vars}} + ]; + + $this->solution = [{{#requiredPathParams}}{{#vendorExtensions.x-is-parent-param}}'{{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}' => ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}, {{/vendorExtensions.x-is-parent-param}}{{^vendorExtensions.x-is-parent-param}}'{{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}' => ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}} ?: $this->properties['{{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}'], {{/vendorExtensions.x-is-parent-param}}{{/requiredPathParams}}]; + } + +{{#metaProperties.x-is-context-operation}} + /** + * Generate an instance context for the instance, the context is capable of + * performing various actions. All instance actions are proxied to the context + * + * @return {{classname}}Context Context for this {{classname}}Instance + */ + protected function proxy(): {{classname}}Context + { + if (!$this->context) { + $this->context = new {{classname}}Context( + $this->version{{#requiredPathParams.0}},{{/requiredPathParams.0}} + {{#requiredPathParams}} + $this->solution['{{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}']{{^-last}},{{/-last}} + {{/requiredPathParams}} + ); + } + + return $this->context; + } + +{{/metaProperties.x-is-context-operation}} +{{#apiOperations}} +{{#vendorExtensions.instanceOperation}}{{>method}} + return $this->proxy()->{{#lambda.camelcase}}{{vendorExtensions.x-name}}{{/lambda.camelcase}}({{#requiredParams}}{{^isPathParam}}${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}{{^-last}}, {{/-last}}{{/isPathParam}}{{/requiredParams}}{{#vendorExtensions.hasRequiredNonPathParams}}{{#vendorExtensions.hasOptionalQueryParams}}, {{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{#vendorExtensions.hasOptionalFormParams}}, {{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalFormParams}}{{#vendorExtensions.hasOptionalHeaderParams}}, {{/vendorExtensions.hasOptionalHeaderParams}}{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{/vendorExtensions.hasRequiredNonPathParams}}{{#vendorExtensions.hasOptionalQueryParams}}$options{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{#vendorExtensions.hasOptionalFormParams}}$options{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalFormParams}}{{#vendorExtensions.hasOptionalHeaderParams}}$options{{/vendorExtensions.hasOptionalHeaderParams}}{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}); + } + +{{/vendorExtensions.instanceOperation}} +{{/apiOperations}} +{{#metaProperties.contextImportProperties}} + /** + * Access the {{#lambda.camelcase}}{{mountName}}{{/lambda.camelcase}} + */ + protected function get{{#lambda.titlecase}}{{mountName}}{{/lambda.titlecase}}(): {{filename}}List + { + return $this->proxy()->{{#lambda.camelcase}}{{mountName}}{{/lambda.camelcase}}; + } + +{{/metaProperties.contextImportProperties}} + /** + * Magic getter to access properties + * + * @param string $name Property to access + * @return mixed The requested property + * @throws TwilioException For unknown properties + */ + public function __get(string $name) + { + if (\array_key_exists($name, $this->properties)) { + return $this->properties[$name]; + } + + if (\property_exists($this, '_' . $name)) { + $method = 'get' . \ucfirst($name); + return $this->$method(); + } + + throw new TwilioException('Unknown property: ' . $name); + } + + /** + * Provide a friendly representation + * + * @return string Machine friendly representation + */ + public function __toString(): string + { + {{#metaProperties.x-is-context-operation}} + $context = []; + foreach ($this->solution as $key => $value) { + $context[] = "$key=$value"; + } + {{/metaProperties.x-is-context-operation}} + return '[Twilio.{{domainName}}.{{version}}.{{classname}}Instance{{#metaProperties.x-is-context-operation}} ' . \implode(' ', $context) . '{{/metaProperties.x-is-context-operation}}]'; + } +} +{{/responseInstanceModels}} +{{/isApiV1}} diff --git a/src/main/resources/twilio-php/method.mustache b/src/main/resources/twilio-php/method.mustache index 4e9c91954..afa46638b 100644 --- a/src/main/resources/twilio-php/method.mustache +++ b/src/main/resources/twilio-php/method.mustache @@ -1,5 +1,5 @@ /** - * {{vendorExtensions.x-name}} the {{apiName}}Instance + * {{vendorExtensions.x-name}} the {{^isApiV1}}{{apiName}}{{/isApiV1}}{{#isApiV1}}{{returnBaseType}}{{/isApiV1}}Instance * {{#requiredParams}} {{^isPathParam}} @@ -20,12 +20,12 @@ {{/vendorExtensions.hasOptionalFormParams}} {{/vendorExtensions.hasOptionalQueryParams}} {{^vendorExtensions.x-is-delete-operation}} - * @return {{apiName}}Instance {{#vendorExtensions.x-is-fetch-operation}}{{vendorExtensions.x-name}}ed{{/vendorExtensions.x-is-fetch-operation}}{{^vendorExtensions.x-is-fetch-operation}}{{vendorExtensions.x-name}}d{{/vendorExtensions.x-is-fetch-operation}} {{apiName}}Instance + * @return {{^isApiV1}}{{apiName}}{{/isApiV1}}{{#isApiV1}}{{returnBaseType}}{{/isApiV1}}Instance {{#vendorExtensions.x-is-fetch-operation}}{{vendorExtensions.x-name}}ed{{/vendorExtensions.x-is-fetch-operation}}{{^vendorExtensions.x-is-fetch-operation}}{{vendorExtensions.x-name}}d{{/vendorExtensions.x-is-fetch-operation}} {{^isApiV1}}{{apiName}}{{/isApiV1}}{{#isApiV1}}{{returnBaseType}}{{/isApiV1}}Instance {{/vendorExtensions.x-is-delete-operation}} {{#vendorExtensions.x-is-delete-operation}} * @return bool True if delete succeeds, false otherwise {{/vendorExtensions.x-is-delete-operation}} * @throws TwilioException When an HTTP error occurs. */ - public function {{#lambda.camelcase}}{{vendorExtensions.x-name}}{{/lambda.camelcase}}({{#requiredParams}}{{^isPathParam}}{{^vendorExtensions.x-serialize-map}}{{{dataType}}} ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}{{/vendorExtensions.x-serialize-map}}{{#vendorExtensions.x-serialize-map}}array ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}{{/vendorExtensions.x-serialize-map}}{{^-last}}, {{/-last}}{{/isPathParam}}{{/requiredParams}}{{#vendorExtensions.hasRequiredNonPathParams}}{{#vendorExtensions.hasOptionalQueryParams}}, {{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{#vendorExtensions.hasOptionalFormParams}}, {{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalFormParams}}{{#vendorExtensions.hasOptionalHeaderParams}}, {{/vendorExtensions.hasOptionalHeaderParams}}{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{/vendorExtensions.hasRequiredNonPathParams}}{{#vendorExtensions.hasOptionalQueryParams}}array $options = []{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{#vendorExtensions.hasOptionalFormParams}}array $options = []{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalFormParams}}{{#vendorExtensions.hasOptionalHeaderParams}}array $options = []{{/vendorExtensions.hasOptionalHeaderParams}}{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}): {{#vendorExtensions.x-is-delete-operation}}bool{{/vendorExtensions.x-is-delete-operation}}{{^vendorExtensions.x-is-delete-operation}}{{apiName}}Instance{{/vendorExtensions.x-is-delete-operation}} + public function {{#lambda.camelcase}}{{vendorExtensions.x-name}}{{/lambda.camelcase}}({{#requiredParams}}{{^isPathParam}}{{^vendorExtensions.x-serialize-map}}{{{dataType}}} ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}{{/vendorExtensions.x-serialize-map}}{{#vendorExtensions.x-serialize-map}}array ${{#lambda.camelcase}}{{baseName}}{{/lambda.camelcase}}{{/vendorExtensions.x-serialize-map}}{{^-last}}, {{/-last}}{{/isPathParam}}{{/requiredParams}}{{#vendorExtensions.hasRequiredNonPathParams}}{{#vendorExtensions.hasOptionalQueryParams}}, {{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{#vendorExtensions.hasOptionalFormParams}}, {{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalFormParams}}{{#vendorExtensions.hasOptionalHeaderParams}}, {{/vendorExtensions.hasOptionalHeaderParams}}{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{/vendorExtensions.hasRequiredNonPathParams}}{{#vendorExtensions.hasOptionalQueryParams}}array $options = []{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{#vendorExtensions.hasOptionalFormParams}}array $options = []{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalQueryParams}}{{^vendorExtensions.hasOptionalFormParams}}{{#vendorExtensions.hasOptionalHeaderParams}}array $options = []{{/vendorExtensions.hasOptionalHeaderParams}}{{/vendorExtensions.hasOptionalFormParams}}{{/vendorExtensions.hasOptionalQueryParams}}): {{#vendorExtensions.x-is-delete-operation}}bool{{/vendorExtensions.x-is-delete-operation}}{{^vendorExtensions.x-is-delete-operation}}{{^isApiV1}}{{apiName}}{{/isApiV1}}{{#isApiV1}}{{returnBaseType}}{{/isApiV1}}Instance{{/vendorExtensions.x-is-delete-operation}} {