Passed
Branch master (05c266)
by Andreas
09:55
created

org_openpsa_widgets_contact::get()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 3
nop 1
dl 0
loc 17
ccs 10
cts 10
cp 1
crap 3
rs 9.9332
c 0
b 0
f 0
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
use midcom\datamanager\storage\blobs;
15
16
/**
17
 * @package org.openpsa.widgets
18
 */
19
class org_openpsa_widgets_contact
20
{
21
    use midcom_baseclasses_components_base;
0 ignored issues
show
introduced by
The trait midcom_baseclasses_components_base requires some properties which are not provided by org_openpsa_widgets_contact: $i18n, $head
Loading history...
22
23
    /**
24
     * Contact information of the person being displayed
25
     */
26
    public $contact_details = [
27
        'guid' => '',
28
        'id' => '',
29
        'firstname' => '',
30
        'lastname' => ''
31
    ];
32
33
    /**
34
     * Optional URI to person details
35
     *
36
     * @var string
37
     */
38
    public $link;
39
40
    /**
41
     * Optional HTML to be placed into the card
42
     *
43
     * @var string
44
     */
45
    public $extra_html;
46
47
    /**
48
     * Optional HTML to be placed into the card (before any other output in the DIV)
49
     *
50
     * @var string
51
     */
52
    public $prefix_html;
53
54
    /**
55
     * Whether to show person's groups in a list
56
     *
57
     * @var boolean
58
     */
59
    public $show_groups = true;
60
61
    /**
62
     * Whether to generate links to the groups using NAP
63
     *
64
     * @var boolean
65
     */
66
    var $link_contacts = true;
67
68
    /**
69
     * @var string
70
     */
71
    private static $_contacts_url;
72
73
    private $person;
74
75
    /**
76
     * Initializes the class and stores the selected person to be shown
77
     */
78 8
    public function __construct(midcom_db_person $person)
79
    {
80 8
        $this->_component = 'org.openpsa.widgets';
81
82 8
        if (null === self::$_contacts_url) {
0 ignored issues
show
introduced by
The condition null === self::_contacts_url is always false.
Loading history...
83 1
            $siteconfig = org_openpsa_core_siteconfig::get_instance();
84 1
            self::$_contacts_url = $siteconfig->get_node_full_url('org.openpsa.contacts');
85
        }
86
87
        // Read properties of provided person object
88
        // TODO: Handle groups as well
89 8
        $this->person = $person;
90 8
        $this->read_object($person);
91
    }
92
93 10
    public static function add_head_elements()
94
    {
95
        static $added = false;
96 10
        if (!$added) {
97 1
            midcom::get()->head->add_stylesheet(MIDCOM_STATIC_URL . "/org.openpsa.widgets/hcard.css");
98 1
            midcom::get()->head->add_stylesheet(MIDCOM_STATIC_URL . '/stock-icons/font-awesome-4.7.0/css/font-awesome.min.css');
99 1
            $added = true;
100
        }
101
    }
102
103
    /**
104
     * Retrieve an object, uses in-request caching
105
     *
106
     * @param mixed $src GUID of object (ids work but are discouraged)
107
     */
108 10
    public static function get($src) : self
109
    {
110 10
        static $cache = [];
111
112 10
        if (isset($cache[$src])) {
113 4
            return $cache[$src];
114
        }
115
116
        try {
117 7
            $person = midcom_db_person::get_cached($src);
118 1
        } catch (midcom_error $e) {
119 1
            return $cache[$src] = new self(new midcom_db_person);
120
        }
121
122 6
        $cache[$person->guid] = new self($person);
123 6
        $cache[$person->id] = $cache[$person->guid];
124 6
        return $cache[$person->guid];
125
    }
126
127
    /**
128
     * Read properties of a person object and populate local fields accordingly
129
     */
130 8
    private function read_object(midcom_db_person $person)
131
    {
132
        // Database identifiers
133 8
        $this->contact_details['guid'] = $person->guid;
134 8
        $this->contact_details['id'] = $person->id;
135
136 8
        if ($person->guid == "") {
137 1
            $this->contact_details['lastname'] = $this->_l10n->get('no person');
138 7
        } elseif ($person->firstname == '' && $person->lastname == '') {
139
            $this->contact_details['lastname'] = "Person #{$person->id}";
140
        } else {
141 7
            $this->contact_details['firstname'] = $person->firstname;
142 7
            $this->contact_details['lastname'] = $person->lastname;
143
        }
144
145 8
        foreach (['handphone', 'workphone', 'homephone', 'email', 'homepage'] as $property) {
146 8
            if ($person->$property) {
147
                $this->contact_details[$property] = $person->$property;
148
            }
149
        }
150
151 8
        if (   $this->_config->get('jabber_enable_presence')
152 8
            && $person->get_parameter('org.openpsa.jabber', 'jid')) {
153
            $this->contact_details['jid'] = $person->get_parameter('org.openpsa.jabber', 'jid');
154
        }
155
156 8
        if (   $this->_config->get('skype_enable_presence')
157 8
            && $person->get_parameter('org.openpsa.skype', 'name')) {
158
            $this->contact_details['skype'] = $person->get_parameter('org.openpsa.skype', 'name');
159
        }
160
    }
161
162 8
    private function _render_name(string $fallback_image) : string
163
    {
164 8
        $name = "<span class=\"given-name\">{$this->contact_details['firstname']}</span> <span class=\"family-name\">{$this->contact_details['lastname']}</span>";
165
166 8
        $url = false;
167
168 8
        if ($this->link) {
169
            $url = $this->link;
170 8
        } elseif ($this->link_contacts && !empty($this->contact_details['guid'])) {
171 8
            if (!self::$_contacts_url) {
172
                $this->link_contacts = false;
173
            } else {
174 8
                $url = self::$_contacts_url . 'person/' . $this->contact_details['guid'] . '/';
175
            }
176
        }
177
178 8
        $name = $this->get_image('thumbnail', $fallback_image) . $name;
179
180 8
        if ($url) {
181 8
            $name = '<a href="' . $url . '">' . $name . '</a>';
182
        }
183
184 8
        return $name;
185
    }
186
187 9
    public function get_image(string $type, string $fallback) : string
188
    {
189 9
        $attachments = blobs::get_attachments($this->person, 'photo');
190 9
        if (!empty($attachments[$type])) {
191
            return '<img class="photo" src="' . midcom_db_attachment::get_url($attachments[$type]) . '">';
192
        }
193 9
        if (   $this->_config->get('gravatar_enable')
194 9
            && !empty($this->contact_details['email'])) {
195
            $size = ($type == 'view') ? 500 : 32;
196
            $gravatar_url = "https://www.gravatar.com/avatar/" . md5(strtolower(trim($this->contact_details['email']))) . "?s=" . $size . '&d=identicon';
197
            return "<img src=\"{$gravatar_url}\" class=\"photo\" />\n";
198
        }
199 9
        return '<i class="fa fa-' . $fallback . '"></i>';
200
    }
201
202
    /**
203
     * Show selected person object inline. Outputs hCard XHTML.
204
     */
205 9
    public function show_inline() : string
206
    {
207 9
        if (!$this->person->id) {
208 2
            return '';
209
        }
210 7
        self::add_head_elements();
211 7
        $inline_string = '';
212
213
        // Start the vCard
214 7
        $inline_string .= "<span class=\"vcard\">";
215
216 7
        if (!empty($this->contact_details['guid'])) {
217
            // Identifier
218 7
            $inline_string .= "<span class=\"uid\" style=\"display: none;\">{$this->contact_details['guid']}</span>";
219
        }
220
221
        // The name sequence
222 7
        $inline_string .= "<span class=\"n\">";
223 7
        $inline_string .= $this->_render_name('address-card-o');
224 7
        $inline_string .= "</span>";
225
226 7
        $inline_string .= "</span>";
227
228 7
        return $inline_string;
229
    }
230
231
    /**
232
     * Show the selected person. Outputs hCard XHTML.
233
     */
234 2
    public function show()
235
    {
236 2
        if (!$this->person->id) {
237
            return;
238
        }
239
240 2
        self::add_head_elements();
241
        // Start the vCard
242 2
        echo "<div class=\"vcard\" id=\"org_openpsa_widgets_contact-{$this->contact_details['guid']}\">\n";
243 2
        if ($this->prefix_html) {
244
            echo $this->prefix_html;
245
        }
246
247 2
        if (!empty($this->contact_details['guid'])) {
248
            // Identifier
249 2
            echo "<span class=\"uid\" style=\"display: none;\">{$this->contact_details['guid']}</span>";
250
        }
251
252
        // The Name sequence
253 2
        echo "<div class=\"n\">\n";
254 2
        echo $this->_render_name('user-o');
255 2
        echo "</div>\n";
256
257
        // Contact information sequence
258 2
        echo "<ul class=\"contact_information\">\n";
259 2
        if ($this->extra_html) {
260
            echo $this->extra_html;
261
        }
262
263 2
        $this->_show_groups();
264
265 2
        $this->_show_phone_number('handphone', 'mobile');
266 2
        $this->_show_phone_number('workphone', 'phone');
267 2
        $this->_show_phone_number('homephone', 'home');
268
269 2
        if (!empty($this->contact_details['email'])) {
270
            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";
271
        }
272
273 2
        if (!empty($this->contact_details['skype'])) {
274
            echo "<li>";
275
            echo "<a href=\"skype:{$this->contact_details['skype']}?call\"><i class=\"fa fa-skype\"></i>{$this->contact_details['skype']}</a></li>\n";
276
        }
277
278
        // Instant messaging contact information
279 2
        if (!empty($this->contact_details['jid'])) {
280
            echo "<li>";
281
            echo "<a href=\"xmpp:{$this->contact_details['jid']}\"";
282
            $edgar_url = $this->_config->get('jabber_edgar_url');
283
            if (!empty($edgar_url)) {
284
                echo " style=\"background-repeat: no-repeat;background-image: url('{$edgar_url}?jid={$this->contact_details['jid']}&type=image');\"";
285
            }
286
            echo "><i class=\"fa fa-comment-o\"></i>{$this->contact_details['jid']}</a></li>\n";
287
        }
288
289 2
        if (!empty($this->contact_details['homepage'])) {
290
            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";
291
        }
292
293 2
        echo "</ul>\n";
294 2
        echo "</div>\n";
295
    }
296
297 2
    private function _show_phone_number(string $field, string $type)
298
    {
299 2
        if (!empty($this->contact_details[$field])) {
300
            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";
301
        }
302
    }
303
304 2
    private function _show_groups()
305
    {
306 2
        if (   !$this->show_groups
307 2
            || empty($this->contact_details['id'])) {
308
            return;
309
        }
310 2
        $link_contacts = $this->link_contacts && self::$_contacts_url;
311
312 2
        $mc = org_openpsa_contacts_member_dba::new_collector('uid', $this->contact_details['id']);
313 2
        $mc->add_constraint('gid.orgOpenpsaObtype', '>=', org_openpsa_contacts_group_dba::ORGANIZATION);
314
315 2
        foreach ($mc->get_rows(['gid', 'extra']) as $data) {
316
            try {
317
                $group = org_openpsa_contacts_group_dba::get_cached($data['gid']);
318
            } catch (midcom_error $e) {
319
                $e->log();
320
                continue;
321
            }
322
323
            echo "<li>";
324
325
            if ($data['extra']) {
326
                echo "<span class=\"title\">" . htmlspecialchars($data['extra']) . "</span>, ";
327
            }
328
329
            $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

329
            $group_label = htmlspecialchars($group->/** @scrutinizer ignore-call */ get_label());
Loading history...
330
            if ($link_contacts) {
331
                $group_label = "<a href=\"" . self::$_contacts_url . "group/{$group->guid}/\"><i class=\"fa fa-users\"></i>" . $group_label . '</a>';
332
            }
333
334
            echo "<span class=\"organization-name\">{$group_label}</span>";
335
            echo "</li>\n";
336
        }
337
    }
338
339
    /**
340
     * Renderer for organization address cards
341
     */
342 1
    public static function show_address_card($customer, array $cards)
343
    {
344 1
        $cards_to_show = [];
345 1
        $multiple_addresses = false;
346 1
        $inherited_cards_only = true;
347 1
        $default_shown = false;
348 1
        $siteconfig = org_openpsa_core_siteconfig::get_instance();
349 1
        $contacts_url = $siteconfig->get_node_full_url('org.openpsa.contacts');
350
351 1
        foreach ($cards as $cardname) {
352 1
            if ($cardname == 'visiting') {
353 1
                if ($customer->street) {
354
                    $default_shown = true;
355
                    $cards_to_show[] = $cardname;
356
                }
357 1
                continue;
358
            }
359
360 1
            $property = $cardname . 'Street';
361
362 1
            if (empty($cards_to_show)) {
363 1
                if ($customer->$property) {
364 1
                    $inherited_cards_only = false;
365 1
                    $cards_to_show[] = $cardname;
366
                } elseif (!$default_shown && $customer->street) {
367
                    $default_shown = true;
368 1
                    $cards_to_show[] = $cardname;
369
                }
370
            } elseif (    $customer->$property
371
                      || ($customer->street && !$inherited_cards_only && !$default_shown)) {
372
                $inherited_cards_only = false;
373
                $multiple_addresses = true;
374
                $cards_to_show[] = $cardname;
375
            }
376
        }
377
378 1
        if (empty($cards_to_show)) {
379
            return;
380
        }
381
382 1
        $parent_name = false;
383 1
        if ($parent = $customer->get_parent()) {
384
            $root_group = org_openpsa_contacts_interface::find_root_group();
385
            if ($parent->id != $root_group->id) {
386
                $parent_name = $parent->get_label();
387
            }
388
        }
389
390 1
        foreach ($cards_to_show as $cardname) {
391 1
            echo '<div class="vcard">';
392 1
            if (   $multiple_addresses
393 1
                || (   $cardname != 'visiting'
394
                    && !$inherited_cards_only)) {
395 1
                echo '<div style="text-align:center"><em>' . midcom::get()->i18n->get_string($cardname . ' address', 'org.openpsa.contacts') . "</em></div>\n";
396
            }
397 1
            echo "<strong>\n";
398 1
            if ($parent_name) {
399
                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

399
                echo '<a href="' . /** @scrutinizer ignore-type */ $contacts_url . 'group/' . $parent->guid . '/">' . $parent_name . "</a><br />\n";
Loading history...
400
            }
401
402 1
            $label = $customer->get_label();
403
404 1
            if ($cardname != 'visiting') {
405 1
                $label_property = $cardname . '_label';
406 1
                $label = $customer->$label_property;
407
            }
408
409 1
            echo $label . "\n";
410 1
            echo "</strong>\n";
411
412 1
            $property_street = 'street';
413 1
            $property_postcode = 'postcode';
414 1
            $property_city = 'city';
415
416 1
            if ($cardname != 'visiting') {
417 1
                $property_street = $cardname . 'Street';
418 1
                $property_postcode = $cardname . 'Postcode';
419 1
                $property_city = $cardname . 'City';
420
            }
421 1
            if ($customer->$property_street) {
422 1
                echo "<p>{$customer->$property_street}<br />\n";
423 1
                echo "{$customer->$property_postcode} {$customer->$property_city}</p>\n";
424
            } elseif ($customer->street) {
425
                echo "<p>{$customer->street}<br />\n";
426
                echo "{$customer->postcode} {$customer->city}</p>\n";
427
            }
428 1
            echo "</div>\n";
429
        }
430
    }
431
}
432