1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @package midcom.services.rcs |
4
|
|
|
* @author CONTENT CONTROL http://www.contentcontrol-berlin.de/ |
5
|
|
|
* @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/ |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
use Symfony\Component\HttpFoundation\Request; |
9
|
|
|
use midcom\datamanager\schemabuilder; |
10
|
|
|
use midcom\datamanager\datamanager; |
11
|
|
|
use Symfony\Component\HttpFoundation\Response; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* @package midcom.services.rcs |
15
|
|
|
*/ |
16
|
|
|
abstract class midcom_services_rcs_handler extends midcom_baseclasses_components_handler |
17
|
|
|
{ |
18
|
|
|
/** |
19
|
|
|
* @var midcom_services_rcs_backend |
20
|
|
|
*/ |
21
|
|
|
private $backend; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @var midcom_core_dbaobject |
25
|
|
|
*/ |
26
|
|
|
protected $object; |
27
|
|
|
|
28
|
|
|
protected $style_prefix = ''; |
29
|
|
|
|
30
|
|
|
protected $url_prefix = ''; |
31
|
|
|
|
32
|
|
|
abstract protected function get_object_url() : string; |
33
|
|
|
|
34
|
|
|
abstract protected function reply(string $element) : Response; |
35
|
|
|
|
36
|
|
|
abstract protected function get_breadcrumbs() : array; |
37
|
|
|
|
38
|
4 |
|
protected function resolve_object_title() |
39
|
|
|
{ |
40
|
4 |
|
return midcom_helper_reflector::get($this->object)->get_object_label($this->object); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Load the object and the rcs backend |
45
|
|
|
*/ |
46
|
6 |
|
private function load_object(string $guid) |
47
|
|
|
{ |
48
|
6 |
|
$this->object = midcom::get()->dbfactory->get_object_by_guid($guid); |
49
|
|
|
|
50
|
6 |
|
if ( !midcom::get()->config->get('midcom_services_rcs_enable') |
51
|
6 |
|
|| !$this->object->_use_rcs) { |
52
|
|
|
throw new midcom_error_notfound("Revision control not supported for " . get_class($this->object) . "."); |
53
|
|
|
} |
54
|
|
|
|
55
|
6 |
|
$this->backend = midcom::get()->rcs->load_backend($this->object); |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Prepare version control toolbar |
60
|
|
|
*/ |
61
|
4 |
|
private function rcs_toolbar(array $revision, array $revision2 = null) |
62
|
|
|
{ |
63
|
4 |
|
$this->add_stylesheet(MIDCOM_STATIC_URL . "/midcom.services.rcs/rcs.css"); |
64
|
4 |
|
$prefix = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX) . $this->url_prefix; |
|
|
|
|
65
|
4 |
|
$history = $this->backend->get_history(); |
66
|
4 |
|
$this->_request_data['rcs_toolbar'] = new midcom_helper_toolbar(); |
67
|
4 |
|
$this->populate_rcs_toolbar($history, $prefix, $revision, $revision2); |
68
|
|
|
|
69
|
|
|
// RCS functional toolbar |
70
|
4 |
|
$this->_request_data['rcs_toolbar_2'] = new midcom_helper_toolbar(); |
71
|
4 |
|
$restore = $revision2 ?: $revision; |
72
|
|
|
|
73
|
4 |
|
$buttons = [ |
74
|
|
|
[ |
75
|
4 |
|
MIDCOM_TOOLBAR_URL => "{$prefix}{$this->object->guid}/", |
76
|
4 |
|
MIDCOM_TOOLBAR_LABEL => $this->_l10n->get('show history'), |
77
|
|
|
MIDCOM_TOOLBAR_GLYPHICON => 'history', |
78
|
|
|
], [ |
79
|
4 |
|
MIDCOM_TOOLBAR_URL => "{$prefix}restore/{$this->object->guid}/{$restore['revision']}/", |
80
|
4 |
|
MIDCOM_TOOLBAR_LABEL => sprintf($this->_l10n->get('restore version %s'), $restore['version']), |
81
|
|
|
MIDCOM_TOOLBAR_GLYPHICON => 'recycle', |
82
|
4 |
|
MIDCOM_TOOLBAR_ENABLED => ($restore['revision'] !== $history->get_last()['revision']), |
83
|
|
|
] |
84
|
|
|
]; |
85
|
4 |
|
$this->_request_data['rcs_toolbar_2']->add_items($buttons); |
86
|
|
|
} |
87
|
|
|
|
88
|
4 |
|
private function populate_rcs_toolbar(midcom_services_rcs_history $history, string $prefix, array $revision, ?array $revision2) |
89
|
|
|
{ |
90
|
4 |
|
$first = $history->get_first(); |
91
|
4 |
|
$last = $history->get_last(); |
92
|
|
|
|
93
|
4 |
|
$diff_view = !empty($revision2); |
94
|
4 |
|
$revision2 = $revision2 ?? $revision; |
95
|
|
|
|
96
|
4 |
|
if ($previous = $history->get_previous($revision['revision'])) { |
97
|
|
|
$enabled = true; |
98
|
|
|
} else { |
99
|
4 |
|
$enabled = false; |
100
|
4 |
|
$previous = $first; |
101
|
|
|
} |
102
|
4 |
|
$this->add_preview_button($prefix, $first, 'fast-backward', $enabled || $diff_view); |
|
|
|
|
103
|
4 |
|
$this->add_preview_button($prefix, $diff_view ? $revision : $previous, 'backward', $enabled || $diff_view); |
104
|
4 |
|
$this->add_diff_button($prefix, $previous, $revision, 'step-backward', $enabled); |
|
|
|
|
105
|
|
|
|
106
|
4 |
|
$this->_request_data['rcs_toolbar']->add_item([ |
107
|
4 |
|
MIDCOM_TOOLBAR_URL => "{$prefix}preview/{$this->object->guid}/{$revision2['revision']}/", |
108
|
4 |
|
MIDCOM_TOOLBAR_LABEL => sprintf($this->_l10n->get('version %s'), $revision2['version']), |
109
|
|
|
MIDCOM_TOOLBAR_GLYPHICON => 'file-o', |
110
|
|
|
MIDCOM_TOOLBAR_ENABLED => $diff_view, |
111
|
|
|
]); |
112
|
|
|
|
113
|
4 |
|
if ($next = $history->get_next($revision2['revision'])) { |
114
|
2 |
|
$enabled = true; |
115
|
|
|
} else { |
116
|
2 |
|
$enabled = false; |
117
|
2 |
|
$next = $last; |
118
|
|
|
} |
119
|
4 |
|
$this->add_diff_button($prefix, $revision2, $next, 'step-forward', $enabled); |
|
|
|
|
120
|
4 |
|
$this->add_preview_button($prefix, $next, 'forward', $enabled || $diff_view); |
121
|
4 |
|
$this->add_preview_button($prefix, $last, 'fast-forward', $enabled || $diff_view); |
122
|
|
|
} |
123
|
|
|
|
124
|
4 |
|
private function add_preview_button(string $prefix, array $entry, string $icon, bool $enabled) |
125
|
|
|
{ |
126
|
4 |
|
$this->_request_data['rcs_toolbar']->add_item([ |
127
|
4 |
|
MIDCOM_TOOLBAR_URL => "{$prefix}preview/{$this->object->guid}/{$entry['revision']}/", |
128
|
4 |
|
MIDCOM_TOOLBAR_LABEL => $entry['version'], |
129
|
|
|
MIDCOM_TOOLBAR_GLYPHICON => $icon, |
130
|
|
|
MIDCOM_TOOLBAR_ENABLED => $enabled, |
131
|
|
|
]); |
132
|
|
|
} |
133
|
|
|
|
134
|
4 |
|
private function add_diff_button(string $prefix, array $first, array $second, string $icon, bool $enabled) |
135
|
|
|
{ |
136
|
4 |
|
$this->_request_data['rcs_toolbar']->add_item([ |
137
|
4 |
|
MIDCOM_TOOLBAR_URL => "{$prefix}diff/{$this->object->guid}/{$first['revision']}/{$second['revision']}/", |
138
|
4 |
|
MIDCOM_TOOLBAR_LABEL => $this->_l10n->get('show differences'), |
139
|
|
|
MIDCOM_TOOLBAR_GLYPHICON => $icon, |
140
|
|
|
MIDCOM_TOOLBAR_ENABLED => $enabled, |
141
|
|
|
]); |
142
|
|
|
} |
143
|
|
|
|
144
|
6 |
|
private function prepare_request_data(string $view_title) |
145
|
|
|
{ |
146
|
6 |
|
foreach ($this->get_breadcrumbs() as $item) { |
147
|
6 |
|
$this->add_breadcrumb($item[MIDCOM_NAV_URL], $item[MIDCOM_NAV_NAME]); |
148
|
|
|
} |
149
|
6 |
|
$this->add_breadcrumb($this->url_prefix . "{$this->object->guid}/", $this->_l10n->get('show history')); |
150
|
|
|
|
151
|
6 |
|
$this->_request_data['handler'] = $this; |
152
|
6 |
|
$this->_request_data['view_title'] = $view_title; |
153
|
6 |
|
midcom::get()->head->set_pagetitle($view_title); |
154
|
|
|
} |
155
|
|
|
|
156
|
2 |
|
public function translate(string $string) : string |
157
|
|
|
{ |
158
|
2 |
|
$stack = [$this->_component, 'midcom']; |
159
|
2 |
|
if ($component = midcom::get()->dbclassloader->get_component_for_class($this->object->__midcom_class_name__)) { |
160
|
2 |
|
array_unshift($stack, $component); |
161
|
|
|
} |
162
|
2 |
|
foreach ($stack as $db) { |
163
|
2 |
|
$translated = $this->_i18n->get_string($string, $db); |
164
|
2 |
|
if ($translated != $string) { |
165
|
|
|
return $translated; |
166
|
|
|
} |
167
|
|
|
} |
168
|
2 |
|
return $string; |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Show the changes done to the object |
173
|
|
|
*/ |
174
|
2 |
|
public function _handler_history(Request $request, array &$data, array $args) |
175
|
|
|
{ |
176
|
|
|
// Check if the comparison request is valid |
177
|
2 |
|
$first = $request->query->get('first'); |
178
|
2 |
|
$last = $request->query->get('last'); |
179
|
2 |
|
if ($first && $last && $first != $last) { |
180
|
|
|
return new midcom_response_relocate($this->url_prefix . "diff/{$args[0]}/{$first}/{$last}/"); |
181
|
|
|
} |
182
|
|
|
|
183
|
2 |
|
$this->load_object($args[0]); |
184
|
2 |
|
$view_title = sprintf($this->_l10n->get('revision history of %s'), $this->resolve_object_title()); |
185
|
|
|
|
186
|
2 |
|
$this->prepare_request_data($view_title); |
187
|
2 |
|
$data['history'] = $this->backend->get_history(); |
188
|
2 |
|
$data['guid'] = $this->object->guid; |
189
|
2 |
|
return $this->reply($this->style_prefix . 'history'); |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
/** |
193
|
|
|
* Show a diff between two versions |
194
|
|
|
*/ |
195
|
2 |
|
public function _handler_diff(array $args, array &$data) |
196
|
|
|
{ |
197
|
2 |
|
$this->load_object($args[0]); |
198
|
2 |
|
$history = $this->backend->get_history(); |
199
|
|
|
|
200
|
2 |
|
$compare_revision = $history->get($args[1]); |
201
|
2 |
|
$latest_revision = $history->get($args[2]); |
202
|
|
|
|
203
|
2 |
|
if (!$compare_revision || !$latest_revision) { |
204
|
|
|
throw new midcom_error_notfound("One of the revisions {$args[1]} or {$args[2]} does not exist."); |
205
|
|
|
} |
206
|
|
|
|
207
|
2 |
|
$data['diff'] = array_filter($this->backend->get_diff($args[1], $args[2]), function($value, $key) { |
208
|
2 |
|
return array_key_exists('diff', $value) |
209
|
2 |
|
&& !is_array($value['diff']) |
210
|
2 |
|
&& midcom_services_rcs::is_field_showable($key); |
211
|
|
|
}, ARRAY_FILTER_USE_BOTH); |
212
|
2 |
|
$data['comment'] = $latest_revision; |
213
|
2 |
|
$data['revision_info1'] = $this->render_revision_info($compare_revision); |
214
|
2 |
|
$data['revision_info2'] = $this->render_revision_info($latest_revision); |
215
|
|
|
|
216
|
|
|
// Set the version numbers |
217
|
2 |
|
$data['guid'] = $args[0]; |
218
|
|
|
|
219
|
2 |
|
$view_title = sprintf($this->_l10n->get('changes between revisions %s and %s'), $compare_revision['version'], $latest_revision['version']); |
220
|
|
|
|
221
|
|
|
// Load the toolbars |
222
|
2 |
|
$this->rcs_toolbar($compare_revision, $latest_revision); |
223
|
2 |
|
$this->prepare_request_data($view_title); |
224
|
2 |
|
$this->add_breadcrumb( |
225
|
2 |
|
$this->url_prefix . "diff/{$this->object->guid}/{$compare_revision['revision']}/{$latest_revision['revision']}/", |
226
|
2 |
|
sprintf($this->_l10n->get('differences between %s and %s'), $compare_revision['version'], $latest_revision['version']) |
227
|
|
|
); |
228
|
|
|
|
229
|
2 |
|
return $this->reply($this->style_prefix . 'diff'); |
230
|
|
|
} |
231
|
|
|
|
232
|
2 |
|
private function render_revision_info(array $metadata) : string |
233
|
|
|
{ |
234
|
2 |
|
$output = sprintf($this->_l10n->get('version %s'), $metadata['version']) . ' <span>'; |
235
|
|
|
|
236
|
2 |
|
if ($user = midcom::get()->auth->get_user($metadata['user'])) { |
237
|
2 |
|
$output .= $user->get_storage()->name; |
238
|
|
|
} else { |
239
|
|
|
$output .= $this->_l10n_midcom->get('unknown user'); |
240
|
|
|
} |
241
|
|
|
|
242
|
2 |
|
$output .= ', ' . $this->_l10n->get_formatter()->datetime($metadata['date']) . '</span>'; |
243
|
|
|
|
244
|
2 |
|
return $output; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* View previews |
249
|
|
|
*/ |
250
|
2 |
|
public function _handler_preview(array $args, array &$data) |
251
|
|
|
{ |
252
|
2 |
|
$revision = $args[1]; |
253
|
2 |
|
$data['latest_revision'] = $revision; |
254
|
2 |
|
$data['guid'] = $args[0]; |
255
|
2 |
|
$this->load_object($args[0]); |
256
|
2 |
|
$metadata = $this->backend->get_history()->get($args[1]); |
257
|
2 |
|
if (!$metadata) { |
258
|
|
|
throw new midcom_error_notfound("Revision {$args[1]} does not exist."); |
259
|
|
|
} |
260
|
|
|
|
261
|
2 |
|
$data['preview'] = array_filter($this->backend->get_revision($revision), function ($value, $key) { |
262
|
2 |
|
return !is_array($value) |
263
|
2 |
|
&& !in_array($value, ['', '0000-00-00']) |
264
|
2 |
|
&& midcom_services_rcs::is_field_showable($key); |
265
|
|
|
}, ARRAY_FILTER_USE_BOTH); |
266
|
|
|
|
267
|
2 |
|
$schemadb = (new schemabuilder($this->object))->create(null); |
268
|
2 |
|
$data['datamanager'] = (new datamanager($schemadb)) |
269
|
2 |
|
->set_defaults($data['preview']) |
270
|
2 |
|
->set_storage(new $this->object->__midcom_class_name__); |
271
|
|
|
|
272
|
2 |
|
$this->_view_toolbar->hide_item($this->url_prefix . "preview/{$this->object->guid}/{$revision}/"); |
273
|
|
|
|
274
|
2 |
|
$view_title = sprintf($this->_l10n->get('viewing version %s from %s'), $metadata['version'], $this->_l10n->get_formatter()->datetime($metadata['date'])); |
275
|
|
|
// Load the toolbars |
276
|
2 |
|
$this->rcs_toolbar($metadata); |
277
|
2 |
|
$this->prepare_request_data($view_title); |
278
|
2 |
|
return $this->reply($this->style_prefix . 'preview'); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* Restore to diff |
283
|
|
|
*/ |
284
|
|
|
public function _handler_restore(array $args) |
285
|
|
|
{ |
286
|
|
|
$this->load_object($args[0]); |
287
|
|
|
|
288
|
|
|
$this->object->require_do('midgard:update'); |
289
|
|
|
// TODO: set another privilege for restoring? |
290
|
|
|
|
291
|
|
|
if ( $this->backend->get_history()->version_exists($args[1]) |
292
|
|
|
&& $this->backend->restore_to_revision($args[1])) { |
293
|
|
|
midcom::get()->uimessages->add($this->_l10n->get('midcom.admin.rcs'), sprintf($this->_l10n->get('restore to version %s successful'), $args[1])); |
294
|
|
|
return new midcom_response_relocate($this->get_object_url()); |
295
|
|
|
} |
296
|
|
|
throw new midcom_error(sprintf($this->_l10n->get('restore to version %s failed, reason %s'), $args[1], midcom_connection::get_error_string())); |
297
|
|
|
} |
298
|
|
|
} |
299
|
|
|
|