Passed
Push — master ( a4dff3...a51da9 )
by Andreas
16:37 queued 06:39
created

org_openpsa_relatedto_handler_relatedto   B

Complexity

Total Complexity 52

Size/Duplication

Total Lines 408
Duplicated Lines 0 %

Test Coverage

Coverage 49.47%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 186
c 4
b 0
f 0
dl 0
loc 408
ccs 93
cts 188
cp 0.4947
rs 7.44
wmc 52

20 Methods

Rating   Name   Duplication   Size   Complexity  
A _handler_delete() 0 14 2
A _render_line_task() 0 17 3
A _render_line_salesproject() 0 11 2
B _render_line() 0 33 9
A _render_line_invoice() 0 10 2
A get_node_url() 0 3 1
A _show_render() 0 8 1
A _render_line_event() 0 16 2
A _handler_render() 0 16 3
A _get_object_links_sort_time() 0 8 3
A _render_line_default() 0 18 2
A _handler_ajax() 0 22 5
A _show_list() 0 17 3
A _render_line_wikipage() 0 12 2
A _sort_by_time() 0 8 2
A _render_line_document() 0 5 1
A _get_object_links() 0 32 4
A render_line_controls() 0 15 3
A _on_initialize() 0 3 1
A _prepare_request_data() 0 27 1

How to fix   Complexity   

Complex Class

Complex classes like org_openpsa_relatedto_handler_relatedto 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 org_openpsa_relatedto_handler_relatedto, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package org.openpsa.relatedto
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
use Symfony\Component\HttpFoundation\JsonResponse;
10
11
/**
12
 * relatedto ajax/ahah handler
13
 *
14
 * @package org.openpsa.relatedto
15
 */
16
class org_openpsa_relatedto_handler_relatedto extends midcom_baseclasses_components_handler
17
{
18
    private midcom_core_dbaobject $_object;
19
20
    /**
21
     * The mode we're in
22
     */
23
    private string $_mode;
24
25
    /**
26
     * The sort order
27
     */
28
    private string $_sort = 'default';
29
30
    /**
31
     * The link array
32
     */
33
    private array $_links = [];
34
35 2
    public function _on_initialize()
36
    {
37 2
        midcom::get()->style->prepend_component_styledir('org.openpsa.relatedto');
38
    }
39
40 2
    public function _handler_render(string $guid, string $mode, string $sort = 'default')
41
    {
42 2
        $this->_object = midcom::get()->dbfactory->get_object_by_guid($guid);
43 2
        $this->_mode = $mode;
44 2
        $this->_sort = $sort;
45
46 2
        if ($this->_mode !== 'in') {
47 2
            $this->_links['outgoing'] = $this->_get_object_links(true);
48
        }
49 2
        if ($this->_mode !== 'out') {
50 2
            $this->_links['incoming'] = $this->_get_object_links(false);
51
        }
52
53 2
        $this->_prepare_request_data();
54 2
        midcom::get()->head->add_jsfile(MIDCOM_STATIC_URL . "/org.openpsa.relatedto/related_to.js");
55 2
        midcom::get()->head->add_stylesheet(MIDCOM_STATIC_URL . "/org.openpsa.relatedto/related_to.css");
56
    }
57
58 2
    private function _prepare_request_data()
59
    {
60 2
        $ref = midcom_helper_reflector::get($this->_object);
61 2
        $object_label = $ref->get_object_label($this->_object);
62
63 2
        $object_url = midcom::get()->permalinks->create_permalink($this->_object->guid);
64 2
        $this->_view_toolbar->add_item([
65 2
            MIDCOM_TOOLBAR_URL => $object_url,
66 2
            MIDCOM_TOOLBAR_LABEL => $this->_l10n_midcom->get('back'),
67 2
            MIDCOM_TOOLBAR_GLYPHICON => 'eject',
68 2
        ]);
69 2
        $this->add_breadcrumb($object_url, $object_label);
0 ignored issues
show
Bug introduced by
It seems like $object_label can also be of type null; however, parameter $title of midcom_baseclasses_compo...ndler::add_breadcrumb() 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

69
        $this->add_breadcrumb($object_url, /** @scrutinizer ignore-type */ $object_label);
Loading history...
70
71 2
        $this->add_breadcrumb("", $this->_l10n->get('view related information'));
72
73
        // Load "Create X" buttons for all the related info
74 2
        $relatedto_button_settings = org_openpsa_relatedto_plugin::common_toolbar_buttons_defaults();
75
76 2
        $class_label = $ref->get_class_label();
77 2
        $date_label = $this->_l10n->get_formatter()->datetime();
78 2
        $relatedto_button_settings['wikinote']['wikiword'] = str_replace('/', '-', sprintf($this->_l10n->get('notes for %s %s on %s'), $class_label, $object_label, $date_label));
79
80 2
        org_openpsa_relatedto_plugin::common_node_toolbar_buttons($this->_view_toolbar, $this->_object, $this->_topic->component, $relatedto_button_settings);
81 2
        org_openpsa_relatedto_plugin::add_journal_entry_button($this->_view_toolbar, $this->_object->guid);
82
83 2
        $this->_request_data['object'] = $this->_object;
84 2
        $this->_request_data['show_title'] = ($this->_mode == 'both');
85
    }
86
87
    /**
88
     * Get object's relatedtos
89
     *
90
     * @param boolean $inbound True means toGuid == $obj->guid, false fromGuid == $obj->guid
91
     */
92 2
    private function _get_object_links(bool $inbound) : array
93
    {
94 2
        $arr = [];
95 2
        if ($inbound) {
96 2
            $other = 'from';
97 2
            $mc = org_openpsa_relatedto_dba::new_collector('toGuid', $this->_object->guid);
98
        } else {
99 2
            $other = 'to';
100 2
            $mc = org_openpsa_relatedto_dba::new_collector('fromGuid', $this->_object->guid);
101
        }
102
103 2
        $mc->add_constraint('status', '<>', org_openpsa_relatedto_dba::NOTRELATED);
104 2
        $links = $mc->get_rows([$other . 'Component', $other . 'Class', 'status', $other . 'Guid']);
105
106 2
        foreach ($links as $guid => $link) {
107
            //TODO: check for duplicates ?
108
            try {
109 2
                $result = ['other_obj' => midcom::get()->dbfactory->get_object_by_guid($link[$other . 'Guid'])];
110
            } catch (midcom_error $e) {
111
                continue;
112
            }
113 2
            $result['link'] = [
114 2
                'guid' => $guid,
115 2
                'component' => $link[$other . 'Component'],
116 2
                'class' => $link[$other . 'Class'],
117 2
                'status' => $link['status']
118 2
            ];
119
120 2
            $result['sort_time'] = $this->_get_object_links_sort_time($result['other_obj']);
121 2
            $arr[] = $result;
122
        }
123 2
        return $arr;
124
    }
125
126
    /**
127
     * returns a unix timestamp for sorting relatedto arrays
128
     */
129 2
    private function _get_object_links_sort_time(midcom_core_dbaobject $obj)
130
    {
131
        switch (true) {
132 2
            case $obj instanceof org_openpsa_calendar_event_dba:
133 2
            case $obj instanceof org_openpsa_projects_task_dba:
134
                return $obj->start;
0 ignored issues
show
Bug Best Practice introduced by
The property start does not exist on midcom_core_dbaobject. Since you implemented __get, consider adding a @property annotation.
Loading history...
135
            default:
136 2
                return $obj->metadata->created;
137
        }
138
    }
139
140
    /**
141
     * Renders the selected view
142
     */
143 2
    public function _show_render(string $handler_id, array &$data)
144
    {
145 2
        midcom_show_style('relatedto_start');
146
147 2
        $this->_show_list('incoming');
148 2
        $this->_show_list('outgoing');
149
150 2
        midcom_show_style('relatedto_end');
151
    }
152
153 2
    private function _show_list(string $direction)
154
    {
155 2
        if (empty($this->_links[$direction])) {
156 2
            return;
157
        }
158 2
        $this->_request_data['direction'] = $direction;
159
160
        //Sort the array of links
161 2
        uasort($this->_links[$direction], [$this, '_sort_by_time']);
162
163 2
        midcom_show_style('relatedto_list_top');
164
165 2
        foreach ($this->_links[$direction] as $linkdata) {
166 2
            $this->_render_line($linkdata['link'], $linkdata['other_obj']);
167
        }
168
169 2
        midcom_show_style('relatedto_list_bottom');
170
    }
171
172
    /**
173
     * Code to sort array by key 'sort_time', from smallest to greatest
174
     */
175
    private function _sort_by_time($a, $b)
176
    {
177
        $ap = $a['sort_time'];
178
        $bp = $b['sort_time'];
179
        if ($this->_sort == 'reverse') {
180
            return $bp <=> $ap;
181
        }
182
        return $ap <=> $bp;
183
    }
184
185
    /**
186
     * Renders single link line
187
     *
188
     * @param array $link The necessary link information
189
     */
190 2
    private function _render_line(array $link, midcom_core_dbaobject &$other_obj)
191
    {
192 2
        $this->_request_data['link'] = $link;
193 2
        $this->_request_data['other_obj'] =& $other_obj;
194 2
        $this->_request_data['icon'] = midcom_helper_reflector::get_object_icon($other_obj);
195
196 2
        if (get_class($other_obj) != $link['class']) {
197 2
            $other_obj = new $link['class']($other_obj);
198
        }
199
200 2
        switch ($link['class']) {
201
            case net_nemein_wiki_wikipage::class:
202
                $this->_render_line_wikipage($other_obj);
203
                break;
204
            case org_openpsa_calendar_event_dba::class:
205
                $this->_render_line_event($other_obj);
206
                break;
207
            case org_openpsa_projects_task_dba::class:
208
            case org_openpsa_projects_project::class:
209
                $this->_render_line_task($other_obj);
210
                break;
211
            case org_openpsa_documents_document_dba::class:
212
                $this->_render_line_document($other_obj);
213
                break;
214
            case org_openpsa_sales_salesproject_dba::class:
215 2
                $this->_render_line_salesproject($other_obj);
216 2
                break;
217
            case org_openpsa_invoices_invoice_dba::class:
218
                $this->_render_line_invoice($other_obj);
219
                break;
220
            default:
221
                $this->_render_line_default($link, $other_obj);
222
                break;
223
        }
224
    }
225
226 2
    private function get_node_url(string $component)
227
    {
228 2
        return org_openpsa_core_siteconfig::get_instance()->get_node_full_url($component);
229
    }
230
231
    /**
232
     * Renders a document line
233
     */
234
    private function _render_line_document(org_openpsa_documents_document_dba $other_obj)
235
    {
236
        $this->_request_data['document_url'] = midcom::get()->permalinks->create_permalink($other_obj->guid);
237
238
        midcom_show_style('relatedto_list_item_document');
239
    }
240
241
    /**
242
     * Renders a wikipage line
243
     */
244
    private function _render_line_wikipage(net_nemein_wiki_wikipage $other_obj)
245
    {
246
        $nap = new midcom_helper_nav();
247
        $node = $nap->get_node($other_obj->topic);
248
        if (!$node) {
249
            // The page isn't from this site
250
            return;
251
        }
252
253
        $this->_request_data['page_url'] = $node[MIDCOM_NAV_FULLURL];
254
255
        midcom_show_style('relatedto_list_item_wikipage');
256
    }
257
258
    /**
259
     * Renders an event line
260
     */
261
    private function _render_line_event(org_openpsa_calendar_event_dba $other_obj)
262
    {
263
        $this->_request_data['raw_url'] = '';
264
265
        $title = $other_obj->title;
266
267
        if ($url = $this->get_node_url('org.openpsa.calendar')) {
268
            //Calendar node found, render a better view
269
            $this->_request_data['raw_url'] = $url . 'event/raw/' . $other_obj->guid . '/';
270
            $workflow = $this->get_workflow('viewer');
271
            $title = '<a href="' . $url . 'event/' . $other_obj->guid . '/" ' . $workflow->render_attributes() . '>' . $title . "</a>\n";
272
        }
273
274
        $this->_request_data['title'] = $title;
275
276
        midcom_show_style('relatedto_list_item_event');
277
    }
278
279
    /**
280
     * Renders a task line
281
     *
282
     * @param object $other_obj The link target
283
     */
284
    private function _render_line_task($other_obj)
285
    {
286
        if ($other_obj instanceof org_openpsa_projects_task_dba) {
287
            $type = 'task';
288
        } else {
289
            $type = 'project';
290
        }
291
292
        $title = $other_obj->title;
293
294
        if ($url = $this->get_node_url('org.openpsa.projects')) {
295
            $title = '<a href="' . $url . $type . '/' . $other_obj->guid . '/" target="task_' . $other_obj->guid . '">' . $title . "</a>\n";
296
        }
297
        $this->_request_data['title'] = $title;
298
        $this->_request_data['type'] = $type;
299
300
        midcom_show_style('relatedto_list_item_task');
301
    }
302
303
    /**
304
     * Renders a sales project line
305
     */
306 2
    private function _render_line_salesproject(org_openpsa_sales_salesproject_dba $other_obj)
307
    {
308 2
        $title = $other_obj->title;
309
310 2
        if ($url = $this->get_node_url('org.openpsa.sales')) {
311 2
            $title = '<a href="' . $url . 'salesproject/' . $other_obj->guid . '/" target="salesproject_' . $other_obj->guid . '">' . $title . "</a>\n";
312
        }
313
314 2
        $this->_request_data['title'] = $title;
315
316 2
        midcom_show_style('relatedto_list_item_salesproject');
317
    }
318
319
    /**
320
     * Renders an invoice line
321
     */
322
    private function _render_line_invoice(org_openpsa_invoices_invoice_dba $other_obj)
323
    {
324
        $title = $this->_i18n->get_string('invoice', 'org.openpsa.invoices') . ' ' . $other_obj->get_label();
325
326
        if ($url = $this->get_node_url('org.openpsa.invoices')) {
327
            $title = '<a href="' . $url . 'invoice/' . $other_obj->guid . '/" target="invoice_' . $other_obj->guid . '">' . $title . "</a>\n";
328
        }
329
        $this->_request_data['title'] = $title;
330
331
        midcom_show_style('relatedto_list_item_invoice');
332
    }
333
334
    /**
335
     * Default line rendering, used if a specific renderer cannot be found
336
     *
337
     * Tries to find certain properties likely to hold semi-useful information about
338
     * the object, failing that outputs class and guid.
339
     *
340
     * @param array $link The necessary link information
341
     * @param object $other_obj The link target
342
     */
343
    private function _render_line_default(array $link, $other_obj)
344
    {
345
        $class = get_class($other_obj);
346
347
        $ref = midcom_helper_reflector::get($other_obj);
348
        $object_label = $ref->get_object_label($other_obj);
349
        if ($url = midcom::get()->permalinks->create_permalink($other_obj->guid)) {
350
            $object_label = '<a href="' . $url . '" target="' . $class . $this->_object->guid . '">' . $object_label . '</a>';
351
        }
352
353
        echo "            <li class=\"unknown {$class}\" id=\"org_openpsa_relatedto_line_{$link['guid']}\">\n";
354
        echo '                <span class="icon">' . $this->_request_data['icon'] . "</span>\n";
355
        echo '                <span class="title">' . $object_label . "</span>\n";
356
        echo '                <ul class="metadata">';
357
        echo '                    <li>' . $ref->get_class_label() . "</li>\n";
358
        echo "                </ul>\n";
359
        self::render_line_controls($link, $other_obj);
360
        echo "</li>\n";
361
    }
362
363
    /**
364
     * Renders (if necessary) controls for confirming/deleting link object
365
     *
366
     * @param array $link The necessary link information
367
     * @param object $other_obj The link target
368
     */
369 2
    public static function render_line_controls(array $link, $other_obj)
370
    {
371 2
        echo "<ul class=\"relatedto_toolbar\" data-link-guid=\"{$link['guid']}\" data-other-guid=\"{$other_obj->guid}\">\n";
372
373 2
        if (in_array($link['component'], ['net.nemein.wiki', 'org.openpsa.calendar'])) {
374
            echo "<li><input type=\"button\" class=\"button info\" value=\"" . midcom::get()->i18n->get_string('details', 'org.openpsa.relatedto') . "\" /></li>\n";
375
        }
376
377 2
        if ($link['status'] == org_openpsa_relatedto_dba::SUSPECTED) {
378
            echo "<li><input type=\"button\" class=\"button confirm\" value=\"" . midcom::get()->i18n->get_string('confirm relation', 'org.openpsa.relatedto') . "\" /></li>\n";
379
            echo "<li><input type=\"button\" class=\"button deny\" value=\"" . midcom::get()->i18n->get_string('deny relation', 'org.openpsa.relatedto') . "\" /></li>\n";
380
        }
381
382 2
        echo '<li><input type="button" class="button delete" id="org_openpsa_relatedto_delete-' . $link['guid'] . '" value="' . midcom::get()->i18n->get_string('delete relation', 'org.openpsa.relatedto') . '" /></li>';
383 2
        echo "</ul>\n";
384
    }
385
386
    public function _handler_ajax(string $guid, string $mode)
387
    {
388
        midcom::get()->auth->require_valid_user();
389
390
        $response = ['result' => false];
391
392
        try {
393
            $this->_object = midcom::get()->dbfactory->get_object_by_guid($guid);
394
            if (!($this->_object instanceof org_openpsa_relatedto_dba)) {
395
                $response['status'] = "method requires guid of a link object as an argument";
396
            }
397
        } catch (midcom_error $e) {
398
            $response['status'] = "error: " . $e->getMessage();
399
        }
400
401
        if (empty($response['status'])) {
402
            $this->_object->status = $mode == 'deny' ? org_openpsa_relatedto_dba::NOTRELATED : org_openpsa_relatedto_dba::CONFIRMED;
0 ignored issues
show
Bug Best Practice introduced by
The property status does not exist on midcom_core_dbaobject. Since you implemented __set, consider adding a @property annotation.
Loading history...
403
            $response['result'] = $this->_object->update();
404
            $response['status'] = 'error:' . midcom_connection::get_error_string();
405
        }
406
407
        return new JsonResponse($response);
408
    }
409
410
    public function _handler_delete(string $guid)
411
    {
412
        midcom::get()->auth->require_valid_user();
413
414
        try {
415
            $relation = new org_openpsa_relatedto_dba($guid);
416
            $result = $relation->delete();
417
            $status = 'Last message: ' . midcom_connection::get_error_string();
418
        } catch (midcom_error $e) {
419
            $result = false;
420
            $status = "Object '{$guid}' could not be loaded, error:" . $e->getMessage();
421
        }
422
423
        return new JsonResponse(['result' => $result, 'status' => $status]);
424
    }
425
}
426