1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
17:
18: namespace OpenCloud\Common\Service;
19:
20: use Guzzle\Http\ClientInterface;
21: use Guzzle\Http\Exception\BadResponseException;
22: use Guzzle\Http\Url;
23: use OpenCloud\Common\Base;
24: use OpenCloud\Common\Exceptions;
25: use OpenCloud\Common\Http\Message\Formatter;
26: use OpenCloud\OpenStack;
27: use Symfony\Component\EventDispatcher\EventSubscriberInterface;
28:
29: abstract class CatalogService extends AbstractService
30: {
31: const DEFAULT_URL_TYPE = 'publicURL';
32: const SUPPORTED_VERSION = null;
33:
34: 35: 36:
37: private $type;
38:
39: 40: 41:
42: private $name;
43:
44: 45: 46:
47: private $region;
48:
49: 50: 51:
52: private $urlType;
53:
54: 55: 56: 57:
58: protected $regionless = false;
59:
60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73:
74: public function __construct(ClientInterface $client, $type = null, $name = null, $region = null, $urlType = null)
75: {
76: if (($client instanceof Base || $client instanceof OpenStack) && $client->hasLogger()) {
77: $this->setLogger($client->getLogger());
78: }
79:
80: $this->setClient($client);
81:
82: $this->name = $name ? : static::DEFAULT_NAME;
83: $this->region = $region;
84:
85: $this->region = $region;
86: if ($this->regionless !== true && !$this->region) {
87: throw new Exceptions\ServiceException(sprintf(
88: 'The %s service must have a region set. You can either pass in a region string as an argument param, or'
89: . ' set a default region for your user account by executing User::setDefaultRegion and ::update().',
90: $this->name
91: ));
92: }
93:
94: $this->type = $type ? : static::DEFAULT_TYPE;
95: $this->urlType = $urlType ? : static::DEFAULT_URL_TYPE;
96: $this->setEndpoint($this->findEndpoint());
97:
98: $this->client->setBaseUrl($this->getBaseUrl());
99:
100: if ($this instanceof EventSubscriberInterface) {
101: $this->client->getEventDispatcher()->addSubscriber($this);
102: }
103: }
104:
105: 106: 107:
108: public function getType()
109: {
110: return $this->type;
111: }
112:
113: 114: 115:
116: public function getRegion()
117: {
118: return $this->region;
119: }
120:
121: 122: 123:
124: public function getName()
125: {
126: return $this->name;
127: }
128:
129: 130: 131:
132: public function getUrlType()
133: {
134: return $this->urlType;
135: }
136:
137: 138: 139:
140: public function region()
141: {
142: return $this->getRegion();
143: }
144:
145: 146: 147:
148: public function name()
149: {
150: return $this->name;
151: }
152:
153: 154: 155: 156: 157: 158: 159:
160: public function getUrl($path = null, array $query = array())
161: {
162: return Url::factory($this->getBaseUrl())
163: ->addPath($path)
164: ->setQuery($query);
165: }
166:
167: 168: 169:
170: public function url($path = null, array $query = array())
171: {
172: return $this->getUrl($path, $query);
173: }
174:
175: 176: 177: 178: 179: 180:
181: public function getExtensions()
182: {
183: $ext = $this->getMetaUrl('extensions');
184:
185: return (is_object($ext) && isset($ext->extensions)) ? $ext->extensions : array();
186: }
187:
188: 189: 190: 191: 192:
193: public function limits()
194: {
195: $limits = $this->getMetaUrl('limits');
196:
197: return (is_object($limits)) ? $limits->limits : array();
198: }
199:
200: 201: 202: 203: 204: 205: 206:
207: private function findEndpoint()
208: {
209: if (!$this->getClient()->getCatalog()) {
210: $this->getClient()->authenticate();
211: }
212:
213: $catalog = $this->getClient()->getCatalog();
214:
215:
216: foreach ($catalog->getItems() as $service) {
217: if ($service->hasType($this->type) && $service->hasName($this->name)) {
218: return Endpoint::factory($service->getEndpointFromRegion($this->region), static::SUPPORTED_VERSION, $this->getClient());
219: }
220: }
221:
222: throw new Exceptions\EndpointError(sprintf(
223: 'No endpoints for service type [%s], name [%s], region [%s] and urlType [%s]',
224: $this->type,
225: $this->name,
226: $this->region,
227: $this->urlType
228: ));
229: }
230:
231: 232: 233: 234: 235: 236: 237: 238: 239: 240:
241: private function getMetaUrl($resource)
242: {
243: $url = clone $this->getBaseUrl();
244: $url->addPath($resource);
245: try {
246: $response = $this->getClient()->get($url)->send();
247:
248: return Formatter::decode($response);
249: } catch (BadResponseException $e) {
250:
251: return array();
252:
253: }
254: }
255:
256: 257: 258: 259: 260:
261: public function getBaseUrl()
262: {
263: $url = ($this->urlType == 'publicURL')
264: ? $this->endpoint->getPublicUrl()
265: : $this->endpoint->getPrivateUrl();
266:
267: if ($url === null) {
268: throw new Exceptions\ServiceException(sprintf(
269: 'The base %s could not be found. Perhaps the service '
270: . 'you are using requires a different URL type, or does '
271: . 'not support this region.',
272: $this->urlType
273: ));
274: }
275:
276: return $url;
277: }
278: }
279: