PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Guzzle/Service/Client.php

http://github.com/guzzle/guzzle
PHP | 335 lines | 165 code | 37 blank | 133 comment | 15 complexity | ffdd85de9fce774218dbcf6ff5e07fc3 MD5 | raw file
  1. <?php
  2. namespace Guzzle\Service;
  3. use Guzzle\Common\Collection;
  4. use Guzzle\Common\Exception\InvalidArgumentException;
  5. use Guzzle\Common\Exception\BadMethodCallException;
  6. use Guzzle\Inflection\InflectorInterface;
  7. use Guzzle\Inflection\Inflector;
  8. use Guzzle\Http\Client as HttpClient;
  9. use Guzzle\Http\Message\RequestInterface;
  10. use Guzzle\Service\Command\CommandInterface;
  11. use Guzzle\Service\Command\Factory\CompositeFactory;
  12. use Guzzle\Service\Command\Factory\ServiceDescriptionFactory;
  13. use Guzzle\Service\Command\Factory\FactoryInterface as CommandFactoryInterface;
  14. use Guzzle\Service\Resource\ResourceIteratorClassFactory;
  15. use Guzzle\Service\Resource\ResourceIteratorFactoryInterface;
  16. use Guzzle\Service\Description\ServiceDescription;
  17. /**
  18. * Client object for executing commands on a web service.
  19. */
  20. class Client extends HttpClient implements ClientInterface
  21. {
  22. /**
  23. * @var ServiceDescription Description of the service and possible commands
  24. */
  25. protected $serviceDescription;
  26. /**
  27. * @var string Setting to use for magic method calls
  28. */
  29. protected $magicMethodBehavior = false;
  30. /**
  31. * @var CommandFactoryInterface
  32. */
  33. protected $commandFactory;
  34. /**
  35. * @var ResourceIteratorFactoryInterface
  36. */
  37. protected $resourceIteratorFactory;
  38. /**
  39. * @var InflectorInterface Inflector associated with the service/client
  40. */
  41. protected $inflector;
  42. /**
  43. * Basic factory method to create a new client. Extend this method in
  44. * subclasses to build more complex clients.
  45. *
  46. * @param array|Collection $config Configuration data
  47. *
  48. * @return Client
  49. */
  50. public static function factory($config = array())
  51. {
  52. return new static($config['base_url'], $config);
  53. }
  54. /**
  55. * {@inheritdoc}
  56. */
  57. public static function getAllEvents()
  58. {
  59. return array_merge(HttpClient::getAllEvents(), array(
  60. 'client.command.create',
  61. 'command.before_prepare',
  62. 'command.before_send',
  63. 'command.after_send'
  64. ));
  65. }
  66. /**
  67. * Helper method to find and execute a command. Magic method calls must be
  68. * enabled on the client to use this functionality.
  69. *
  70. * @param string $method Name of the command object to instantiate
  71. * @param array $args Arguments to pass to the command
  72. *
  73. * @return mixed
  74. * @throws BadMethodCallException when a command is not found or magic
  75. * methods are disabled
  76. */
  77. public function __call($method, $args = null)
  78. {
  79. if ($this->magicMethodBehavior == self::MAGIC_CALL_DISABLED) {
  80. throw new BadMethodCallException(
  81. "Missing method {$method}. Enable magic calls to use magic methods with command names."
  82. );
  83. }
  84. $command = $this->getCommand($method, isset($args[0]) ? $args[0] : array());
  85. return $this->magicMethodBehavior == self::MAGIC_CALL_RETURN ? $command : $this->execute($command);
  86. }
  87. /**
  88. * Set the behavior for missing methods
  89. *
  90. * @param int $behavior Behavior to use when a missing method is called.
  91. * - Client::MAGIC_CALL_DISABLED: Disable magic method calls
  92. * - Client::MAGIC_CALL_EXECUTE: Execute commands and return the result
  93. * - Client::MAGIC_CALL_RETURN: Instantiate and return the command
  94. *
  95. * @return Client
  96. */
  97. public function setMagicCallBehavior($behavior)
  98. {
  99. $this->magicMethodBehavior = (int) $behavior;
  100. return $this;
  101. }
  102. /**
  103. * Get a command by name. First, the client will see if it has a service
  104. * description and if the service description defines a command by the
  105. * supplied name. If no dynamic command is found, the client will look for
  106. * a concrete command class exists matching the name supplied. If neither
  107. * are found, an InvalidArgumentException is thrown.
  108. *
  109. * @param string $name Name of the command to retrieve
  110. * @param array $args Arguments to pass to the command
  111. *
  112. * @return CommandInterface
  113. * @throws InvalidArgumentException if no command can be found by name
  114. */
  115. public function getCommand($name, array $args = array())
  116. {
  117. $command = $this->getCommandFactory()->factory($name, $args);
  118. if (!$command) {
  119. throw new InvalidArgumentException("Command was not found matching {$name}");
  120. }
  121. $command->setClient($this);
  122. $this->dispatch('client.command.create', array(
  123. 'client' => $this,
  124. 'command' => $command
  125. ));
  126. return $command;
  127. }
  128. /**
  129. * Set the command factory used to create commands by name
  130. *
  131. * @param CommandFactoryInterface $factory Command factory
  132. *
  133. * @return Client
  134. */
  135. public function setCommandFactory(CommandFactoryInterface $factory)
  136. {
  137. $this->commandFactory = $factory;
  138. return $this;
  139. }
  140. /**
  141. * Set the resource iterator factory associated with the client
  142. *
  143. * @param ResourceIteratorFactoryInterface $factory Resource iterator factory
  144. *
  145. * @return Client
  146. */
  147. public function setResourceIteratorFactory(ResourceIteratorFactoryInterface $factory)
  148. {
  149. $this->resourceIteratorFactory = $factory;
  150. return $this;
  151. }
  152. /**
  153. * Get a resource iterator from the client.
  154. *
  155. * @param string|CommandInterface $command Command class or command name.
  156. * @param array $commandOptions Command options used when creating commands.
  157. * @param array $iteratorOptions Iterator options passed to the iterator when it is instantiated.
  158. *
  159. * @return ResourceIteratorInterface
  160. */
  161. public function getIterator($command, array $commandOptions = null, array $iteratorOptions = array())
  162. {
  163. if (!($command instanceof CommandInterface)) {
  164. $command = $this->getCommand($command, $commandOptions ?: array());
  165. }
  166. return $this->getResourceIteratorFactory()->build($command, $iteratorOptions);
  167. }
  168. /**
  169. * Execute one or more commands
  170. *
  171. * @param CommandInterface|array $command Command or array of commands to execute
  172. *
  173. * @return mixed Returns the result of the executed command or an array of
  174. * commands if an array of commands was passed.
  175. * @throws InvalidArgumentException if an invalid command is passed
  176. */
  177. public function execute($command)
  178. {
  179. if ($command instanceof CommandInterface) {
  180. $command = array($command);
  181. $singleCommand = true;
  182. } elseif (is_array($command)) {
  183. $singleCommand = false;
  184. } else {
  185. throw new InvalidArgumentException('Command must be a command or array of commands');
  186. }
  187. $requests = array();
  188. foreach ($command as $c) {
  189. $event = array('command' => $c->setClient($this));
  190. $this->dispatch('command.before_prepare', $event);
  191. // Set the state to new if the command was previously executed
  192. $requests[] = $c->prepare()->setState(RequestInterface::STATE_NEW);
  193. $this->dispatch('command.before_send', $event);
  194. }
  195. if ($singleCommand) {
  196. $this->send($requests[0]);
  197. } else {
  198. $this->send($requests);
  199. }
  200. foreach ($command as $c) {
  201. $this->dispatch('command.after_send', array('command' => $c));
  202. }
  203. return $singleCommand ? end($command)->getResult() : $command;
  204. }
  205. /**
  206. * Set the service description of the client
  207. *
  208. * @param ServiceDescription $service Service description
  209. * @param bool $updateFactory Set to FALSE to not update the service description based
  210. * command factory if it is not already on the client.
  211. *
  212. * @return Client
  213. */
  214. public function setDescription(ServiceDescription $service, $updateFactory = true)
  215. {
  216. $this->serviceDescription = $service;
  217. // Add the service description factory to the factory chain if it is not set
  218. if ($updateFactory) {
  219. // Convert non chain factories to a chain factory
  220. if (!($this->getCommandFactory() instanceof CompositeFactory)) {
  221. $this->commandFactory = new CompositeFactory(array($this->commandFactory));
  222. }
  223. // Add a service description factory if one does not already exist
  224. if (!$this->commandFactory->has('Guzzle\\Service\\Command\\Factory\\ServiceDescriptionFactory')) {
  225. // Add the service description factory before the concrete factory
  226. $this->commandFactory->add(new ServiceDescriptionFactory($service), 'Guzzle\\Service\\Command\\Factory\\ConcreteClassFactory');
  227. } else {
  228. // Update an existing service description factory
  229. $factory = $this->commandFactory->find('Guzzle\\Service\\Command\\Factory\\ServiceDescriptionFactory');
  230. $factory->setServiceDescription($service);
  231. }
  232. }
  233. return $this;
  234. }
  235. /**
  236. * Get the service description of the client
  237. *
  238. * @return ServiceDescription|null
  239. */
  240. public function getDescription()
  241. {
  242. return $this->serviceDescription;
  243. }
  244. /**
  245. * Set the inflector used with the client
  246. *
  247. * @param InflectorInterface $inflector Inflection object
  248. *
  249. * @return Client
  250. */
  251. public function setInflector(InflectorInterface $inflector)
  252. {
  253. $this->inflector = $inflector;
  254. return $this;
  255. }
  256. /**
  257. * Get the inflector used with the client
  258. *
  259. * @return InflectorInterface
  260. */
  261. public function getInflector()
  262. {
  263. if (!$this->inflector) {
  264. $this->inflector = Inflector::getDefault();
  265. }
  266. return $this->inflector;
  267. }
  268. /**
  269. * Get the resource iterator factory associated with the client
  270. *
  271. * @return ResourceIteratorFactoryInterface
  272. */
  273. protected function getResourceIteratorFactory()
  274. {
  275. if (!$this->resourceIteratorFactory) {
  276. // Build the default resource iterator factory if one is not set
  277. $clientClass = get_class($this);
  278. $namespace = substr($clientClass, 0, strrpos($clientClass, '\\')) . '\\Model';
  279. $this->resourceIteratorFactory = new ResourceIteratorClassFactory($namespace);
  280. }
  281. return $this->resourceIteratorFactory;
  282. }
  283. /**
  284. * Get the command factory associated with the client
  285. *
  286. * @return CommandFactoryInterface
  287. */
  288. protected function getCommandFactory()
  289. {
  290. if (!$this->commandFactory) {
  291. $this->commandFactory = CompositeFactory::getDefaultChain($this);
  292. }
  293. return $this->commandFactory;
  294. }
  295. }