Completed
Push — master ( e88a10...327e61 )
by Andreas
17:39
created

org_openpsa_widgets_contact   F

Complexity

Total Complexity 76

Size/Duplication

Total Lines 427
Duplicated Lines 0 %

Test Coverage

Coverage 60.29%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 211
c 3
b 0
f 0
dl 0
loc 427
ccs 126
cts 209
cp 0.6029
rs 2.32
wmc 76

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 2
A add_head_elements() 0 7 2
A get() 0 21 3
C show() 0 60 10
A _render_name() 0 23 6
A get_image() 0 13 5
A _show_phone_number() 0 4 2
A show_inline() 0 24 3
C read_object() 0 37 12
B _show_groups() 0 32 8
F show_address_card() 0 86 23

How to fix   Complexity   

Complex Class

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

1
<?php
2
/**
3
 * Class for rendering person records
4
 *
5
 * Uses the hCard microformat for output.
6
 *
7
 * @author Henri Bergius, http://bergie.iki.fi
8
 * @copyright Nemein Oy, http://www.nemein.com
9
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
10
 * @link http://www.microformats.org/wiki/hcard hCard microformat documentation
11
 * @package org.openpsa.widgets
12
 */
13
14
/**
15
 * @package org.openpsa.widgets
16
 */
17
class org_openpsa_widgets_contact extends midcom_baseclasses_components_purecode
18
{
19
    /**
20
     * Do we have our contact data ?
21
     */
22
    private $_data_read_ok = false;
23
24
    /**
25
     * Contact information of the person being displayed
26
     */
27
    public $contact_details = [
28
        'guid' => '',
29
        'id' => '',
30
        'firstname' => '',
31
        'lastname' => ''
32
    ];
33
34
    /**
35
     * Optional URI to person details
36
     *
37
     * @var string
38
     */
39
    public $link;
40
41
    /**
42
     * Optional HTML to be placed into the card
43
     *
44
     * @var string
45
     */
46
    public $extra_html;
47
48
    /**
49
     * Optional HTML to be placed into the card (before any other output in the DIV)
50
     *
51
     * @var string
52
     */
53
    public $prefix_html;
54
55
    /**
56
     * Whether to show person's groups in a list
57
     *
58
     * @var boolean
59
     */
60
    public $show_groups = true;
61
62
    /**
63
     * Whether to generate links to the groups using NAP
64
     *
65
     * @var boolean
66
     */
67
    var $link_contacts = true;
68
69
    /**
70
     * Default org.openpsa.contacts URL to be used for linking to groups. Will be autoprobed if not supplied.
71
     *
72
     * @var string
73
     */
74
    private static $_contacts_url;
75
76
    private $person;
77
78
    /**
79
     * Initializes the class and stores the selected person to be shown
80
     * The argument should be a MidgardPerson object.
81
     *
82
     * @param mixed $person Person to display either as MidgardPerson
83
     */
84 8
    public function __construct($person = null)
85
    {
86 8
        parent::__construct();
87
88 8
        if (null === self::$_contacts_url) {
0 ignored issues
show
introduced by
The condition null === self::_contacts_url is always false.
Loading history...
89 1
            $siteconfig = org_openpsa_core_siteconfig::get_instance();
90 1
            self::$_contacts_url = $siteconfig->get_node_full_url('org.openpsa.contacts');
91
        }
92
93 8
        $this->person = $person;
94
        // Read properties of provided person object
95
        // TODO: Handle groups as well
96 8
        $this->_data_read_ok = $this->read_object($person);
97 8
    }
98
99 9
    public static function add_head_elements()
100
    {
101 9
        static $added = false;
102 9
        if (!$added) {
103 1
            midcom::get()->head->add_stylesheet(MIDCOM_STATIC_URL . "/org.openpsa.widgets/hcard.css");
104 1
            midcom::get()->head->add_stylesheet(MIDCOM_STATIC_URL . '/stock-icons/font-awesome-4.7.0/css/font-awesome.min.css');
105 1
            $added = true;
106
        }
107 9
    }
108
109
    /**
110
     * Retrieve an object, uses in-request caching
111
     *
112
     * @param mixed $src GUID of object (ids work but are discouraged)
113
     */
114 10
    public static function get($src) : self
115
    {
116 10
        static $cache = [];
117
118 10
        if (isset($cache[$src])) {
119 4
            return $cache[$src];
120
        }
121
122
        try {
123 7
            $person = org_openpsa_contacts_person_dba::get_cached($src);
124 1
        } catch (midcom_error $e) {
125 1
            $widget = new self();
126 1
            $cache[$src] = $widget;
127 1
            return $widget;
128
        }
129
130 6
        $widget = new self($person);
131
132 6
        $cache[$person->guid] = $widget;
133 6
        $cache[$person->id] = $cache[$person->guid];
134 6
        return $cache[$person->guid];
135
    }
136
137
    /**
138
     * Read properties of a person object and populate local fields accordingly
139
     */
140 8
    private function read_object($person) : bool
141
    {
142 8
        if (   !is_object($person)
143 8
            || !$person instanceof midcom_db_person) {
144
            // Given $person is not one
145 1
            return false;
146
        }
147
        // Database identifiers
148 7
        $this->contact_details['guid'] = $person->guid;
149 7
        $this->contact_details['id'] = $person->id;
150
151 7
        if ($person->guid == "") {
152
            $this->contact_details['lastname'] = $this->_l10n->get('no person');
153 7
        } elseif ($person->firstname == '' && $person->lastname == '') {
154 7
            $this->contact_details['lastname'] = "Person #{$person->id}";
155
        } else {
156
            $this->contact_details['firstname'] = $person->firstname;
157
            $this->contact_details['lastname'] = $person->lastname;
158
        }
159
160 7
        foreach (['handphone', 'workphone', 'homephone', 'email', 'homepage'] as $property) {
161 7
            if ($person->$property) {
162
                $this->contact_details[$property] = $person->$property;
163
            }
164
        }
165
166 7
        if (   $this->_config->get('jabber_enable_presence')
167 7
            && $person->get_parameter('org.openpsa.jabber', 'jid')) {
168
            $this->contact_details['jid'] = $person->get_parameter('org.openpsa.jabber', 'jid');
169
        }
170
171 7
        if (   $this->_config->get('skype_enable_presence')
172 7
            && $person->get_parameter('org.openpsa.skype', 'name')) {
173
            $this->contact_details['skype'] = $person->get_parameter('org.openpsa.skype', 'name');
174
        }
175
176 7
        return true;
177
    }
178
179 8
    private function _render_name(string $fallback_image) : string
180
    {
181 8
        $name = "<span class=\"given-name\">{$this->contact_details['firstname']}</span> <span class=\"family-name\">{$this->contact_details['lastname']}</span>";
182
183 8
        $url = false;
184
185 8
        if ($this->link) {
186
            $url = $this->link;
187 8
        } elseif ($this->link_contacts && !empty($this->contact_details['guid'])) {
188 8
            if (!self::$_contacts_url) {
189
                $this->link_contacts = false;
190
            } else {
191 8
                $url = self::$_contacts_url . 'person/' . $this->contact_details['guid'] . '/';
192
            }
193
        }
194
195 8
        $name = $this->get_image('thumbnail', $fallback_image) . $name;
196
197 8
        if ($url) {
198 8
            $name = '<a href="' . $url . '">' . $name . '</a>';
199
        }
200
201 8
        return $name;
202
    }
203
204 9
    public function get_image($type, $fallback) : string
205
    {
206 9
        $attachments = org_openpsa_helpers::get_dm2_attachments($this->person, 'photo');
207 9
        if (!empty($attachments[$type])) {
208
            return '<img class="photo" src="' . midcom_db_attachment::get_url($attachments[$type]) . '">';
209
        }
210 9
        if (   $this->_config->get('gravatar_enable')
211 9
            && !empty($this->contact_details['email'])) {
212
            $size = ($type == 'view') ? 500 : 32;
213
            $gravatar_url = "https://www.gravatar.com/avatar/" . md5(strtolower(trim($this->contact_details['email']))) . "?s=" . $size . '&d=identicon';
214
            return "<img src=\"{$gravatar_url}\" class=\"photo\" />\n";
215
        }
216 9
        return '<i class="fa fa-' . $fallback . '"></i>';
217
    }
218
219
    /**
220
     * Show selected person object inline. Outputs hCard XHTML.
221
     */
222 9
    public function show_inline() : string
223
    {
224 9
        if (!$this->_data_read_ok) {
225 2
            return '';
226
        }
227 7
        self::add_head_elements();
228 7
        $inline_string = '';
229
230
        // Start the vCard
231 7
        $inline_string .= "<span class=\"vcard\">";
232
233 7
        if (!empty($this->contact_details['guid'])) {
234
            // Identifier
235 7
            $inline_string .= "<span class=\"uid\" style=\"display: none;\">{$this->contact_details['guid']}</span>";
236
        }
237
238
        // The name sequence
239 7
        $inline_string .= "<span class=\"n\">";
240 7
        $inline_string .= $this->_render_name('address-card-o');
241 7
        $inline_string .= "</span>";
242
243 7
        $inline_string .= "</span>";
244
245 7
        return $inline_string;
246
    }
247
248
    /**
249
     * Show the selected person. Outputs hCard XHTML.
250
     */
251 2
    public function show()
252
    {
253 2
        if (!$this->_data_read_ok) {
254
            return false;
255
        }
256 2
        self::add_head_elements();
257
        // Start the vCard
258 2
        echo "<div class=\"vcard\" id=\"org_openpsa_widgets_contact-{$this->contact_details['guid']}\">\n";
259 2
        if ($this->prefix_html) {
260
            echo $this->prefix_html;
261
        }
262
263 2
        if (!empty($this->contact_details['guid'])) {
264
            // Identifier
265 2
            echo "<span class=\"uid\" style=\"display: none;\">{$this->contact_details['guid']}</span>";
266
        }
267
268
        // The Name sequence
269 2
        echo "<div class=\"n\">\n";
270 2
        echo $this->_render_name('user-o');
271 2
        echo "</div>\n";
272
273
        // Contact information sequence
274 2
        echo "<ul class=\"contact_information\">\n";
275 2
        if ($this->extra_html) {
276
            echo $this->extra_html;
277
        }
278
279 2
        $this->_show_groups();
280
281 2
        $this->_show_phone_number('handphone', 'mobile');
282 2
        $this->_show_phone_number('workphone', 'phone');
283 2
        $this->_show_phone_number('homephone', 'home');
284
285 2
        if (!empty($this->contact_details['email'])) {
286
            echo "<li><a title=\"{$this->contact_details['email']}\" href=\"mailto:{$this->contact_details['email']}\"><i class=\"fa fa-envelope-o\"></i>{$this->contact_details['email']}</a></li>\n";
287
        }
288
289 2
        if (!empty($this->contact_details['skype'])) {
290
            echo "<li>";
291
            echo "<a href=\"skype:{$this->contact_details['skype']}?call\"><i class=\"fa fa-skype\"></i>{$this->contact_details['skype']}</a></li>\n";
292
        }
293
294
        // Instant messaging contact information
295 2
        if (!empty($this->contact_details['jid'])) {
296
            echo "<li>";
297
            echo "<a href=\"xmpp:{$this->contact_details['jid']}\"";
298
            $edgar_url = $this->_config->get('jabber_edgar_url');
299
            if (!empty($edgar_url)) {
300
                echo " style=\"background-repeat: no-repeat;background-image: url('{$edgar_url}?jid={$this->contact_details['jid']}&type=image');\"";
301
            }
302
            echo "><i class=\"fa fa-comment-o\"></i>{$this->contact_details['jid']}</a></li>\n";
303
        }
304
305 2
        if (!empty($this->contact_details['homepage'])) {
306
            echo "<li><a title=\"{$this->contact_details['homepage']}\" href=\"{$this->contact_details['homepage']}\"><i class=\"fa fa-globe\"></i>{$this->contact_details['homepage']}</a></li>\n";
307
        }
308
309 2
        echo "</ul>\n";
310 2
        echo "</div>\n";
311 2
    }
312
313 2
    private function _show_phone_number(string $field, string $type)
314
    {
315 2
        if (!empty($this->contact_details[$field])) {
316
            echo "<li><a title=\"Dial {$this->contact_details[$field]}\" href=\"tel:{$this->contact_details[$field]}\"><i class=\"fa fa-{$type}\"></i>{$this->contact_details[$field]}</a></li>\n";
317
        }
318 2
    }
319
320 2
    private function _show_groups()
321
    {
322 2
        if (   !$this->show_groups
323 2
            || empty($this->contact_details['id'])) {
324
            return;
325
        }
326 2
        $link_contacts = $this->link_contacts && self::$_contacts_url;
327
328 2
        $mc = org_openpsa_contacts_member_dba::new_collector('uid', $this->contact_details['id']);
329 2
        $mc->add_constraint('gid.orgOpenpsaObtype', '>=', org_openpsa_contacts_group_dba::ORGANIZATION);
330
331 2
        foreach ($mc->get_rows(['gid', 'extra']) as $data) {
332
            try {
333
                $group = org_openpsa_contacts_group_dba::get_cached($data['gid']);
334
            } catch (midcom_error $e) {
335
                $e->log();
336
                continue;
337
            }
338
339
            echo "<li>";
340
341
            if ($data['extra']) {
342
                echo "<span class=\"title\">" . htmlspecialchars($data['extra']) . "</span>, ";
343
            }
344
345
            $group_label = htmlspecialchars($group->get_label());
0 ignored issues
show
Bug introduced by
The method get_label() does not exist on midcom_core_dbaobject. It seems like you code against a sub-type of midcom_core_dbaobject such as org_openpsa_calendar_event_dba or org_openpsa_invoices_invoice_dba or net_nemein_tag_tag_dba or org_openpsa_invoices_invoice_item_dba or midcom_db_parameter or org_openpsa_calendar_event_member_dba or org_openpsa_sales_salesproject_offer_dba or midcom_db_topic or net_nemein_tag_link_dba or org_openpsa_invoices_billing_data_dba or org_openpsa_directmarketing_campaign_member_dba or org_openpsa_contacts_group_dba or midcom_db_person or midcom_db_member or org_openpsa_projects_project or org_openpsa_calendar_event_resource_dba or midcom_db_group or org_openpsa_projects_task_dba or org_openpsa_documents_document_dba. ( Ignorable by Annotation )

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

345
            $group_label = htmlspecialchars($group->/** @scrutinizer ignore-call */ get_label());
Loading history...
346
            if ($link_contacts) {
347
                $group_label = "<a href=\"" . self::$_contacts_url . "group/{$group->guid}/\"><i class=\"fa fa-users\"></i>" . $group_label . '</a>';
348
            }
349
350
            echo "<span class=\"organization-name\">{$group_label}</span>";
351
            echo "</li>\n";
352
        }
353 2
    }
354
355
    /**
356
     * Renderer for organization address cards
357
     */
358 1
    public static function show_address_card($customer, $cards)
359
    {
360 1
        $cards_to_show = [];
361 1
        $multiple_addresses = false;
362 1
        $inherited_cards_only = true;
363 1
        $default_shown = false;
364 1
        $siteconfig = org_openpsa_core_siteconfig::get_instance();
365 1
        $contacts_url = $siteconfig->get_node_full_url('org.openpsa.contacts');
366
367 1
        foreach ($cards as $cardname) {
368 1
            if ($cardname == 'visiting') {
369 1
                if ($customer->street) {
370
                    $default_shown = true;
371
                    $cards_to_show[] = $cardname;
372
                }
373 1
                continue;
374
            }
375
376 1
            $property = $cardname . 'Street';
377
378 1
            if (empty($cards_to_show)) {
379 1
                if ($customer->$property) {
380
                    $inherited_cards_only = false;
381
                    $cards_to_show[] = $cardname;
382 1
                } elseif (!$default_shown && $customer->street) {
383
                    $default_shown = true;
384 1
                    $cards_to_show[] = $cardname;
385
                }
386
            } elseif (    $customer->$property
387
                      || ($customer->street && !$inherited_cards_only && !$default_shown)) {
388
                $inherited_cards_only = false;
389
                $multiple_addresses = true;
390
                $cards_to_show[] = $cardname;
391
            }
392
        }
393
394 1
        if (empty($cards_to_show)) {
395 1
            return;
396
        }
397
398
        $root_group = org_openpsa_contacts_interface::find_root_group();
399
        $parent = $customer->get_parent();
400
        $parent_name = false;
401
        if ($parent->id != $root_group->id) {
402
            $parent_name = $parent->get_label();
403
        }
404
405
        foreach ($cards_to_show as $cardname) {
406
            echo '<div class="vcard">';
407
            if (   $multiple_addresses
408
                || (   $cardname != 'visiting'
409
                    && !$inherited_cards_only)) {
410
                echo '<div style="text-align:center"><em>' . midcom::get()->i18n->get_string($cardname . ' address', 'org.openpsa.contacts') . "</em></div>\n";
411
            }
412
            echo "<strong>\n";
413
            if ($parent_name) {
414
                echo '<a href="' . $contacts_url . 'group/' . $parent->guid . '/">' . $parent_name . "</a><br />\n";
0 ignored issues
show
Bug introduced by
Are you sure $contacts_url of type false|mixed|null 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

414
                echo '<a href="' . /** @scrutinizer ignore-type */ $contacts_url . 'group/' . $parent->guid . '/">' . $parent_name . "</a><br />\n";
Loading history...
415
            }
416
417
            $label = $customer->get_label();
418
419
            if ($cardname != 'visiting') {
420
                $label_property = $cardname . '_label';
421
                $label = $customer->$label_property;
422
            }
423
424
            echo $label . "\n";
425
            echo "</strong>\n";
426
427
            $property_street = 'street';
428
            $property_postcode = 'postcode';
429
            $property_city = 'city';
430
431
            if ($cardname != 'visiting') {
432
                $property_street = $cardname . 'Street';
433
                $property_postcode = $cardname . 'Postcode';
434
                $property_city = $cardname . 'City';
435
            }
436
            if ($customer->$property_street) {
437
                echo "<p>{$customer->$property_street}<br />\n";
438
                echo "{$customer->$property_postcode} {$customer->$property_city}</p>\n";
439
            } elseif ($customer->street) {
440
                echo "<p>{$customer->street}<br />\n";
441
                echo "{$customer->postcode} {$customer->city}</p>\n";
442
            }
443
            echo "</div>\n";
444
        }
445
    }
446
}
447