Passed
Push — master ( f60bb5...62b0c9 )
by Andreas
28:15
created

midcom_services_rcs_handler   A

Complexity

Total Complexity 41

Size/Duplication

Total Lines 285
Duplicated Lines 0 %

Test Coverage

Coverage 91.22%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 134
c 1
b 0
f 0
dl 0
loc 285
ccs 135
cts 148
cp 0.9122
rs 9.1199
wmc 41

15 Methods

Rating   Name   Duplication   Size   Complexity  
A load_object() 0 10 3
A resolve_object_title() 0 3 1
A rcs_toolbar() 0 25 2
B populate_rcs_toolbar() 0 34 8
A add_diff_button() 0 7 1
A add_preview_button() 0 7 1
A _show_preview() 0 3 1
A prepare_request_data() 0 10 2
A translate() 0 14 4
A _handler_diff() 0 33 5
A _handler_preview() 0 24 4
A _handler_history() 0 14 4
A _handler_restore() 0 13 3
A _show_diff() 0 3 1
A _show_history() 0 5 1

How to fix   Complexity   

Complex Class

Complex classes like midcom_services_rcs_handler often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use midcom_services_rcs_handler, and based on these observations, apply Extract Interface, too.

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
10
/**
11
 * @package midcom.services.rcs
12
 */
13
abstract class midcom_services_rcs_handler extends midcom_baseclasses_components_handler
14
{
15
    /**
16
     * RCS backend
17
     *
18
     * @var midcom_services_rcs_backend
19
     */
20
    private $backend;
21
22
    /**
23
     * Pointer to midgard object
24
     *
25
     * @var midcom_core_dbaobject
26
     */
27
    protected $object;
28
29
    protected $style_prefix = '';
30
31
    protected $url_prefix = '';
32
33
    abstract protected function get_object_url() : string;
34
35
    abstract protected function handler_callback(string $handler_id);
36
37
    abstract protected function get_breadcrumbs() : array;
38
39 4
    protected function resolve_object_title()
40
    {
41 4
        return midcom_helper_reflector::get($this->object)->get_object_label($this->object);
42
    }
43
44
    /**
45
     * Load the object and the rcs backend
46
     */
47 6
    private function load_object(string $guid)
48
    {
49 6
        $this->object = midcom::get()->dbfactory->get_object_by_guid($guid);
50
51 6
        if (   !midcom::get()->config->get('midcom_services_rcs_enable')
52 6
            || !$this->object->_use_rcs) {
53
            throw new midcom_error_notfound("Revision control not supported for " . get_class($this->object) . ".");
54
        }
55
56 6
        $this->backend = midcom::get()->rcs->load_backend($this->object);
57 6
    }
58
59
    /**
60
     * Prepare version control toolbar
61
     */
62 4
    private function rcs_toolbar(array $revision, array $revision2 = null)
63
    {
64 4
        $this->add_stylesheet(MIDCOM_STATIC_URL . "/midcom.services.rcs/rcs.css");
65 4
        $prefix = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX) . $this->url_prefix;
0 ignored issues
show
Bug introduced by
Are you sure midcom_core_context::get...M_CONTEXT_ANCHORPREFIX) of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

65
        $prefix = /** @scrutinizer ignore-type */ midcom_core_context::get()->get_key(MIDCOM_CONTEXT_ANCHORPREFIX) . $this->url_prefix;
Loading history...
66 4
        $history = $this->backend->get_history();
67 4
        $this->_request_data['rcs_toolbar'] = new midcom_helper_toolbar();
68 4
        $this->populate_rcs_toolbar($history, $prefix, $revision, $revision2);
69
70
        // RCS functional toolbar
71 4
        $this->_request_data['rcs_toolbar_2'] = new midcom_helper_toolbar();
72 4
        $restore = $revision2 ?: $revision;
73
74
        $buttons = [
75
            [
76 4
                MIDCOM_TOOLBAR_URL => "{$prefix}{$this->object->guid}/",
77 4
                MIDCOM_TOOLBAR_LABEL => $this->_l10n->get('show history'),
78 4
                MIDCOM_TOOLBAR_GLYPHICON => 'history',
79
            ], [
80 4
                MIDCOM_TOOLBAR_URL => "{$prefix}restore/{$this->object->guid}/{$restore['revision']}/",
81 4
                MIDCOM_TOOLBAR_LABEL => sprintf($this->_l10n->get('restore version %s'), $restore['version']),
82 4
                MIDCOM_TOOLBAR_GLYPHICON => 'recycle',
83 4
                MIDCOM_TOOLBAR_ENABLED => ($restore['revision'] !== $history->get_last()['revision']),
84
            ]
85
        ];
86 4
        $this->_request_data['rcs_toolbar_2']->add_items($buttons);
87 4
    }
88
89 4
    private function populate_rcs_toolbar(midcom_services_rcs_history $history, string $prefix, array $revision, ?array $revision2)
90
    {
91 4
        $first = $history->get_first();
92 4
        $last = $history->get_last();
93
94 4
        $diff_view = !empty($revision2);
95 4
        $revision2 = $revision2 ?? $revision;
96
97 4
        if ($previous = $history->get_previous($revision['revision'])) {
98
            $enabled = true;
99
        } else {
100 4
            $enabled = false;
101 4
            $previous = $first;
102
        }
103 4
        $this->add_preview_button($prefix, $first, 'fast-backward', $enabled || $diff_view);
0 ignored issues
show
Bug introduced by
It seems like $first can also be of type null; however, parameter $entry of midcom_services_rcs_handler::add_preview_button() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

103
        $this->add_preview_button($prefix, /** @scrutinizer ignore-type */ $first, 'fast-backward', $enabled || $diff_view);
Loading history...
104 4
        $this->add_preview_button($prefix, $diff_view ? $revision : $previous, 'backward', $enabled || $diff_view);
105 4
        $this->add_diff_button($prefix, $previous, $revision, 'step-backward', $enabled);
0 ignored issues
show
Bug introduced by
It seems like $previous can also be of type null; however, parameter $first of midcom_services_rcs_handler::add_diff_button() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

105
        $this->add_diff_button($prefix, /** @scrutinizer ignore-type */ $previous, $revision, 'step-backward', $enabled);
Loading history...
106
107 4
        $this->_request_data['rcs_toolbar']->add_item([
108 4
            MIDCOM_TOOLBAR_URL => "{$prefix}preview/{$this->object->guid}/{$revision2['revision']}/",
109 4
            MIDCOM_TOOLBAR_LABEL => sprintf($this->_l10n->get('version %s'), $revision2['version']),
110 4
            MIDCOM_TOOLBAR_GLYPHICON => 'file-o',
111 4
            MIDCOM_TOOLBAR_ENABLED => $diff_view,
112
        ]);
113
114 4
        if ($next = $history->get_next($revision2['revision'])) {
115 2
            $enabled = true;
116
        } else {
117 2
            $enabled = false;
118 2
            $next = $last;
119
        }
120 4
        $this->add_diff_button($prefix, $revision2, $next, 'step-forward', $enabled);
0 ignored issues
show
Bug introduced by
It seems like $next can also be of type null; however, parameter $second of midcom_services_rcs_handler::add_diff_button() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

120
        $this->add_diff_button($prefix, $revision2, /** @scrutinizer ignore-type */ $next, 'step-forward', $enabled);
Loading history...
121 4
        $this->add_preview_button($prefix, $next, 'forward', $enabled || $diff_view);
122 4
        $this->add_preview_button($prefix, $last, 'fast-forward', $enabled || $diff_view);
123 4
    }
124
125 4
    private function add_preview_button(string $prefix, array $entry, string $icon, bool $enabled)
126
    {
127 4
        $this->_request_data['rcs_toolbar']->add_item([
128 4
            MIDCOM_TOOLBAR_URL => "{$prefix}preview/{$this->object->guid}/{$entry['revision']}/",
129 4
            MIDCOM_TOOLBAR_LABEL => $entry['version'],
130 4
            MIDCOM_TOOLBAR_GLYPHICON => $icon,
131 4
            MIDCOM_TOOLBAR_ENABLED => $enabled,
132
        ]);
133 4
    }
134
135 4
    private function add_diff_button(string $prefix, array $first, array $second, string $icon, bool $enabled)
136
    {
137 4
        $this->_request_data['rcs_toolbar']->add_item([
138 4
            MIDCOM_TOOLBAR_URL => "{$prefix}diff/{$this->object->guid}/{$first['revision']}/{$second['revision']}/",
139 4
            MIDCOM_TOOLBAR_LABEL => $this->_l10n->get('show differences'),
140 4
            MIDCOM_TOOLBAR_GLYPHICON => $icon,
141 4
            MIDCOM_TOOLBAR_ENABLED => $enabled,
142
        ]);
143 4
    }
144
145 6
    private function prepare_request_data(string $view_title)
146
    {
147 6
        foreach ($this->get_breadcrumbs() as $item) {
148 6
            $this->add_breadcrumb($item[MIDCOM_NAV_URL], $item[MIDCOM_NAV_NAME]);
149
        }
150 6
        $this->add_breadcrumb($this->url_prefix . "{$this->object->guid}/", $this->_l10n->get('show history'));
151
152 6
        $this->_request_data['handler'] = $this;
153 6
        $this->_request_data['view_title'] = $view_title;
154 6
        midcom::get()->head->set_pagetitle($view_title);
155 6
    }
156
157 2
    public function translate(string $string) : string
158
    {
159 2
        $translated = $string;
160 2
        $component = midcom::get()->dbclassloader->get_component_for_class($this->object->__midcom_class_name__);
161 2
        if (midcom::get()->componentloader->is_installed($component)) {
0 ignored issues
show
Bug introduced by
It seems like $component can also be of type null; however, parameter $path of midcom_helper__componentloader::is_installed() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

161
        if (midcom::get()->componentloader->is_installed(/** @scrutinizer ignore-type */ $component)) {
Loading history...
162 2
            $translated = midcom::get()->i18n->get_l10n($component)->get($string);
0 ignored issues
show
Bug introduced by
It seems like $component can also be of type null; however, parameter $component of midcom_services_i18n::get_l10n() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

162
            $translated = midcom::get()->i18n->get_l10n(/** @scrutinizer ignore-type */ $component)->get($string);
Loading history...
163
        }
164 2
        if ($translated === $string) {
165 2
            $translated = $this->_l10n->get($string);
166 2
            if ($translated === $string) {
167 2
                $translated = $this->_l10n_midcom->get($string);
168
            }
169
        }
170 2
        return $translated;
171
    }
172
173
    /**
174
     * Show the changes done to the object
175
     */
176 2
    public function _handler_history(Request $request, string $handler_id, array $args)
177
    {
178
        // Check if the comparison request is valid
179 2
        $first = $request->query->get('first');
180 2
        $last = $request->query->get('last');
181 2
        if ($first && $last && $first != $last) {
182
            return new midcom_response_relocate($this->url_prefix . "diff/{$args[0]}/{$first}/{$last}/");
183
        }
184
185 2
        $this->load_object($args[0]);
186 2
        $view_title = sprintf($this->_l10n->get('revision history of %s'), $this->resolve_object_title());
187
188 2
        $this->prepare_request_data($view_title);
189 2
        return $this->handler_callback($handler_id);
190
    }
191
192
    /**
193
     * @param array $data The local request data.
194
     */
195 2
    public function _show_history(string $handler_id, array &$data)
196
    {
197 2
        $data['history'] = $this->backend->get_history();
198 2
        $data['guid'] = $this->object->guid;
199 2
        midcom_show_style($this->style_prefix . 'history');
200 2
    }
201
202
    /**
203
     * Show a diff between two versions
204
     */
205 2
    public function _handler_diff(string $handler_id, array $args, array &$data)
206
    {
207 2
        $this->load_object($args[0]);
208 2
        $history = $this->backend->get_history();
209
210 2
        $compare_revision = $history->get($args[1]);
211 2
        $latest_revision = $history->get($args[2]);
212
213 2
        if (!$compare_revision || !$latest_revision) {
214
            throw new midcom_error_notfound("One of the revisions {$args[1]} or {$args[2]} does not exist.");
215
        }
216
217
        $data['diff'] = array_filter($this->backend->get_diff($args[1], $args[2]), function($value, $key) {
218 2
            return array_key_exists('diff', $value)
219 2
                && !is_array($value['diff'])
220 2
                && midcom_services_rcs::is_field_showable($key);
221 2
        }, ARRAY_FILTER_USE_BOTH);
222 2
        $data['comment'] = $latest_revision;
223
224
        // Set the version numbers
225 2
        $data['guid'] = $args[0];
226
227 2
        $view_title = sprintf($this->_l10n->get('changes between revisions %s and %s'), $compare_revision['version'], $latest_revision['version']);
228
229
        // Load the toolbars
230 2
        $this->rcs_toolbar($compare_revision, $latest_revision);
231 2
        $this->prepare_request_data($view_title);
232 2
        $this->add_breadcrumb(
233 2
            $this->url_prefix . "diff/{$this->object->guid}/{$compare_revision['revision']}/{$latest_revision['revision']}/",
234 2
            sprintf($this->_l10n->get('differences between %s and %s'), $compare_revision['version'], $latest_revision['version'])
235
        );
236
237 2
        return $this->handler_callback($handler_id);
238
    }
239
240
    /**
241
     * Show the differences between the versions
242
     */
243 2
    public function _show_diff()
244
    {
245 2
        midcom_show_style($this->style_prefix . 'diff');
246 2
    }
247
248
    /**
249
     * View previews
250
     */
251 2
    public function _handler_preview(string $handler_id, array $args, array &$data)
252
    {
253 2
        $revision = $args[1];
254 2
        $data['latest_revision'] = $revision;
255 2
        $data['guid'] = $args[0];
256 2
        $this->load_object($args[0]);
257 2
        $metadata = $this->backend->get_history()->get($args[1]);
258 2
        if (!$metadata) {
259
            throw new midcom_error_notfound("Revision {$args[1]} does not exist.");
260
        }
261
262
        $data['preview'] = array_filter($this->backend->get_revision($revision), function ($value, $key) {
263 2
            return !is_array($value)
264 2
                && !in_array($value, ['', '0000-00-00'])
265 2
                && midcom_services_rcs::is_field_showable($key);
266 2
        }, ARRAY_FILTER_USE_BOTH);
267
268 2
        $this->_view_toolbar->hide_item($this->url_prefix . "preview/{$this->object->guid}/{$revision}/");
269
270 2
        $view_title = sprintf($this->_l10n->get('viewing version %s from %s'), $metadata['version'], $this->_l10n->get_formatter()->datetime($metadata['date']));
271
        // Load the toolbars
272 2
        $this->rcs_toolbar($metadata);
273 2
        $this->prepare_request_data($view_title);
274 2
        return $this->handler_callback($handler_id);
275
    }
276
277 2
    public function _show_preview()
278
    {
279 2
        midcom_show_style($this->style_prefix . 'preview');
280 2
    }
281
282
    /**
283
     * Restore to diff
284
     */
285
    public function _handler_restore(array $args)
286
    {
287
        $this->load_object($args[0]);
288
289
        $this->object->require_do('midgard:update');
290
        // TODO: set another privilege for restoring?
291
292
        if (   $this->backend->get_history()->version_exists($args[1])
293
            && $this->backend->restore_to_revision($args[1])) {
294
            midcom::get()->uimessages->add($this->_l10n->get('midcom.admin.rcs'), sprintf($this->_l10n->get('restore to version %s successful'), $args[1]));
295
            return new midcom_response_relocate($this->get_object_url());
296
        }
297
        throw new midcom_error(sprintf($this->_l10n->get('restore to version %s failed, reason %s'), $args[1], midcom_connection::get_error_string()));
298
    }
299
}
300