Repository navigation
Expand file tree
/
Copy pathDatePath.php
More file actions
75 lines (66 loc) · 2.48 KB
/
Copy pathDatePath.php
File metadata and controls
75 lines (66 loc) · 2.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?php
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
/**
* Italix Storage - DatePath
*
* @package Italix\Storage
*/
declare(strict_types=1);
namespace Italix\Storage;
/**
* `{folder}/{YYYY}/{MM}/…` — for corpora that are read, archived and expired by
* date rather than by owner.
*
* Invoices, statements, exports, scans: the operational questions are "archive
* everything before last year" and "how much did we write in March", and both
* are a directory listing when the layout says so and a full scan when it does
* not.
*
* new DatePath(new HashedPath(1))
*
* invoices -> invoices/2026/08/9f/9f2c….pdf
*
* Note what this gives up: content de-duplication is now per month. The same
* bytes stored in July and in August are two files, because they are at two
* paths. That is usually the point — an archive wants each period to be
* self-contained — but it is a real trade and worth stating.
*/
final class DatePath implements PathStrategy
{
private PathStrategy $inner;
private string $format_c;
/** @var callable():int */
private $clock;
/**
* @param PathStrategy $inner what lays out the file once dated
* @param string $format_c any `date()` format producing path segments, e.g. 'Y/m' or 'Y/m/d'
* @param callable():int|null $clock injectable, so a test does not have to wait for next month
*/
public function __construct(PathStrategy $inner, string $format_c = 'Y/m', ?callable $clock = null)
{
if (preg_match('~^[A-Za-z0-9/]+$~', $format_c) !== 1) {
throw new StorageException(
"\"{$format_c}\" is not a usable date format for a path: date() letters and slashes only."
);
}
$this->inner = $inner;
$this->format_c = $format_c;
$this->clock = $clock ?? static function (): int {
return time();
};
}
public function path_for(string $folder, string $sha256_c, string $extension_c): string
{
$dated = date($this->format_c, ($this->clock)());
$under = $folder === '' ? $dated : $folder . '/' . $dated;
return $this->inner->path_for($under, $sha256_c, $extension_c);
}
public function describe(): string
{
return "{folder}/{$this->format_c}/ then " . $this->inner->describe();
}
}