Skip to content

Commit

Permalink
Add rest-spec parser/generator
Browse files Browse the repository at this point in the history
Re-adding the old parser/generator to programmatically generate
endpoints.  Several tweaks to get it back up to speed compared
to the old version
  • Loading branch information
polyfractal committed Jan 20, 2014
1 parent bfd47f0 commit b814211
Show file tree
Hide file tree
Showing 3 changed files with 359 additions and 0 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"symfony/yaml": "2.4.*@dev",
"satooshi/php-coveralls": "dev-master",
"mikey179/vfsStream": "~1.2",
"twig/twig": "1.*",
"elasticsearch/elasticsearch_src" : "dev-master"
},
"autoload": {
Expand Down
199 changes: 199 additions & 0 deletions util/SpecParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
<?php

require_once '../vendor/autoload.php';

$loader = new Twig_Loader_Filesystem('templates');
$twig = new Twig_Environment($loader);
$template = $twig->loadTemplate('endpoint.twig');

$counter = 0;

if ($handle = opendir('../vendor/elasticsearch/elasticsearch_src/rest-api-spec/api/')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
generateTemplate($entry, $template);
}

}
closedir($handle);
}


function processURLPaths($data)
{
$final = array();

$containsType = false;
$containsIndex = false;
foreach ($data['url']['paths'] as $path) {
$params = array();
preg_match_all('/{(.*?)}/', $path, $params);
$params = $params[1];
$count = count($params);
$parsedPath = str_replace('}','',$path);
$parsedPath = str_replace('{','$',$parsedPath);

if (array_search('index', $params) !== false) {
$containsIndex = true;
}

if (array_search('type', $params) !== false) {
$containsType = true;
}

$duplicate = false;
foreach ($final as $existing) {
if ($existing['params'] === $params) {
$duplicate = true;
}
}

if ($duplicate !== true) {
$final[] = array(
'path' => $path,
'parsedPath' => $parsedPath,
'params' => $params,
'count' => $count
);
}
}

/*
foreach ($final as &$existing) {
if ($containsIndex === true && array_search('index', $existing['params']) === false && array_search('type', $existing['params']) !== false) {
$existing['parsedPath'] = '/_all'.$existing['parsedPath'];
}
}
*/

usort($final, function($a, $b) {
if ($a['count'] == $b['count']) {
return 0;
}
return ($a['count'] > $b['count']) ? -1 : 1;
});

return $final;
}

function getDefaultPath($path) {
if ($path['count'] === 0) {
return $path['path'];
} else {
$final = str_replace('}','',$path['path']);
$final = str_replace('{','$',$final);
return $final;
}
}

function forbid($key, $value)
{
$forbid = array(
'GET' => array(
'/_nodes/hotthreads',
'/_nodes/{node_id}/hotthreads',
'/_nodes/{metric}'
),
'HEAD' => array(),
'PUT' => array(
'/{index}/{type}/_mapping'
),
'POST' => array(
'/_all/{type}/_bulk',
'/_all/{type}/_mget'
),
'DELETE' => array(
'/{index}/{type}',
'/{index}/{type}/_mapping'
),
'QS' => array(
'operation_threading',
'field_data'
)
);

if (isset($forbid['key']) && $forbid['key'] === $value) {
return true;
} else {
return false;
}
}

function generateTemplate($path, $template)
{
$ignoreList = array(
'index.json', 'bulk.json'
);

if (array_search($path, $ignoreList) !== false) {
return;
}

$path = '../vendor/elasticsearch/elasticsearch_src/rest-api-spec/api/'.$path;
$json = file_get_contents($path);
$data = json_decode($json, true);

reset($data);
$namespace = key($data);
$data = $data[$namespace];
$namespace = explode(".", $namespace);

$underscoreNamespace = array(
'get',
'put',
'post',
'delete',
'exists',
'update',
'create'
);

$exceptions = array(
'delete_by_query'
);

if (strpos($namespace[count($namespace)-1], '_')) {
$temp = explode('_',$namespace[count($namespace)-1]);

if (array_search($temp[0], $underscoreNamespace) !== false && array_search($namespace[count($namespace)-1], $exceptions) === false) {
$namespace[count($namespace)-1] = $temp[1];
$namespace[] = $temp[0];
} else {
$namespace[count($namespace)-1] = str_replace('_', '', $namespace[count($namespace)-1]);
}

}



$data['url']['processed'] = processURLPaths($data);
$data['url']['default'] = getDefaultPath($data['url']['processed'][count($data['url']['processed'])-1]);

$renderVars = array(
'json' => $json,
'data' => $data,
'namespace' => $namespace,
'className' => ucfirst($namespace[count($namespace)-1]),
);

$ret = $template->render($renderVars);

$dir = './output/'.implode('/', array_map("ucfirst", array_splice($namespace,0,count($namespace)-1)));

if (substr($dir,-1) !== '/') {
$dir .= '/';
}
if (!file_exists($dir)) {
echo 'making dir: '.$dir."\n\n";
$oldumask = umask(0);
mkdir($dir, 0777, true);
umask($oldumask);
}

echo $dir."\n\n";
$path = $dir.$renderVars['className'].'.php';
echo $path."\n\n";;

file_put_contents($path, $ret);
echo $ret;
}
159 changes: 159 additions & 0 deletions util/templates/endpoint.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?php
/**
* User: zach
* Date: {{ "now"|date("m/d/Y") }}
* Time: {{ "now"|date("H:i:s a") }}
*/
namespace Elasticsearch\Endpoints{% for class in namespace %}{{ loop.last ? ';' : '\\' ~ class|title }}{% endfor %}
use Elasticsearch\Endpoints\AbstractEndpoint;
use Elasticsearch\Common\Exceptions;
/**
* Class {{ className|title }}
*
* @category Elasticsearch
* @package Elasticsearch\Endpoints{% for class in namespace %}{{ loop.last ? '' : '\\' ~ class|title }}{% endfor %}
* @author Zachary Tong <[email protected]>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache2
* @link http://elasticsearch.org
*/
class {{ className|title }} extends AbstractEndpoint
{
{% for part, info in data.url.parts %}
{% if part != 'index' and part != 'type' and part != 'id' %}
// {{info.description }}
private ${{part}};
{% endif %}
{% endfor %}
{% if data.body is not null %}
/**
* @param array $body
*
* @throws \Elasticsearch\Common\Exceptions\InvalidArgumentException
* @return $this
*/
public function setBody($body)
{
if (isset($body) !== true) {
return $this;
}
if (is_array($body) !== true) {
throw new Exceptions\InvalidArgumentException(
'Body must be an array'
);
}
$this->body = $body;
return $this;
}
{% endif %}
{% for part, info in data.url.parts %}
{% if part != 'index' and part != 'type' and part != 'id' %}
/**
* @param ${{part}}
*
* @return $this
*/
public function set{{part|title}}(${{part}})
{
if (isset(${{part}}) !== true) {
return $this;
}
$this->{{part}} = ${{part}};
return $this;
}
{% endif %}
{% endfor %}
{% set exception = '' %}
/**
{% for part, info in data.url.parts %}
{% if info.required is not null %}
{% set exception = ' * @throws \\Elasticsearch\\Common\\Exceptions\\BadMethodCallException
' %}
{% endif %}
{% endfor %}{% autoescape false %}{{ exception }}{% endautoescape %}
* @return string
*/
protected function getURI()
{
{% for part, info in data.url.parts %}
{% if info.required == true %}
if (isset($this->{{ part }}) !== true) {
throw new Exceptions\BadMethodCallException(
'{{ part }} is required for {{ className }}'
);
}
{% endif %}
{% endfor %}
{% for part, info in data.url.parts %}
${{ part }} = $this->{{ part }};
{% endfor %}
$uri = "{{ data.url.default }}";
{% for part, info in data.url.processed %}
{% if info.count > 0 %}
{% set counter = 0 %}
if ({% for param in info.params %}{% if counter == 0 %}isset(${{ param }}) === true{% else %} && isset(${{ param }}) === true{% endif %}{% set counter = counter + 1 %}{% endfor %}) {
$uri = "{{ info.parsedPath }}";
}
{% endif %}
{% endfor %}
return $uri;
}
/**
* @return string[]
*/
protected function getParamWhitelist()
{
return array(
{% for param, options in data.url.params %}
'{{ param }}',
{% endfor %}
);
}
{% if data.body.required == true %}
/**
* @return array
* @throws \Elasticsearch\Common\Exceptions\RuntimeException
*/
protected function getBody()
{
if (isset($this->body) !== true) {
throw new Exceptions\RuntimeException('Body is required for Put');
}
return $this->body;
}
{% endif %}
/**
* @return string
*/
protected function getMethod()
{
{% if data.methods|length > 1 %}
//TODO Fix Me!
return '{{ data.methods|join(',') }}';
{% else %}
return '{{ data.methods[0] }}';
{% endif %}
}
}

0 comments on commit b814211

Please sign in to comment.