]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - application/History.php
Merge pull request #1234 from virtualtam/lint
[github/shaarli/Shaarli.git] / application / History.php
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 }