GContact::getPrimaryItemIndex()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 4
nop 1
dl 0
loc 12
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace SKien\Google;
5
6
/**
7
 * This class represents one single contact/person within the google contacts.
8
 *
9
 * @link https://developers.google.com/people/api/rest/v1/people#Person
10
 *
11
 * @author Stefanius <[email protected]>
12
 * @copyright MIT License - see the LICENSE file for details
13
 *
14
 * @extends \ArrayObject<string, mixed>
15
 */
16
class GContact extends \ArrayObject
17
{
18
    /** Values for the personFields/readMask    */
19
    /** array of all available addresses
20
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Address    */
21
    public const PF_ADDRESSES = 'addresses';
22
    /** array of the persons age ranges: one of the self::AR_xxx constants
23
     *  @link https://developers.google.com/people/api/rest/v1/people#agerangetype    */
24
    public const PF_AGE_RANGES = 'ageRanges';
25
    /** array - singleton with the biographie (usually simply containes the notes to a person)
26
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Biography  */
27
    public const PF_BIOGRAPHIES = 'biographies';
28
    /** array - singleton containing the birthday
29
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Birthday  */
30
    public const PF_BIRTHDAYS = 'birthdays';
31
    /** array with a person's calendar URLs.
32
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.CalendarUrl    */
33
    public const PF_CALENDAR_URLS = 'calendarUrls';
34
    /** array with arbitrary client data that is populated by clients
35
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.ClientData     */
36
    public const PF_CLIENT_DATA = 'clientData';
37
    /** Array with a person's cover photos. A large image shown on the person's profile page
38
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.CoverPhoto     */
39
    public const PF_COVER_PHOTOS = 'coverPhotos';
40
    /** Array with a person's email addresses
41
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.EmailAddress     */
42
    public const PF_EMAIL_ADDRESSES = 'emailAddresses';
43
    /** Array with events related to the person
44
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Event     */
45
    public const PF_EVENTS = 'events';
46
    /** Array of identifiers from external entities related to the person
47
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.ExternalId     */
48
    public const PF_EXTERNAL_IDS = 'externalIds';
49
    /** Array - singleton contains the gender of the person (male, female, unspecified, userdefined)
50
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Gender     */
51
    public const PF_GENDERS = 'genders';
52
    /** Array with the person's instant messaging clients
53
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.ImClient     */
54
    public const PF_IM_CLIENTS = 'imClients';
55
    /** Array with the person's insterests
56
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Interest     */
57
    public const PF_INTERESTS = 'interests';
58
    /** Array with the person's locale preferences (IETF BCP 47 language tag)
59
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Locale     */
60
    public const PF_LOCALES = 'locales';
61
    /** Array with the person's locations
62
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Location     */
63
    public const PF_LOCATIONS = 'locations';
64
    /** Array containing the person's memberships to groups
65
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Membership     */
66
    public const PF_MEMBERSHIPS = 'memberships';
67
    /** The metadata about a person
68
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.PersonMetadata     */
69
    public const PF_METADATA = 'metadata';
70
    /** Array with miscellaneous keywords to the person
71
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.MiscKeyword     */
72
    public const PF_MISC_KEYWORDS = 'miscKeywords';
73
    /** Array - singleton containuing all names (except nicknames) of the person
74
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Name      */
75
    public const PF_NAMES = 'names';
76
    /** Array with the person's nicknames
77
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Nickname     */
78
    public const PF_NICKNAMES = 'nicknames';
79
    /** Array with the person's occupations
80
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Occupation     */
81
    public const PF_OCCUPATIONS = 'occupations';
82
    /** Array with the person's past or current organizations. Overlapping date ranges are permitted
83
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Organization     */
84
    public const PF_ORGANIZATIONS = 'organizations';
85
    /** Array containing all of the person's phone numbers
86
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.PhoneNumber     */
87
    public const PF_PHONE_NUMBERS = 'phoneNumbers';
88
    /** Array with the person's photos. Pictures shown next to the person's name
89
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Photo     */
90
    public const PF_PHOTOS = 'photos';
91
    /** Array with the person's relations to another person.
92
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Relation     */
93
    public const PF_RELATIONS = 'relations';
94
    /** Array with a person's SIP addresses (Session Initial Protocol addresses)
95
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.SipAddress     */
96
    public const PF_SIP_ADDRESSES = 'sipAddresses';
97
    /** Array containing the skills that the person has.
98
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Skill     */
99
    public const PF_SKILLS = 'skills';
100
    /** Array with the person's associated URLs. (Homepage, work, blog, ...)
101
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.Url     */
102
    public const PF_URLS = 'urls';
103
    /** Arbitrary user data that is populated by the end users
104
     *  @link https://developers.google.com/people/api/rest/v1/people#Person.UserDefined     */
105
    public const PF_USER_DEFINED = 'userDefined';
106
107
    /** Age range unspecified   */
108
    public const AR_UNSPECIFIED = 'AGE_RANGE_UNSPECIFIED';
109
    /** Age range: Younger than eighteen.   */
110
    public const AR_LESS_THAN_EIGHTEEN = 'LESS_THAN_EIGHTEEN';
111
    /** Age range: Between eighteen and twenty. */
112
    public const AR_EIGHTEEN_TO_TWENTY = 'EIGHTEEN_TO_TWENTY';
113
    /** Age range: Twenty-one and older.   */
114
    public const AR_TWENTY_ONE_OR_OLDER = 'TWENTY_ONE_OR_OLDER';
115
116
    /** Date type: string */
117
    public const DT_STRING = 0;
118
    /** Date type: unix timestamp */
119
    public const DT_UNIX_TIMESTAMP = 1;
120
    /** Date type: DateTime - Object */
121
    public const DT_OBJECT = 2;
122
123
    /**
124
     * @param array<mixed> $aData
125
     */
126
    public function __construct(array $aData = null)
127
    {
128
        if ($aData !== null) {
129
            $this->exchangeArray($aData);
130
        }
131
    }
132
133
    /**
134
     * Create a instance from a array.
135
     * @param array<mixed> $aData
136
     * @return GContact
137
     */
138
    static public function fromArray(array $aData) : GContact
139
    {
140
        return new GContact($aData);
141
    }
142
143
    /**
144
     * Create a instance from a fetched JSON contact.
145
     * @param string $strJSON
146
     * @param array<string> $aPersonFields
147
     * @return GContact
148
     */
149
    static public function fromJSON(string $strJSON, array $aPersonFields = null) : GContact
150
    {
151
        // since the result of the API request only contains the personFields that are set,
152
        // we first create an empty object that contains at least the base personField
153
        // elements.
154
        $oContact = self::createEmpty($aPersonFields);
155
        $aData = array_merge($oContact->getArrayCopy(), json_decode($strJSON, true));
156
157
        return new GContact($aData);
158
    }
159
160
    /**
161
     * Create a template object with an empty element for each requested personField - section.
162
     * Adds empty metadata to the object.
163
     * @param array<string> $aPersonFields
164
     * @return GContact
165
     */
166
    static public function createEmpty(array $aPersonFields = null) : GContact
167
    {
168
        $aFields = $aPersonFields ?? GContacts::DEF_DETAIL_PERSON_FIELDS;
169
        $aEmpty = [];
170
        foreach ($aFields as $strPersonFields) {
171
            $aEmpty[$strPersonFields] = [];
172
        }
173
        $aEmpty['metadata'] = [
174
            'sources' => [[
175
                'type' => 'CONTACT',
176
                'id' => '',
177
                'etag' => '',
178
            ]],
179
        ];
180
        $aCreatePersonFields = [
181
            self::PF_ADDRESSES,
182
            self::PF_PHONE_NUMBERS,
183
            self::PF_EMAIL_ADDRESSES,
184
        ];
185
        foreach ($aCreatePersonFields as $strFields) {
186
            if (isset($aEmpty[$strFields])) {
187
                $aEmpty[$strFields][0] = [];
188
            }
189
        }
190
        return new GContact($aEmpty);
191
    }
192
193
    /**
194
     * @return string
195
     */
196
    public function getResourceName() : string
197
    {
198
        return $this['resourceName'] ?? '';
199
    }
200
201
    /**
202
     * @return string
203
     */
204
    public function getDisplayName() : string
205
    {
206
        $strDisplayName = '';
207
        if (isset($this['names']) && isset($this['names'][0])) {
208
            $strDisplayName = $this['names'][0]['displayName'] ?? '[unset]';
209
        }
210
        return $strDisplayName;
211
    }
212
213
    /**
214
     * Get last modification timestamp.
215
     * @param string $strTimezone   valid timezone
216
     * @return int unixtimestamp of last modification
217
     */
218
    public function getLastModified(string $strTimezone = null) : int
219
    {
220
        $uxtsLastModified = 0;
221
        if (isset($this['metadata']) && isset($this['metadata']['sources']) && isset($this['metadata']['sources'][0])) {
222
            $strLastModified = $this['metadata']['sources'][0]['updateTime'] ?? '';
223
        }
224
        if (!empty($strLastModified)) {
225
            $dtLastModified = new \DateTime($strLastModified);
226
            $dtLastModified->setTimezone(new \DateTimeZone($strTimezone ?? 'Europe/Berlin'));
227
            $uxtsLastModified = $dtLastModified->getTimestamp();
228
        }
229
        return $uxtsLastModified;
230
    }
231
232
    /**
233
     * Checks, if current contact belongs to requested contact group.
234
     * @param string $strGroupResourceName
235
     * @return bool
236
     */
237
    public function belongsToGroup(string $strGroupResourceName) : bool
238
    {
239
        $bIsMember = false;
240
        if (isset($this['memberships'])) {
241
            foreach ($this['memberships'] as $aMembership) {
242
                if (isset($aMembership['contactGroupMembership'])) {
243
                    $strResourceName = $aMembership['contactGroupMembership']['contactGroupResourceName'] ?? '';
244
                    if ($strResourceName == $strGroupResourceName) {
245
                        $bIsMember = true;
246
                        break;
247
                    }
248
                }
249
            }
250
        }
251
        return $bIsMember;
252
    }
253
254
    /**
255
     * Checks, if current contact is starred.
256
     * The property 'starred' just means, the contact belongs to the system
257
     * group `contactGroups/starred`.
258
     * @return bool
259
     */
260
    public function isStarred() : bool
261
    {
262
        return $this->belongsToGroup(GContactGroups::GRP_STARRED);
263
    }
264
265
    /**
266
     * Set the meta data for the contact.
267
     * The server returns a 400 error if person.metadata.sources is not specified
268
     * for a contact to be updated or if there is no contact source.
269
     * The server returns a 400 error with reason "failedPrecondition" if
270
     * person.metadata.sources.etag is different than the contact's etag, which
271
     * indicates the contact has changed since its data was read. In this case,
272
     * clients should fetch the latest changes and merge their updates.
273
     * @param string $strType
274
     * @param string $strID
275
     * @param string $strETag
276
     */
277
    public function setMetaData(string $strType, string $strID, string $strETag) : void
278
    {
279
        if (!isset($this['metadata']['sources'])) {
280
            $this['metadata']['sources'] = [];
281
        }
282
        $this['metadata']['sources'][0] = [
283
            'type' => $strType,
284
            'id' => $strID,
285
            'etag' => $strETag,
286
        ];
287
    }
288
289
    /**
290
     * Set the primary item for the given personFields.
291
     * Reset the primary marker for all other items in the same array.
292
     * @link https://developers.google.com/people/api/rest/v1/people#fieldmetadata
293
     * @param string $strPersonFields
294
     * @param int $iPrimary
295
     */
296
    public function setPrimaryItem(string $strPersonFields, int $iPrimary) : void
297
    {
298
        foreach ($this[$strPersonFields] as $i => $aFields) {
299
            if (!isset($aFields['metadata'])) {
300
                $this[$strPersonFields][$i]['metadata'] = [];
301
            }
302
            $this[$strPersonFields][$i]['metadata']['sourcePrimary'] = ($i == $iPrimary);
303
        }
304
    }
305
306
    /**
307
     * Get the index of the primary item of the given personFields.
308
     * @link https://developers.google.com/people/api/rest/v1/people#fieldmetadata
309
     * @param string $strPersonFields
310
     * @return int $iPrimaryIndex   -1 if no items found or no item marked as primary
311
     */
312
    public function getPrimaryItemIndex(string $strPersonFields) : int
313
    {
314
        $iPrimary = -1;
315
        foreach ($this[$strPersonFields] as $i => $aFields) {
316
            if (isset($aFields['metadata'])) {
317
                $bPrimary = $this[$strPersonFields][$i]['metadata']['primary'] ?? false;
318
                if ($bPrimary) {
319
                    $iPrimary = $i;
320
                }
321
            }
322
        }
323
        return $iPrimary;
324
    }
325
326
    /**
327
     * Checks, if given item is marked as primary item.
328
     * @link https://developers.google.com/people/api/rest/v1/people#fieldmetadata
329
     * @param array<mixed> $aItem
330
     * @return bool
331
     */
332
    public function isPrimaryItem(array $aItem) : bool
333
    {
334
        return (isset($aItem['metadata']) && isset($aItem['metadata']['primary']) && $aItem['metadata']['primary'] == true);
335
    }
336
337
    /**
338
     * Set date of birth.
339
     * @param string|int|\DateTime $DateOfBirth    can be string (format YYYY-MM-DD), int (unixtimestamp) or DateTime - object
340
     */
341
    public function setDateOfBirth($DateOfBirth) : void
342
    {
343
        $uxts = 0;
344
        if (!isset($this['birthdays'][0])) {
345
            $this['birthdays'][0] = [];
346
        }
347
        if (!isset($this['birthdays'][0]['date'])) {
348
            $this['birthdays'][0]['date'] = [];
349
        }
350
        if (is_object($DateOfBirth)) {
351
            // DateTime -object
352
            $uxts = $DateOfBirth->getTimestamp();
353
        } else if (is_string($DateOfBirth)) {
354
            $oBirth = new \DateTime($DateOfBirth);
355
            $uxts = $oBirth->getTimestamp();
356
        } else {
357
            $uxts = $DateOfBirth;
358
        }
359
        if ($uxts > 0) {
360
            $this['birthdays'][0]['date']['month'] = intval(date('m', $uxts));
361
            $this['birthdays'][0]['date']['day'] = intval(date('d', $uxts));
362
            $this['birthdays'][0]['date']['year'] = intval(date('Y', $uxts));
363
        }
364
    }
365
366
    /**
367
     * Get date of birth.
368
     * The return type can be specified in the `$iType`parameter: <ul>
369
     * <li><b> self::DT_STRING (default):</b> Date as String in the format set with `$strFormat`param (default = 'Y-m-d') </li>
370
     * <li><b> self::DT_UNIX_TIMESTAMP:</b> Date as unix timestamp</li>
371
     * <li><b> self::DT_OBJECT:</b> Date as DateTime object </li></ul>
372
     *
373
     * if the property is not set in the contact method returns: <ul>
374
     * <li><b> self::DT_STRING:</b> empty string </li>
375
     * <li><b> self::DT_UNIX_TIMESTAMP:</b> integer 0</li>
376
     * <li><b> self::DT_OBJECT:</b> null </li></ul>
377
     *
378
     * @link https://datatracker.ietf.org/doc/html/rfc2426#section-3.1.5
379
     * @link https://www.php.net/manual/en/datetime.format.php
380
     * @param int $iType    self::DT_STRING (default), self::DT_UNIX_TIMESTAMP or self::DT_OBJECT
381
     * @param string $strFormat Date format compliant to DateTime::format() (default 'Y-m-d')
382
     * @return string|int|\DateTime|null
383
     */
384
    public function getDateOfBirth(int $iType = self::DT_STRING, string $strFormat = 'Y-m-d')
385
    {
386
        $result = '';
387
        $uxtsBirth = 0;
388
        if (isset($this['birthdays'][0]['date'])) {
389
            $aDate = $this['birthdays'][0]['date'];
390
            $uxtsBirth = mktime(0, 0, 0, $aDate['month'], $aDate['day'], $aDate['year']);
391
        }
392
        if ($iType == self::DT_UNIX_TIMESTAMP) {
393
            $result = $uxtsBirth;
394
        } else if ($iType == self::DT_OBJECT) {
395
            $dtBirth = null;
396
            if ($uxtsBirth > 0) {
397
                $dtBirth = new \DateTime();
398
                $dtBirth->setTimestamp($uxtsBirth);
399
            }
400
            $result = $dtBirth;
401
        } else if ($uxtsBirth > 0) {
402
            $result = date($strFormat, $uxtsBirth);
403
        }
404
        return $result;
405
    }
406
}