Merge pull request #12166 from helmutschneider/aws-2.7.5

Upgrade AWS sdk to 2.7.5. Fixes #12023
This commit is contained in:
Lukas Reschke 2014-12-05 20:12:53 +01:00
commit 1be5a3ca89
51 changed files with 710 additions and 254 deletions

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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';

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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',

View File

@ -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'
)
)
);

View File

@ -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", "*/*");
}
}

View File

@ -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('');
}

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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);
}
}

View File

@ -64,7 +64,7 @@ class DeleteObjectsTransfer implements BatchTransferInterface
*
* @param string $token MFA token
*
* @return self
* @return $this
*/
public function setMfa($token)
{

View File

@ -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
*/

View File

@ -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}\"";
}

View File

@ -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)
{

View File

@ -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',

View File

@ -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();
}
/**

View File

@ -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';
}
/**

View File

@ -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) {

View File

@ -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();

View File

@ -38,7 +38,7 @@ class DownloadSyncBuilder extends AbstractSyncBuilder
*
* @param string $directory Directory
*
* @return self
* @return $this
*/
public function setDirectory($directory)
{

View File

@ -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)
{

View File

@ -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);
}
}

View File

@ -71,7 +71,6 @@ class ClassMapGenerator
foreach ($classes as $class) {
$map[$class] = $path;
}
}
return $map;

View File

@ -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;
}

View 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

View File

@ -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.',
),
);
}
}
}

View File

@ -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',

View File

@ -2,4 +2,6 @@
namespace ClassesWithParents;
class A extends B {}
class A extends B
{
}

View File

@ -2,4 +2,6 @@
namespace ClassesWithParents;
class B implements CInterface {}
class B implements CInterface
{
}

View File

@ -13,5 +13,4 @@ namespace ClassMap;
class SomeClass extends SomeParent implements SomeInterface
{
}

View File

@ -13,5 +13,4 @@ namespace ClassMap;
interface SomeInterface
{
}

View File

@ -13,5 +13,4 @@ namespace ClassMap;
abstract class SomeParent
{
}

View File

@ -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
{
}
}

View File

@ -11,5 +11,9 @@
namespace Foo\Bar;
class A {}
class B {}
class A
{
}
class B
{
}

View File

@ -1,7 +1,8 @@
<?php
trait TD
{}
{
}
trait TZ
{

View File

@ -25,6 +25,7 @@ namespace Foo {
class CBar implements IBar
{
use TBar, TFooBar;
use TBar;
use TFooBar;
}
}

View File

@ -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'),
);
}
}

View File

@ -287,7 +287,6 @@ class UniversalClassLoader
return $file;
}
}
} else {
// PEAR-like class name
$normalizedClass = str_replace('_', DIRECTORY_SEPARATOR, $class).'.php';

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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);

View File

@ -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
---------

View File

@ -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\".");

View File

@ -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()
{
}
}

View File

@ -362,7 +362,7 @@ class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterfa
{
return array('pre.foo' => array(
array('preFoo1'),
array('preFoo2', 10)
array('preFoo2', 10),
));
}
}

View File

@ -18,7 +18,6 @@ use Symfony\Component\EventDispatcher\GenericEvent;
*/
class GenericEventTest extends \PHPUnit_Framework_TestCase
{
/**
* @var GenericEvent
*/

View File

@ -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"