GContactFromVCard::readAddresses()   B
last analyzed

Complexity

Conditions 7
Paths 11

Size

Total Lines 25
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 7
eloc 20
c 1
b 0
f 1
nc 11
nop 1
dl 0
loc 25
rs 8.6666
1
<?php
2
declare(strict_types=1);
3
4
namespace SKien\Google;
5
6
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...
7
8
/**
9
 * Class representing a GContact created from a VCard contact.
10
 * When creating a Google contact from a VCard contact, there are two important
11
 * points to keep in mind:
12
 *  1.  In order to use the categories from the VCard as group membership for the
13
 *      Google contact, the group name (...the category) must be converted to the
14
 *      Google group resource. In order to prevent the Google groups from being
15
 *      re-read for each contact when reading a VCard file with multiple contacts,
16
 *      this conversion and assignment must take place outside of this class before
17
 *      the contact is saved.
18
 *  2.  Because a contact's portrait/photo can't be set for a new contact until
19
 *      they've been assigned a resource name, this must be done as a second step
20
 *      after the contact is saved. In addition, setting a photo must be done via
21
 *      a separate API function anyway.
22
 *
23
 * > Due to the different structure of Google and VCard contacts and taking into
24
 * > account that the package used to read a VCard file does not support all VCard
25
 * > properties, data may be lost when reading in.
26
 *
27
 * @author Stefanius <[email protected]>
28
 * @copyright MIT License - see the LICENSE file for details
29
 */
30
class GContactFromVCard extends GContact
31
{
32
    /**
33
     * Protected constructor.
34
     * Only way to create an instance is to use the static method
35
     * VCardContact::fromVCardContact().
36
     * @param VCardContact $oVCContact
37
     */
38
    protected function __construct(VCardContact $oVCContact)
39
    {
40
        // names personFields must always exists as singleton
41
        parent::__construct([
42
            GContact::PF_NAMES => [[
43
                'honorificPrefix' => $oVCContact->getPrefix(),
44
                'familyName' => $oVCContact->getLastName(),
45
                'givenName' => $oVCContact->getFirstName(),
46
                'honorificSuffix' => $oVCContact->getSuffix(),
47
            ]],
48
        ]);
49
50
        $this->readAddresses($oVCContact);
51
        $this->readPhoneNumbers($oVCContact);
52
        $this->readEmailAddresses($oVCContact);
53
        $this->readHomepages($oVCContact);
54
        $this->readOrganization($oVCContact);
55
        $this->readMiscellaneous($oVCContact);
56
    }
57
58
    /**
59
     * The only way to create an instance of this class.
60
     * @param VCardContact $oVCContact
61
     * @return GContactFromVCard
62
     */
63
    static public function fromVCardContact(VCardContact $oVCContact) : GContactFromVCard
64
    {
65
        return new GContactFromVCard($oVCContact);
66
    }
67
68
    /**
69
     * Add a groupmembership.
70
     * For the membership we have to assign the group names (categories from VCard)
71
     * outside of this class to the according group resource name.
72
     * @param string $strGroupResourceName
73
     */
74
    public function addGroupMembership(string $strGroupResourceName) : void
75
    {
76
        if (!empty($strGroupResourceName)) {
77
            if (!isset($this[GContact::PF_MEMBERSHIPS])) {
78
                $this[GContact::PF_MEMBERSHIPS] = [];
79
            }
80
            $this[GContact::PF_MEMBERSHIPS][] = [
81
                'contactGroupMembership' => [
82
                    'contactGroupResourceName' => $strGroupResourceName
83
                ]
84
            ];
85
        }
86
    }
87
88
    /**
89
     * Read the address data from the VCard contact.
90
     * Values taken from the VCard:
91
     * - type:
92
     * - streetAddress
93
     * - postalCode
94
     * - city
95
     * - POBox
96
     * - ext. address
97
     * - country / countryCode
98
     * > Although according to the VCard specification the country is given with its
99
     * > full name, we interpret it as a country code (ISO 3166-1 alpha-2) if it is
100
     * > exactly 2 characters long!
101
     * @param VCardContact $oVCContact
102
     */
103
    protected function readAddresses(VCardContact $oVCContact) : void
104
    {
105
        $iCount = $oVCContact->getAddressCount();
106
        $iPrimary = -1;
107
        for ($i = 0; $i < $iCount; $i++) {
108
            $oAddress = $oVCContact->getAddress($i);
109
            if ($oAddress !== null) {
110
                $iIndex = $this->setValue(GContact::PF_ADDRESSES, -1, 'type', $this->getAddressTypeFromVCard($oAddress->getType()));
111
                $iIndex = $this->setValue(GContact::PF_ADDRESSES, $iIndex, 'streetAddress', $oAddress->getStr());
112
                $iIndex = $this->setValue(GContact::PF_ADDRESSES, $iIndex, 'postalCode', $oAddress->getPostcode());
113
                $iIndex = $this->setValue(GContact::PF_ADDRESSES, $iIndex, 'city', $oAddress->getCity());
114
                $iIndex = $this->setValue(GContact::PF_ADDRESSES, $iIndex, 'poBox', $oAddress->getPOBox());
115
                $iIndex = $this->setValue(GContact::PF_ADDRESSES, $iIndex, 'extendedAddress', $oAddress->getExtAddress());
116
                $strCountry = $oAddress->getCountry();
117
                if (strlen($strCountry) == 2) {
118
                    $iIndex = $this->setValue(GContact::PF_ADDRESSES, $iIndex, 'countryCode', strtoupper($strCountry));
119
                } else {
120
                    $iIndex = $this->setValue(GContact::PF_ADDRESSES, $iIndex, 'country', $strCountry);
121
                }
122
                if ($iPrimary < 0 && $oAddress->isPreferred()) {
123
                    $iPrimary = $iIndex;
124
                }
125
            }
126
            if ($iPrimary >= 0) {
127
                $this->setPrimaryItem(self::PF_ADDRESSES, $iPrimary);
128
            }
129
        }
130
    }
131
132
    /**
133
     * Read phone numbers from the VCard contact.
134
     * @param VCardContact $oVCContact
135
     */
136
    protected function readPhoneNumbers(VCardContact $oVCContact) : void
137
    {
138
        $iCount = $oVCContact->getPhoneCount();
139
        $iPrimary = -1;
140
        for ($i = 0; $i < $iCount; $i++) {
141
            $aPhone = $oVCContact->getPhone($i);
142
            $iIndex = $this->setValue(GContact::PF_PHONE_NUMBERS, -1, 'value', $aPhone['strPhone']);
143
            $iIndex = $this->setValue(GContact::PF_PHONE_NUMBERS, $iIndex, 'type', $this->getPhoneTypeFromVCard($aPhone['strType']));
144
            if ($iPrimary < 0 && strpos(strtoupper($aPhone['strType']), 'PREF') !== false) {
145
                $iPrimary = $iIndex;
146
            }
147
        }
148
        if ($iPrimary >= 0) {
149
            $this->setPrimaryItem(self::PF_PHONE_NUMBERS, $iPrimary);
150
        }
151
    }
152
153
    /**
154
     * Read email addresses from the VCard contact.
155
     * Since the used VCard library don't support the different possible types of
156
     * email addresses (home, work, blog,...), we set each entry type to 'other'
157
     * @param VCardContact $oVCContact
158
     */
159
    protected function readEmailAddresses(VCardContact $oVCContact) : void
160
    {
161
        $iCount = $oVCContact->getEMailCount();
162
        for ($i = 0; $i < $iCount; $i++) {
163
            $iIndex = $this->setValue(GContact::PF_EMAIL_ADDRESSES, -1, 'value', $oVCContact->getEMail($i));
164
            $iIndex = $this->setValue(GContact::PF_EMAIL_ADDRESSES, $iIndex, 'type', 'other');
0 ignored issues
show
Unused Code introduced by
The assignment to $iIndex is dead and can be removed.
Loading history...
165
        }
166
    }
167
168
    /**
169
     * Read homepage/url data from the VCard contact.
170
     * Since the used VCard library don't support the different possible types of
171
     * hompeages (home, work, blog,...), we set each URL type to 'other'
172
     * @param VCardContact $oVCContact
173
     */
174
    protected function readHomepages(VCardContact $oVCContact) : void
175
    {
176
        $iCount = $oVCContact->getHomepageCount();
177
        for ($i = 0; $i < $iCount; $i++) {
178
            $iIndex = $this->setValue(GContact::PF_URLS, -1, 'value', $oVCContact->getHomepage($i));
179
            $iIndex = $this->setValue(GContact::PF_URLS, $iIndex, 'type', 'other');
0 ignored issues
show
Unused Code introduced by
The assignment to $iIndex is dead and can be removed.
Loading history...
180
        }
181
    }
182
183
    /**
184
     * Read organization related data from the VCard contact.
185
     * @param VCardContact $oVCContact
186
     */
187
    protected function readOrganization(VCardContact $oVCContact) : void
188
    {
189
        // informations about organization, title, ...
190
        $iOrg = $this->setValue(GContact::PF_ORGANIZATIONS, -1, 'name', $oVCContact->getOrganisation());
191
        $iOrg = $this->setValue(GContact::PF_ORGANIZATIONS, $iOrg, 'title', $oVCContact->getPosition());
192
        $iOrg = $this->setValue(GContact::PF_ORGANIZATIONS, $iOrg, 'department', $oVCContact->getSection());
0 ignored issues
show
Unused Code introduced by
The assignment to $iOrg is dead and can be removed.
Loading history...
193
    }
194
195
    /**
196
     * Read miscealaneous data from the VCard contact.
197
     * - nickname
198
     * - note -> biography
199
     * - role -> occupations
200
     * - date of birth
201
     * - gender
202
     * @param VCardContact $oVCContact
203
     */
204
    protected function readMiscellaneous(VCardContact $oVCContact) : void
205
    {
206
        $this->setValue(GContact::PF_NICKNAMES, -1, 'value', $oVCContact->getNickName());
207
        $this->setValue(GContact::PF_BIOGRAPHIES, -1, 'value', $oVCContact->getNote());
208
        $this->setValue(GContact::PF_OCCUPATIONS, -1, 'value', $oVCContact->getRole());
209
210
        if (($uxtsDoB = $oVCContact->getDateOfBirth(VCardContact::DT_UNIX_TIMESTAMP)) > 0) {    // @phpstan-ignore-line
211
            $this->setDateOfBirth($uxtsDoB);
212
        }
213
        if (($strGender = $oVCContact->getGender()) !== '') {
214
            $this->setValue(GContact::PF_GENDERS, -1, 'value', $this->getGenderFromVCard($strGender));
215
        }
216
    }
217
218
    /**
219
     * Set a value.
220
     * If the requested personfield does not exist yet, it will be created and
221
     * the personfield will be added to the internal list. All personfields in
222
     * a GContact contains an array (although some of them are singletons). <br/>
223
     * To add a new item, the requested index must be set to -1, the function
224
     * then returns the newly created index. Empty or unset values are ignored
225
     * and no new index is created in this case.
226
     * @param string $strPersonFields
227
     * @param int $iIndex
228
     * @param string $strField
229
     * @param string $strValue
230
     * @return int
231
     */
232
    private function setValue(string $strPersonFields, int $iIndex, string $strField, ?string $strValue) : int
233
    {
234
        if (!isset($strValue) || empty($strValue)) {
235
            return $iIndex;
236
        }
237
        if (!isset($this[$strPersonFields])) {
238
            $this[$strPersonFields] = [];
239
        }
240
        if ($iIndex >= count($this[$strPersonFields])) {
241
            // if index is specified, it must already exist!
242
            return $iIndex;
243
        }
244
        if ($iIndex < 0) {
245
            $this[$strPersonFields][] = [];
246
            $iIndex = count($this[$strPersonFields]) - 1;
247
        }
248
        $this[$strPersonFields][$iIndex][$strField] = $strValue;
249
250
        return $iIndex;
251
    }
252
253
    /**
254
     * Get the GContact phone type from the VCard phone type.
255
     * 'HOME', 'CELL' and 'WORK' is converted to 'home', 'mobile' and 'work', all
256
     * other types are set to 'other'.
257
     * @param string $strVCType
258
     * @return string
259
     */
260
    private function getPhoneTypeFromVCard(string $strVCType) : string
261
    {
262
        $strType = 'other';
263
        if (strpos(strtoupper($strVCType), 'HOME') !== false) {
264
            $strType = 'home';
265
        } else if (strpos(strtoupper($strVCType), 'CELL') !== false) {
266
            $strType = 'mobile';
267
        } else if (strpos(strtoupper($strVCType), 'WORK') !== false) {
268
            $strType = 'work';
269
        }
270
        return $strType;
271
    }
272
273
    /**
274
     * Get the GContact address type from the VCard address type.
275
     * 'HOME' and 'WORK' is converted to 'home' and 'work', all other types are
276
     * set to 'other'.
277
     * @param string $strVCType
278
     * @return string
279
     */
280
    private function getAddressTypeFromVCard($strVCType) : string
281
    {
282
        $strType = 'other';
283
        if (strpos(strtoupper($strVCType), 'HOME') !== false) {
284
            $strType = 'home';
285
        } else if (strpos(strtoupper($strVCType), 'WORK') !== false) {
286
            $strType = 'work';
287
        }
288
        return $strType;
289
    }
290
291
    /**
292
     * Get the GContact gender from the VCard gender.
293
     * VCard values:
294
     *  - M: "male"
295
     *  - F: "female"
296
     *  - O: "other"
297
     *  - N: "none or not applicable"
298
     *  - U: "unknown".
299
     * to GContact values:
300
     *  - male
301
     *  - female
302
     *  - unspecified
303
     * @param string $strVCGender
304
     * @return string
305
     */
306
    private function getGenderFromVCard($strVCGender) : string
307
    {
308
        $strGender = 'unspecified';
309
        if ($strVCGender == 'M') {
310
            $strGender = 'male';
311
        } else if ($strVCGender == 'F') {
312
            $strGender = 'female';
313
        }
314
        return $strGender;
315
    }
316
}
317