Lifecycle.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. <?php
  2. /**
  3. * Copyright 2018 Google LLC
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. namespace Google\Cloud\Storage;
  18. use Google\Cloud\Core\Timestamp;
  19. /**
  20. * Object Lifecycle Management supports common use cases like setting a Time to
  21. * Live (TTL) for objects, archiving older versions of objects, or "downgrading"
  22. * storage classes of objects to help manage costs.
  23. *
  24. * This builder does not execute any network requests and is intended to be used
  25. * in combination with either
  26. * {@see StorageClient::createBucket()}
  27. * or {@see Bucket::update()}.
  28. *
  29. * Example:
  30. * ```
  31. * // Access a builder preconfigured with rules already existing on a given
  32. * // bucket.
  33. * use Google\Cloud\Storage\StorageClient;
  34. *
  35. * $storage = new StorageClient();
  36. * $bucket = $storage->bucket('my-bucket');
  37. * $lifecycle = $bucket->currentLifecycle();
  38. * ```
  39. *
  40. * ```
  41. * // Or get a fresh builder by using the static factory method.
  42. * use Google\Cloud\Storage\Bucket;
  43. *
  44. * $lifecycle = Bucket::lifecycle();
  45. * ```
  46. *
  47. * @see https://cloud.google.com/storage/docs/lifecycle Object Lifecycle Management API Documentation
  48. */
  49. class Lifecycle implements \ArrayAccess, \IteratorAggregate
  50. {
  51. /**
  52. * @var array
  53. */
  54. private $lifecycle;
  55. /**
  56. * @param array $lifecycle [optional] A lifecycle configuration. Please see
  57. * [here](https://cloud.google.com/storage/docs/json_api/v1/buckets#lifecycle)
  58. * for the expected structure.
  59. */
  60. public function __construct(array $lifecycle = [])
  61. {
  62. $this->lifecycle = $lifecycle;
  63. }
  64. /**
  65. * Adds an Object Lifecycle Delete Rule.
  66. *
  67. * Example:
  68. * ```
  69. * $lifecycle->addDeleteRule([
  70. * 'age' => 50,
  71. * 'isLive' => true
  72. * ]);
  73. * ```
  74. *
  75. * @param array $condition {
  76. * The condition(s) where the rule will apply.
  77. *
  78. * @type int $age Age of an object (in days). This condition is
  79. * satisfied when an object reaches the specified age.
  80. * @type \DateTimeInterface|string $createdBefore This condition is
  81. * satisfied when an object is created before midnight of the
  82. * specified date in UTC. If a string is given, it must be a date
  83. * in RFC 3339 format with only the date part (for instance,
  84. * "2013-01-15").
  85. * @type \DateTimeInterface|string $customTimeBefore This condition is
  86. * satisfied when the custom time on an object is before this date
  87. * in UTC. If a string is given, it must be a date in RFC 3339
  88. * format with only the date part (for instance, "2013-01-15").
  89. * @type int $daysSinceCustomTime Number of days elapsed since the
  90. * user-specified timestamp set on an object. The condition is
  91. * satisfied if the days elapsed is at least this number. If no
  92. * custom timestamp is specified on an object, the condition does
  93. * not apply.
  94. * @type int $daysSinceNoncurrentTime Number of days elapsed since the
  95. * noncurrent timestamp of an object. The condition is satisfied
  96. * if the days elapsed is at least this number. This condition is
  97. * relevant only for versioned objects. The value of the field
  98. * must be a nonnegative integer. If it's zero, the object version
  99. * will become eligible for Lifecycle action as soon as it becomes
  100. * noncurrent.
  101. * @type bool $isLive Relevant only for versioned objects. If the value
  102. * is `true`, this condition matches live objects; if the value is
  103. * `false`, it matches archived objects.
  104. * @type string[] $matchesStorageClass Objects having any of the storage
  105. * classes specified by this condition will be matched. Values
  106. * include `"MULTI_REGIONAL"`, `"REGIONAL"`, `"NEARLINE"`,
  107. * `"ARCHIVE"`, `"COLDLINE"`, `"STANDARD"`, and
  108. * `"DURABLE_REDUCED_AVAILABILITY"`.
  109. * @type \DateTimeInterface|string $noncurrentTimeBefore This condition
  110. * is satisfied when the noncurrent time on an object is before
  111. * this timestamp. This condition is relevant only for versioned
  112. * objects. If a string is given, it must be a date in RFC 3339
  113. * format with only the date part (for instance, "2013-01-15").
  114. * @type int $numNewerVersions Relevant only for versioned objects. If
  115. * the value is N, this condition is satisfied when there are at
  116. * least N versions (including the live version) newer than this
  117. * version of the object.
  118. * @type string[] $matchesPrefix Objects having names which start with
  119. * values specified by this condition will be matched.
  120. * @type string[] $matchesSuffix Objects having names which end with
  121. * values specified by this condition will be matched.
  122. * }
  123. * @return Lifecycle
  124. */
  125. public function addDeleteRule(array $condition)
  126. {
  127. $this->lifecycle['rule'][] = [
  128. 'action' => [
  129. 'type' => 'Delete'
  130. ],
  131. 'condition' => $this->formatCondition($condition)
  132. ];
  133. return $this;
  134. }
  135. /**
  136. * Adds an Object Lifecycle Set Storage Class Rule.
  137. *
  138. * Example:
  139. * ```
  140. * $lifecycle->addSetStorageClassRule('COLDLINE', [
  141. * 'age' => 50,
  142. * 'isLive' => true
  143. * ]);
  144. * ```
  145. *
  146. * ```
  147. * // Using customTimeBefore rule with an object's custom time setting.
  148. * $lifecycle->addSetStorageClassRule('NEARLINE', [
  149. * 'customTimeBefore' => (new \DateTime())->add(
  150. * \DateInterval::createFromDateString('+10 days')
  151. * )
  152. * ]);
  153. *
  154. * $bucket->update(['lifecycle' => $lifecycle]);
  155. *
  156. * $object = $bucket->object($objectName);
  157. * $object->update([
  158. * 'metadata' => [
  159. * 'customTime' => '2020-08-17'
  160. * ]
  161. * ]);
  162. * ```
  163. *
  164. * @param string $storageClass The target storage class. Values include
  165. * `"MULTI_REGIONAL"`, `"REGIONAL"`, `"NEARLINE"`, `"COLDLINE"`,
  166. * `"STANDARD"`, and `"DURABLE_REDUCED_AVAILABILITY"`.
  167. * @param array $condition {
  168. * The condition(s) where the rule will apply.
  169. *
  170. * @type int $age Age of an object (in days). This condition is
  171. * satisfied when an object reaches the specified age.
  172. * @type \DateTimeInterface|string $createdBefore This condition is
  173. * satisfied when an object is created before midnight of the
  174. * specified date in UTC. If a string is given, it must be a date
  175. * in RFC 3339 format with only the date part (for instance,
  176. * "2013-01-15").
  177. * @type \DateTimeInterface|string $customTimeBefore This condition is
  178. * satisfied when the custom time on an object is before this date
  179. * in UTC. If a string is given, it must be a date in RFC 3339
  180. * format with only the date part (for instance, "2013-01-15").
  181. * @type int $daysSinceCustomTime Number of days elapsed since the
  182. * user-specified timestamp set on an object. The condition is
  183. * satisfied if the days elapsed is at least this number. If no
  184. * custom timestamp is specified on an object, the condition does
  185. * not apply.
  186. * @type int $daysSinceNoncurrentTime Number of days elapsed since the
  187. * noncurrent timestamp of an object. The condition is satisfied
  188. * if the days elapsed is at least this number. This condition is
  189. * relevant only for versioned objects. The value of the field
  190. * must be a nonnegative integer. If it's zero, the object version
  191. * will become eligible for Lifecycle action as soon as it becomes
  192. * noncurrent.
  193. * @type bool $isLive Relevant only for versioned objects. If the value
  194. * is `true`, this condition matches live objects; if the value is
  195. * `false`, it matches archived objects.
  196. * @type string[] $matchesStorageClass Objects having any of the storage
  197. * classes specified by this condition will be matched. Values
  198. * include `"MULTI_REGIONAL"`, `"REGIONAL"`, `"NEARLINE"`,
  199. * `"ARCHIVE"`, `"COLDLINE"`, `"STANDARD"`, and
  200. * `"DURABLE_REDUCED_AVAILABILITY"`.
  201. * @type \DateTimeInterface|string $noncurrentTimeBefore This condition
  202. * is satisfied when the noncurrent time on an object is before
  203. * this timestamp. This condition is relevant only for versioned
  204. * objects. If a string is given, it must be a date in RFC 3339
  205. * format with only the date part (for instance, "2013-01-15").
  206. * @type int $numNewerVersions Relevant only for versioned objects. If
  207. * the value is N, this condition is satisfied when there are at
  208. * least N versions (including the live version) newer than this
  209. * version of the object.
  210. * @type string[] $matchesPrefix Objects having names which start with
  211. * values specified by this condition will be matched.
  212. * @type string[] $matchesSuffix Objects having names which end with
  213. * values specified by this condition will be matched.
  214. * }
  215. * @return Lifecycle
  216. */
  217. public function addSetStorageClassRule($storageClass, array $condition)
  218. {
  219. $this->lifecycle['rule'][] = [
  220. 'action' => [
  221. 'type' => 'SetStorageClass',
  222. 'storageClass' => $storageClass
  223. ],
  224. 'condition' => $this->formatCondition($condition)
  225. ];
  226. return $this;
  227. }
  228. /**
  229. * Clear all Object Lifecycle rules or rules of a certain action type.
  230. *
  231. * Example:
  232. * ```
  233. * // Remove all rules.
  234. * $lifecycle->clearRules();
  235. * ```
  236. *
  237. * ```
  238. * // Remove all "Delete" based rules.
  239. * $lifecycle->clearRules('Delete');
  240. * ```
  241. *
  242. * ```
  243. * // Clear any rules which have an age equal to 50.
  244. * $lifecycle->clearRules(function (array $rule) {
  245. * return $rule['condition']['age'] === 50
  246. * ? false
  247. * : true;
  248. * });
  249. * ```
  250. *
  251. * @param string|callable $action [optional] If a string is provided, it
  252. * must be the name of the type of rule to remove (`SetStorageClass`
  253. * or `Delete`). All rules of this type will then be cleared. When
  254. * providing a callable you may define a custom route for how you
  255. * would like to remove rules. The provided callable will be run
  256. * through
  257. * [array_filter](http://php.net/manual/en/function.array-filter.php).
  258. * The callable's argument will be a single lifecycle rule as an
  259. * associative array. When returning true from the callable the rule
  260. * will be preserved, and if false it will be removed.
  261. * **Defaults to** `null`, clearing all assigned rules.
  262. * @return Lifecycle
  263. * @throws \InvalidArgumentException If a type other than a string or
  264. * callabe is provided.
  265. */
  266. public function clearRules($action = null)
  267. {
  268. if (!$action) {
  269. $this->lifecycle = [];
  270. return $this;
  271. }
  272. if (!is_string($action) && !is_callable($action)) {
  273. throw new \InvalidArgumentException(
  274. sprintf(
  275. 'Expected either a string or callable, instead got \'%s\'.',
  276. gettype($action)
  277. )
  278. );
  279. }
  280. if (isset($this->lifecycle['rule'])) {
  281. if (is_string($action)) {
  282. $action = function ($rule) use ($action) {
  283. return $rule['action']['type'] !== $action;
  284. };
  285. }
  286. $this->lifecycle['rule'] = array_filter(
  287. $this->lifecycle['rule'],
  288. $action
  289. );
  290. if (!$this->lifecycle['rule']) {
  291. $this->lifecycle = [];
  292. }
  293. }
  294. return $this;
  295. }
  296. /**
  297. * @access private
  298. * @return \Generator
  299. */
  300. #[\ReturnTypeWillChange]
  301. public function getIterator()
  302. {
  303. if (!isset($this->lifecycle['rule'])) {
  304. return;
  305. }
  306. foreach ($this->lifecycle['rule'] as $rule) {
  307. yield $rule;
  308. }
  309. }
  310. /**
  311. * @access private
  312. * @return array
  313. */
  314. public function toArray()
  315. {
  316. return $this->lifecycle;
  317. }
  318. /**
  319. * @access private
  320. * @param string $offset
  321. * @param mixed $value
  322. */
  323. #[\ReturnTypeWillChange]
  324. public function offsetSet($offset, $value)
  325. {
  326. $this->lifecycle['rule'][$offset] = $value;
  327. }
  328. /**
  329. * @access private
  330. * @param string $offset
  331. * @return bool
  332. */
  333. #[\ReturnTypeWillChange]
  334. public function offsetExists($offset)
  335. {
  336. return isset($this->lifecycle['rule'][$offset]);
  337. }
  338. /**
  339. * @access private
  340. * @param string $offset
  341. */
  342. #[\ReturnTypeWillChange]
  343. public function offsetUnset($offset)
  344. {
  345. unset($this->lifecycle['rule'][$offset]);
  346. }
  347. /**
  348. * @access private
  349. * @param string $offset
  350. * @return mixed
  351. */
  352. #[\ReturnTypeWillChange]
  353. public function offsetGet($offset)
  354. {
  355. return isset($this->lifecycle['rule'][$offset])
  356. ? $this->lifecycle['rule'][$offset]
  357. : null;
  358. }
  359. /**
  360. * Apply condition-specific formatting rules (such as date formatting) to
  361. * conditions.
  362. *
  363. * @param array $condition
  364. * @return array
  365. */
  366. private function formatCondition(array $condition)
  367. {
  368. $rfc339DateFields = [
  369. 'createdBefore',
  370. 'customTimeBefore',
  371. 'noncurrentTimeBefore'
  372. ];
  373. foreach ($rfc339DateFields as $field) {
  374. if (isset($condition[$field]) && $condition[$field] instanceof \DateTimeInterface) {
  375. $condition[$field] = $condition[$field]->format('Y-m-d');
  376. }
  377. }
  378. return $condition;
  379. }
  380. }