GContactToVCard::readGroups()   B
last analyzed

Complexity

Conditions 10
Paths 7

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 10
eloc 9
c 1
b 0
f 1
nc 7
nop 1
dl 0
loc 11
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
namespace SKien\Google;
5
6
use SKien\VCard\VCard;
0 ignored issues
show
Bug introduced by
The type SKien\VCard\VCard was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use SKien\VCard\VCardAddress;
0 ignored issues
show
Bug introduced by
The type SKien\VCard\VCardAddress was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use SKien\VCard\VCardContact;
0 ignored issues
show
Bug introduced by
The type SKien\VCard\VCardContact was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
9
10
/**
11
 * Class to convert a Google contact to a vcard.
12
 *
13
 * @author Stefanius <[email protected]>
14
 * @copyright MIT License - see the LICENSE file for details
15
 */
16
class GContactToVCard extends VCardContact
17
{
18
    /** @var int  options to control the export     */
19
    protected int $iOptions = 0;
20
    /** @var array<string,string>   group maping resourceName -> groupName     */
21
    protected array $aGroups = [];
22
    /** @var string surrogate category name to use for 'starred' contacts
23
     *              (-> contacts belonging to the predefined system group 'starred')     */
24
    protected string $strStarredCategory = '';
25
26
    /**
27
     * Constructor.
28
     * @param int $iOptions
29
     */
30
    protected function __construct(array $aGroupNames, int $iOptions)
31
    {
32
        $this->aGroups = $aGroupNames;
33
        $this->iOptions = $iOptions;
34
    }
35
36
    /**
37
     * Sets the category to use for 'starred' contacts.
38
     * @param string $strStarredCategory
39
     */
40
    public function setStarredCategory(string $strStarredCategory) : void
41
    {
42
        $this->strStarredCategory = $strStarredCategory;
43
    }
44
45
    /**
46
     * Load data from given Google contact.
47
     * @param GContact $oGContact
48
     * @return bool
49
     */
50
    public function loadGContact(GContact $oGContact) : bool
51
    {
52
        // GContact::PF_NAMES is defined as singleton so it must exist exactly one time
53
        if (isset($oGContact[GContact::PF_NAMES]) && is_array($oGContact[GContact::PF_NAMES]) && count($oGContact[GContact::PF_NAMES]) == 1) {
54
            // PF_NAMES is always a singleton
55
            $this->strLastName = $oGContact[GContact::PF_NAMES][0]['familyName'] ?? '';
0 ignored issues
show
Bug Best Practice introduced by
The property strLastName does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
56
            $this->strFirstName = $oGContact[GContact::PF_NAMES][0]['givenName'] ?? '';
0 ignored issues
show
Bug Best Practice introduced by
The property strFirstName does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
57
            $this->strPrefix = $oGContact[GContact::PF_NAMES][0]['honorificPrefix'] ?? '';
0 ignored issues
show
Bug Best Practice introduced by
The property strPrefix does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
58
            $this->strSuffix = $oGContact[GContact::PF_NAMES][0]['honorificSuffix'] ?? '';
0 ignored issues
show
Bug Best Practice introduced by
The property strSuffix does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
59
        } else {
60
            return false;
61
        }
62
63
        $this->readAddresses($oGContact);
64
        $this->readPhoneNumbers($oGContact);
65
        $this->readEmailAddresses($oGContact);
66
        $this->readHomepages($oGContact);
67
        $this->readOrganization($oGContact);
68
        $this->readMiscellaneous($oGContact);
69
        $this->readPhoto($oGContact);
70
71
        return true;
72
    }
73
74
    /**
75
     * Reads the address data.
76
     * Values taken from the GContact:
77
     * - type
78
     * - streetAddress
79
     * - postalCode
80
     * - city
81
     * - POBox
82
     * - ext. address
83
     * - country / countryCode
84
     * @param GContact $oGContact
85
     */
86
    protected function readAddresses(GContact $oGContact) : void
87
    {
88
        if (isset($oGContact[GContact::PF_ADDRESSES]) && is_array($oGContact[GContact::PF_ADDRESSES])) {
89
            foreach ($oGContact[GContact::PF_ADDRESSES] as $aAddress) {
90
                $oAddress = new VCardAddress();
91
                $oAddress->setType($this->getAddressTypeForVCard($aAddress['type'] ?? ''));
92
                $oAddress->setStr($aAddress['streetAddress'] ?? '');
93
                $oAddress->setPostcode($aAddress['postalCode'] ?? '');
94
                $oAddress->setCity($aAddress['city'] ?? '');
95
                $oAddress->setPOBox($aAddress['poBox'] ?? '');
96
                $oAddress->setExtAddress($aAddress['extendedAddress'] ?? '');
97
                if (isset($aAddress['country'])) {
98
                    $oAddress->setCountry($aAddress['country']);
99
                } else {
100
                    $oAddress->setCountry($aAddress['countryCode'] ?? '');
101
                }
102
                $this->addAddress($oAddress, $oGContact->isPrimaryItem($aAddress));
103
            }
104
        }
105
    }
106
107
    /**
108
     * Reads phone numbers.
109
     * @param GContact $oGContact
110
     */
111
    protected function readPhoneNumbers(GContact $oGContact) : void
112
    {
113
        if (isset($oGContact[GContact::PF_PHONE_NUMBERS]) && is_array($oGContact[GContact::PF_PHONE_NUMBERS])) {
114
            foreach ($oGContact[GContact::PF_PHONE_NUMBERS] as $aPhone) {
115
                $strType = $this->getPhoneTypeForVCard($aPhone['type'] ?? '');
116
                $this->addPhone($aPhone['value'] ?? '', $strType, $oGContact->isPrimaryItem($aPhone));
117
            }
118
        }
119
    }
120
121
    /**
122
     * Reads email addresses.
123
     * Since the used VCard library don't support the different possible types of
124
     * email addresses (home, work, blog,...), we ignore the type
125
     * @param GContact $oGContact
126
     */
127
    protected function readEmailAddresses(GContact $oGContact) : void
128
    {
129
        if (isset($oGContact[GContact::PF_EMAIL_ADDRESSES]) && is_array($oGContact[GContact::PF_EMAIL_ADDRESSES])) {
130
            foreach ($oGContact[GContact::PF_EMAIL_ADDRESSES] as $aMail) {
131
                $this->addEMail($aMail['value'] ?? '', $oGContact->isPrimaryItem($aMail));
132
            }
133
        }
134
    }
135
136
    /**
137
     * Reads homepage/url data.
138
     * Since the used VCard library don't support the different possible types of
139
     * homepages (home, work, blog,...), we ignore the type.
140
     * @param GContact $oGContact
141
     */
142
    protected function readHomepages(GContact $oGContact) : void
143
    {
144
        if (isset($oGContact[GContact::PF_URLS]) && is_array($oGContact[GContact::PF_URLS])) {
145
            foreach ($oGContact[GContact::PF_URLS] as $aURL) {
146
                $this->addHomepage($aURL['value'] ?? '');
147
            }
148
        }
149
    }
150
151
    /**
152
     * Reads organization related data.
153
     * @param GContact $oGContact
154
     */
155
    protected function readOrganization(GContact $oGContact) : void
156
    {
157
        if (isset($oGContact[GContact::PF_ORGANIZATIONS]) && is_array($oGContact[GContact::PF_ORGANIZATIONS]) && count($oGContact[GContact::PF_ORGANIZATIONS]) > 0 ) {
158
            // use first org. contained...
159
            $aOrg = $oGContact[GContact::PF_ORGANIZATIONS][0];
160
161
            $this->setOrganisation($aOrg['name'] ?? '');
162
            $this->setPosition($aOrg['title'] ?? '');
163
            $this->setSection($aOrg['department'] ?? '');
164
        }
165
    }
166
167
    /**
168
     * Reads photo from GContact.
169
     * If any custom photo is set, the first of that is used for the portrait.
170
     * If no custom photo found, the first conaitned deafult photo (created by google) is
171
     * set as VCard portrait, if configured in the options.
172
     * @param GContact $oGContact
173
     */
174
    protected function readPhoto(GContact $oGContact) : void
175
    {
176
        if (($this->iOptions & VCardExport::OPT_EXPORT_PHOTO) !== 0) {
177
            if (isset($oGContact[GContact::PF_PHOTOS]) && is_array($oGContact[GContact::PF_PHOTOS])) {
178
                // in the first loop we search for the first custom set photo...
179
                foreach ($oGContact[GContact::PF_PHOTOS] as $aPhoto) {
180
                    if (isset($aPhoto['url']) && (!isset($aPhoto['default']) || $aPhoto['default'] == false)) {
181
                        $this->setPortraitFile($aPhoto['url']);
182
                        return;
183
                    }
184
                }
185
                // ... and if configured, we look in a second loop for the first default created photo...
186
                if (($this->iOptions & VCardExport::OPT_USE_DEFAULT_PHOTO) !== 0) {
187
                    foreach ($oGContact[GContact::PF_PHOTOS] as $aPhoto) {
188
                        if (isset($aPhoto['url'])) {
189
                            $this->setPortraitFile($aPhoto['url']);
190
                            return;
191
                        }
192
                    }
193
                }
194
            }
195
        }
196
    }
197
198
    /**
199
     * Reads the group membership as VCard categories.
200
     * Only works, if group mapping is available or at least the 'starred' membership
201
     * should be mapped to a category.
202
     * @param GContact $oGContact
203
     */
204
    protected function readGroups(GContact $oGContact) : void
205
    {
206
        if (count($this->aGroups) > 0 || !empty($this->strStarredCategory)) {
207
            if (isset($oGContact[GContact::PF_MEMBERSHIPS]) && is_array($oGContact[GContact::PF_MEMBERSHIPS])) {
208
                foreach ($oGContact[GContact::PF_MEMBERSHIPS] as $aMembership) {
209
                    if (isset($aMembership['contactGroupMembership'])) {
210
                        $strResourceName = $aMembership['contactGroupMembership']['contactGroupResourceName'] ?? '';
211
                        if (!empty($this->strStarredCategory) && $strResourceName == 'contactGroups/starred') {
212
                            $this->addCategory($this->strStarredCategory);
213
                        } else if (isset($this->aGroups[$strResourceName])) {
214
                            $this->addCategory($this->aGroups[$strResourceName]);
215
                        }
216
                    }
217
                }
218
            }
219
        }
220
    }
221
222
    /**
223
     * Reads miscealaneous data and set it to the VCard contact.
224
     * - nickname
225
     * - biography -> note
226
     * - occupations -> role
227
     * - date of birth
228
     * - gender
229
     * @param GContact $oGContact
230
     */
231
    protected function readMiscellaneous(GContact $oGContact) : void
232
    {
233
        $this->setNickName($oGContact[GContact::PF_NICKNAMES][0]['value'] ?? '');
234
        $this->setNote($oGContact[GContact::PF_BIOGRAPHIES][0]['value'] ?? '');
235
        $this->setRole($oGContact[GContact::PF_OCCUPATIONS][0]['value'] ?? '');
236
        if (($uxtsDoB = $oGContact->getDateOfBirth(GContact::DT_UNIX_TIMESTAMP)) > 0) {
237
            $this->setDateOfBirth($uxtsDoB);
238
        }
239
        $this->setGender($oGContact[GContact::PF_GENDERS][0]['value'] ?? '');
240
    }
241
242
    /**
243
     * Get the VCard address type from the GContact address type.
244
     * 'home' and 'work' is converted to 'HOME' and 'WORK', for 'other'
245
     * the VCard type is left empty.
246
     * @param string $strGType
247
     * @return string
248
     */
249
    private function getAddressTypeForVCard($strGType) : string
250
    {
251
        $strType = '';
252
        if (strpos(strtolower($strGType), 'home') !== false) {
253
            $strType = 'HOME';
254
        } else if (strpos(strtoupper($strGType), 'work') !== false) {
255
            $strType = 'WORK';
256
        }
257
        return $strType;
258
    }
259
260
    /**
261
     * Get the VCard phone type from the GContact phone type.
262
     * 'home', 'mobile' and 'work' is converted to 'HOME', 'CELL' and 'WORK', all
263
     * other types are set to 'VOICE'.
264
     * @param string $strVCType
265
     * @return string
266
     */
267
    private function getPhoneTypeForVCard(string $strGType) : string
268
    {
269
        $strType = VCard::VOICE;
270
        if (strpos(strtolower($strGType), 'home') !== false) {
271
            $strType = VCard::HOME;
272
        } else if (strpos(strtolower($strGType), 'mobile') !== false) {
273
            $strType = VCard::CELL;
274
        } else if (strpos(strtolower($strGType), 'work') !== false) {
275
            $strType = VCard::WORK;
276
        }
277
        return $strType;
278
    }
279
}