@@ -28,7 +28,7 @@ class Aws extends ServiceBuilder | |||
/** | |||
* @var string Current version of the SDK | |||
*/ | |||
const VERSION = '2.6.15'; | |||
const VERSION = '2.7.5'; | |||
/** | |||
* Create a new service locator for the AWS SDK |
@@ -17,7 +17,6 @@ | |||
namespace Aws\Common\Client; | |||
use Aws\Common\Aws; | |||
use Aws\Common\Credentials\Credentials; | |||
use Aws\Common\Credentials\CredentialsInterface; | |||
use Aws\Common\Credentials\NullCredentials; | |||
use Aws\Common\Enum\ClientOptions as Options; | |||
@@ -111,13 +110,7 @@ abstract class AbstractClient extends Client implements AwsClientInterface | |||
/** | |||
* Get an endpoint for a specific region from a service description | |||
* | |||
* @param ServiceDescriptionInterface $description Service description | |||
* @param string $region Region of the endpoint | |||
* @param string $scheme URL scheme | |||
* | |||
* @return string | |||
* @throws InvalidArgumentException | |||
* @deprecated This function will no longer be updated to work with new regions. | |||
*/ | |||
public static function getEndpoint(ServiceDescriptionInterface $description, $region, $scheme) | |||
{ | |||
@@ -177,12 +170,27 @@ abstract class AbstractClient extends Client implements AwsClientInterface | |||
$config = $this->getConfig(); | |||
$formerRegion = $config->get(Options::REGION); | |||
$global = $this->serviceDescription->getData('globalEndpoint'); | |||
$provider = $config->get('endpoint_provider'); | |||
if (!$provider) { | |||
throw new \RuntimeException('No endpoint provider configured'); | |||
} | |||
// Only change the region if the service does not have a global endpoint | |||
if (!$global || $this->serviceDescription->getData('namespace') === 'S3') { | |||
$baseUrl = self::getEndpoint($this->serviceDescription, $region, $config->get(Options::SCHEME)); | |||
$this->setBaseUrl($baseUrl); | |||
$config->set(Options::BASE_URL, $baseUrl)->set(Options::REGION, $region); | |||
$endpoint = call_user_func( | |||
$provider, | |||
array( | |||
'scheme' => $config->get(Options::SCHEME), | |||
'region' => $region, | |||
'service' => $config->get(Options::SERVICE) | |||
) | |||
); | |||
$this->setBaseUrl($endpoint['endpoint']); | |||
$config->set(Options::BASE_URL, $endpoint['endpoint']); | |||
$config->set(Options::REGION, $region); | |||
// Update the signature if necessary | |||
$signature = $this->getSignature(); |
@@ -20,13 +20,13 @@ use Aws\Common\Credentials\Credentials; | |||
use Aws\Common\Credentials\CredentialsInterface; | |||
use Aws\Common\Credentials\NullCredentials; | |||
use Aws\Common\Enum\ClientOptions as Options; | |||
use Aws\Common\Enum\Region; | |||
use Aws\Common\Exception\ExceptionListener; | |||
use Aws\Common\Exception\InvalidArgumentException; | |||
use Aws\Common\Exception\NamespaceExceptionFactory; | |||
use Aws\Common\Exception\Parser\DefaultXmlExceptionParser; | |||
use Aws\Common\Exception\Parser\ExceptionParserInterface; | |||
use Aws\Common\Iterator\AwsResourceIteratorFactory; | |||
use Aws\Common\RulesEndpointProvider; | |||
use Aws\Common\Signature\EndpointSignatureInterface; | |||
use Aws\Common\Signature\SignatureInterface; | |||
use Aws\Common\Signature\SignatureV2; | |||
@@ -38,7 +38,6 @@ use Guzzle\Plugin\Backoff\CurlBackoffStrategy; | |||
use Guzzle\Plugin\Backoff\ExponentialBackoffStrategy; | |||
use Guzzle\Plugin\Backoff\HttpBackoffStrategy; | |||
use Guzzle\Plugin\Backoff\TruncatedBackoffStrategy; | |||
use Guzzle\Service\Client; | |||
use Guzzle\Service\Description\ServiceDescription; | |||
use Guzzle\Service\Resource\ResourceIteratorClassFactory; | |||
use Guzzle\Log\LogAdapterInterface; | |||
@@ -200,6 +199,10 @@ class ClientBuilder | |||
(self::$commonConfigRequirements + $this->configRequirements) | |||
); | |||
if (!isset($config['endpoint_provider'])) { | |||
$config['endpoint_provider'] = RulesEndpointProvider::fromDefaults(); | |||
} | |||
// Resolve the endpoint, signature, and credentials | |||
$description = $this->updateConfigFromDescription($config); | |||
$signature = $this->getSignature($description, $config); | |||
@@ -366,33 +369,36 @@ class ClientBuilder | |||
$this->setIteratorsConfig($iterators); | |||
} | |||
// Ensure that the service description has regions | |||
if (!$description->getData('regions')) { | |||
throw new InvalidArgumentException( | |||
'No regions found in the ' . $description->getData('serviceFullName'). ' description' | |||
); | |||
} | |||
// Make sure a valid region is set | |||
$region = $config->get(Options::REGION); | |||
$global = $description->getData('globalEndpoint'); | |||
if (!$global && !$region) { | |||
throw new InvalidArgumentException( | |||
'A region is required when using ' . $description->getData('serviceFullName') | |||
. '. Set "region" to one of: ' . implode(', ', array_keys($description->getData('regions'))) | |||
); | |||
} elseif ($global && (!$region || $description->getData('namespace') !== 'S3')) { | |||
$region = Region::US_EAST_1; | |||
$config->set(Options::REGION, $region); | |||
$region = 'us-east-1'; | |||
$config->set(Options::REGION, 'us-east-1'); | |||
} | |||
if (!$config->get(Options::BASE_URL)) { | |||
// Set the base URL using the scheme and hostname of the service's region | |||
$config->set(Options::BASE_URL, AbstractClient::getEndpoint( | |||
$description, | |||
$region, | |||
$config->get(Options::SCHEME) | |||
)); | |||
$endpoint = call_user_func( | |||
$config->get('endpoint_provider'), | |||
array( | |||
'scheme' => $config->get(Options::SCHEME), | |||
'region' => $region, | |||
'service' => $config->get(Options::SERVICE) | |||
) | |||
); | |||
$config->set(Options::BASE_URL, $endpoint['endpoint']); | |||
// Set a signature if one was not explicitly provided. | |||
if (!$config->hasKey(Options::SIGNATURE) | |||
&& isset($endpoint['signatureVersion']) | |||
) { | |||
$config->set(Options::SIGNATURE, $endpoint['signatureVersion']); | |||
} | |||
} | |||
return $description; |
@@ -39,6 +39,9 @@ class Region extends Enum | |||
const EU_WEST_1 = 'eu-west-1'; | |||
const IRELAND = 'eu-west-1'; | |||
const EU_CENTRAL_1 = 'eu-central-1'; | |||
const FRANKFURT = 'eu-central-1'; | |||
const AP_SOUTHEAST_1 = 'ap-southeast-1'; | |||
const SINGAPORE = 'ap-southeast-1'; |
@@ -38,6 +38,10 @@ class HashUtils | |||
$useNative = function_exists('hex2bin'); | |||
} | |||
if (!$useNative && strlen($hash) % 2 !== 0) { | |||
$hash = '0' . $hash; | |||
} | |||
return $useNative ? hex2bin($hash) : pack("H*", $hash); | |||
} | |||
@@ -49,7 +49,7 @@ abstract class AbstractUploadBuilder | |||
/** | |||
* Return a new instance of the UploadBuilder | |||
* | |||
* @return self | |||
* @return static | |||
*/ | |||
public static function newInstance() | |||
{ | |||
@@ -61,7 +61,7 @@ abstract class AbstractUploadBuilder | |||
* | |||
* @param AwsClientInterface $client Client to use | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setClient(AwsClientInterface $client) | |||
{ | |||
@@ -78,7 +78,7 @@ abstract class AbstractUploadBuilder | |||
* multipart upload. When an ID is passed, the builder will create a | |||
* state object using the data from a ListParts API response. | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function resumeFrom($state) | |||
{ | |||
@@ -94,7 +94,7 @@ abstract class AbstractUploadBuilder | |||
* You can also stream from a resource returned from fopen or a Guzzle | |||
* {@see EntityBody} object. | |||
* | |||
* @return self | |||
* @return $this | |||
* @throws InvalidArgumentException when the source cannot be found or opened | |||
*/ | |||
public function setSource($source) | |||
@@ -123,7 +123,7 @@ abstract class AbstractUploadBuilder | |||
* | |||
* @param array $headers Headers to add to the uploaded object | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setHeaders(array $headers) | |||
{ |
@@ -78,6 +78,12 @@ return array( | |||
'class' => 'Aws\CloudWatch\CloudWatchClient' | |||
), | |||
'cloudwatchlogs' => array( | |||
'alias' => 'CloudWatchLogs', | |||
'extends' => 'default_settings', | |||
'class' => 'Aws\CloudWatchLogs\CloudWatchLogsClient' | |||
), | |||
'cognito-identity' => array( | |||
'alias' => 'CognitoIdentity', | |||
'extends' => 'default_settings', | |||
@@ -94,10 +100,16 @@ return array( | |||
'cognitosync' => array('extends' => 'cognito-sync'), | |||
'cloudwatchlogs' => array( | |||
'alias' => 'CloudWatchLogs', | |||
'codedeploy' => array( | |||
'alias' => 'CodeDeploy', | |||
'extends' => 'default_settings', | |||
'class' => 'Aws\CloudWatchLogs\CloudWatchLogsClient' | |||
'class' => 'Aws\CodeDeploy\CodeDeployClient' | |||
), | |||
'config' => array( | |||
'alias' => 'ConfigService', | |||
'extends' => 'default_settings', | |||
'class' => 'Aws\ConfigService\ConfigServiceClient' | |||
), | |||
'datapipeline' => array( | |||
@@ -173,6 +185,18 @@ return array( | |||
'class' => 'Aws\Kinesis\KinesisClient' | |||
), | |||
'kms' => array( | |||
'alias' => 'Kms', | |||
'extends' => 'default_settings', | |||
'class' => 'Aws\Kms\KmsClient' | |||
), | |||
'lambda' => array( | |||
'alias' => 'Lambda', | |||
'extends' => 'default_settings', | |||
'class' => 'Aws\Lambda\LambdaClient' | |||
), | |||
'iam' => array( | |||
'alias' => 'Iam', | |||
'extends' => 'default_settings', |
@@ -0,0 +1,64 @@ | |||
<?php | |||
return array( | |||
'version' => 2, | |||
'endpoints' => array( | |||
'*/*' => array( | |||
'endpoint' => '{service}.{region}.amazonaws.com' | |||
), | |||
'cn-north-1/*' => array( | |||
'endpoint' => '{service}.{region}.amazonaws.com.cn', | |||
'signatureVersion' => 'v4' | |||
), | |||
'us-gov-west-1/iam' => array( | |||
'endpoint' => 'iam.us-gov.amazonaws.com' | |||
), | |||
'us-gov-west-1/sts' => array( | |||
'endpoint' => 'sts.us-gov.amazonaws.com' | |||
), | |||
'us-gov-west-1/s3' => array( | |||
'endpoint' => 's3-{region}.amazonaws.com' | |||
), | |||
'*/cloudfront' => array( | |||
'endpoint' => 'cloudfront.amazonaws.com' | |||
), | |||
'*/iam' => array( | |||
'endpoint' => 'iam.amazonaws.com' | |||
), | |||
'*/importexport' => array( | |||
'endpoint' => 'importexport.amazonaws.com' | |||
), | |||
'*/route53' => array( | |||
'endpoint' => 'route53.amazonaws.com' | |||
), | |||
'*/sts' => array( | |||
'endpoint' => 'sts.amazonaws.com' | |||
), | |||
'us-east-1/sdb' => array( | |||
'endpoint' => 'sdb.amazonaws.com' | |||
), | |||
'us-east-1/s3' => array( | |||
'endpoint' => 's3.amazonaws.com' | |||
), | |||
'us-west-1/s3' => array( | |||
'endpoint' => 's3-{region}.amazonaws.com' | |||
), | |||
'us-west-2/s3' => array( | |||
'endpoint' => 's3-{region}.amazonaws.com' | |||
), | |||
'eu-west-1/s3' => array( | |||
'endpoint' => 's3-{region}.amazonaws.com' | |||
), | |||
'ap-southeast-1/s3' => array( | |||
'endpoint' => 's3-{region}.amazonaws.com' | |||
), | |||
'ap-southeast-2/s3' => array( | |||
'endpoint' => 's3-{region}.amazonaws.com' | |||
), | |||
'ap-northeast-1/s3' => array( | |||
'endpoint' => 's3-{region}.amazonaws.com' | |||
), | |||
'sa-east-1/s3' => array( | |||
'endpoint' => 's3-{region}.amazonaws.com' | |||
) | |||
) | |||
); |
@@ -0,0 +1,67 @@ | |||
<?php | |||
namespace Aws\Common; | |||
/** | |||
* Provides endpoints based on a rules configuration file. | |||
*/ | |||
class RulesEndpointProvider | |||
{ | |||
/** @var array */ | |||
private $patterns; | |||
/** | |||
* @param array $patterns Hash of endpoint patterns mapping to endpoint | |||
* configurations. | |||
*/ | |||
public function __construct(array $patterns) | |||
{ | |||
$this->patterns = $patterns; | |||
} | |||
/** | |||
* Creates and returns the default RulesEndpointProvider based on the | |||
* public rule sets. | |||
* | |||
* @return self | |||
*/ | |||
public static function fromDefaults() | |||
{ | |||
return new self(require __DIR__ . '/Resources/public-endpoints.php'); | |||
} | |||
public function __invoke(array $args = array()) | |||
{ | |||
if (!isset($args['service'])) { | |||
throw new \InvalidArgumentException('Requires a "service" value'); | |||
} | |||
if (!isset($args['region'])) { | |||
throw new \InvalidArgumentException('Requires a "region" value'); | |||
} | |||
foreach ($this->getKeys($args['region'], $args['service']) as $key) { | |||
if (isset($this->patterns['endpoints'][$key])) { | |||
return $this->expand($this->patterns['endpoints'][$key], $args); | |||
} | |||
} | |||
throw new \RuntimeException('Could not resolve endpoint'); | |||
} | |||
private function expand(array $config, array $args) | |||
{ | |||
$scheme = isset($args['scheme']) ? $args['scheme'] : 'https'; | |||
$config['endpoint'] = $scheme . '://' . str_replace( | |||
array('{service}', '{region}'), | |||
array($args['service'], $args['region']), | |||
$config['endpoint'] | |||
); | |||
return $config; | |||
} | |||
private function getKeys($region, $service) | |||
{ | |||
return array("$region/$service", "$region/*", "*/$service", "*/*"); | |||
} | |||
} |
@@ -19,7 +19,6 @@ namespace Aws\Common\Signature; | |||
use Aws\Common\Credentials\CredentialsInterface; | |||
use Aws\Common\Enum\DateFormat; | |||
use Aws\Common\HostNameUtils; | |||
use Guzzle\Http\Message\EntityEnclosingRequest; | |||
use Guzzle\Http\Message\EntityEnclosingRequestInterface; | |||
use Guzzle\Http\Message\RequestFactory; | |||
use Guzzle\Http\Message\RequestInterface; | |||
@@ -304,43 +303,42 @@ class SignatureV4 extends AbstractSignature implements EndpointSignatureInterfac | |||
*/ | |||
private function createSigningContext(RequestInterface $request, $payload) | |||
{ | |||
$signable = array( | |||
'host' => true, | |||
'date' => true, | |||
'content-md5' => true | |||
); | |||
// Normalize the path as required by SigV4 and ensure it's absolute | |||
$canon = $request->getMethod() . "\n" | |||
. $this->createCanonicalizedPath($request) . "\n" | |||
. $this->getCanonicalizedQueryString($request) . "\n"; | |||
// Create the canonical headers | |||
$headers = array(); | |||
$canonHeaders = array(); | |||
foreach ($request->getHeaders()->getAll() as $key => $values) { | |||
$key = strtolower($key); | |||
if ($key != 'user-agent') { | |||
$headers[$key] = array(); | |||
foreach ($values as $value) { | |||
$headers[$key][] = preg_replace('/\s+/', ' ', trim($value)); | |||
} | |||
// Sort the value if there is more than one | |||
if (count($values) > 1) { | |||
sort($headers[$key]); | |||
if (isset($signable[$key]) || substr($key, 0, 6) === 'x-amz-') { | |||
$values = $values->toArray(); | |||
if (count($values) == 1) { | |||
$values = $values[0]; | |||
} else { | |||
sort($values); | |||
$values = implode(',', $values); | |||
} | |||
$canonHeaders[$key] = $key . ':' . preg_replace('/\s+/', ' ', $values); | |||
} | |||
} | |||
// The headers must be sorted | |||
ksort($headers); | |||
// Continue to build the canonical request by adding headers | |||
foreach ($headers as $key => $values) { | |||
// Combine multi-value headers into a comma separated list | |||
$canon .= $key . ':' . implode(',', $values) . "\n"; | |||
} | |||
// Create the signed headers | |||
$signedHeaders = implode(';', array_keys($headers)); | |||
$canon .= "\n{$signedHeaders}\n{$payload}"; | |||
ksort($canonHeaders); | |||
$signedHeadersString = implode(';', array_keys($canonHeaders)); | |||
$canon .= implode("\n", $canonHeaders) . "\n\n" | |||
. $signedHeadersString . "\n" | |||
. $payload; | |||
return array( | |||
'canonical_request' => $canon, | |||
'signed_headers' => $signedHeaders | |||
'signed_headers' => $signedHeadersString | |||
); | |||
} | |||
@@ -394,6 +392,8 @@ class SignatureV4 extends AbstractSignature implements EndpointSignatureInterfac | |||
foreach ($queryParams as $key => $values) { | |||
if (is_array($values)) { | |||
sort($values); | |||
} elseif ($values === 0) { | |||
$values = array('0'); | |||
} elseif (!$values) { | |||
$values = array(''); | |||
} |
@@ -54,7 +54,7 @@ class Acp implements ToArrayInterface, \IteratorAggregate, \Countable | |||
* | |||
* @param array $data Array of ACP data | |||
* | |||
* @return self | |||
* @return Acp | |||
*/ | |||
public static function fromArray(array $data) | |||
{ | |||
@@ -100,7 +100,7 @@ class Acp implements ToArrayInterface, \IteratorAggregate, \Countable | |||
* | |||
* @param Grantee $owner ACP policy owner | |||
* | |||
* @return self | |||
* @return $this | |||
* | |||
* @throws InvalidArgumentException if the grantee does not have an ID set | |||
*/ | |||
@@ -130,7 +130,7 @@ class Acp implements ToArrayInterface, \IteratorAggregate, \Countable | |||
* | |||
* @param array|\Traversable $grants List of grants for the ACP | |||
* | |||
* @return self | |||
* @return $this | |||
* | |||
* @throws InvalidArgumentException | |||
*/ | |||
@@ -167,7 +167,7 @@ class Acp implements ToArrayInterface, \IteratorAggregate, \Countable | |||
* | |||
* @param Grant $grant Grant to add | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function addGrant(Grant $grant) | |||
{ | |||
@@ -205,7 +205,7 @@ class Acp implements ToArrayInterface, \IteratorAggregate, \Countable | |||
* | |||
* @param AbstractCommand $command Command to be updated | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function updateCommand(AbstractCommand $command) | |||
{ |
@@ -36,11 +36,11 @@ class AcpBuilder | |||
/** | |||
* Static method for chainable instantiation | |||
* | |||
* @return self | |||
* @return static | |||
*/ | |||
public static function newInstance() | |||
{ | |||
return new self; | |||
return new static; | |||
} | |||
/** | |||
@@ -49,7 +49,7 @@ class AcpBuilder | |||
* @param string $id Owner identifier | |||
* @param string $displayName Owner display name | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setOwner($id, $displayName = null) | |||
{ | |||
@@ -65,7 +65,7 @@ class AcpBuilder | |||
* @param string $id Grantee identifier | |||
* @param string $displayName Grantee display name | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function addGrantForUser($permission, $id, $displayName = null) | |||
{ | |||
@@ -81,7 +81,7 @@ class AcpBuilder | |||
* @param string $permission Permission for the Grant | |||
* @param string $email Grantee email address | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function addGrantForEmail($permission, $email) | |||
{ | |||
@@ -97,7 +97,7 @@ class AcpBuilder | |||
* @param string $permission Permission for the Grant | |||
* @param string $group Grantee group | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function addGrantForGroup($permission, $group) | |||
{ | |||
@@ -113,7 +113,7 @@ class AcpBuilder | |||
* @param string $permission Permission for the Grant | |||
* @param Grantee $grantee The Grantee for the Grant | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function addGrant($permission, Grantee $grantee) | |||
{ |
@@ -81,7 +81,7 @@ class ClearBucket extends AbstractHasDispatcher | |||
* | |||
* @param string $bucket Name of the bucket to clear | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setBucket($bucket) | |||
{ | |||
@@ -114,7 +114,7 @@ class ClearBucket extends AbstractHasDispatcher | |||
* | |||
* @param \Iterator $iterator Iterator used to yield the keys to be deleted | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setIterator(\Iterator $iterator) | |||
{ | |||
@@ -129,7 +129,7 @@ class ClearBucket extends AbstractHasDispatcher | |||
* @param string $mfa MFA token to send with each request. The value is the concatenation of the authentication | |||
* device's serial number, a space, and the value displayed on your authentication device. | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setMfa($mfa) | |||
{ |
@@ -38,7 +38,7 @@ class DeleteObjectsBatch extends AbstractBatchDecorator | |||
* @param string $bucket Bucket that contains the objects to delete | |||
* @param string $mfa MFA token to use with the request | |||
* | |||
* @return self | |||
* @return static | |||
*/ | |||
public static function factory(AwsClientInterface $client, $bucket, $mfa = null) | |||
{ | |||
@@ -47,7 +47,7 @@ class DeleteObjectsBatch extends AbstractBatchDecorator | |||
->transferWith(new DeleteObjectsTransfer($client, $bucket, $mfa)) | |||
->build(); | |||
return new self($batch); | |||
return new static($batch); | |||
} | |||
/** | |||
@@ -56,7 +56,7 @@ class DeleteObjectsBatch extends AbstractBatchDecorator | |||
* @param string $key Key of the object | |||
* @param string $versionId VersionID of the object | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function addKey($key, $versionId = null) | |||
{ | |||
@@ -82,6 +82,6 @@ class DeleteObjectsBatch extends AbstractBatchDecorator | |||
throw new InvalidArgumentException('Item must be a DeleteObject command or array containing a Key and VersionId key.'); | |||
} | |||
return $this->decoratedBatch->add($item); | |||
return parent::add($item); | |||
} | |||
} |
@@ -64,7 +64,7 @@ class DeleteObjectsTransfer implements BatchTransferInterface | |||
* | |||
* @param string $token MFA token | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setMfa($token) | |||
{ |
@@ -63,7 +63,7 @@ class Grant implements ToArrayInterface | |||
* | |||
* @param Grantee $grantee Affected grantee | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setGrantee(Grantee $grantee) | |||
{ | |||
@@ -87,7 +87,7 @@ class Grant implements ToArrayInterface | |||
* | |||
* @param string $permission Permission applied | |||
* | |||
* @return self | |||
* @return $this | |||
* | |||
* @throws InvalidArgumentException | |||
*/ |
@@ -214,7 +214,7 @@ class Grantee implements ToArrayInterface | |||
*/ | |||
public function getHeaderValue() | |||
{ | |||
$key = self::$headerMap[$this->type]; | |||
$key = static::$headerMap[$this->type]; | |||
return "{$key}=\"{$this->id}\""; | |||
} |
@@ -67,7 +67,7 @@ class UploadBuilder extends AbstractUploadBuilder | |||
* | |||
* @param string $bucket Name of the bucket | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setBucket($bucket) | |||
{ | |||
@@ -79,7 +79,7 @@ class UploadBuilder extends AbstractUploadBuilder | |||
* | |||
* @param string $key Key of the object to upload | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setKey($key) | |||
{ | |||
@@ -91,7 +91,7 @@ class UploadBuilder extends AbstractUploadBuilder | |||
* | |||
* @param int $minSize Minimum acceptable part size in bytes | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setMinPartSize($minSize) | |||
{ | |||
@@ -107,7 +107,7 @@ class UploadBuilder extends AbstractUploadBuilder | |||
* | |||
* @param int $concurrency Concurrency level | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setConcurrency($concurrency) | |||
{ | |||
@@ -121,7 +121,7 @@ class UploadBuilder extends AbstractUploadBuilder | |||
* | |||
* @param string $md5 MD5 hash of the entire body | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setMd5($md5) | |||
{ | |||
@@ -137,7 +137,7 @@ class UploadBuilder extends AbstractUploadBuilder | |||
* | |||
* @param bool $calculateMd5 Set to true to calculate the MD5 hash of the body | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function calculateMd5($calculateMd5) | |||
{ | |||
@@ -152,7 +152,7 @@ class UploadBuilder extends AbstractUploadBuilder | |||
* | |||
* @param bool $usePartMd5 Set to true to calculate the MD5 has of each part | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function calculatePartMd5($usePartMd5) | |||
{ | |||
@@ -166,7 +166,7 @@ class UploadBuilder extends AbstractUploadBuilder | |||
* | |||
* @param Acp $acp ACP to set on the object | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setAcp(Acp $acp) | |||
{ | |||
@@ -179,7 +179,7 @@ class UploadBuilder extends AbstractUploadBuilder | |||
* @param string $name Option name | |||
* @param string $value Option value | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setOption($name, $value) | |||
{ | |||
@@ -193,7 +193,7 @@ class UploadBuilder extends AbstractUploadBuilder | |||
* | |||
* @param array $options Array of CreateMultipartUpload operation parameters | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function addOptions(array $options) | |||
{ | |||
@@ -207,7 +207,7 @@ class UploadBuilder extends AbstractUploadBuilder | |||
* | |||
* @param array $options Transfer options | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setTransferOptions(array $options) | |||
{ |
@@ -45,6 +45,11 @@ return array ( | |||
'https' => true, | |||
'hostname' => 's3-eu-west-1.amazonaws.com', | |||
), | |||
'eu-central-1' => array( | |||
'http' => true, | |||
'https' => true, | |||
'hostname' => 's3-eu-central-1.amazonaws.com', | |||
), | |||
'ap-northeast-1' => array( | |||
'http' => true, | |||
'https' => true, | |||
@@ -355,6 +360,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-copy-source-server-side-encryption-customer-key-MD5', | |||
), | |||
'CopySourceSSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-copy-source-server-side-encryption-aws-kms-key-id', | |||
), | |||
'ACP' => array( | |||
'type' => 'object', | |||
'additionalProperties' => true, | |||
@@ -564,6 +574,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'ACP' => array( | |||
'type' => 'object', | |||
'additionalProperties' => true, | |||
@@ -1068,6 +1083,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'SaveAs' => array( | |||
'location' => 'response_body', | |||
), | |||
@@ -1236,6 +1256,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
), | |||
'errorResponses' => array( | |||
array( | |||
@@ -1843,10 +1868,22 @@ return array ( | |||
'location' => 'uri', | |||
), | |||
'TopicConfiguration' => array( | |||
'required' => true, | |||
'type' => 'object', | |||
'location' => 'xml', | |||
'properties' => array( | |||
'Id' => array( | |||
'type' => 'string', | |||
), | |||
'Events' => array( | |||
'type' => 'array', | |||
'data' => array( | |||
'xmlFlattened' => true, | |||
), | |||
'items' => array( | |||
'name' => 'Event', | |||
'type' => 'string', | |||
), | |||
), | |||
'Event' => array( | |||
'type' => 'string', | |||
), | |||
@@ -1855,6 +1892,59 @@ return array ( | |||
), | |||
), | |||
), | |||
'QueueConfiguration' => array( | |||
'type' => 'object', | |||
'location' => 'xml', | |||
'properties' => array( | |||
'Id' => array( | |||
'type' => 'string', | |||
), | |||
'Event' => array( | |||
'type' => 'string', | |||
), | |||
'Events' => array( | |||
'type' => 'array', | |||
'data' => array( | |||
'xmlFlattened' => true, | |||
), | |||
'items' => array( | |||
'name' => 'Event', | |||
'type' => 'string', | |||
), | |||
), | |||
'Queue' => array( | |||
'type' => 'string', | |||
), | |||
), | |||
), | |||
'CloudFunctionConfiguration' => array( | |||
'type' => 'object', | |||
'location' => 'xml', | |||
'properties' => array( | |||
'Id' => array( | |||
'type' => 'string', | |||
), | |||
'Event' => array( | |||
'type' => 'string', | |||
), | |||
'Events' => array( | |||
'type' => 'array', | |||
'data' => array( | |||
'xmlFlattened' => true, | |||
), | |||
'items' => array( | |||
'name' => 'Event', | |||
'type' => 'string', | |||
), | |||
), | |||
'CloudFunction' => array( | |||
'type' => 'string', | |||
), | |||
'InvocationRole' => array( | |||
'type' => 'string', | |||
), | |||
), | |||
), | |||
), | |||
), | |||
'PutBucketPolicy' => array( | |||
@@ -2241,6 +2331,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'ACP' => array( | |||
'type' => 'object', | |||
'additionalProperties' => true, | |||
@@ -2399,6 +2494,11 @@ return array ( | |||
'Aws\\S3\\S3Client::explodeKey', | |||
), | |||
), | |||
'VersionId' => array( | |||
'type' => 'string', | |||
'location' => 'query', | |||
'sentAs' => 'versionId', | |||
), | |||
'Days' => array( | |||
'required' => true, | |||
'type' => 'numeric', | |||
@@ -2488,6 +2588,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
), | |||
), | |||
'UploadPartCopy' => array( | |||
@@ -2602,6 +2707,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-copy-source-server-side-encryption-customer-key-MD5', | |||
), | |||
'CopySourceSSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'command.expects' => array( | |||
'static' => true, | |||
'default' => 'application/xml', | |||
@@ -2655,6 +2765,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-version-id', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'RequestId' => array( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-request-id', | |||
@@ -2698,6 +2813,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'RequestId' => array( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-request-id', | |||
@@ -2750,6 +2870,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'RequestId' => array( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-request-id', | |||
@@ -3197,6 +3322,21 @@ return array ( | |||
'type' => 'object', | |||
'location' => 'xml', | |||
'properties' => array( | |||
'Id' => array( | |||
'type' => 'string', | |||
), | |||
'Events' => array( | |||
'type' => 'array', | |||
'sentAs' => 'Event', | |||
'data' => array( | |||
'xmlFlattened' => true, | |||
), | |||
'items' => array( | |||
'name' => 'Event', | |||
'type' => 'string', | |||
'sentAs' => 'Event', | |||
), | |||
), | |||
'Event' => array( | |||
'type' => 'string', | |||
), | |||
@@ -3205,6 +3345,63 @@ return array ( | |||
), | |||
), | |||
), | |||
'QueueConfiguration' => array( | |||
'type' => 'object', | |||
'location' => 'xml', | |||
'properties' => array( | |||
'Id' => array( | |||
'type' => 'string', | |||
), | |||
'Event' => array( | |||
'type' => 'string', | |||
), | |||
'Events' => array( | |||
'type' => 'array', | |||
'sentAs' => 'Event', | |||
'data' => array( | |||
'xmlFlattened' => true, | |||
), | |||
'items' => array( | |||
'name' => 'Event', | |||
'type' => 'string', | |||
'sentAs' => 'Event', | |||
), | |||
), | |||
'Queue' => array( | |||
'type' => 'string', | |||
), | |||
), | |||
), | |||
'CloudFunctionConfiguration' => array( | |||
'type' => 'object', | |||
'location' => 'xml', | |||
'properties' => array( | |||
'Id' => array( | |||
'type' => 'string', | |||
), | |||
'Event' => array( | |||
'type' => 'string', | |||
), | |||
'Events' => array( | |||
'type' => 'array', | |||
'sentAs' => 'Event', | |||
'data' => array( | |||
'xmlFlattened' => true, | |||
), | |||
'items' => array( | |||
'name' => 'Event', | |||
'type' => 'string', | |||
'sentAs' => 'Event', | |||
), | |||
), | |||
'CloudFunction' => array( | |||
'type' => 'string', | |||
), | |||
'InvocationRole' => array( | |||
'type' => 'string', | |||
), | |||
), | |||
), | |||
'RequestId' => array( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-request-id', | |||
@@ -3478,6 +3675,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'RequestId' => array( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-request-id', | |||
@@ -3676,6 +3878,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'RequestId' => array( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-request-id', | |||
@@ -3745,6 +3952,10 @@ return array ( | |||
'type' => 'string', | |||
'location' => 'xml', | |||
), | |||
'Delimiter' => array( | |||
'type' => 'string', | |||
'location' => 'xml', | |||
), | |||
'NextUploadIdMarker' => array( | |||
'type' => 'string', | |||
'location' => 'xml', | |||
@@ -3949,6 +4160,10 @@ return array ( | |||
'type' => 'string', | |||
'location' => 'xml', | |||
), | |||
'Delimiter' => array( | |||
'type' => 'string', | |||
'location' => 'xml', | |||
), | |||
'MaxKeys' => array( | |||
'type' => 'numeric', | |||
'location' => 'xml', | |||
@@ -4042,6 +4257,10 @@ return array ( | |||
'type' => 'string', | |||
'location' => 'xml', | |||
), | |||
'Delimiter' => array( | |||
'type' => 'string', | |||
'location' => 'xml', | |||
), | |||
'MaxKeys' => array( | |||
'type' => 'numeric', | |||
'location' => 'xml', | |||
@@ -4298,6 +4517,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'RequestId' => array( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-request-id', | |||
@@ -4349,6 +4573,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'RequestId' => array( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-request-id', | |||
@@ -4387,6 +4616,11 @@ return array ( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-customer-key-MD5', | |||
), | |||
'SSEKMSKeyId' => array( | |||
'type' => 'string', | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-server-side-encryption-aws-kms-key-id', | |||
), | |||
'RequestId' => array( | |||
'location' => 'header', | |||
'sentAs' => 'x-amz-request-id', |
@@ -24,7 +24,6 @@ use Aws\Common\Enum\ClientOptions as Options; | |||
use Aws\Common\Exception\RuntimeException; | |||
use Aws\Common\Exception\InvalidArgumentException; | |||
use Aws\Common\Signature\SignatureV4; | |||
use Aws\Common\Signature\SignatureInterface; | |||
use Aws\Common\Model\MultipartUpload\AbstractTransfer; | |||
use Aws\S3\Exception\AccessDeniedException; | |||
use Aws\S3\Exception\Parser\S3ExceptionParser; | |||
@@ -156,7 +155,7 @@ class S3Client extends AbstractClient | |||
* | |||
* @param array|Collection $config Client configuration data | |||
* | |||
* @return self | |||
* @return S3Client | |||
* @link http://docs.aws.amazon.com/aws-sdk-php/guide/latest/configuration.html#client-configuration-options | |||
*/ | |||
public static function factory($config = array()) | |||
@@ -165,10 +164,10 @@ class S3Client extends AbstractClient | |||
// Configure the custom exponential backoff plugin for retrying S3 specific errors | |||
if (!isset($config[Options::BACKOFF])) { | |||
$config[Options::BACKOFF] = self::createBackoffPlugin($exceptionParser); | |||
$config[Options::BACKOFF] = static::createBackoffPlugin($exceptionParser); | |||
} | |||
$config[Options::SIGNATURE] = $signature = self::createSignature($config); | |||
$config[Options::SIGNATURE] = $signature = static::createSignature($config); | |||
$client = ClientBuilder::factory(__NAMESPACE__) | |||
->setConfig($config) | |||
@@ -222,7 +221,7 @@ class S3Client extends AbstractClient | |||
// Add aliases for some S3 operations | |||
$default = CompositeFactory::getDefaultChain($client); | |||
$default->add( | |||
new AliasFactory($client, self::$commandAliases), | |||
new AliasFactory($client, static::$commandAliases), | |||
'Guzzle\Service\Command\Factory\ServiceDescriptionFactory' | |||
); | |||
$client->setCommandFactory($default); | |||
@@ -266,11 +265,16 @@ class S3Client extends AbstractClient | |||
{ | |||
$currentValue = isset($config[Options::SIGNATURE]) ? $config[Options::SIGNATURE] : null; | |||
// Force v4 if no value is provided, a region is in the config, and | |||
// the region starts with "cn-" or "eu-central-". | |||
$requiresV4 = !$currentValue | |||
&& isset($config['region']) | |||
&& (strpos($config['region'], 'eu-central-') === 0 | |||
|| strpos($config['region'], 'cn-') === 0); | |||
// Use the Amazon S3 signature V4 when the value is set to "v4" or when | |||
// the value is not set and the region starts with "cn-". | |||
if ($currentValue == 'v4' || | |||
(!$currentValue && isset($config['region']) && substr($config['region'], 0, 3) == 'cn-') | |||
) { | |||
if ($currentValue == 'v4' || $requiresV4) { | |||
// Force SignatureV4 for specific regions or if specified in the config | |||
$currentValue = new S3SignatureV4('s3'); | |||
} elseif (!$currentValue || $currentValue == 's3') { | |||
@@ -456,7 +460,7 @@ class S3Client extends AbstractClient | |||
/** | |||
* Register the Amazon S3 stream wrapper and associates it with this client object | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function registerStreamWrapper() | |||
{ | |||
@@ -515,8 +519,7 @@ class S3Client extends AbstractClient | |||
->setTransferOptions($options->toArray()) | |||
->addOptions($options['params']) | |||
->setOption('ACL', $acl) | |||
->build() | |||
->upload(); | |||
->build(); | |||
if ($options['before_upload']) { | |||
$transfer->getEventDispatcher()->addListener( | |||
@@ -525,7 +528,7 @@ class S3Client extends AbstractClient | |||
); | |||
} | |||
return $transfer; | |||
return $transfer->upload(); | |||
} | |||
/** |
@@ -32,7 +32,10 @@ class S3SignatureV4 extends SignatureV4 implements S3SignatureInterface | |||
public function signRequest(RequestInterface $request, CredentialsInterface $credentials) | |||
{ | |||
if (!$request->hasHeader('x-amz-content-sha256')) { | |||
$request->setHeader('x-amz-content-sha256', $this->getPresignedPayload($request)); | |||
$request->setHeader( | |||
'x-amz-content-sha256', | |||
$this->getPayload($request) | |||
); | |||
} | |||
parent::signRequest($request, $credentials); | |||
@@ -44,14 +47,7 @@ class S3SignatureV4 extends SignatureV4 implements S3SignatureInterface | |||
*/ | |||
protected function getPresignedPayload(RequestInterface $request) | |||
{ | |||
$result = parent::getPresignedPayload($request); | |||
// If the body is empty, then sign with 'UNSIGNED-PAYLOAD' | |||
if ($result === self::DEFAULT_PAYLOAD) { | |||
$result = hash('sha256', 'UNSIGNED-PAYLOAD'); | |||
} | |||
return $result; | |||
return 'UNSIGNED-PAYLOAD'; | |||
} | |||
/** |
@@ -133,7 +133,7 @@ class StreamWrapper | |||
} | |||
stream_wrapper_register('s3', get_called_class(), STREAM_IS_URL); | |||
self::$client = $client; | |||
static::$client = $client; | |||
} | |||
/** | |||
@@ -172,7 +172,7 @@ class StreamWrapper | |||
} | |||
// When using mode "x" validate if the file exists before attempting to read | |||
if ($mode == 'x' && self::$client->doesObjectExist($params['Bucket'], $params['Key'], $this->getOptions())) { | |||
if ($mode == 'x' && static::$client->doesObjectExist($params['Bucket'], $params['Key'], $this->getOptions())) { | |||
$errors[] = "{$path} already exists on Amazon S3"; | |||
} | |||
@@ -219,7 +219,7 @@ class StreamWrapper | |||
} | |||
try { | |||
self::$client->putObject($params); | |||
static::$client->putObject($params); | |||
return true; | |||
} catch (\Exception $e) { | |||
return $this->triggerError($e->getMessage()); | |||
@@ -283,7 +283,7 @@ class StreamWrapper | |||
{ | |||
try { | |||
$this->clearStatInfo($path); | |||
self::$client->deleteObject($this->getParams($path)); | |||
static::$client->deleteObject($this->getParams($path)); | |||
return true; | |||
} catch (\Exception $e) { | |||
return $this->triggerError($e->getMessage()); | |||
@@ -316,15 +316,15 @@ class StreamWrapper | |||
public function url_stat($path, $flags) | |||
{ | |||
// Check if this path is in the url_stat cache | |||
if (isset(self::$nextStat[$path])) { | |||
return self::$nextStat[$path]; | |||
if (isset(static::$nextStat[$path])) { | |||
return static::$nextStat[$path]; | |||
} | |||
$parts = $this->getParams($path); | |||
if (!$parts['Key']) { | |||
// Stat "directories": buckets, or "s3://" | |||
if (!$parts['Bucket'] || self::$client->doesBucketExist($parts['Bucket'])) { | |||
if (!$parts['Bucket'] || static::$client->doesBucketExist($parts['Bucket'])) { | |||
return $this->formatUrlStat($path); | |||
} else { | |||
return $this->triggerError("File or directory not found: {$path}", $flags); | |||
@@ -333,7 +333,7 @@ class StreamWrapper | |||
try { | |||
try { | |||
$result = self::$client->headObject($parts)->toArray(); | |||
$result = static::$client->headObject($parts)->toArray(); | |||
if (substr($parts['Key'], -1, 1) == '/' && $result['ContentLength'] == 0) { | |||
// Return as if it is a bucket to account for console bucket objects (e.g., zero-byte object "foo/") | |||
return $this->formatUrlStat($path); | |||
@@ -343,7 +343,7 @@ class StreamWrapper | |||
} | |||
} catch (NoSuchKeyException $e) { | |||
// Maybe this isn't an actual key, but a prefix. Do a prefix listing of objects to determine. | |||
$result = self::$client->listObjects(array( | |||
$result = static::$client->listObjects(array( | |||
'Bucket' => $parts['Bucket'], | |||
'Prefix' => rtrim($parts['Key'], '/') . '/', | |||
'MaxKeys' => 1 | |||
@@ -404,7 +404,7 @@ class StreamWrapper | |||
try { | |||
if (!$params['Key']) { | |||
self::$client->deleteBucket(array('Bucket' => $params['Bucket'])); | |||
static::$client->deleteBucket(array('Bucket' => $params['Bucket'])); | |||
$this->clearStatInfo($path); | |||
return true; | |||
} | |||
@@ -412,7 +412,7 @@ class StreamWrapper | |||
// Use a key that adds a trailing slash if needed. | |||
$prefix = rtrim($params['Key'], '/') . '/'; | |||
$result = self::$client->listObjects(array( | |||
$result = static::$client->listObjects(array( | |||
'Bucket' => $params['Bucket'], | |||
'Prefix' => $prefix, | |||
'MaxKeys' => 1 | |||
@@ -476,7 +476,7 @@ class StreamWrapper | |||
$operationParams['Delimiter'] = $delimiter; | |||
} | |||
$objectIterator = self::$client->getIterator('ListObjects', $operationParams, array( | |||
$objectIterator = static::$client->getIterator('ListObjects', $operationParams, array( | |||
'return_prefixes' => true, | |||
'sort_results' => true | |||
)); | |||
@@ -554,7 +554,7 @@ class StreamWrapper | |||
// Cache the object data for quick url_stat lookups used with | |||
// RecursiveDirectoryIterator. | |||
self::$nextStat = array($key => $stat); | |||
static::$nextStat = array($key => $stat); | |||
$this->objectIterator->next(); | |||
return $result; | |||
@@ -582,14 +582,14 @@ class StreamWrapper | |||
try { | |||
// Copy the object and allow overriding default parameters if desired, but by default copy metadata | |||
self::$client->copyObject($this->getOptions() + array( | |||
static::$client->copyObject($this->getOptions() + array( | |||
'Bucket' => $partsTo['Bucket'], | |||
'Key' => $partsTo['Key'], | |||
'CopySource' => '/' . $partsFrom['Bucket'] . '/' . rawurlencode($partsFrom['Key']), | |||
'MetadataDirective' => 'COPY' | |||
)); | |||
// Delete the original object | |||
self::$client->deleteObject(array( | |||
static::$client->deleteObject(array( | |||
'Bucket' => $partsFrom['Bucket'], | |||
'Key' => $partsFrom['Key'] | |||
) + $this->getOptions()); | |||
@@ -685,7 +685,7 @@ class StreamWrapper | |||
protected function openReadStream(array $params, array &$errors) | |||
{ | |||
// Create the command and serialize the request | |||
$request = $this->getSignedRequest(self::$client->getCommand('GetObject', $params)); | |||
$request = $this->getSignedRequest(static::$client->getCommand('GetObject', $params)); | |||
// Create a stream that uses the EntityBody object | |||
$factory = $this->getOption('stream_factory') ?: new PhpStreamRequestFactory(); | |||
$this->body = $factory->fromRequest($request, array(), array('stream_class' => 'Guzzle\Http\EntityBody')); | |||
@@ -723,7 +723,7 @@ class StreamWrapper | |||
{ | |||
try { | |||
// Get the body of the object | |||
$this->body = self::$client->getObject($params)->get('Body'); | |||
$this->body = static::$client->getObject($params)->get('Body'); | |||
$this->body->seek(0, SEEK_END); | |||
} catch (S3Exception $e) { | |||
// The object does not exist, so use a simple write stream | |||
@@ -810,7 +810,7 @@ class StreamWrapper | |||
*/ | |||
protected function clearStatInfo($path = null) | |||
{ | |||
self::$nextStat = array(); | |||
static::$nextStat = array(); | |||
if ($path) { | |||
clearstatcache(true, $path); | |||
} | |||
@@ -826,12 +826,12 @@ class StreamWrapper | |||
*/ | |||
private function createBucket($path, array $params) | |||
{ | |||
if (self::$client->doesBucketExist($params['Bucket'])) { | |||
if (static::$client->doesBucketExist($params['Bucket'])) { | |||
return $this->triggerError("Directory already exists: {$path}"); | |||
} | |||
try { | |||
self::$client->createBucket($params); | |||
static::$client->createBucket($params); | |||
$this->clearStatInfo($path); | |||
return true; | |||
} catch (\Exception $e) { | |||
@@ -854,12 +854,12 @@ class StreamWrapper | |||
$params['Body'] = ''; | |||
// Fail if this pseudo directory key already exists | |||
if (self::$client->doesObjectExist($params['Bucket'], $params['Key'])) { | |||
if (static::$client->doesObjectExist($params['Bucket'], $params['Key'])) { | |||
return $this->triggerError("Directory already exists: {$path}"); | |||
} | |||
try { | |||
self::$client->putObject($params); | |||
static::$client->putObject($params); | |||
$this->clearStatInfo($path); | |||
return true; | |||
} catch (\Exception $e) { |
@@ -65,7 +65,7 @@ abstract class AbstractSyncBuilder | |||
protected $debug; | |||
/** | |||
* @return self | |||
* @return static | |||
*/ | |||
public static function getInstance() | |||
{ | |||
@@ -77,7 +77,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param string $bucket Amazon S3 bucket name | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setBucket($bucket) | |||
{ | |||
@@ -91,7 +91,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param S3Client $client Amazon S3 client | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setClient(S3Client $client) | |||
{ | |||
@@ -105,7 +105,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param \Iterator $iterator | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setSourceIterator(\Iterator $iterator) | |||
{ | |||
@@ -119,7 +119,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param FileNameConverterInterface $converter Filename to object key provider | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setSourceFilenameConverter(FilenameConverterInterface $converter) | |||
{ | |||
@@ -133,7 +133,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param FileNameConverterInterface $converter Filename to object key provider | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setTargetFilenameConverter(FilenameConverterInterface $converter) | |||
{ | |||
@@ -148,7 +148,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param string $baseDir Base directory, which will be deleted from each uploaded object key | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setBaseDir($baseDir) | |||
{ | |||
@@ -164,7 +164,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param string $keyPrefix Prefix for each uploaded key | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setKeyPrefix($keyPrefix) | |||
{ | |||
@@ -179,7 +179,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param string $delimiter Delimiter to use to separate paths | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setDelimiter($delimiter) | |||
{ | |||
@@ -193,7 +193,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param array $params Associative array of PutObject (upload) GetObject (download) parameters | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setOperationParams(array $params) | |||
{ | |||
@@ -207,7 +207,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param int $concurrency Number of concurrent transfers | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setConcurrency($concurrency) | |||
{ | |||
@@ -221,7 +221,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param bool $force Set to true to force transfers without checking if it has changed | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function force($force = false) | |||
{ | |||
@@ -235,7 +235,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param bool|resource $enabledOrResource Set to true or false to enable or disable debug output. Pass an opened | |||
* fopen resource to write to instead of writing to standard out. | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function enableDebugOutput($enabledOrResource = true) | |||
{ | |||
@@ -249,7 +249,7 @@ abstract class AbstractSyncBuilder | |||
* | |||
* @param string $search Regular expression search (in preg_match format). Any filename that matches this regex | |||
* will not be transferred. | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function addRegexFilter($search) | |||
{ | |||
@@ -301,7 +301,7 @@ abstract class AbstractSyncBuilder | |||
/** | |||
* Hook to implement in subclasses | |||
* | |||
* @return self | |||
* @return AbstractSync | |||
*/ | |||
abstract protected function specificBuild(); | |||
@@ -38,7 +38,7 @@ class DownloadSyncBuilder extends AbstractSyncBuilder | |||
* | |||
* @param string $directory Directory | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setDirectory($directory) | |||
{ |
@@ -36,7 +36,7 @@ class UploadSyncBuilder extends AbstractSyncBuilder | |||
* | |||
* @param string $path Path that contains files to upload | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function uploadFromDirectory($path) | |||
{ | |||
@@ -54,7 +54,7 @@ class UploadSyncBuilder extends AbstractSyncBuilder | |||
* | |||
* @param string $glob Glob expression | |||
* | |||
* @return self | |||
* @return $this | |||
* @link http://www.php.net/manual/en/function.glob.php | |||
*/ | |||
public function uploadFromGlob($glob) | |||
@@ -71,7 +71,7 @@ class UploadSyncBuilder extends AbstractSyncBuilder | |||
* | |||
* @param string $acl Canned ACL for each upload | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setAcl($acl) | |||
{ | |||
@@ -85,7 +85,7 @@ class UploadSyncBuilder extends AbstractSyncBuilder | |||
* | |||
* @param Acp $acp Access control policy | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setAcp(Acp $acp) | |||
{ | |||
@@ -100,7 +100,7 @@ class UploadSyncBuilder extends AbstractSyncBuilder | |||
* | |||
* @param int $size Size threshold | |||
* | |||
* @return self | |||
* @return $this | |||
*/ | |||
public function setMultipartUploadSize($size) | |||
{ |
@@ -15,7 +15,7 @@ namespace Symfony\Component\ClassLoader; | |||
* ApcClassLoader implements a wrapping autoloader cached in APC for PHP 5.3. | |||
* | |||
* It expects an object implementing a findFile method to find the file. This | |||
* allow using it as a wrapper around the other loaders of the component (the | |||
* allows using it as a wrapper around the other loaders of the component (the | |||
* ClassLoader and the UniversalClassLoader for instance) but also around any | |||
* other autoloader following this convention (the Composer one for instance) | |||
* | |||
@@ -46,7 +46,7 @@ class ApcClassLoader | |||
/** | |||
* The class loader object being decorated. | |||
* | |||
* @var \Symfony\Component\ClassLoader\ClassLoader | |||
* @var object | |||
* A class loader object that implements the findFile() method. | |||
*/ | |||
protected $decorated; | |||
@@ -133,5 +133,4 @@ class ApcClassLoader | |||
{ | |||
return call_user_func_array(array($this->decorated, $method), $args); | |||
} | |||
} |
@@ -71,7 +71,6 @@ class ClassMapGenerator | |||
foreach ($classes as $class) { | |||
$map[$class] = $path; | |||
} | |||
} | |||
return $map; |
@@ -32,7 +32,7 @@ class Psr4ClassLoader | |||
public function addPrefix($prefix, $baseDir) | |||
{ | |||
$prefix = trim($prefix, '\\').'\\'; | |||
$baseDir = rtrim($baseDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; | |||
$baseDir = rtrim($baseDir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; | |||
$this->prefixes[] = array($prefix, $baseDir); | |||
} | |||
@@ -49,7 +49,7 @@ class Psr4ClassLoader | |||
list($currentPrefix, $currentBaseDir) = $current; | |||
if (0 === strpos($class, $currentPrefix)) { | |||
$classWithoutPrefix = substr($class, strlen($currentPrefix)); | |||
$file = $currentBaseDir . str_replace('\\', DIRECTORY_SEPARATOR, $classWithoutPrefix) . '.php'; | |||
$file = $currentBaseDir.str_replace('\\', DIRECTORY_SEPARATOR, $classWithoutPrefix).'.php'; | |||
if (file_exists($file)) { | |||
return $file; | |||
} |
@@ -9,51 +9,63 @@ standard or the PEAR naming convention. | |||
First, register the autoloader: | |||
require_once __DIR__.'/src/Symfony/Component/ClassLoader/UniversalClassLoader.php'; | |||
```php | |||
require_once __DIR__.'/src/Symfony/Component/ClassLoader/UniversalClassLoader.php'; | |||
use Symfony\Component\ClassLoader\UniversalClassLoader; | |||
use Symfony\Component\ClassLoader\UniversalClassLoader; | |||
$loader = new UniversalClassLoader(); | |||
$loader->register(); | |||
$loader = new UniversalClassLoader(); | |||
$loader->register(); | |||
``` | |||
Then, register some namespaces with the `registerNamespace()` method: | |||
$loader->registerNamespace('Symfony', __DIR__.'/src'); | |||
$loader->registerNamespace('Monolog', __DIR__.'/vendor/monolog/src'); | |||
```php | |||
$loader->registerNamespace('Symfony', __DIR__.'/src'); | |||
$loader->registerNamespace('Monolog', __DIR__.'/vendor/monolog/src'); | |||
``` | |||
The `registerNamespace()` method takes a namespace prefix and a path where to | |||
look for the classes as arguments. | |||
You can also register a sub-namespaces: | |||
$loader->registerNamespace('Doctrine\\Common', __DIR__.'/vendor/doctrine-common/lib'); | |||
```php | |||
$loader->registerNamespace('Doctrine\\Common', __DIR__.'/vendor/doctrine-common/lib'); | |||
``` | |||
The order of registration is significant and the first registered namespace | |||
takes precedence over later registered one. | |||
You can also register more than one path for a given namespace: | |||
$loader->registerNamespace('Symfony', array(__DIR__.'/src', __DIR__.'/symfony/src')); | |||
```php | |||
$loader->registerNamespace('Symfony', array(__DIR__.'/src', __DIR__.'/symfony/src')); | |||
``` | |||
Alternatively, you can use the `registerNamespaces()` method to register more | |||
than one namespace at once: | |||
$loader->registerNamespaces(array( | |||
'Symfony' => array(__DIR__.'/src', __DIR__.'/symfony/src'), | |||
'Doctrine\\Common' => __DIR__.'/vendor/doctrine-common/lib', | |||
'Doctrine' => __DIR__.'/vendor/doctrine/lib', | |||
'Monolog' => __DIR__.'/vendor/monolog/src', | |||
)); | |||
```php | |||
$loader->registerNamespaces(array( | |||
'Symfony' => array(__DIR__.'/src', __DIR__.'/symfony/src'), | |||
'Doctrine\\Common' => __DIR__.'/vendor/doctrine-common/lib', | |||
'Doctrine' => __DIR__.'/vendor/doctrine/lib', | |||
'Monolog' => __DIR__.'/vendor/monolog/src', | |||
)); | |||
``` | |||
For better performance, you can use the APC based version of the universal | |||
class loader: | |||
require_once __DIR__.'/src/Symfony/Component/ClassLoader/UniversalClassLoader.php'; | |||
require_once __DIR__.'/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php'; | |||
```php | |||
require_once __DIR__.'/src/Symfony/Component/ClassLoader/UniversalClassLoader.php'; | |||
require_once __DIR__.'/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php'; | |||
use Symfony\Component\ClassLoader\ApcUniversalClassLoader; | |||
use Symfony\Component\ClassLoader\ApcUniversalClassLoader; | |||
$loader = new ApcUniversalClassLoader('apc.prefix.'); | |||
$loader = new ApcUniversalClassLoader('apc.prefix.'); | |||
``` | |||
Furthermore, the component provides tools to aggregate classes into a single | |||
file, which is especially useful to improve performance on servers that do not |
@@ -55,13 +55,13 @@ class ApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase | |||
$this->assertTrue(class_exists($className), $message); | |||
} | |||
public function getLoadClassTests() | |||
{ | |||
return array( | |||
public function getLoadClassTests() | |||
{ | |||
return array( | |||
array('\\Apc\\Namespaced\\Foo', 'Apc\\Namespaced\\Foo', '->loadClass() loads Apc\Namespaced\Foo class'), | |||
array('Apc_Pearlike_Foo', 'Apc_Pearlike_Foo', '->loadClass() loads Apc_Pearlike_Foo class'), | |||
); | |||
} | |||
} | |||
/** | |||
* @dataProvider getLoadClassFromFallbackTests | |||
@@ -77,15 +77,15 @@ class ApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase | |||
$this->assertTrue(class_exists($className), $message); | |||
} | |||
public function getLoadClassFromFallbackTests() | |||
{ | |||
return array( | |||
public function getLoadClassFromFallbackTests() | |||
{ | |||
return array( | |||
array('\\Apc\\Namespaced\\Baz', 'Apc\\Namespaced\\Baz', '->loadClass() loads Apc\Namespaced\Baz class'), | |||
array('Apc_Pearlike_Baz', 'Apc_Pearlike_Baz', '->loadClass() loads Apc_Pearlike_Baz class'), | |||
array('\\Apc\\Namespaced\\FooBar', 'Apc\\Namespaced\\FooBar', '->loadClass() loads Apc\Namespaced\Baz class from fallback dir'), | |||
array('Apc_Pearlike_FooBar', 'Apc_Pearlike_FooBar', '->loadClass() loads Apc_Pearlike_Baz class from fallback dir'), | |||
); | |||
} | |||
} | |||
/** | |||
* @dataProvider getLoadClassNamespaceCollisionTests | |||
@@ -100,9 +100,9 @@ class ApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase | |||
$this->assertTrue(class_exists($className), $message); | |||
} | |||
public function getLoadClassNamespaceCollisionTests() | |||
{ | |||
return array( | |||
public function getLoadClassNamespaceCollisionTests() | |||
{ | |||
return array( | |||
array( | |||
array( | |||
'Apc\\NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha', | |||
@@ -136,7 +136,7 @@ class ApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase | |||
'->loadClass() loads NamespaceCollision\A\B\Bar from beta.', | |||
), | |||
); | |||
} | |||
} | |||
/** | |||
* @dataProvider getLoadClassPrefixCollisionTests | |||
@@ -150,9 +150,9 @@ class ApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase | |||
$this->assertTrue(class_exists($className), $message); | |||
} | |||
public function getLoadClassPrefixCollisionTests() | |||
{ | |||
return array( | |||
public function getLoadClassPrefixCollisionTests() | |||
{ | |||
return array( | |||
array( | |||
array( | |||
'ApcPrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/alpha/Apc', | |||
@@ -186,5 +186,5 @@ class ApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase | |||
'->loadClass() loads ApcPrefixCollision_A_B_Bar from beta.', | |||
), | |||
); | |||
} | |||
} | |||
} |
@@ -76,7 +76,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase | |||
'Namespaced\\Foo' => realpath(__DIR__).'/Fixtures/Namespaced/Foo.php', | |||
'Namespaced\\Baz' => realpath(__DIR__).'/Fixtures/Namespaced/Baz.php', | |||
'Namespaced\\WithComments' => realpath(__DIR__).'/Fixtures/Namespaced/WithComments.php', | |||
) | |||
), | |||
), | |||
array(__DIR__.'/Fixtures/beta/NamespaceCollision', array( | |||
'NamespaceCollision\\A\\B\\Bar' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/A/B/Bar.php', |
@@ -2,4 +2,6 @@ | |||
namespace ClassesWithParents; | |||
class A extends B {} | |||
class A extends B | |||
{ | |||
} |
@@ -2,4 +2,6 @@ | |||
namespace ClassesWithParents; | |||
class B implements CInterface {} | |||
class B implements CInterface | |||
{ | |||
} |
@@ -13,5 +13,4 @@ namespace ClassMap; | |||
class SomeClass extends SomeParent implements SomeInterface | |||
{ | |||
} |
@@ -13,5 +13,4 @@ namespace ClassMap; | |||
interface SomeInterface | |||
{ | |||
} |
@@ -13,5 +13,4 @@ namespace ClassMap; | |||
abstract class SomeParent | |||
{ | |||
} |
@@ -1,14 +1,24 @@ | |||
<?php | |||
namespace { | |||
class A {} | |||
class A | |||
{ | |||
} | |||
} | |||
namespace Alpha { | |||
class A {} | |||
class B {} | |||
class A | |||
{ | |||
} | |||
class B | |||
{ | |||
} | |||
} | |||
namespace Beta { | |||
class A {} | |||
class B {} | |||
class A | |||
{ | |||
} | |||
class B | |||
{ | |||
} | |||
} |
@@ -11,5 +11,9 @@ | |||
namespace Foo\Bar; | |||
class A {} | |||
class B {} | |||
class A | |||
{ | |||
} | |||
class B | |||
{ | |||
} |
@@ -1,7 +1,8 @@ | |||
<?php | |||
trait TD | |||
{} | |||
{ | |||
} | |||
trait TZ | |||
{ |
@@ -25,6 +25,7 @@ namespace Foo { | |||
class CBar implements IBar | |||
{ | |||
use TBar, TFooBar; | |||
use TBar; | |||
use TFooBar; | |||
} | |||
} |
@@ -24,7 +24,7 @@ class Psr4ClassLoaderTest extends \PHPUnit_Framework_TestCase | |||
$loader = new Psr4ClassLoader(); | |||
$loader->addPrefix( | |||
'Acme\\DemoLib', | |||
__DIR__ . DIRECTORY_SEPARATOR . 'Fixtures' . DIRECTORY_SEPARATOR . 'psr-4' | |||
__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'psr-4' | |||
); | |||
$loader->loadClass($className); | |||
$this->assertTrue(class_exists($className), sprintf('loadClass() should load %s', $className)); | |||
@@ -39,7 +39,7 @@ class Psr4ClassLoaderTest extends \PHPUnit_Framework_TestCase | |||
array('Acme\\DemoLib\\Foo'), | |||
array('Acme\\DemoLib\\Class_With_Underscores'), | |||
array('Acme\\DemoLib\\Lets\\Go\\Deeper\\Foo'), | |||
array('Acme\\DemoLib\\Lets\\Go\\Deeper\\Class_With_Underscores') | |||
array('Acme\\DemoLib\\Lets\\Go\\Deeper\\Class_With_Underscores'), | |||
); | |||
} | |||
@@ -52,7 +52,7 @@ class Psr4ClassLoaderTest extends \PHPUnit_Framework_TestCase | |||
$loader = new Psr4ClassLoader(); | |||
$loader->addPrefix( | |||
'Acme\\DemoLib', | |||
__DIR__ . DIRECTORY_SEPARATOR . 'Fixtures' . DIRECTORY_SEPARATOR . 'psr-4' | |||
__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'psr-4' | |||
); | |||
$loader->loadClass($className); | |||
$this->assertFalse(class_exists($className), sprintf('loadClass() should not load %s', $className)); | |||
@@ -65,7 +65,7 @@ class Psr4ClassLoaderTest extends \PHPUnit_Framework_TestCase | |||
{ | |||
return array( | |||
array('Acme\\DemoLib\\I_Do_Not_Exist'), | |||
array('UnknownVendor\\SomeLib\\I_Do_Not_Exist') | |||
array('UnknownVendor\\SomeLib\\I_Do_Not_Exist'), | |||
); | |||
} | |||
} |
@@ -287,7 +287,6 @@ class UniversalClassLoader | |||
return $file; | |||
} | |||
} | |||
} else { | |||
// PEAR-like class name | |||
$normalizedClass = str_replace('_', DIRECTORY_SEPARATOR, $class).'.php'; |
@@ -12,7 +12,7 @@ | |||
namespace Symfony\Component\ClassLoader; | |||
/** | |||
* XcacheClassLoader implements a wrapping autoloader cached in Xcache for PHP 5.3. | |||
* XcacheClassLoader implements a wrapping autoloader cached in XCache for PHP 5.3. | |||
* | |||
* It expects an object implementing a findFile method to find the file. This | |||
* allows using it as a wrapper around the other loaders of the component (the | |||
@@ -43,31 +43,35 @@ namespace Symfony\Component\ClassLoader; | |||
class XcacheClassLoader | |||
{ | |||
private $prefix; | |||
private $classFinder; | |||
/** | |||
* @var object A class loader object that implements the findFile() method | |||
*/ | |||
private $decorated; | |||
/** | |||
* Constructor. | |||
* | |||
* @param string $prefix A prefix to create a namespace in Xcache | |||
* @param object $classFinder An object that implements findFile() method. | |||
* @param string $prefix The XCache namespace prefix to use. | |||
* @param object $decorated A class loader object that implements the findFile() method. | |||
* | |||
* @throws \RuntimeException | |||
* @throws \InvalidArgumentException | |||
* | |||
* @api | |||
*/ | |||
public function __construct($prefix, $classFinder) | |||
public function __construct($prefix, $decorated) | |||
{ | |||
if (!extension_loaded('Xcache')) { | |||
throw new \RuntimeException('Unable to use XcacheClassLoader as Xcache is not enabled.'); | |||
if (!extension_loaded('xcache')) { | |||
throw new \RuntimeException('Unable to use XcacheClassLoader as XCache is not enabled.'); | |||
} | |||
if (!method_exists($classFinder, 'findFile')) { | |||
if (!method_exists($decorated, 'findFile')) { | |||
throw new \InvalidArgumentException('The class finder must implement a "findFile" method.'); | |||
} | |||
$this->prefix = $prefix; | |||
$this->classFinder = $classFinder; | |||
$this->decorated = $decorated; | |||
} | |||
/** | |||
@@ -116,10 +120,18 @@ class XcacheClassLoader | |||
if (xcache_isset($this->prefix.$class)) { | |||
$file = xcache_get($this->prefix.$class); | |||
} else { | |||
$file = $this->classFinder->findFile($class); | |||
$file = $this->decorated->findFile($class); | |||
xcache_set($this->prefix.$class, $file); | |||
} | |||
return $file; | |||
} | |||
/** | |||
* Passes through all unknown calls onto the decorated object. | |||
*/ | |||
public function __call($method, $args) | |||
{ | |||
return call_user_func_array(array($this->decorated, $method), $args); | |||
} | |||
} |
@@ -271,7 +271,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface | |||
if ($listener instanceof \Closure) { | |||
$info += array( | |||
'type' => 'Closure', | |||
'pretty' => 'closure' | |||
'pretty' => 'closure', | |||
); | |||
} elseif (is_string($listener)) { | |||
try { |
@@ -64,8 +64,8 @@ interface EventDispatcherInterface | |||
/** | |||
* Removes an event listener from the specified events. | |||
* | |||
* @param string|array $eventName The event(s) to remove a listener from | |||
* @param callable $listener The listener to remove | |||
* @param string $eventName The event to remove a listener from | |||
* @param callable $listener The listener to remove | |||
*/ | |||
public function removeListener($eventName, $listener); | |||
@@ -4,16 +4,18 @@ EventDispatcher Component | |||
The Symfony2 EventDispatcher component implements the Mediator pattern in a | |||
simple and effective way to make your projects truly extensible. | |||
use Symfony\Component\EventDispatcher\EventDispatcher; | |||
use Symfony\Component\EventDispatcher\Event; | |||
```php | |||
use Symfony\Component\EventDispatcher\EventDispatcher; | |||
use Symfony\Component\EventDispatcher\Event; | |||
$dispatcher = new EventDispatcher(); | |||
$dispatcher = new EventDispatcher(); | |||
$dispatcher->addListener('event_name', function (Event $event) { | |||
// ... | |||
}); | |||
$dispatcher->addListener('event_name', function (Event $event) { | |||
// ... | |||
}); | |||
$dispatcher->dispatch('event_name'); | |||
$dispatcher->dispatch('event_name'); | |||
``` | |||
Resources | |||
--------- |
@@ -24,7 +24,7 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase | |||
$dispatcher = new EventDispatcher(); | |||
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); | |||
$tdispatcher->addListener('foo', $listener = function () { ; }); | |||
$tdispatcher->addListener('foo', $listener = function () {; }); | |||
$listeners = $dispatcher->getListeners('foo'); | |||
$this->assertCount(1, $listeners); | |||
$this->assertSame($listener, $listeners[0]); | |||
@@ -38,7 +38,7 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase | |||
$dispatcher = new EventDispatcher(); | |||
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); | |||
$tdispatcher->addListener('foo', $listener = function () { ; }); | |||
$tdispatcher->addListener('foo', $listener = function () {; }); | |||
$this->assertSame($dispatcher->getListeners('foo'), $tdispatcher->getListeners('foo')); | |||
} | |||
@@ -50,7 +50,7 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase | |||
$this->assertFalse($dispatcher->hasListeners('foo')); | |||
$this->assertFalse($tdispatcher->hasListeners('foo')); | |||
$tdispatcher->addListener('foo', $listener = function () { ; }); | |||
$tdispatcher->addListener('foo', $listener = function () {; }); | |||
$this->assertTrue($dispatcher->hasListeners('foo')); | |||
$this->assertTrue($tdispatcher->hasListeners('foo')); | |||
} | |||
@@ -75,7 +75,7 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase | |||
{ | |||
$dispatcher = new EventDispatcher(); | |||
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); | |||
$tdispatcher->addListener('foo', $listener = function () { ; }); | |||
$tdispatcher->addListener('foo', $listener = function () {; }); | |||
$this->assertEquals(array(), $tdispatcher->getCalledListeners()); | |||
$this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure')), $tdispatcher->getNotCalledListeners()); | |||
@@ -92,8 +92,8 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase | |||
$dispatcher = new EventDispatcher(); | |||
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); | |||
$tdispatcher->addListener('foo', $listener1 = function () { ; }); | |||
$tdispatcher->addListener('foo', $listener2 = function () { ; }); | |||
$tdispatcher->addListener('foo', $listener1 = function () {; }); | |||
$tdispatcher->addListener('foo', $listener2 = function () {; }); | |||
$logger->expects($this->at(0))->method('debug')->with("Notified event \"foo\" to listener \"closure\"."); | |||
$logger->expects($this->at(1))->method('debug')->with("Notified event \"foo\" to listener \"closure\"."); | |||
@@ -108,7 +108,7 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase | |||
$dispatcher = new EventDispatcher(); | |||
$tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); | |||
$tdispatcher->addListener('foo', $listener1 = function (Event $event) { $event->stopPropagation(); }); | |||
$tdispatcher->addListener('foo', $listener2 = function () { ; }); | |||
$tdispatcher->addListener('foo', $listener2 = function () {; }); | |||
$logger->expects($this->at(0))->method('debug')->with("Notified event \"foo\" to listener \"closure\"."); | |||
$logger->expects($this->at(1))->method('debug')->with("Listener \"closure\" stopped propagation of the event \"foo\"."); |
@@ -37,7 +37,10 @@ class RegisterListenersPassTest extends \PHPUnit_Framework_TestCase | |||
->method('getClass') | |||
->will($this->returnValue('stdClass')); | |||
$builder = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); | |||
$builder = $this->getMock( | |||
'Symfony\Component\DependencyInjection\ContainerBuilder', | |||
array('hasDefinition', 'findTaggedServiceIds', 'getDefinition') | |||
); | |||
$builder->expects($this->any()) | |||
->method('hasDefinition') | |||
->will($this->returnValue(true)); | |||
@@ -69,7 +72,10 @@ class RegisterListenersPassTest extends \PHPUnit_Framework_TestCase | |||
->method('getClass') | |||
->will($this->returnValue('Symfony\Component\EventDispatcher\Tests\DependencyInjection\SubscriberService')); | |||
$builder = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); | |||
$builder = $this->getMock( | |||
'Symfony\Component\DependencyInjection\ContainerBuilder', | |||
array('hasDefinition', 'findTaggedServiceIds', 'getDefinition', 'findDefinition') | |||
); | |||
$builder->expects($this->any()) | |||
->method('hasDefinition') | |||
->will($this->returnValue(true)); | |||
@@ -136,5 +142,7 @@ class RegisterListenersPassTest extends \PHPUnit_Framework_TestCase | |||
class SubscriberService implements \Symfony\Component\EventDispatcher\EventSubscriberInterface | |||
{ | |||
public static function getSubscribedEvents() {} | |||
public static function getSubscribedEvents() | |||
{ | |||
} | |||
} |
@@ -362,7 +362,7 @@ class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterfa | |||
{ | |||
return array('pre.foo' => array( | |||
array('preFoo1'), | |||
array('preFoo2', 10) | |||
array('preFoo2', 10), | |||
)); | |||
} | |||
} |
@@ -18,7 +18,6 @@ use Symfony\Component\EventDispatcher\GenericEvent; | |||
*/ | |||
class GenericEventTest extends \PHPUnit_Framework_TestCase | |||
{ | |||
/** | |||
* @var GenericEvent | |||
*/ |
@@ -19,7 +19,7 @@ | |||
"php": ">=5.3.3" | |||
}, | |||
"require-dev": { | |||
"symfony/dependency-injection": "~2.0", | |||
"symfony/dependency-injection": "~2.0,<2.6.0", | |||
"symfony/config": "~2.0", | |||
"symfony/stopwatch": "~2.2", | |||
"psr/log": "~1.0" |