Skip to content

Commit cb05fea

Browse files
authored
Generate PutBucketTagging method for s3 client (#1451)
generate PutBucketTagging method for s3 client
1 parent ebfe9c4 commit cb05fea

File tree

9 files changed

+558
-3
lines changed

9 files changed

+558
-3
lines changed

docs/clients/s3.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,32 @@ foreach ($result->getBody()->getChunks() as $chunk) {
104104
}
105105
```
106106

107+
### Add tags to a bucket
108+
109+
You can add tags to your buckets to help you find related resources in the AWS cost explorer; eg all AWS resources tagged
110+
with `environment = staging` would show you the amount you're spending on your pre-prod environment each month
111+
112+
```
113+
$client->putBucketTagging(
114+
new PutBucketTaggingRequest([
115+
'Bucket' => 'my-website-assets-bucket',
116+
117+
'Tagging' => new Tagging([
118+
'TagSet' => [
119+
new Tag([
120+
'Key' => 'environment',
121+
'Value' => 'production',
122+
]),
123+
new Tag([
124+
'Key' => 'project-name',
125+
'Value' => 'unicorn',
126+
])
127+
],
128+
]),
129+
])
130+
);
131+
```
132+
107133
## Virtual Hosted-Style Requests
108134

109135
When calling AWS endpoints, AsyncAws uses [Virtual Hosted-Style Requests](https://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html):

manifest.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@
554554
"ObjectNotExists",
555555
"PutBucketCors",
556556
"PutBucketNotificationConfiguration",
557+
"PutBucketTagging",
557558
"PutObject",
558559
"PutObjectAcl",
559560
"UploadPart"
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
<?php
2+
3+
namespace AsyncAws\S3\Input;
4+
5+
use AsyncAws\Core\Exception\InvalidArgument;
6+
use AsyncAws\Core\Input;
7+
use AsyncAws\Core\Request;
8+
use AsyncAws\Core\Stream\StreamFactory;
9+
use AsyncAws\S3\Enum\ChecksumAlgorithm;
10+
use AsyncAws\S3\ValueObject\Tag;
11+
use AsyncAws\S3\ValueObject\Tagging;
12+
13+
final class PutBucketTaggingRequest extends Input
14+
{
15+
/**
16+
* The bucket name.
17+
*
18+
* @required
19+
*
20+
* @var string|null
21+
*/
22+
private $bucket;
23+
24+
/**
25+
* The base64-encoded 128-bit MD5 digest of the data. You must use this header as a message integrity check to verify
26+
* that the request body was not corrupted in transit. For more information, see RFC 1864 [^1].
27+
*
28+
* For requests made using the Amazon Web Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field
29+
* is calculated automatically.
30+
*
31+
* [^1]: http://www.ietf.org/rfc/rfc1864.txt
32+
*
33+
* @var string|null
34+
*/
35+
private $contentMd5;
36+
37+
/**
38+
* Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide
39+
* any additional functionality if not using the SDK. When sending this header, there must be a corresponding
40+
* `x-amz-checksum` or `x-amz-trailer` header sent. Otherwise, Amazon S3 fails the request with the HTTP status code
41+
* `400 Bad Request`. For more information, see Checking object integrity [^1] in the *Amazon S3 User Guide*.
42+
*
43+
* If you provide an individual checksum, Amazon S3 ignores any provided `ChecksumAlgorithm` parameter.
44+
*
45+
* [^1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html
46+
*
47+
* @var ChecksumAlgorithm::*|null
48+
*/
49+
private $checksumAlgorithm;
50+
51+
/**
52+
* Container for the `TagSet` and `Tag` elements.
53+
*
54+
* @required
55+
*
56+
* @var Tagging|null
57+
*/
58+
private $tagging;
59+
60+
/**
61+
* The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with
62+
* the HTTP status code `403 Forbidden` (access denied).
63+
*
64+
* @var string|null
65+
*/
66+
private $expectedBucketOwner;
67+
68+
/**
69+
* @param array{
70+
* Bucket?: string,
71+
* ContentMD5?: string,
72+
* ChecksumAlgorithm?: ChecksumAlgorithm::*,
73+
* Tagging?: Tagging|array,
74+
* ExpectedBucketOwner?: string,
75+
*
76+
* @region?: string,
77+
* } $input
78+
*/
79+
public function __construct(array $input = [])
80+
{
81+
$this->bucket = $input['Bucket'] ?? null;
82+
$this->contentMd5 = $input['ContentMD5'] ?? null;
83+
$this->checksumAlgorithm = $input['ChecksumAlgorithm'] ?? null;
84+
$this->tagging = isset($input['Tagging']) ? Tagging::create($input['Tagging']) : null;
85+
$this->expectedBucketOwner = $input['ExpectedBucketOwner'] ?? null;
86+
parent::__construct($input);
87+
}
88+
89+
public static function create($input): self
90+
{
91+
return $input instanceof self ? $input : new self($input);
92+
}
93+
94+
public function getBucket(): ?string
95+
{
96+
return $this->bucket;
97+
}
98+
99+
/**
100+
* @return ChecksumAlgorithm::*|null
101+
*/
102+
public function getChecksumAlgorithm(): ?string
103+
{
104+
return $this->checksumAlgorithm;
105+
}
106+
107+
public function getContentMd5(): ?string
108+
{
109+
return $this->contentMd5;
110+
}
111+
112+
public function getExpectedBucketOwner(): ?string
113+
{
114+
return $this->expectedBucketOwner;
115+
}
116+
117+
public function getTagging(): ?Tagging
118+
{
119+
return $this->tagging;
120+
}
121+
122+
/**
123+
* @internal
124+
*/
125+
public function request(): Request
126+
{
127+
// Prepare headers
128+
$headers = ['content-type' => 'application/xml'];
129+
if (null !== $this->contentMd5) {
130+
$headers['Content-MD5'] = $this->contentMd5;
131+
}
132+
if (null !== $this->checksumAlgorithm) {
133+
if (!ChecksumAlgorithm::exists($this->checksumAlgorithm)) {
134+
throw new InvalidArgument(sprintf('Invalid parameter "ChecksumAlgorithm" for "%s". The value "%s" is not a valid "ChecksumAlgorithm".', __CLASS__, $this->checksumAlgorithm));
135+
}
136+
$headers['x-amz-sdk-checksum-algorithm'] = $this->checksumAlgorithm;
137+
}
138+
if (null !== $this->expectedBucketOwner) {
139+
$headers['x-amz-expected-bucket-owner'] = $this->expectedBucketOwner;
140+
}
141+
142+
// Prepare query
143+
$query = [];
144+
145+
// Prepare URI
146+
$uri = [];
147+
if (null === $v = $this->bucket) {
148+
throw new InvalidArgument(sprintf('Missing parameter "Bucket" for "%s". The value cannot be null.', __CLASS__));
149+
}
150+
$uri['Bucket'] = $v;
151+
$uriString = '/' . rawurlencode($uri['Bucket']) . '?tagging';
152+
153+
// Prepare Body
154+
155+
$document = new \DOMDocument('1.0', 'UTF-8');
156+
$document->formatOutput = false;
157+
$this->requestBody($document, $document);
158+
$body = $document->hasChildNodes() ? $document->saveXML() : '';
159+
160+
// Return the Request
161+
return new Request('PUT', $uriString, $query, $headers, StreamFactory::create($body));
162+
}
163+
164+
public function setBucket(?string $value): self
165+
{
166+
$this->bucket = $value;
167+
168+
return $this;
169+
}
170+
171+
/**
172+
* @param ChecksumAlgorithm::*|null $value
173+
*/
174+
public function setChecksumAlgorithm(?string $value): self
175+
{
176+
$this->checksumAlgorithm = $value;
177+
178+
return $this;
179+
}
180+
181+
public function setContentMd5(?string $value): self
182+
{
183+
$this->contentMd5 = $value;
184+
185+
return $this;
186+
}
187+
188+
public function setExpectedBucketOwner(?string $value): self
189+
{
190+
$this->expectedBucketOwner = $value;
191+
192+
return $this;
193+
}
194+
195+
public function setTagging(?Tagging $value): self
196+
{
197+
$this->tagging = $value;
198+
199+
return $this;
200+
}
201+
202+
private function requestBody(\DOMNode $node, \DOMDocument $document): void
203+
{
204+
if (null === $v = $this->tagging) {
205+
throw new InvalidArgument(sprintf('Missing parameter "Tagging" for "%s". The value cannot be null.', __CLASS__));
206+
}
207+
208+
$node->appendChild($child = $document->createElement('Tagging'));
209+
$child->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');
210+
$v->requestBody($child, $document);
211+
}
212+
}

src/Service/S3/src/S3Client.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
use AsyncAws\S3\Input\ListPartsRequest;
5050
use AsyncAws\S3\Input\PutBucketCorsRequest;
5151
use AsyncAws\S3\Input\PutBucketNotificationConfigurationRequest;
52+
use AsyncAws\S3\Input\PutBucketTaggingRequest;
5253
use AsyncAws\S3\Input\PutObjectAclRequest;
5354
use AsyncAws\S3\Input\PutObjectRequest;
5455
use AsyncAws\S3\Input\UploadPartRequest;
@@ -84,6 +85,7 @@
8485
use AsyncAws\S3\ValueObject\MultipartUpload;
8586
use AsyncAws\S3\ValueObject\NotificationConfiguration;
8687
use AsyncAws\S3\ValueObject\Part;
88+
use AsyncAws\S3\ValueObject\Tagging;
8789

8890
class S3Client extends AbstractApi
8991
{
@@ -1832,6 +1834,81 @@ public function putBucketNotificationConfiguration($input): Result
18321834
return new Result($response);
18331835
}
18341836

1837+
/**
1838+
* Sets the tags for a bucket.
1839+
*
1840+
* Use tags to organize your Amazon Web Services bill to reflect your own cost structure. To do this, sign up to get
1841+
* your Amazon Web Services account bill with tag key values included. Then, to see the cost of combined resources,
1842+
* organize your billing information according to resources with the same tag key values. For example, you can tag
1843+
* several resources with a specific application name, and then organize your billing information to see the total cost
1844+
* of that application across several services. For more information, see Cost Allocation and Tagging [^1] and Using
1845+
* Cost Allocation in Amazon S3 Bucket Tags [^2].
1846+
*
1847+
* > When this operation sets the tags for a bucket, it will overwrite any current tags the bucket already has. You
1848+
* > cannot use this operation to add tags to an existing list of tags.
1849+
*
1850+
* To use this operation, you must have permissions to perform the `s3:PutBucketTagging` action. The bucket owner has
1851+
* this permission by default and can grant this permission to others. For more information about permissions, see
1852+
* Permissions Related to Bucket Subresource Operations [^3] and Managing Access Permissions to Your Amazon S3 Resources
1853+
* [^4].
1854+
*
1855+
* `PutBucketTagging` has the following special errors:
1856+
*
1857+
* - Error code: `InvalidTagError`
1858+
*
1859+
* - Description: The tag provided was not a valid tag. This error can occur if the tag did not pass input validation.
1860+
* For information about tag restrictions, see User-Defined Tag Restrictions [^5] and Amazon Web Services-Generated
1861+
* Cost Allocation Tag Restrictions [^6].
1862+
*
1863+
* - Error code: `MalformedXMLError`
1864+
*
1865+
* - Description: The XML provided does not match the schema.
1866+
*
1867+
* - Error code: `OperationAbortedError `
1868+
*
1869+
* - Description: A conflicting conditional action is currently in progress against this resource. Please try again.
1870+
*
1871+
* - Error code: `InternalError`
1872+
*
1873+
* - Description: The service was unable to apply the provided tag to the bucket.
1874+
*
1875+
*
1876+
* The following operations are related to `PutBucketTagging`:
1877+
*
1878+
* - GetBucketTagging [^7]
1879+
* - DeleteBucketTagging [^8]
1880+
*
1881+
* [^1]: https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html
1882+
* [^2]: https://docs.aws.amazon.com/AmazonS3/latest/dev/CostAllocTagging.html
1883+
* [^3]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-bucket-subresources
1884+
* [^4]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html
1885+
* [^5]: https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/allocation-tag-restrictions.html
1886+
* [^6]: https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/aws-tag-restrictions.html
1887+
* [^7]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketTagging.html
1888+
* [^8]: https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketTagging.html
1889+
*
1890+
* @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTtagging.html
1891+
* @see https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketTagging.html
1892+
* @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#putbuckettagging
1893+
*
1894+
* @param array{
1895+
* Bucket: string,
1896+
* ContentMD5?: string,
1897+
* ChecksumAlgorithm?: ChecksumAlgorithm::*,
1898+
* Tagging: Tagging|array,
1899+
* ExpectedBucketOwner?: string,
1900+
*
1901+
* @region?: string,
1902+
* }|PutBucketTaggingRequest $input
1903+
*/
1904+
public function putBucketTagging($input): Result
1905+
{
1906+
$input = PutBucketTaggingRequest::create($input);
1907+
$response = $this->getResponse($input->request(), new RequestContext(['operation' => 'PutBucketTagging', 'region' => $input->getRegion()]));
1908+
1909+
return new Result($response);
1910+
}
1911+
18351912
/**
18361913
* Adds an object to a bucket. You must have WRITE permissions on a bucket to add an object to it.
18371914
*

0 commit comments

Comments
 (0)