Skip to content

Commit fd027b8

Browse files
author
Jamie Hannaford
committed
move to repo
0 parents  commit fd027b8

File tree

83 files changed

+5788
-0
lines changed

Some content is hidden

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

83 files changed

+5788
-0
lines changed

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.idea/
2+
.test/
3+
coverage/
4+
vendor/
5+
6+
*.pyc
7+
8+
phpunit.xml
9+
coverage.xml
10+
composer.lock

composer.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "php-opencloud/common",
3+
"authors": [
4+
{
5+
"name": "Jamie Hannaford",
6+
"email": "jamie.hannaford@rackspace.com",
7+
"homepage" : "https://github.com/jamiehannaford"
8+
}
9+
],
10+
"autoload": {
11+
"psr-4": {
12+
"OpenCloud\\": "src/",
13+
"OpenCloud\\Test\\": "tests/unit/",
14+
"OpenCloud\\Integration\\": "tests/integration/"
15+
}
16+
},
17+
"repositories": [
18+
{
19+
"type": "vcs",
20+
"url": "https://github.com/php-opencloud/Sami"
21+
}
22+
],
23+
"require": {
24+
"php": "~7.0",
25+
"guzzlehttp/guzzle": "~6.1",
26+
"justinrainbow/json-schema": "~1.3"
27+
},
28+
"require-dev": {
29+
"phpunit/phpunit": "~4.0",
30+
"sami/sami": "dev-master",
31+
"psr/log": "~1.0",
32+
"satooshi/php-coveralls": "~1.0",
33+
"jakub-onderka/php-parallel-lint": "0.*",
34+
"fabpot/php-cs-fixer": "~1.0"
35+
}
36+
}

phpunit.xml.dist

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit bootstrap="./vendor/autoload.php" colors="true">
3+
4+
<testsuites>
5+
<testsuite name="OpenStack">
6+
<directory>tests/unit</directory>
7+
</testsuite>
8+
</testsuites>
9+
10+
<filter>
11+
<whitelist>
12+
<directory suffix=".php">./src</directory>
13+
<exclude>
14+
<directory suffix="Interface.php">./src</directory>
15+
<directory suffix="Api.php">./src</directory>
16+
<directory suffix="Params.php">./src</directory>
17+
</exclude>
18+
</whitelist>
19+
</filter>
20+
21+
</phpunit>

src/Common/Api/AbstractApi.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace OpenCloud\Common\Api;
4+
5+
abstract class AbstractApi implements ApiInterface
6+
{
7+
protected $params;
8+
9+
protected function isRequired(array $param)
10+
{
11+
return array_merge($param, ['required' => true]);
12+
}
13+
14+
protected function notRequired(array $param)
15+
{
16+
return array_merge($param, ['required' => false]);
17+
}
18+
19+
protected function query(array $param)
20+
{
21+
return array_merge($param, ['location' => AbstractParams::QUERY]);
22+
}
23+
24+
protected function url(array $param)
25+
{
26+
return array_merge($param, ['location' => AbstractParams::URL]);
27+
}
28+
29+
public function documented(array $param)
30+
{
31+
return array_merge($param, ['required' => true]);
32+
}
33+
}

src/Common/Api/AbstractParams.php

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
namespace OpenCloud\Common\Api;
4+
5+
abstract class AbstractParams
6+
{
7+
// locations
8+
const QUERY = 'query';
9+
const HEADER = 'header';
10+
const URL = 'url';
11+
const JSON = 'json';
12+
const RAW = 'raw';
13+
14+
// types
15+
const STRING_TYPE = "string";
16+
const BOOL_TYPE = "boolean";
17+
const BOOLEAN_TYPE = self::BOOL_TYPE;
18+
const OBJECT_TYPE = "object";
19+
const ARRAY_TYPE = "array";
20+
const NULL_TYPE = "NULL";
21+
const INT_TYPE = 'integer';
22+
const INTEGER_TYPE = self::INT_TYPE;
23+
24+
public static function isSupportedLocation($val)
25+
{
26+
return in_array($val, [self::QUERY, self::HEADER, self::URL, self::JSON, self::RAW]);
27+
}
28+
29+
public function limit()
30+
{
31+
return [
32+
'type' => self::INT_TYPE,
33+
'location' => 'query',
34+
'description' => <<<DESC
35+
This will limit the total amount of elements returned in a list up to the number specified. For example, specifying a
36+
limit of 10 will return 10 elements, regardless of the actual count.
37+
DESC
38+
];
39+
}
40+
41+
public function marker()
42+
{
43+
return [
44+
'type' => 'string',
45+
'location' => 'query',
46+
'description' => <<<DESC
47+
Specifying a marker will begin the list from the value specified. Elements will have a particular attribute that
48+
identifies them, such as a name or ID. The marker value will search for an element whose identifying attribute matches
49+
the marker value, and begin the list from there.
50+
DESC
51+
];
52+
}
53+
54+
public function id($type)
55+
{
56+
return [
57+
'description' => sprintf("The unique ID, or identifier, for the %s", $type),
58+
'type' => self::STRING_TYPE,
59+
'location' => self::JSON,
60+
];
61+
}
62+
63+
public function idPath()
64+
{
65+
return [
66+
'type' => self::STRING_TYPE,
67+
'location' => self::URL,
68+
'description' => 'The unique ID of the resource',
69+
];
70+
}
71+
72+
public function name($resource)
73+
{
74+
return [
75+
'description' => sprintf("The name of the %s", $resource),
76+
'type' => self::STRING_TYPE,
77+
'location' => self::JSON,
78+
];
79+
}
80+
81+
82+
public function sortDir()
83+
{
84+
return [
85+
'type' => self::STRING_TYPE,
86+
'location' => self::QUERY,
87+
'description' => "Sorts by one or more sets of attribute and sort direction combinations.",
88+
'enum' => ['asc', 'desc']
89+
];
90+
}
91+
92+
public function sortKey()
93+
{
94+
return [
95+
'type' => self::STRING_TYPE,
96+
'location' => self::QUERY,
97+
'description' => "Sorts by one or more sets of attribute and sort direction combinations.",
98+
];
99+
}
100+
}

src/Common/Api/ApiInterface.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace OpenCloud\Common\Api;
4+
5+
/**
6+
* All classes which implement this interface are a data representation of a remote OpenCloud API.
7+
* They do not execute functionality, but instead return data for each API operation for other parts
8+
* of the SDK to use. Usually, the data is injected into {@see OpenCloud\Common\Api\Operation} objects.
9+
* The operation is then serialized into a {@see GuzzleHttp\Message\Request} and sent to the API.
10+
*
11+
* The reason for storing all the API-specific data is to decouple service information from client
12+
* HTTP functionality. Too often it is mixed all across different layers, leading to duplication and
13+
* no separation of concerns. The choice was made for storage in PHP classes, rather than YAML or JSON
14+
* syntax, due to performance concerns.
15+
*
16+
* @package OpenCloud\Common\Api
17+
*/
18+
interface ApiInterface
19+
{
20+
}

src/Common/Api/Operation.php

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?php
2+
3+
namespace OpenCloud\Common\Api;
4+
5+
use GuzzleHttp\Utils;
6+
7+
/**
8+
* This class represents an OpenCloud API operation. It encapsulates most aspects of the REST operation: its HTTP
9+
* method, the URL path, its top-level JSON key, and all of its {@see Parameter} objects.
10+
*
11+
* An operation not only represents a remote operation, but it also provides the mechanism for executing it
12+
* over HTTP. To do this, it uses a {@see ClientInterface} that allows a {@see GuzzleHttp\Message\Request}
13+
* to be created from the user values provided. Once this request is assembled, it is then sent to the
14+
* remote API and the response is returned to whoever first invoked the Operation class.
15+
*
16+
* @package OpenCloud\Common\Api
17+
*/
18+
class Operation
19+
{
20+
/** @var string The HTTP method */
21+
private $method;
22+
23+
/** @var string The URL path */
24+
private $path;
25+
26+
/** @var string The top-level JSON key */
27+
private $jsonKey;
28+
29+
/** @var []Parameter The parameters of this operation */
30+
private $params;
31+
32+
/**
33+
* @param array $definition The data definition (in array form) that will populate this
34+
* operation. Usually this is retrieved from an {@see ApiInterface}
35+
* object method.
36+
*/
37+
public function __construct(array $definition)
38+
{
39+
$this->method = $definition['method'];
40+
$this->path = $definition['path'];
41+
42+
if (isset($definition['jsonKey'])) {
43+
$this->jsonKey = $definition['jsonKey'];
44+
}
45+
46+
$this->params = self::toParamArray($definition['params']);
47+
}
48+
49+
/**
50+
* @return string
51+
*/
52+
public function getPath()
53+
{
54+
return $this->path;
55+
}
56+
57+
/**
58+
* @return string
59+
*/
60+
public function getMethod()
61+
{
62+
return $this->method;
63+
}
64+
65+
/**
66+
* Indicates whether this operation supports a parameter.
67+
*
68+
* @param $key The name of a parameter
69+
*
70+
* @return bool
71+
*/
72+
public function hasParam($key)
73+
{
74+
return isset($this->params[$key]);
75+
}
76+
77+
/**
78+
* @param $name
79+
*
80+
* @return Parameter
81+
*/
82+
public function getParam($name)
83+
{
84+
return isset($this->params[$name]) ? $this->params[$name] : null;
85+
}
86+
87+
/**
88+
* @return string
89+
*/
90+
public function getJsonKey()
91+
{
92+
return $this->jsonKey;
93+
}
94+
95+
/**
96+
* A convenience method that will take a generic array of data and convert it into an array of
97+
* {@see Parameter} objects.
98+
*
99+
* @param array $data A generic data array
100+
*
101+
* @return array
102+
*/
103+
public static function toParamArray(array $data)
104+
{
105+
$params = [];
106+
107+
foreach ($data as $name => $param) {
108+
$params[$name] = new Parameter($param + ['name' => $name]);
109+
}
110+
111+
return $params;
112+
}
113+
114+
/**
115+
* This method will validate all of the user-provided values and throw an exception if any
116+
* failures are detected. This is useful for basic sanity-checking before a request is
117+
* serialized and sent to the API.
118+
*
119+
* @param array $userValues The user-defined values
120+
*
121+
* @return bool TRUE if validation passes
122+
* @throws \Exception If validate fails
123+
*/
124+
public function validate(array $userValues)
125+
{
126+
foreach ($this->params as $paramName => $param) {
127+
if (array_key_exists($paramName, $userValues)) {
128+
$param->validate($userValues[$paramName]);
129+
} elseif ($param->isRequired()) {
130+
throw new \Exception(sprintf('"%s" is a required option, but it was not provided', $paramName));
131+
}
132+
}
133+
134+
return true;
135+
}
136+
}

0 commit comments

Comments
 (0)