diff options
author | ArthurHoaro <arthur@hoa.ro> | 2018-07-28 11:07:55 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2018-07-28 11:07:55 +0200 |
commit | 83faedadff76c5bdca036f39f13943f63b27e164 (patch) | |
tree | 6f44cede16ec6a60f10b9699e211e0818f06d2c8 /application/History.php | |
parent | 1d9eb22a3df85b67fe6652c0876cd7382c2fb525 (diff) | |
parent | 658988f3aeba7a5a938783249ccf2765251e5597 (diff) | |
download | Shaarli-83faedadff76c5bdca036f39f13943f63b27e164.tar.gz Shaarli-83faedadff76c5bdca036f39f13943f63b27e164.tar.zst Shaarli-83faedadff76c5bdca036f39f13943f63b27e164.zip |
Merge tag 'v0.9.7' into stable
Release v0.9.7
Diffstat (limited to 'application/History.php')
-rw-r--r-- | application/History.php | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/application/History.php b/application/History.php new file mode 100644 index 00000000..35ec016a --- /dev/null +++ b/application/History.php | |||
@@ -0,0 +1,216 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Class History | ||
5 | * | ||
6 | * Handle the history file tracing events in Shaarli. | ||
7 | * The history is stored as JSON in a file set by 'resource.history' setting. | ||
8 | * | ||
9 | * Available data: | ||
10 | * - event: event key | ||
11 | * - datetime: event date, in ISO8601 format. | ||
12 | * - id: event item identifier (currently only link IDs). | ||
13 | * | ||
14 | * Available event keys: | ||
15 | * - CREATED: new link | ||
16 | * - UPDATED: link updated | ||
17 | * - DELETED: link deleted | ||
18 | * - SETTINGS: the settings have been updated through the UI. | ||
19 | * - IMPORT: bulk links import | ||
20 | * | ||
21 | * Note: new events are put at the beginning of the file and history array. | ||
22 | */ | ||
23 | class History | ||
24 | { | ||
25 | /** | ||
26 | * @var string Action key: a new link has been created. | ||
27 | */ | ||
28 | const CREATED = 'CREATED'; | ||
29 | |||
30 | /** | ||
31 | * @var string Action key: a link has been updated. | ||
32 | */ | ||
33 | const UPDATED = 'UPDATED'; | ||
34 | |||
35 | /** | ||
36 | * @var string Action key: a link has been deleted. | ||
37 | */ | ||
38 | const DELETED = 'DELETED'; | ||
39 | |||
40 | /** | ||
41 | * @var string Action key: settings have been updated. | ||
42 | */ | ||
43 | const SETTINGS = 'SETTINGS'; | ||
44 | |||
45 | /** | ||
46 | * @var string Action key: a bulk import has been processed. | ||
47 | */ | ||
48 | const IMPORT = 'IMPORT'; | ||
49 | |||
50 | /** | ||
51 | * @var string History file path. | ||
52 | */ | ||
53 | protected $historyFilePath; | ||
54 | |||
55 | /** | ||
56 | * @var array History data. | ||
57 | */ | ||
58 | protected $history; | ||
59 | |||
60 | /** | ||
61 | * @var int History retention time in seconds (1 month). | ||
62 | */ | ||
63 | protected $retentionTime = 2678400; | ||
64 | |||
65 | /** | ||
66 | * History constructor. | ||
67 | * | ||
68 | * @param string $historyFilePath History file path. | ||
69 | * @param int $retentionTime History content rentention time in seconds. | ||
70 | * | ||
71 | * @throws Exception if something goes wrong. | ||
72 | */ | ||
73 | public function __construct($historyFilePath, $retentionTime = null) | ||
74 | { | ||
75 | $this->historyFilePath = $historyFilePath; | ||
76 | if ($retentionTime !== null) { | ||
77 | $this->retentionTime = $retentionTime; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * Initialize: read history file. | ||
83 | * | ||
84 | * Allow lazy loading (don't read the file if it isn't necessary). | ||
85 | */ | ||
86 | protected function initialize() | ||
87 | { | ||
88 | $this->check(); | ||
89 | $this->read(); | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * Add Event: new link. | ||
94 | * | ||
95 | * @param array $link Link data. | ||
96 | */ | ||
97 | public function addLink($link) | ||
98 | { | ||
99 | $this->addEvent(self::CREATED, $link['id']); | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * Add Event: update existing link. | ||
104 | * | ||
105 | * @param array $link Link data. | ||
106 | */ | ||
107 | public function updateLink($link) | ||
108 | { | ||
109 | $this->addEvent(self::UPDATED, $link['id']); | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * Add Event: delete existing link. | ||
114 | * | ||
115 | * @param array $link Link data. | ||
116 | */ | ||
117 | public function deleteLink($link) | ||
118 | { | ||
119 | $this->addEvent(self::DELETED, $link['id']); | ||
120 | } | ||
121 | |||
122 | /** | ||
123 | * Add Event: settings updated. | ||
124 | */ | ||
125 | public function updateSettings() | ||
126 | { | ||
127 | $this->addEvent(self::SETTINGS); | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * Add Event: bulk import. | ||
132 | * | ||
133 | * Note: we don't store links add/update one by one since it can have a huge impact on performances. | ||
134 | */ | ||
135 | public function importLinks() | ||
136 | { | ||
137 | $this->addEvent(self::IMPORT); | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * Save a new event and write it in the history file. | ||
142 | * | ||
143 | * @param string $status Event key, should be defined as constant. | ||
144 | * @param mixed $id Event item identifier (e.g. link ID). | ||
145 | */ | ||
146 | protected function addEvent($status, $id = null) | ||
147 | { | ||
148 | if ($this->history === null) { | ||
149 | $this->initialize(); | ||
150 | } | ||
151 | |||
152 | $item = [ | ||
153 | 'event' => $status, | ||
154 | 'datetime' => new DateTime(), | ||
155 | 'id' => $id !== null ? $id : '', | ||
156 | ]; | ||
157 | $this->history = array_merge([$item], $this->history); | ||
158 | $this->write(); | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * Check that the history file is writable. | ||
163 | * Create the file if it doesn't exist. | ||
164 | * | ||
165 | * @throws Exception if it isn't writable. | ||
166 | */ | ||
167 | protected function check() | ||
168 | { | ||
169 | if (! is_file($this->historyFilePath)) { | ||
170 | FileUtils::writeFlatDB($this->historyFilePath, []); | ||
171 | } | ||
172 | |||
173 | if (! is_writable($this->historyFilePath)) { | ||
174 | throw new Exception(t('History file isn\'t readable or writable')); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * Read JSON history file. | ||
180 | */ | ||
181 | protected function read() | ||
182 | { | ||
183 | $this->history = FileUtils::readFlatDB($this->historyFilePath, []); | ||
184 | if ($this->history === false) { | ||
185 | throw new Exception(t('Could not parse history file')); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | /** | ||
190 | * Write JSON history file and delete old entries. | ||
191 | */ | ||
192 | protected function write() | ||
193 | { | ||
194 | $comparaison = new DateTime('-'. $this->retentionTime . ' seconds'); | ||
195 | foreach ($this->history as $key => $value) { | ||
196 | if ($value['datetime'] < $comparaison) { | ||
197 | unset($this->history[$key]); | ||
198 | } | ||
199 | } | ||
200 | FileUtils::writeFlatDB($this->historyFilePath, array_values($this->history)); | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * Get the History. | ||
205 | * | ||
206 | * @return array | ||
207 | */ | ||
208 | public function getHistory() | ||
209 | { | ||
210 | if ($this->history === null) { | ||
211 | $this->initialize(); | ||
212 | } | ||
213 | |||
214 | return $this->history; | ||
215 | } | ||
216 | } | ||