1<?php 2 3/** 4 * OAuth service factory. 5 * 6 * PHP version 5.4 7 * 8 * @category OAuth 9 * @author David Desberg <david@daviddesberg.com> 10 * @author Pieter Hordijk <info@pieterhordijk.com> 11 * @copyright Copyright (c) 2013 The authors 12 * @license http://www.opensource.org/licenses/mit-license.html MIT License 13 */ 14 15namespace OAuth; 16 17use OAuth\Common\Service\ServiceInterface; 18use OAuth\Common\Consumer\CredentialsInterface; 19use OAuth\Common\Storage\TokenStorageInterface; 20use OAuth\Common\Http\Client\ClientInterface; 21use OAuth\Common\Http\Client\StreamClient; 22use OAuth\Common\Http\Uri\UriInterface; 23use OAuth\Common\Exception\Exception; 24use OAuth\OAuth1\Signature\Signature; 25 26class ServiceFactory 27{ 28 /** 29 *@var ClientInterface 30 */ 31 protected $httpClient; 32 33 /** 34 * @var array 35 */ 36 protected $serviceClassMap = array( 37 'OAuth1' => array(), 38 'OAuth2' => array() 39 ); 40 41 /** 42 * @var array 43 */ 44 protected $serviceBuilders = array( 45 'OAuth2' => 'buildV2Service', 46 'OAuth1' => 'buildV1Service', 47 ); 48 49 /** 50 * @param ClientInterface $httpClient 51 * 52 * @return ServiceFactory 53 */ 54 public function setHttpClient(ClientInterface $httpClient) 55 { 56 $this->httpClient = $httpClient; 57 58 return $this; 59 } 60 61 /** 62 * Register a custom service to classname mapping. 63 * 64 * @param string $serviceName Name of the service 65 * @param string $className Class to instantiate 66 * 67 * @return ServiceFactory 68 * 69 * @throws Exception If the class is nonexistent or does not implement a valid ServiceInterface 70 */ 71 public function registerService($serviceName, $className) 72 { 73 if (!class_exists($className)) { 74 throw new Exception(sprintf('Service class %s does not exist.', $className)); 75 } 76 77 $reflClass = new \ReflectionClass($className); 78 79 foreach (array('OAuth2', 'OAuth1') as $version) { 80 if ($reflClass->implementsInterface('OAuth\\' . $version . '\\Service\\ServiceInterface')) { 81 $this->serviceClassMap[$version][ucfirst($serviceName)] = $className; 82 83 return $this; 84 } 85 } 86 87 throw new Exception(sprintf('Service class %s must implement ServiceInterface.', $className)); 88 } 89 90 /** 91 * Builds and returns oauth services 92 * 93 * It will first try to build an OAuth2 service and if none found it will try to build an OAuth1 service 94 * 95 * @param string $serviceName Name of service to create 96 * @param CredentialsInterface $credentials 97 * @param TokenStorageInterface $storage 98 * @param array|null $scopes If creating an oauth2 service, array of scopes 99 * @param UriInterface|null $baseApiUri 100 * 101 * @return ServiceInterface 102 */ 103 public function createService( 104 $serviceName, 105 CredentialsInterface $credentials, 106 TokenStorageInterface $storage, 107 $scopes = array(), 108 UriInterface $baseApiUri = null 109 ) { 110 if (!$this->httpClient) { 111 // for backwards compatibility. 112 $this->httpClient = new StreamClient(); 113 } 114 115 foreach ($this->serviceBuilders as $version => $buildMethod) { 116 $fullyQualifiedServiceName = $this->getFullyQualifiedServiceName($serviceName, $version); 117 118 if (class_exists($fullyQualifiedServiceName)) { 119 return $this->$buildMethod($fullyQualifiedServiceName, $credentials, $storage, $scopes, $baseApiUri); 120 } 121 } 122 123 return null; 124 } 125 126 /** 127 * Gets the fully qualified name of the service 128 * 129 * @param string $serviceName The name of the service of which to get the fully qualified name 130 * @param string $type The type of the service to get (either OAuth1 or OAuth2) 131 * 132 * @return string The fully qualified name of the service 133 */ 134 private function getFullyQualifiedServiceName($serviceName, $type) 135 { 136 $serviceName = ucfirst($serviceName); 137 138 if (isset($this->serviceClassMap[$type][$serviceName])) { 139 return $this->serviceClassMap[$type][$serviceName]; 140 } 141 142 return '\\OAuth\\' . $type . '\\Service\\' . $serviceName; 143 } 144 145 /** 146 * Builds v2 services 147 * 148 * @param string $serviceName The fully qualified service name 149 * @param CredentialsInterface $credentials 150 * @param TokenStorageInterface $storage 151 * @param array|null $scopes Array of scopes for the service 152 * @param UriInterface|null $baseApiUri 153 * 154 * @return ServiceInterface 155 * 156 * @throws Exception 157 */ 158 private function buildV2Service( 159 $serviceName, 160 CredentialsInterface $credentials, 161 TokenStorageInterface $storage, 162 array $scopes, 163 UriInterface $baseApiUri = null 164 ) { 165 return new $serviceName( 166 $credentials, 167 $this->httpClient, 168 $storage, 169 $this->resolveScopes($serviceName, $scopes), 170 $baseApiUri 171 ); 172 } 173 174 /** 175 * Resolves scopes for v2 services 176 * 177 * @param string $serviceName The fully qualified service name 178 * @param array $scopes List of scopes for the service 179 * 180 * @return array List of resolved scopes 181 */ 182 private function resolveScopes($serviceName, array $scopes) 183 { 184 $reflClass = new \ReflectionClass($serviceName); 185 $constants = $reflClass->getConstants(); 186 187 $resolvedScopes = array(); 188 foreach ($scopes as $scope) { 189 $key = strtoupper('SCOPE_' . $scope); 190 191 if (array_key_exists($key, $constants)) { 192 $resolvedScopes[] = $constants[$key]; 193 } else { 194 $resolvedScopes[] = $scope; 195 } 196 } 197 198 return $resolvedScopes; 199 } 200 201 /** 202 * Builds v1 services 203 * 204 * @param string $serviceName The fully qualified service name 205 * @param CredentialsInterface $credentials 206 * @param TokenStorageInterface $storage 207 * @param array $scopes 208 * @param UriInterface $baseApiUri 209 * 210 * @return ServiceInterface 211 * 212 * @throws Exception 213 */ 214 private function buildV1Service( 215 $serviceName, 216 CredentialsInterface $credentials, 217 TokenStorageInterface $storage, 218 $scopes, 219 UriInterface $baseApiUri = null 220 ) { 221 if (!empty($scopes)) { 222 throw new Exception( 223 'Scopes passed to ServiceFactory::createService but an OAuth1 service was requested.' 224 ); 225 } 226 227 return new $serviceName($credentials, $this->httpClient, $storage, new Signature($credentials), $baseApiUri); 228 } 229} 230