Skip to content

Commit 21da0fa

Browse files
More docs
1 parent a3eee25 commit 21da0fa

File tree

2 files changed

+217
-0
lines changed

2 files changed

+217
-0
lines changed

docs/userguide/Clients.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Clients
2+
3+
## Overview
4+
5+
A Client is the object responsibile for issuing HTTP requests and receiving responses from the API. In short, it forms the core of the SDK because it controls how functionality is executed. All services depend on the client to work.
6+
7+
Users have access to two types of client: `OpenCloud\OpenStack` and `OpenCloud\Rackspace`. The latter extends the former, meaning that much of the functionality is shared between them. The OpenStack client extends functionality from other base classes, that trace all the way back to Guzzle's root class:
8+
9+
1. `Guzzle\Http\Client`
10+
2. `OpenCloud\Common\Http\Client`
11+
3. `OpenCloud\OpenStack`
12+
4. `OpenCloud\Rackspace`
13+
14+
## Initializing a client
15+
16+
### Rackspace
17+
18+
First, you need to select the Identity endpoint you want to authenticate against. If you're using Rackspace, you can either use the UK or US endpoints. There are class constants defined for your convenience:
19+
20+
- `OpenCloud\Rackspace::US_IDENTITY_ENDPOINT` (https://identity.api.rackspacecloud.com/v2.0)
21+
- `OpenCloud\Rackspace::UK_IDENTITY_ENDPOINT` (https://lon.identity.api.rackspacecloud.com/v2.0)
22+
23+
Then you need to find your username and apiKey. Your username will be visible at the top right of the Rackspace Control panel; and your API key can be retrieved by going to Account Settings. Once this is done:
24+
25+
```php
26+
use OpenCloud\OpenStack;
27+
28+
$client = new Rackspace(Rackspace::US_IDENTITY_ENDPOINT, array(
29+
'username' => 'foo',
30+
'apiKey' => 'bar'
31+
));
32+
```
33+
34+
### OpenStack
35+
36+
To initialize an OpenStack client, the process is the same:
37+
38+
```php
39+
use OpenCloud\OpenStack;
40+
41+
$client = new OpenStack('http://identity.my-openstack.com/v2.0', array(
42+
'username' => 'foo',
43+
'password' => 'bar'
44+
));
45+
```
46+
47+
## Authentication
48+
49+
The Client does not automatically authenticate against the API on object creation - it waits for an API call. When this happens, it checks whether the current "token" has expired, and (re-)authenticates if necessary.
50+
51+
You can force authentication, by calling:
52+
53+
```php
54+
$client->authenticate();
55+
```
56+
57+
If the credentials are incorrect, a `401` error will be returned. If credentials are correct, a `200` status is returned with your Service Catalog.
58+
59+
## Service Catalog
60+
61+
The Service Catalog is returned on successful authentication, and is composed of all the different API services available to the current tenant. All of this functionality is encapsulated in the `Catalog` object, which allows you greater control and interactivity.
62+
63+
```php
64+
/** @var OpenCloud\Common\Service\Catalog */
65+
$catalog = $client->getCatalog();
66+
67+
// Return a list of OpenCloud\Common\Service\CatalogItem objects
68+
foreach ($catalog->getItems() as $catalogItem) {
69+
70+
$name = $catalogItem->getName();
71+
$type = $catalogItem->getType();
72+
73+
if ($name == 'cloudServersOpenStack' && $type == 'compute') {
74+
break;
75+
}
76+
77+
// Array of OpenCloud\Common\Service\Endpoint objects
78+
$endpoints = $catalogItem->getEndpoints();
79+
foreach ($endpoints as $endpoint) {
80+
if ($endpoint->getRegion() == 'DFW') {
81+
echo $endpoint->getPublicUrl();
82+
}
83+
}
84+
}
85+
```
86+
87+
As you can see, you have access to each Service's name, type and list of endpoints. Each endpoint provides access to the specific region, along with its public and private endpoint URLs.
88+
89+
## Default HTTP headers
90+
91+
To set default HTTP headers:
92+
93+
```php
94+
$client->setDefaultOption('headers/X-Custom-Header', 'FooBar');
95+
```
96+
97+
## Other functionality
98+
99+
For a full list of functionality provided by Guzzle, please consult the [official documentation](http://docs.guzzlephp.org/en/latest/http-client/client.html).

docs/userguide/Iterators.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Iterators
2+
3+
## Intro
4+
5+
Iterators allow you to traverse over collections of your resources in an efficient and easy way. Currently there are two Iterators provided by the SDK:
6+
7+
- **ResourceIterator**. The standard iterator class that implements SPL's standard [Iterator](http://php.net/manual/en/class.iterator.php), [ArrayAccess](http://www.php.net/manual/en/class.arrayaccess.php) and [Countable](http://php.net/manual/en/class.countable.php) interfaces. In short, this allows you to traverse this object (using `foreach`), count its internal elements like an array (using `count` or `sizeof`), and access its internal elements like an array (using `$iterator[1]`).
8+
9+
10+
- **PaginatedIterator**. This is a child of ResourceIterator, and as such inherits all of its functionality. The difference however is that when it reaches the end of the current collection, it attempts to construct a URL to access the API based on predictive paginated collection templates.
11+
12+
## Common behaviour
13+
14+
```php
15+
$iterator = $computeService->flavorList();
16+
```
17+
18+
There are two ways to traverse an iterator. The first is the longer, more traditional way:
19+
20+
```php
21+
while ($iterator->valid()) {
22+
$flavor = $iterator->current();
23+
24+
// do stuff..
25+
echo $flavor->id;
26+
27+
$iterator->next();
28+
}
29+
```
30+
31+
There is also a shorter and more intuitive version:
32+
33+
```php
34+
foreach ($iterator as $flavor) {
35+
// do stuff...
36+
echo $flavor->id;
37+
}
38+
```
39+
40+
Because the iterator implements PHP's native `Iterator` interface, it can inherit all the native functionality of traversible data structures with `foreach`.
41+
42+
## Very important note
43+
44+
Until now, users have been expected to do this:
45+
46+
```php
47+
while ($flavor = $iterator->next()) {
48+
// ...
49+
}
50+
```
51+
52+
which is **incorrect**. The single responsibility of `next` is to move the internal pointer forward. It is the job of `current` to retrieve the current element.
53+
54+
For your convenience, these two Iterator classes are fully backward compatible: they exhibit all the functionality you'd expect from a correctly implemented iterator, but they also allow previous behaviour.
55+
56+
## Using paginated collections
57+
58+
For large collections, such as retrieving DataObjects from CloudFiles/Swift, you need to use pagination. Each resource will have a different limit per page; so once that page is traversed, there needs to be another API call to retrieve to *next* page's resources.
59+
60+
There are two key concepts:
61+
62+
- **limit** is the amount of resources returned per page
63+
- **marker** is the way you define a starting point. It is some form of identifier that allows the collection to begin from a specific resource
64+
65+
### Resource classes
66+
67+
When the iterator returns a current element in the internal list, it populates the relevant resource class with all the data returned to the API. In most cases, a `stdClass` object will become an instance of `OpenCloud\Common\PersistentObject`.
68+
69+
In order for this instantiation to happen, the `resourceClass` option must correspond to some method in the parent class that creates the resource. For example, if we specify 'ScalingPolicy' as the `resourceClass`, the parent object (in this case `OpenCloud\Autoscale\Group`, needs to have some method will allows the iterator to instantiate the child resource class. These are all valid:
70+
71+
1. `Group::scalingGroup($data);`
72+
73+
2. `Group::getScalingGroup($data);`
74+
75+
3. `Group::resource('ScalingGroup', $data);`
76+
77+
where `$data` is the standard object. This list runs in order of precedence.
78+
79+
## Setting up a PaginatedIterator
80+
81+
```php
82+
use OpenCloud\Common\Collection\PaginatedIterator;
83+
84+
$service = $client->computeService();
85+
86+
$flavors = PaginatedIterator::factory($service, array(
87+
'resourceClass' => 'Flavor',
88+
'baseUrl' => $service->getUrl('flavors')
89+
'limit.total' => 350,
90+
'limit.page' => 100,
91+
'key.collection' => 'flavors'
92+
));
93+
94+
foreach ($flavors as $flavor) {
95+
echo $flavor->getId();
96+
}
97+
```
98+
99+
As you can see, there are a lot of configuration parameters to pass in - and getting it right can be quite fiddly, involving a lot of API research. For this reason, using the convenience methods like `flavorList` is recommended because it hides the complexity.
100+
101+
### PaginatedIterator options
102+
103+
There are certain configuration options that the paginated iterator needs to work. These are:
104+
105+
Name|Description|Type|Required|Default
106+
---|---|---|---|---
107+
resourceClass|The resource class that is instantiated when the current element is retrieved. This is relative to the parent/service which called the iterator.|string|Yes|-
108+
baseUrl|The base URL that is used for making new calls to the API for new pages|`Guzzle\Http\Url`|Yes|-
109+
limit.total|The total amount of resources you want to traverse in your collection. The iterator will stop as this limit is reached, regardless if there are more items in the list|int|No|10000
110+
limit.page|The amount of resources each page contains|int|No|100
111+
key.links|Often, API responses will contain "links" that allow easy access to the next page of a resource collection. This option specifies what that JSON element is called (its key). For example, for Rackspace Compute images it is `images_links`.|string|No|links
112+
key.collection|The top-level key for the array of resources. For example, servers are returned with this data structure: `{"servers": [...]}`. The **key.collection** value in this case would be `servers`.|string|No|`null`
113+
key.collectionElement|Rarely used. But it indicates the key name for each nested resource element. KeyPairs, for example, are listed like this: `{"keypairs": [ {"keypair": {...}} ] }`. So in this case the collectionElement key would be `keypair`.|string|No|`null`
114+
key.marker|The value used as the marker. It needs to represent a valid property in the JSON resource objects. Often it is `id` or `name`.|string|No|name
115+
request.method|The HTTP method used when making API calls for new pages|string|No|GET
116+
request.headers|The HTTP headers to send when making API calls for new pages|array|No|`array()`
117+
request.body|The HTTP entity body to send when making API calls for new pages|`Guzzle\Http\EntityBody`|No|`null`
118+
request.curlOptions|Additional cURL options to use when making API calls for new pages|array|No|`array()`

0 commit comments

Comments
 (0)