aboutsummaryrefslogtreecommitdiffhomepage
path: root/application/History.php
diff options
context:
space:
mode:
authorArthurHoaro <arthur@hoa.ro>2017-01-16 12:31:08 +0100
committerArthurHoaro <arthur@hoa.ro>2017-03-21 20:29:20 +0100
commit4306b184c4471825f916d895b047ed03fdf58985 (patch)
treeae4ffd760d74e58bf469f743076aecf838f634f2 /application/History.php
parentb2306b0c783365e3f8110ae25bc93f2630b8b2c8 (diff)
downloadShaarli-4306b184c4471825f916d895b047ed03fdf58985.tar.gz
Shaarli-4306b184c4471825f916d895b047ed03fdf58985.tar.zst
Shaarli-4306b184c4471825f916d895b047ed03fdf58985.zip
History mechanism
Use case: rest API service * saved by default in data/history * same format as datastore.php * traced events: * save/edit/delete link * change settings or plugins settings * rename tag
Diffstat (limited to 'application/History.php')
-rw-r--r--application/History.php183
1 files changed, 183 insertions, 0 deletions
diff --git a/application/History.php b/application/History.php
new file mode 100644
index 00000000..c06067df
--- /dev/null
+++ b/application/History.php
@@ -0,0 +1,183 @@
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 *
20 * Note: new events are put at the beginning of the file and history array.
21 */
22class History
23{
24 /**
25 * @var string Action key: a new link has been created.
26 */
27 const CREATED = 'CREATED';
28
29 /**
30 * @var string Action key: a link has been updated.
31 */
32 const UPDATED = 'UPDATED';
33
34 /**
35 * @var string Action key: a link has been deleted.
36 */
37 const DELETED = 'DELETED';
38
39 /**
40 * @var string Action key: settings have been updated.
41 */
42 const SETTINGS = 'SETTINGS';
43
44 /**
45 * @var string History file path.
46 */
47 protected $historyFilePath;
48
49 /**
50 * @var array History data.
51 */
52 protected $history;
53
54 /**
55 * @var int History retention time in seconds (1 month).
56 */
57 protected $retentionTime = 2678400;
58
59 /**
60 * History constructor.
61 *
62 * @param string $historyFilePath History file path.
63 * @param int $retentionTime History content rentention time in seconds.
64 *
65 * @throws Exception if something goes wrong.
66 */
67 public function __construct($historyFilePath, $retentionTime = null)
68 {
69 $this->historyFilePath = $historyFilePath;
70 if ($retentionTime !== null) {
71 $this->retentionTime = $retentionTime;
72 }
73 $this->check();
74 $this->read();
75 }
76
77 /**
78 * Add Event: new link.
79 *
80 * @param array $link Link data.
81 */
82 public function addLink($link)
83 {
84 $this->addEvent(self::CREATED, $link['id']);
85 }
86
87 /**
88 * Add Event: update existing link.
89 *
90 * @param array $link Link data.
91 */
92 public function updateLink($link)
93 {
94 $this->addEvent(self::UPDATED, $link['id']);
95 }
96
97 /**
98 * Add Event: delete existing link.
99 *
100 * @param array $link Link data.
101 */
102 public function deleteLink($link)
103 {
104 $this->addEvent(self::DELETED, $link['id']);
105 }
106
107 /**
108 * Add Event: settings updated.
109 */
110 public function updateSettings()
111 {
112 $this->addEvent(self::SETTINGS);
113 }
114
115 /**
116 * Save a new event and write it in the history file.
117 *
118 * @param string $status Event key, should be defined as constant.
119 * @param mixed $id Event item identifier (e.g. link ID).
120 */
121 protected function addEvent($status, $id = null)
122 {
123 $item = [
124 'event' => $status,
125 'datetime' => (new DateTime())->format(DateTime::ATOM),
126 'id' => $id !== null ? $id : '',
127 ];
128 $this->history = array_merge([$item], $this->history);
129 $this->write();
130 }
131
132 /**
133 * Check that the history file is writable.
134 * Create the file if it doesn't exist.
135 *
136 * @throws Exception if it isn't writable.
137 */
138 protected function check()
139 {
140 if (! is_file($this->historyFilePath)) {
141 FileUtils::writeFlatDB($this->historyFilePath, []);
142 }
143
144 if (! is_writable($this->historyFilePath)) {
145 throw new Exception('History file isn\'t readable or writable');
146 }
147 }
148
149 /**
150 * Read JSON history file.
151 */
152 protected function read()
153 {
154 $this->history = FileUtils::readFlatDB($this->historyFilePath, []);
155 if ($this->history === false) {
156 throw new Exception('Could not parse history file');
157 }
158 }
159
160 /**
161 * Write JSON history file and delete old entries.
162 */
163 protected function write()
164 {
165 $comparaison = new DateTime('-'. $this->retentionTime . ' seconds');
166 foreach ($this->history as $key => $value) {
167 if (DateTime::createFromFormat(DateTime::ATOM, $value['datetime']) < $comparaison) {
168 unset($this->history[$key]);
169 }
170 }
171 FileUtils::writeFlatDB($this->historyFilePath, array_values($this->history));
172 }
173
174 /**
175 * Get the History.
176 *
177 * @return array
178 */
179 public function getHistory()
180 {
181 return $this->history;
182 }
183}