1: <?php
2:
3: namespace Guzzle\Service;
4:
5: use Guzzle\Common\Collection;
6: use Guzzle\Common\Exception\InvalidArgumentException;
7: use Guzzle\Common\Exception\BadMethodCallException;
8: use Guzzle\Inflection\InflectorInterface;
9: use Guzzle\Inflection\Inflector;
10: use Guzzle\Http\Client as HttpClient;
11: use Guzzle\Http\Exception\MultiTransferException;
12: use Guzzle\Service\Exception\CommandTransferException;
13: use Guzzle\Http\Message\RequestInterface;
14: use Guzzle\Service\Command\CommandInterface;
15: use Guzzle\Service\Command\Factory\CompositeFactory;
16: use Guzzle\Service\Command\Factory\FactoryInterface as CommandFactoryInterface;
17: use Guzzle\Service\Resource\ResourceIteratorClassFactory;
18: use Guzzle\Service\Resource\ResourceIteratorFactoryInterface;
19: use Guzzle\Service\Description\ServiceDescriptionInterface;
20:
21: 22: 23:
24: class Client extends HttpClient implements ClientInterface
25: {
26: const COMMAND_PARAMS = 'command.params';
27:
28: 29: 30:
31: protected $serviceDescription;
32:
33: 34: 35:
36: protected $enableMagicMethods = true;
37:
38: 39: 40:
41: protected $commandFactory;
42:
43: 44: 45:
46: protected $resourceIteratorFactory;
47:
48: 49: 50:
51: protected $inflector;
52:
53: 54: 55: 56: 57: 58: 59:
60: public static function factory($config = array())
61: {
62: return new static(isset($config['base_url']) ? $config['base_url'] : null, $config);
63: }
64:
65: 66: 67:
68: public static function getAllEvents()
69: {
70: return array_merge(HttpClient::getAllEvents(), array(
71: 'client.command.create',
72: 'command.before_prepare',
73: 'command.after_prepare',
74: 'command.before_send',
75: 'command.after_send'
76: ));
77: }
78:
79: 80: 81: 82: 83: 84: 85: 86: 87:
88: public function __call($method, $args = null)
89: {
90: if (!$this->enableMagicMethods) {
91: throw new BadMethodCallException("Missing method {$method}. This client has not enabled magic methods.");
92: }
93:
94: return $this->getCommand($method, isset($args[0]) ? $args[0] : array())->getResult();
95: }
96:
97: 98: 99: 100: 101: 102: 103:
104: public function enableMagicMethods($isEnabled)
105: {
106: $this->enableMagicMethods = $isEnabled;
107:
108: return $this;
109: }
110:
111: 112: 113:
114: public function getCommand($name, array $args = array())
115: {
116: if (!($command = $this->getCommandFactory()->factory($name, $args))) {
117: throw new InvalidArgumentException("Command was not found matching {$name}");
118: }
119:
120: $command->setClient($this);
121:
122:
123: if ($command instanceof Collection) {
124: if ($options = $this->getConfig(self::COMMAND_PARAMS)) {
125: foreach ($options as $key => $value) {
126: if (!$command->hasKey($key)) {
127: $command->set($key, $value);
128: }
129: }
130: }
131: }
132:
133: $this->dispatch('client.command.create', array(
134: 'client' => $this,
135: 'command' => $command
136: ));
137:
138: return $command;
139: }
140:
141: 142: 143:
144: public function setCommandFactory(CommandFactoryInterface $factory)
145: {
146: $this->commandFactory = $factory;
147:
148: return $this;
149: }
150:
151: 152: 153:
154: public function setResourceIteratorFactory(ResourceIteratorFactoryInterface $factory)
155: {
156: $this->resourceIteratorFactory = $factory;
157:
158: return $this;
159: }
160:
161: 162: 163:
164: public function getIterator($command, array $commandOptions = null, array $iteratorOptions = array())
165: {
166: if (!($command instanceof CommandInterface)) {
167: $command = $this->getCommand($command, $commandOptions ?: array());
168: }
169:
170: return $this->getResourceIteratorFactory()->build($command, $iteratorOptions);
171: }
172:
173: 174: 175:
176: public function execute($command)
177: {
178: if ($command instanceof CommandInterface) {
179: $command = array($command);
180: $singleCommand = true;
181: } elseif (is_array($command)) {
182: $singleCommand = false;
183: } else {
184: throw new InvalidArgumentException('Command must be a command or array of commands');
185: }
186:
187: $failureException = null;
188: $requests = array();
189: $commandRequests = new \SplObjectStorage();
190:
191: foreach ($command as $c) {
192: $c->setClient($this);
193:
194: $request = $c->prepare()->setState(RequestInterface::STATE_NEW);
195: $commandRequests[$request] = $c;
196: $requests[] = $request;
197: $this->dispatch('command.before_send', array('command' => $c));
198: }
199:
200: try {
201: $this->send($requests);
202: foreach ($command as $c) {
203: $this->dispatch('command.after_send', array('command' => $c));
204: }
205: return $singleCommand ? end($command)->getResult() : $command;
206: } catch (MultiTransferException $failureException) {
207:
208: if ($singleCommand) {
209:
210: throw $failureException->getFirst();
211: }
212:
213:
214: $e = CommandTransferException::fromMultiTransferException($failureException);
215:
216:
217: foreach ($failureException->getFailedRequests() as $request) {
218: if (isset($commandRequests[$request])) {
219: $e->addFailedCommand($commandRequests[$request]);
220: unset($commandRequests[$request]);
221: }
222: }
223:
224:
225: foreach ($commandRequests as $success) {
226: $e->addSuccessfulCommand($commandRequests[$success]);
227: $this->dispatch('command.after_send', array('command' => $commandRequests[$success]));
228: }
229:
230: throw $e;
231: }
232: }
233:
234: 235: 236:
237: public function setDescription(ServiceDescriptionInterface $service)
238: {
239: $this->serviceDescription = $service;
240:
241:
242: if ($baseUrl = $service->getBaseUrl()) {
243: $this->setBaseUrl($baseUrl);
244: }
245:
246: return $this;
247: }
248:
249: 250: 251:
252: public function getDescription()
253: {
254: return $this->serviceDescription;
255: }
256:
257: 258: 259:
260: public function setInflector(InflectorInterface $inflector)
261: {
262: $this->inflector = $inflector;
263:
264: return $this;
265: }
266:
267: 268: 269:
270: public function getInflector()
271: {
272: if (!$this->inflector) {
273: $this->inflector = Inflector::getDefault();
274: }
275:
276: return $this->inflector;
277: }
278:
279: 280: 281:
282: protected function getResourceIteratorFactory()
283: {
284: if (!$this->resourceIteratorFactory) {
285:
286: $clientClass = get_class($this);
287: $prefix = substr($clientClass, 0, strrpos($clientClass, '\\'));
288: $this->resourceIteratorFactory = new ResourceIteratorClassFactory(array(
289: "{$prefix}\\Iterator",
290: "{$prefix}\\Model"
291: ));
292: }
293:
294: return $this->resourceIteratorFactory;
295: }
296:
297: 298: 299: 300: 301:
302: protected function getCommandFactory()
303: {
304: if (!$this->commandFactory) {
305: $this->commandFactory = CompositeFactory::getDefaultChain($this);
306: }
307:
308: return $this->commandFactory;
309: }
310: }
311: