1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
17:
18: namespace OpenCloud\Common\Resource;
19:
20: use Guzzle\Http\Url;
21: use OpenCloud\Common\Constants\State;
22: use OpenCloud\Common\Exceptions\CreateError;
23: use OpenCloud\Common\Exceptions\DeleteError;
24: use OpenCloud\Common\Exceptions\IdRequiredError;
25: use OpenCloud\Common\Exceptions\NameError;
26: use OpenCloud\Common\Exceptions\UnsupportedExtensionError;
27: use OpenCloud\Common\Exceptions\UpdateError;
28:
29: abstract class PersistentResource extends BaseResource
30: {
31: 32: 33: 34: 35: 36:
37: public function create($params = array())
38: {
39:
40: if (!empty($params)) {
41: $this->populate($params, false);
42: }
43:
44:
45: $json = json_encode($this->createJson());
46: $this->checkJsonError();
47:
48: $createUrl = $this->createUrl();
49:
50: $response = $this->getClient()->post($createUrl, self::getJsonHeader(), $json)->send();
51:
52:
53:
54:
55: if (null !== ($decoded = $this->parseResponse($response))) {
56: $this->populate($decoded);
57: } elseif ($location = $response->getHeader('Location')) {
58: $this->refreshFromLocationUrl($location);
59: }
60:
61: return $response;
62: }
63:
64: 65: 66: 67: 68: 69:
70: public function update($params = array())
71: {
72:
73: if (!empty($params)) {
74: $this->populate($params);
75: }
76:
77:
78: $json = json_encode($this->updateJson($params));
79: $this->checkJsonError();
80:
81:
82: return $this->getClient()->put($this->getUrl(), self::getJsonHeader(), $json)->send();
83: }
84:
85: 86: 87: 88: 89:
90: public function delete()
91: {
92: return $this->getClient()->delete($this->getUrl())->send();
93: }
94:
95: 96: 97: 98: 99: 100: 101: 102:
103: public function refresh($id = null, $url = null)
104: {
105: $primaryKey = $this->primaryKeyField();
106: $primaryKeyVal = $this->getProperty($primaryKey);
107:
108: if (!$url) {
109: if (!$id = $id ?: $primaryKeyVal) {
110: $message = sprintf("This resource cannot be refreshed because it has no %s", $primaryKey);
111: throw new IdRequiredError($message);
112: }
113:
114: if ($primaryKeyVal != $id) {
115: $this->setProperty($primaryKey, $id);
116: }
117:
118: $url = $this->getUrl();
119: }
120:
121:
122: if ($this->getProperty('status')) {
123: $this->setProperty('status', null);
124: }
125:
126: $response = $this->getClient()->get($url)->send();
127:
128: if (null !== ($decoded = $this->parseResponse($response))) {
129: $this->populate($decoded);
130: }
131:
132: return $response;
133: }
134:
135: 136: 137: 138: 139:
140: public function refreshFromLocationUrl($url)
141: {
142: $fullUrl = Url::factory($url);
143:
144: $response = $this->getClient()->get($fullUrl)->send();
145:
146: if (null !== ($decoded = $this->parseResponse($response))) {
147: $this->populate($decoded);
148: }
149: }
150:
151: 152: 153: 154: 155: 156: 157: 158:
159: public function waitFor($state = null, $timeout = null, $callback = null, $interval = null)
160: {
161: $state = $state ?: State::ACTIVE;
162: $timeout = $timeout ?: State::DEFAULT_TIMEOUT;
163: $interval = $interval ?: State::DEFAULT_INTERVAL;
164:
165:
166: $startTime = time();
167:
168: $states = array('ERROR', $state);
169:
170: while (true) {
171:
172: $this->refresh($this->getProperty($this->primaryKeyField()));
173:
174: if ($callback) {
175: call_user_func($callback, $this);
176: }
177:
178: if (in_array($this->status(), $states) || (time() - $startTime) > $timeout) {
179: return;
180: }
181:
182: sleep($interval);
183: }
184: }
185:
186: 187: 188: 189: 190: 191:
192: protected function createJson()
193: {
194: if (!isset($this->createKeys)) {
195: throw new \RuntimeException(sprintf(
196: 'This resource object [%s] must have a visible createKeys array',
197: get_class($this)
198: ));
199: }
200:
201: $element = (object) array();
202:
203: foreach ($this->createKeys as $key) {
204: if (null !== ($property = $this->getProperty($key))) {
205: $element->{$this->getAlias($key)} = $property;
206: }
207: }
208:
209: if (isset($this->metadata) && count($this->metadata)) {
210: $element->metadata = (object) $this->metadata->toArray();
211: }
212:
213: return (object) array($this->jsonName() => (object) $element);
214: }
215:
216: 217: 218: 219: 220: 221: 222:
223: protected function getAlias($key)
224: {
225: if (false !== ($alias = array_search($key, $this->aliases))) {
226: return $alias;
227: }
228:
229: return $key;
230: }
231:
232: 233: 234:
235: protected function updateJson($params = array())
236: {
237: throw new UpdateError('updateJson() must be overriden in order for an update to happen');
238: }
239:
240: 241: 242:
243: protected function noCreate()
244: {
245: throw new CreateError('This resource does not support the create operation');
246: }
247:
248: 249: 250:
251: protected function noDelete()
252: {
253: throw new DeleteError('This resource does not support the delete operation');
254: }
255:
256: 257: 258:
259: protected function noUpdate()
260: {
261: throw new UpdateError('his resource does not support the update operation');
262: }
263:
264: 265: 266: 267: 268: 269: 270:
271: public function checkExtension($alias)
272: {
273: if (!in_array($alias, $this->getService()->namespaces())) {
274: throw new UnsupportedExtensionError(sprintf("%s extension is not installed", $alias));
275: }
276:
277: return true;
278: }
279:
280:
281:
282: 283: 284: 285: 286:
287: public function name()
288: {
289: if (null !== ($name = $this->getProperty('name'))) {
290: return $name;
291: } else {
292: throw new NameError('Name attribute does not exist for this resource');
293: }
294: }
295:
296: 297: 298: 299:
300: public function id()
301: {
302: return $this->id;
303: }
304:
305: 306: 307: 308:
309: public function status()
310: {
311: return (isset($this->status)) ? $this->status : 'N/A';
312: }
313:
314: 315: 316: 317:
318: public function region()
319: {
320: return $this->getService()->region();
321: }
322:
323: 324: 325: 326:
327: public function createUrl()
328: {
329: return $this->getParent()->getUrl($this->resourceName());
330: }
331: }
332: