Skip to content

Instantly share code, notes, and snippets.

@d8ahazard
Last active February 29, 2024 07:18
Show Gist options
  • Save d8ahazard/087e2e31f192de408378840f8b56b49e to your computer and use it in GitHub Desktop.
Save d8ahazard/087e2e31f192de408378840f8b56b49e to your computer and use it in GitHub Desktop.
Auto-generate PHP class from swagger documentation...
<?php
// You need to have guzzleHttp installed, and require the vendor path here...
header('content-type:text/plain');
$url = $_GET['url'];
$swaggerApi = json_decode(file_get_contents("$url"), true);
$outFile = pathinfo($url)['filename'] . ".php";
$paths = $swaggerApi['paths'];
$defs = $swaggerApi['definitions'];
$pathParts = [];
$i = 0;
$docLines2 = [];
$methodStrings = "";
$docLines = [];
$className = $swaggerApi['info']['title'];
$className = trim(str_replace("Api", "", $className));
$docHeader = '<?php
use GuzzleHttp\Client;
class '.$className.' {
protected $url;
protected $apiKey;
public function __construct($url, $apiKey) {
$this->url = rtrim($url, "/"); // Example: http://127.0.0.1:8989 (no trailing forward-backward slashes)
$this->apiKey = $apiKey;
}
';
$types = [
'boolean'=>'bool',
'integer'=>'int',
'string'=>'string',
'array'=>'array'
];
$methods = [];
$pathParts = [];
foreach($paths as $key => $path) {
$path_parts = explode("/", $key);
foreach($path_parts as $part) {
$pathParts[$part] = ($pathParts[$part] ?? 1) + 1;
}
}
$masterPath = [];
foreach($pathParts as $pathPart=>$partCount) {
if ($partCount == (count($paths) + 1) && trim($pathPart)) {
write_log("Section $pathPart matches count");
array_push($masterPath, $pathPart);
}
}
$masterPath = "/". join("/", $masterPath);
foreach($paths as $key => $path) {
$docLine = [];
$key = str_replace($masterPath, "", $key);
$path_parts = explode("/", $key);
$get = $path['get'] ?? false;
$post = $path['post'] ?? false;
$put = $path['put'] ?? false;
$delete = $path['delete'] ?? false;
if ($get) $method = "get";
if ($post) $method = "post";
if ($put) $method = "put";
if ($delete) $method = "delete";
$summary = $path[$method]['summary'] ?? "";
$name = $method;
$p = 0;
if (empty($pathParts)) $pathParts = $path_parts;
foreach ($path_parts as &$part) {
if (!preg_match("/{/", $part)) {
$name .= ucfirst($part);
} else {
$part = str_replace('{', '$', $part);
$part = str_replace('}', "", $part);
}
$p++;
}
//$name = titleCase($name);
$uri = join('/', $path_parts);
$uri = ltrim($uri,"/");
$params = $path[$method]['parameters'] ?? [];
$strDesc = "";
$new = [];
$optional = [];
foreach($params as $param) {
if ($param['type'] !== 'apiKey') {
if ($param['required']) {
array_push($new, $param);
} else {
array_push($optional, $param);
}
}
}
$params = $new;
foreach($optional as $add) array_push($params, $add);
$docLine[] = '/**';
$docLine[] = "* $name";
$docLine[] = "* $summary";
$docLine[] = "*";
$paramStrings = [];
$paramNames = [];
$j = 0;
$body = false;
$queryString = [];
foreach ($params as $param) {
$defProps = [];
$paramData = [];
$ref = $param['schema']['$ref'] ?? false;
if ($ref) {
$ref = str_replace('#/definitions/', "", $ref);
$defProps = $defs[$ref]['properties'] ?? [];
$paramData = sortDefProps($defProps);
if ($params['in'] ?? "" == "body") {
$body = $paramData;
}
}
$paramName = $param['name'];
$in = $param["in"] ?? false;
if ($in == "query") $queryString[$paramName] = "$" . $paramName;
$required = $param['required'] ? "(required)" : "(optional)";
$description = $required . " " . $param['description'];
$type = $types[$param['type']] ?? $param['type'] ?? "array";
if (! $param['required']) {
$typeLine = "bool | $type";
} else {
$typeLine = $type;
}
$enum = $param['enum'] ?? false;
if (is_array($enum)) $description .= " '".join(" | ", $enum) ."'";
$docLine[] = '* @param '.$typeLine.' $'.$paramName. ' - '. $description;
if (count($paramData)) {
$jsonLines = explode("\n", json_encode($paramData,JSON_PRETTY_PRINT));
foreach($jsonLines as $line) {
$docLine[] = "* $line";
}
}
$reqString = $param['required'] ? "" : "=false";
$paramStrings[] = '$' . $paramName . $reqString;
$paramNames[] = '$' . $paramName;
$j++;
}
if (count($queryString)) {
$uri .= "?".join("&",$queryString);
}
$retType = $path[$method]['produces'][0] ?? false;
$retType = $retType ? "($retType)" : "";
$docLine[] = "*";
$docLine[] = "* @return string $retType";
$responseRef = $path[$method]['responses']['200']['schema']['$ref'] ?? false;
if ($responseRef) {
$responseRef = str_replace('#/definitions/', "", $responseRef);
$defProps = $defs[$responseRef]['properties'] ?? [];
$paramData = sortDefProps($defProps);
if (count($paramData)) {
$jsonLines = explode("\n", json_encode($paramData,JSON_PRETTY_PRINT));
foreach($jsonLines as $line) {
$docLine[] = "* $line";
}
}
}
$docLine[] = '*/';
$paramVal = isset($paramNames[0]) ? $paramNames[0] : 'false';
$ps = count($paramStrings) ? join(", ", $paramStrings) : "";
$docLine[] = "function ${name}(${ps}) {";
$docLine[] = "\t".'$uri = "'.$uri.'";';
if ($method == 'get') {
$docLine[] = "\t".'return $this->processRequest($uri);';
} else {
$docLine[] = "\t".'$method = "'.$method.'";';
$docLine[] = "\t".'return $this->processRequest($uri, '. $paramVal .', $method);';
}
$docLine[] = '}';
$docLine[] = "";
$i++;
foreach($docLine as $dl) array_push($docLines2, $dl);
if (in_array($name, $methods)) {
echo("WARNING: Duplicate method name '$name' detected.".PHP_EOL.PHP_EOL);
} else {
array_push($methods, $name);
}
}
echo $docHeader;
echo PHP_EOL;
foreach($docLines2 as $line) {
echo "\t$line".PHP_EOL;
}
#TODO: Make this figure out a base URL shared across all endpoints, use that here.
echo '/**
* Process requests with Guzzle
*
* @param string $uri
* @param string $type - Default is "get", also accepts post/put/delete
* @param bool | array $body - A JSON array of key/values to submit on POST/PUT
* @return bool|\Psr\Http\Message\ResponseInterface
*/
protected function _request(string $uri, $body, $type) {
$client = new Client();
$url = $this->url . "'.$masterPath.'/$uri";
write_log("URL is $url");
$options = [];
$options[\'headers\'] = [\'apiKey\' => $this->apiKey];
if ($body) $options[\'json\'] = $body;
write_log("Options for $type: ".json_encode($options));
switch ($type) {
case "get":
return $client->get($url, $options);
break;
case "post":
return $client->post($url, $options);
break;
case "put":
return $client->put($url, $options);
break;
case "delete":
return $client->delete($url, $options);
break;
}
return false;
}
/**
* Process requests, catch exceptions, return json response
*
* @param string $uri
* @param bool | array $body - A JSON array of key/values to submit on POST/PUT
* @param string $type
* @return string - A JSON response
*/
protected function processRequest($uri, $body = false, $type = "get") {
try {
$response = $this->_request($uri, $body, $type);
} catch (\Exception $e) {
return json_encode([\'error\' => array(
\'msg\' => $e->getMessage(),
\'code\' => $e->getCode())
]);
}
return $response->getBody()->getContents();
}
}
';
write_log("Final master path: ".json_encode($pathParts));
die();
function sortDefProps($defProps) {
$types = [
'boolean'=>'bool',
'integer'=>'int',
'string'=>'string',
'array'=>'array'
];
$paramData = [];
foreach($defProps as $propName => $data) {
$type = $data['type'];
if ($type !== 'array') {
$paramData[$propName] = $types[$type] ?? $type;
} else {
$ref2 = str_replace('#/definitions/', "", $data['items']['$ref']);
$defProps2 = $defs[$ref2]['properties'] ?? [];
$paramData[$propName] = "array - " . json_encode(sortDefProps($defProps2),true);
}
}
return $paramData;
}
function titleCase($title, $words) {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment