Passed
Push — master ( 1d6e3e...f1fbfb )
by Andreas
11:14
created

net_nehmer_comments_handler_view   A

Complexity

Total Complexity 40

Size/Duplication

Total Lines 238
Duplicated Lines 0 %

Test Coverage

Coverage 58.12%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 117
c 1
b 0
f 0
dl 0
loc 238
ccs 68
cts 117
cp 0.5812
rs 9.2
wmc 40

8 Methods

Rating   Name   Duplication   Size   Complexity  
A _prepare_request_data() 0 4 1
A _init_display_datamanager() 0 5 1
B _load_schemadb() 0 22 7
B _show_comments() 0 29 8
B _process_post() 0 40 10
A _init_post_controller() 0 23 3
A _get_last_modified() 0 5 1
B _handler_comments() 0 47 9

How to fix   Complexity   

Complex Class

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

1
<?php
2
/**
3
 * @package net.nehmer.comments
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 midcom\datamanager\schemadb;
10
use midcom\datamanager\datamanager;
11
use midcom\datamanager\controller;
12
use Symfony\Component\HttpFoundation\Request;
13
14
/**
15
 * Comments view handler.
16
 *
17
 * This handler is a single handler which displays the thread for a given object GUID.
18
 * It checks for various commands in the request during startup and processes them
19
 * if applicable. It relocates to the same page to prevent duplicate request runs.
20
 *
21
 * @package net.nehmer.comments
22
 */
23
class net_nehmer_comments_handler_view extends midcom_baseclasses_components_handler
24
{
25
    use net_nehmer_comments_handler;
0 ignored issues
show
introduced by
The trait net_nehmer_comments_handler requires some properties which are not provided by net_nehmer_comments_handler_view: $auth, $guid
Loading history...
26
27
    private ?schemadb $_schemadb = null;
28
29
    /**
30
     * @var net_nehmer_comments_comment[]
31
     */
32
    private array $_comments = [];
33
34
    private net_nehmer_comments_comment $_new_comment;
35
36
    private string $_objectguid;
37
38
    private controller $_post_controller;
39
40
    private datamanager $_display_datamanager;
41
42
    /**
43
     * Prepares the request data
44
     */
45 2
    private function _prepare_request_data()
46
    {
47 2
        $this->_request_data['objectguid'] = $this->_objectguid;
48 2
        $this->_request_data['post_controller'] = $this->_post_controller;
49
    }
50
51
    /**
52
     * Prepares the _display_datamanager member.
53
     */
54
    private function _init_display_datamanager()
55
    {
56
        $this->_load_schemadb();
57
        $this->_display_datamanager = new datamanager($this->_schemadb);
58
        $this->_request_data['display_datamanager'] = $this->_display_datamanager;
59
    }
60
61
    /**
62
     * Loads the schemadb (unless it has already been loaded).
63
     */
64 2
    private function _load_schemadb()
65
    {
66 2
        if (!$this->_schemadb) {
67 2
            $this->_schemadb = schemadb::from_path($this->_config->get('schemadb'));
0 ignored issues
show
Bug introduced by
It seems like $this->_config->get('schemadb') can also be of type false; however, parameter $path of midcom\datamanager\schemadb::from_path() 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

67
            $this->_schemadb = schemadb::from_path(/** @scrutinizer ignore-type */ $this->_config->get('schemadb'));
Loading history...
68
69 2
            if (   $this->_config->get('use_captcha')
70 2
                || (   !midcom::get()->auth->user
71 2
                    && $this->_config->get('use_captcha_if_anonymous'))) {
72
                $fields = $this->_schemadb->get('comment')->get('fields');
73
                $fields['captcha'] = [
74
                    'title' => $this->_l10n_midcom->get('captcha field title'),
75
                    'storage' => null,
76
                    'type' => 'captcha',
77
                    'widget' => 'captcha',
78
                    'widget_config' => $this->_config->get_array('captcha_config'),
79
                ];
80
                $this->_schemadb->get('comment')->set('fields', $fields);
81
            }
82
83 2
            if (   $this->_config->get('ratings_enable')
84 2
                && $this->_schemadb->get('comment')->has_field('rating')) {
85
                $this->_schemadb->get('comment')->get_field('rating')['hidden'] = false;
86
            }
87
        }
88
    }
89
90
    /**
91
     * Initializes a DM for posting.
92
     */
93 2
    private function _init_post_controller(Request $request)
94
    {
95 2
        $this->_load_schemadb();
96
97 2
        $this->_new_comment = new net_nehmer_comments_comment();
98 2
        $this->_new_comment->objectguid = $this->_objectguid;
99 2
        $this->_new_comment->ip = $request->getClientIp();
100
101 2
        if (midcom::get()->auth->user) {
102 2
            $this->_new_comment->status = net_nehmer_comments_comment::NEW_USER;
103 2
            $this->_new_comment->author = midcom::get()->auth->user->name;
104
        } else {
105
            $this->_new_comment->status = net_nehmer_comments_comment::NEW_ANONYMOUS;
106
        }
107
108 2
        if ($this->_config->get('enable_notify')) {
109 2
            $this->_new_comment->_send_notification = true;
110
        }
111
112 2
        $dm = new datamanager($this->_schemadb);
113 2
        $this->_post_controller = $dm
114 2
            ->set_storage($this->_new_comment)
115 2
            ->get_controller();
116
    }
117
118
    /**
119
     * Loads the comments, does any processing according to the state of the GET list.
120
     * On successful processing we relocate once to ourself.
121
     */
122 2
    public function _handler_comments(Request $request, string $handler_id, array &$data, string $guid, ?string $view = null)
123
    {
124 2
        $this->_objectguid = $guid;
125 2
        midcom::get()->cache->content->register($this->_objectguid);
126
127 2
        if ($handler_id == 'view-comments-nonempty') {
128 1
            $this->_comments = net_nehmer_comments_comment::list_by_objectguid_filter_anonymous(
129 1
                $this->_objectguid,
130 1
                $this->_config->get('items_to_show'),
131 1
                $this->_config->get('item_ordering'),
0 ignored issues
show
Bug introduced by
It seems like $this->_config->get('item_ordering') can also be of type false; however, parameter $order of net_nehmer_comments_comm...guid_filter_anonymous() 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

131
                /** @scrutinizer ignore-type */ $this->_config->get('item_ordering'),
Loading history...
132 1
                $this->_config->get('paging')
133 1
            );
134
        } else {
135 1
            $this->_comments = net_nehmer_comments_comment::list_by_objectguid(
136 1
                $this->_objectguid,
137 1
                $this->_config->get('items_to_show'),
138 1
                $this->_config->get('item_ordering'),
0 ignored issues
show
Bug introduced by
It seems like $this->_config->get('item_ordering') can also be of type false; however, parameter $order of net_nehmer_comments_comment::list_by_objectguid() 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

138
                /** @scrutinizer ignore-type */ $this->_config->get('item_ordering'),
Loading history...
139 1
                $this->_config->get('paging')
140 1
            );
141
        }
142
143 2
        if ($this->_config->get('paging') !== false) {
144
            $data['qb_pager'] = $this->_comments;
145
            $this->_comments = $this->_comments->execute();
146
        }
147
148 2
        if (   midcom::get()->auth->user
149 2
            || $this->_config->get('allow_anonymous')) {
150 2
            $this->_init_post_controller($request);
151 2
            if ($response = $this->_process_post($request)) {
152
                return $response;
153
            }
154
        }
155 2
        if ($this->_comments) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_comments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
156
            $this->_init_display_datamanager();
157
        }
158
159 2
        if ($handler_id == 'view-comments-custom') {
160
            midcom::get()->skip_page_style = true;
161
            $data['custom_view'] = $view;
162
        }
163
164 2
        $this->_prepare_request_data();
165 2
        midcom::get()->metadata->set_request_metadata($this->_get_last_modified(), $this->_objectguid);
166
167 2
        if ($request->isXmlHttpRequest()) {
168
            midcom::get()->skip_page_style = true;
169
        }
170
    }
171
172
    /**
173
     * Checks if a new post has been submitted.
174
     */
175 2
    private function _process_post(Request $request)
176
    {
177 2
        if (   !midcom::get()->auth->user
178 2
            && !midcom::get()->auth->request_sudo('net.nehmer.comments')) {
179
            throw new midcom_error('We were anonymous but could not acquire SUDO privileges, aborting');
180
        }
181
182 2
        switch ($this->_post_controller->handle($request)) {
183 2
            case 'save':
184
                // Check against comment spam
185
                if ($this->_config->get('enable_spam_check')) {
186
                    net_nehmer_comments_spamchecker::check($this->_new_comment);
187
                }
188
189
                $formdata = $this->_post_controller->get_form_values();
190
                if (   $formdata['subscribe']
191
                    && midcom::get()->auth->user) {
192
                    // User wants to subscribe to receive notifications about this comments thread
193
194
                    // Get the object we're commenting
195
                    $parent = midcom::get()->dbfactory->get_object_by_guid($this->_objectguid);
196
197
                    // Sudo so we can update the parent object
198
                    if (midcom::get()->auth->request_sudo($this->_component)) {
199
                        // Save the subscription
200
                        $parent->set_parameter('net.nehmer.comments:subscription', midcom::get()->auth->user->guid, time());
201
202
                        // Return back from the sudo state
203
                        midcom::get()->auth->drop_sudo();
204
                    }
205
                }
206
207
                midcom::get()->cache->invalidate($this->_objectguid);
208
                // Fall-through intentional
209
210 2
            case 'cancel':
211
                if (!midcom::get()->auth->user) {
212
                    midcom::get()->auth->drop_sudo();
213
                }
214
                return new midcom_response_relocate($request->getRequestUri());
215
        }
216
    }
217
218
    /**
219
     * Determines the last modified timestamp. It is the max out of all revised timestamps
220
     * of the comments (or 0 in case nothing was found).
221
     */
222 2
    private function _get_last_modified() : int
223
    {
224 2
        return array_reduce($this->_comments, function ($carry, net_nehmer_comments_comment $item) {
225
            return max($item->metadata->revised, $carry);
226 2
        }, 0);
227
    }
228
229
    /**
230
     * Display the comment list and the submit-comment form.
231
     */
232 2
    public function _show_comments(string $handler_id, array &$data)
233
    {
234 2
        midcom_show_style('comments-header');
235 2
        if ($this->_comments) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_comments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
236
            midcom_show_style('comments-start');
237
            foreach ($this->_comments as $comment) {
238
                $this->_display_datamanager->set_storage($comment);
239
                $data['comment'] = $comment;
240
                $data['comment_toolbar'] = $this->populate_post_toolbar($comment);
241
                midcom_show_style('comments-item');
242
243
                if (   midcom::get()->auth->admin
244
                    || (   midcom::get()->auth->user
245
                        && $comment->can_do('midgard:delete'))) {
246
                    midcom_show_style('comments-admintoolbar');
247
                }
248
            }
249
            midcom_show_style('comments-end');
250
        } else {
251 2
            midcom_show_style('comments-nonefound');
252
        }
253
254 2
        if (   midcom::get()->auth->user
255 2
            || $this->_config->get('allow_anonymous')) {
256 2
            midcom_show_style('post-comment');
257
        } else {
258
            midcom_show_style('post-denied');
259
        }
260 2
        midcom_show_style('comments-footer');
261
    }
262
}
263