1: <?php
2: /**
3: * Copyright 2012-2014 Rackspace US, Inc.
4: *
5: * Licensed under the Apache License, Version 2.0 (the "License");
6: * you may not use this file except in compliance with the License.
7: * You may obtain a copy of the License at
8: *
9: * http://www.apache.org/licenses/LICENSE-2.0
10: *
11: * Unless required by applicable law or agreed to in writing, software
12: * distributed under the License is distributed on an "AS IS" BASIS,
13: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14: * See the License for the specific language governing permissions and
15: * limitations under the License.
16: */
17:
18: namespace OpenCloud\Common\Service;
19:
20: use Guzzle\Http\ClientInterface;
21: use OpenCloud\Common\Base;
22: use OpenCloud\Common\Collection\PaginatedIterator;
23: use OpenCloud\Common\Exceptions;
24:
25: /**
26: * This class defines a cloud service; a relationship between a specific OpenStack
27: * and a provided service, represented by a URL in the service catalog.
28: *
29: * Because Service is an abstract class, it cannot be called directly. Provider
30: * services such as Rackspace Cloud Servers or OpenStack Swift are each
31: * subclassed from Service.
32: */
33: abstract class AbstractService extends Base implements ServiceInterface
34: {
35: /**
36: * @var \OpenCloud\Common\Http\Client The client which interacts with the API.
37: */
38: protected $client;
39:
40: /**
41: * @var \OpenCloud\Common\Service\Endpoint The endpoint for this service.
42: */
43: protected $endpoint;
44:
45: /**
46: * @var array A collection of resource models that this service has control over.
47: */
48: protected $resources = array();
49:
50: /**
51: * @var array Namespaces for this service.
52: */
53: protected $namespaces = array();
54:
55: /**
56: * @param ClientInterface $client
57: */
58: public function setClient(ClientInterface $client)
59: {
60: $this->client = $client;
61: }
62:
63: /**
64: * @return \OpenCloud\Common\Http\Client
65: */
66: public function getClient()
67: {
68: return $this->client;
69: }
70:
71: /**
72: * @param Endpoint $endpoint
73: */
74: public function setEndpoint($endpoint)
75: {
76: $this->endpoint = $endpoint;
77: }
78:
79: /**
80: * @return \OpenCloud\Common\Service\Endpoint
81: */
82: public function getEndpoint()
83: {
84: return $this->endpoint;
85: }
86:
87: /**
88: * Get all associated resources for this service.
89: *
90: * @access public
91: * @return array
92: */
93: public function getResources()
94: {
95: return $this->resources;
96: }
97:
98: /**
99: * Internal method for accessing child namespace from parent scope.
100: *
101: * @return type
102: */
103: protected function getCurrentNamespace()
104: {
105: $namespace = get_class($this);
106:
107: return substr($namespace, 0, strrpos($namespace, '\\'));
108: }
109:
110: /**
111: * Resolves FQCN for local resource.
112: *
113: * @param $resourceName
114: * @return string
115: * @throws \OpenCloud\Common\Exceptions\UnrecognizedServiceError
116: */
117: protected function resolveResourceClass($resourceName)
118: {
119: $className = substr_count($resourceName, '\\')
120: ? $resourceName
121: : $this->getCurrentNamespace() . '\\Resource\\' . ucfirst($resourceName);
122:
123: if (!class_exists($className)) {
124: throw new Exceptions\UnrecognizedServiceError(sprintf(
125: '%s resource does not exist, please try one of the following: %s',
126: $resourceName,
127: implode(', ', $this->getResources())
128: ));
129: }
130:
131: return $className;
132: }
133:
134: /**
135: * Factory method for instantiating resource objects.
136: *
137: * @param string $resourceName
138: * @param mixed $info (default: null)
139: * @param mixed $parent The parent object
140: * @return object
141: */
142: public function resource($resourceName, $info = null, $parent = null)
143: {
144: $className = $this->resolveResourceClass($resourceName);
145:
146: $resource = new $className($this);
147:
148: if ($parent) {
149: $resource->setParent($parent);
150: }
151:
152: $resource->populate($info);
153:
154: return $resource;
155: }
156:
157: /**
158: * Factory method for instantiating a resource collection.
159: *
160: * @param string $resourceName
161: * @param string|null $url
162: * @param string|null $parent
163: * @return PaginatedIterator
164: */
165: public function resourceList($resourceName, $url = null, $parent = null)
166: {
167: $className = $this->resolveResourceClass($resourceName);
168:
169: return $this->collection($className, $url, $parent);
170: }
171:
172: /**
173: * @codeCoverageIgnore
174: */
175: public function collection($class, $url = null, $parent = null, $data = null)
176: {
177: if (!$parent) {
178: $parent = $this;
179: }
180:
181: if (!$url) {
182: $resource = $this->resolveResourceClass($class);
183: $url = $parent->getUrl($resource::resourceName());
184: }
185:
186: $options = $this->makeResourceIteratorOptions($this->resolveResourceClass($class));
187: $options['baseUrl'] = $url;
188:
189: return PaginatedIterator::factory($parent, $options, $data);
190: }
191:
192: /**
193: * @deprecated
194: */
195: public function namespaces()
196: {
197: return $this->getNamespaces();
198: }
199:
200: /**
201: * Returns a list of supported namespaces
202: *
203: * @return array
204: */
205: public function getNamespaces()
206: {
207: return (isset($this->namespaces) && is_array($this->namespaces))
208: ? $this->namespaces
209: : array();
210: }
211: }
212: