Passed
Push — master ( 4cca2c...a3e137 )
by Andreas
27:35 queued 11s
created

org_openpsa_contacts_interface   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 222
Duplicated Lines 0 %

Test Coverage

Coverage 16.66%

Importance

Changes 0
Metric Value
eloc 117
dl 0
loc 222
ccs 20
cts 120
cp 0.1666
rs 9.0399
c 0
b 0
f 0
wmc 42

8 Methods

Rating   Name   Duplication   Size   Complexity  
B _update_from_hcard() 0 35 11
A _check_person_url() 0 18 4
B _get_data_from_url() 0 44 9
A check_url() 0 26 5
A _on_reindex() 0 13 1
A find_root_group() 0 35 4
A _check_group_url() 0 14 3
A resolve_object_link() 0 11 5

How to fix   Complexity   

Complex Class

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

1
<?php
2
/**
3
 * @package org.openpsa.contacts
4
 * @author Nemein Oy http://www.nemein.com/
5
 * @copyright Nemein Oy http://www.nemein.com/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
use midcom\datamanager\datamanager;
10
11
/**
12
 * OpenPSA Contact registers/user manager
13
 *
14
 * @package org.openpsa.contacts
15
 */
16
class org_openpsa_contacts_interface extends midcom_baseclasses_components_interface
17
implements midcom_services_permalinks_resolver
18
{
19
    /**
20
     * Prepares the component's indexer client
21
     */
22
    public function _on_reindex($topic, midcom_helper_configuration $config, midcom_services_indexer $indexer)
23
    {
24
        $qb_organisations = org_openpsa_contacts_group_dba::new_query_builder();
25
        $organisation_dm = datamanager::from_schemadb($config->get('schemadb_group'));
0 ignored issues
show
Bug introduced by
It seems like $config->get('schemadb_group') can also be of type false; however, parameter $path of midcom\datamanager\datamanager::from_schemadb() 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

25
        $organisation_dm = datamanager::from_schemadb(/** @scrutinizer ignore-type */ $config->get('schemadb_group'));
Loading history...
26
27
        $qb_persons = org_openpsa_contacts_person_dba::new_query_builder();
28
        $person_dm = datamanager::from_schemadb($config->get('schemadb_person'));
29
30
        $indexer = new org_openpsa_contacts_midcom_indexer($topic, $indexer);
31
        $indexer->add_query('organisations', $qb_organisations, $organisation_dm);
32
        $indexer->add_query('persons', $qb_persons, $person_dm);
33
34
        return $indexer;
35
    }
36
37
    /**
38
     * Locates the root group
39
     */
40 16
    public static function find_root_group(string $name = '__org_openpsa_contacts') : midcom_db_group
41
    {
42 16
        static $root_groups = [];
43
44
        //Check if we have already initialized
45 16
        if (!empty($root_groups[$name])) {
46 15
            return $root_groups[$name];
47
        }
48
49 1
        $qb = midcom_db_group::new_query_builder();
50 1
        $qb->add_constraint('owner', '=', 0);
51 1
        $qb->add_constraint('name', '=', $name);
52
53 1
        $results = $qb->execute();
54
55 1
        if (!empty($results)) {
56
            $root_groups[$name] = end($results);
57
        } else {
58 1
            debug_add("OpenPSA Contacts root group could not be found", MIDCOM_LOG_WARN);
59
60
            //Attempt to  auto-initialize the group.
61 1
            midcom::get()->auth->request_sudo('org.openpsa.contacts');
62 1
            $grp = new midcom_db_group();
63 1
            $grp->owner = 0;
64 1
            $grp->name = $name;
65 1
            $grp->official = midcom::get()->i18n->get_string($name, 'org.openpsa.contacts');
66 1
            $ret = $grp->create();
67 1
            midcom::get()->auth->drop_sudo();
68 1
            if (!$ret) {
69
                throw new midcom_error("Could not auto-initialize the module, group creation failed: " . midcom_connection::get_error_string());
70
            }
71 1
            $root_groups[$name] = $grp;
72
        }
73
74 1
        return $root_groups[$name];
75
    }
76
77
    public function resolve_object_link(midcom_db_topic $topic, midcom_core_dbaobject $object) : ?string
78
    {
79
        if (   $object instanceof org_openpsa_contacts_group_dba
80
            || $object instanceof midcom_db_group) {
81
            return "group/{$object->guid}/";
82
        }
83
        if (   $object instanceof org_openpsa_contacts_person_dba
84
            || $object instanceof midcom_db_person) {
85
            return "person/{$object->guid}/";
86
        }
87
        return null;
88
    }
89
90
    private function _get_data_from_url(string $url) : array
91
    {
92
        $data = [];
93
94
        // TODO: Error handling
95
        $client = new org_openpsa_httplib();
96
        $html = $client->get($url);
97
98
        // Check for ICBM coordinate information
99
        if ($icbm = org_openpsa_httplib_helpers::get_meta_value($html, 'icbm')) {
100
            $data['icbm'] = $icbm;
101
        }
102
103
        // Check for RSS feed
104
        $rss_url = org_openpsa_httplib_helpers::get_link_values($html, 'alternate');
105
106
        if (!empty($rss_url)) {
107
            $data['rss_url'] = $rss_url[0]['href'];
108
109
            // We have a feed URL, but we should check if it is GeoRSS as well
110
            $items = net_nemein_rss_fetch::raw_fetch($data['rss_url'])->get_items();
111
112
            if (   !empty($items)
113
                && (   $items[0]->get_latitude()
114
                    || $items[0]->get_longitude())) {
115
                // This is a GeoRSS feed
116
                $data['georss_url'] = $data['rss_url'];
117
            }
118
        }
119
120
        $microformats = Mf2\parse($html);
121
        $hcards = [];
122
        foreach ($microformats['items'] as $item) {
123
            if (in_array('h-card', $item['type'])) {
124
                $hcards[] = $item['properties'];
125
            }
126
        }
127
128
        if (!empty($hcards)) {
129
            // We have found hCard data here
130
            $data['hcards'] = $hcards;
131
        }
132
133
        return $data;
134
    }
135
136
    /**
137
     * AT handler for fetching Semantic Web data for person or group
138
     */
139
    public function check_url(array $args, midcom_baseclasses_components_cron_handler $handler) : bool
140
    {
141
        if (array_key_exists('person', $args)) {
142
            $type = 'person';
143
        } elseif (array_key_exists('group', $args)) {
144
            $type = 'group';
145
        } else {
146
            $handler->print_error('Person or Group GUID not set, aborting');
147
            return false;
148
        }
149
150
        $classname = 'org_openpsa_contacts_' . $type . '_dba';
151
        $method = '_check_' . $type . '_url';
152
        $guid = $args[$type];
153
154
        try {
155
            $object = new $classname($guid);
156
        } catch (midcom_error $e) {
157
            $handler->print_error($type . " {$guid} not found, error " . $e->getMessage());
158
            return false;
159
        }
160
        if (!$object->homepage) {
161
            $handler->print_error($type . " {$object->guid} has no homepage, skipping");
162
            return false;
163
        }
164
        return $this->$method($object);
165
    }
166
167
    private function _check_group_url(org_openpsa_contacts_group_dba $group) : bool
168
    {
169
        $data = $this->_get_data_from_url($group->homepage);
170
171
        // TODO: We can use a lot of other data too
172
        if (array_key_exists('hcards', $data)) {
173
            // Process those hCard values that are interesting for us
174
            foreach ($data['hcards'] as $hcard) {
175
                $this->_update_from_hcard($group, $hcard);
176
            }
177
178
            $group->update();
179
        }
180
        return true;
181
    }
182
183
    private function _check_person_url(org_openpsa_contacts_person_dba $person) : bool
184
    {
185
        $data = $this->_get_data_from_url($person->homepage);
186
187
        if (array_key_exists('rss_url', $data)) {
188
            // Instead of using the ICBM position data directly we can subscribe to it so we get modifications too
189
            $person->set_parameter('net.nemein.rss', 'url', $data['rss_url']);
190
        }
191
192
        if (array_key_exists('hcards', $data)) {
193
            // Process those hCard values that are interesting for us
194
            foreach ($data['hcards'] as $hcard) {
195
                $this->_update_from_hcard($person, $hcard);
196
            }
197
198
            $person->update();
199
        }
200
        return true;
201
    }
202
203
    private function _update_from_hcard($object, array $hcard)
204
    {
205
        foreach ($hcard as $key => $val) {
206
            switch ($key) {
207
                case 'email':
208
                    $object->email = reset($val);
209
                    break;
210
211
                case 'tel':
212
                    $object->workphone = reset($val);
213
                    break;
214
215
                case 'note':
216
                    $object->extra = reset($val);
217
                    break;
218
219
                case 'photo':
220
                    // TODO: Importing the photo would be cool
221
                    break;
222
223
                case 'adr':
224
                    $adr = reset($val);
225
                    if (array_key_exists('street-address', $adr['properties'])) {
226
                        $object->street = reset($adr['properties']['street-address']);
227
                    }
228
                    if (array_key_exists('postal-code', $adr['properties'])) {
229
                        $object->postcode = reset($adr['properties']['postal-code']);
230
                    }
231
                    if (array_key_exists('locality', $adr['properties'])) {
232
                        $object->city = reset($adr['properties']['locality']);
233
                    }
234
                    if (array_key_exists('country-name', $adr['properties'])) {
235
                        $object->country = reset($adr['properties']['country-name']);
236
                    }
237
                    break;
238
            }
239
        }
240
    }
241
}
242