Passed
Push — master ( 18a4f7...ef4891 )
by Stefan
01:29
created

GContact::setDateOfBirth()   A

Complexity

Conditions 6
Paths 24

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 16
nc 24
nop 1
dl 0
loc 22
rs 9.1111
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
        $oContact = self::createEmpty($aPersonFields);
152
        $aData = array_merge($oContact->getArrayCopy(), json_decode($strJSON, true));
153
154
        return new GContact($aData);
155
    }
156
157
    /**
158
     * Create a template object with an empty element for each requested personField - section.
159
     * Adds empty metadata to the object.
160
     * @param array<string> $aPersonFields
161
     * @return GContact
162
     */
163
    static public function createEmpty(array $aPersonFields = null) : GContact
164
    {
165
        $aFields = $aPersonFields ?? GContacts::DEF_DETAIL_PERSON_FIELDS;
166
        $aEmpty = [];
167
        foreach ($aFields as $strPersonFields) {
168
            $aEmpty[$strPersonFields] = [];
169
        }
170
        $aEmpty['metadata'] = [
171
            'sources' => [[
172
                'type' => 'CONTACT',
173
                'id' => '',
174
                'etag' => '',
175
            ]],
176
        ];
177
        $aCreatePersonFields = [
178
            self::PF_ADDRESSES,
179
            self::PF_PHONE_NUMBERS,
180
            self::PF_EMAIL_ADDRESSES,
181
        ];
182
        foreach ($aCreatePersonFields as $strFields) {
183
            if (isset($aEmpty[$strFields])) {
184
                $aEmpty[$strFields][0] = [];
185
            }
186
        }
187
        return new GContact($aEmpty);
188
    }
189
190
    /**
191
     * @return string
192
     */
193
    public function getResourceName() : string
194
    {
195
        return $this['resourceName'] ?? '';
196
    }
197
198
    /**
199
     * @return string
200
     */
201
    public function getDisplayName() : string
202
    {
203
        $strDisplayName = '';
204
        if (isset($this['names']) && isset($this['names'][0])) {
205
            $strDisplayName = $this['names'][0]['displayName'] ?? '[unset]';
206
        }
207
        return $strDisplayName;
208
    }
209
210
    /**
211
     * Get last modification timestamp.
212
     * @param string $strTimezone   valid timezone
213
     * @return int unixtimestamp of last modification
214
     */
215
    public function getLastModified(string $strTimezone = null) : int
216
    {
217
        $uxtsLastModified = 0;
218
        if (isset($this['metadata']) && isset($this['metadata']['sources']) && isset($this['metadata']['sources'][0])) {
219
            $strLastModified = $this['metadata']['sources'][0]['updateTime'] ?? '';
220
        }
221
        if (!empty($strLastModified)) {
222
            $dtLastModified = new \DateTime($strLastModified);
223
            $dtLastModified->setTimezone(new \DateTimeZone($strTimezone ?? 'Europe/Berlin'));
224
            $uxtsLastModified = $dtLastModified->getTimestamp();
225
        }
226
        return $uxtsLastModified;
227
    }
228
229
    /**
230
     * Checks, if current contact belongs to requested contact group.
231
     * @param string $strGroupResourceName
232
     * @return bool
233
     */
234
    public function belongsToGroup(string $strGroupResourceName) : bool
235
    {
236
        $bIsMember = false;
237
        if (isset($this['memberships'])) {
238
            foreach ($this['memberships'] as $aMembership) {
239
                if (isset($aMembership['contactGroupMembership'])) {
240
                    $strResourceName = $aMembership['contactGroupMembership']['contactGroupResourceName'] ?? '';
241
                    if ($strResourceName == $strGroupResourceName) {
242
                        $bIsMember = true;
243
                        break;
244
                    }
245
                }
246
            }
247
        }
248
        return $bIsMember;
249
    }
250
251
    /**
252
     * Checks, if current contact is starred.
253
     * The property 'starred' just means, the contact belongs to the system
254
     * group `contactGroups/starred`.
255
     * @return bool
256
     */
257
    public function isStarred() : bool
258
    {
259
        return $this->belongsToGroup(GContactGroups::GRP_STARRED);
260
    }
261
262
    /**
263
     * Set the meta data for the contact.
264
     * The server returns a 400 error if person.metadata.sources is not specified
265
     * for a contact to be updated or if there is no contact source.
266
     * The server returns a 400 error with reason "failedPrecondition" if
267
     * person.metadata.sources.etag is different than the contact's etag, which
268
     * indicates the contact has changed since its data was read. In this case,
269
     * clients should fetch the latest changes and merge their updates.
270
     * @param string $strType
271
     * @param string $strID
272
     * @param string $strETag
273
     */
274
    public function setMetaData(string $strType, string $strID, string $strETag) : void
275
    {
276
        if (!isset($this['metadata']['sources'])) {
277
            $this['metadata']['sources'] = [];
278
        }
279
        $this['metadata']['sources'][0] = [
280
            'type' => $strType,
281
            'id' => $strID,
282
            'etag' => $strETag,
283
        ];
284
    }
285
286
    /**
287
     * Set the primary item for the given personFields.
288
     * Reset the primary marker for all other items in the same array.
289
     * @link https://developers.google.com/people/api/rest/v1/people#fieldmetadata
290
     * @param string $strPersonFields
291
     * @param int $iPrimary
292
     */
293
    public function setPrimaryItem(string $strPersonFields, int $iPrimary) : void
294
    {
295
        foreach ($this[$strPersonFields] as $i => $aFields) {
296
            if (!isset($aFields['metadata'])) {
297
                $this[$strPersonFields][$i]['metadata'] = [];
298
            }
299
            $this[$strPersonFields][$i]['metadata']['sourcePrimary'] = ($i == $iPrimary);
300
        }
301
    }
302
303
    /**
304
     * Get the index of the primary item of the given personFields.
305
     * @link https://developers.google.com/people/api/rest/v1/people#fieldmetadata
306
     * @param string $strPersonFields
307
     * @return int $iPrimaryIndex   -1 if no items found or no item marked as primary
308
     */
309
    public function getPrimaryItemIndex(string $strPersonFields) : int
310
    {
311
        $iPrimary = -1;
312
        foreach ($this[$strPersonFields] as $i => $aFields) {
313
            if (isset($aFields['metadata'])) {
314
                $bPrimary = $this[$strPersonFields][$i]['metadata']['primary'] ?? false;
315
                if ($bPrimary) {
316
                    $iPrimary = $i;
317
                }
318
            }
319
        }
320
        return $iPrimary;
321
    }
322
323
    /**
324
     * Checks, if given item is marked as primary item.
325
     * @link https://developers.google.com/people/api/rest/v1/people#fieldmetadata
326
     * @param array<mixed> $aItem
327
     * @return bool
328
     */
329
    public function isPrimaryItem(array $aItem) : bool
330
    {
331
        return (isset($aItem['metadata']) && isset($aItem['metadata']['primary']) && $aItem['metadata']['primary'] == true);
332
    }
333
334
    /**
335
     * Set date of birth.
336
     * @param string|int|\DateTime $DateOfBirth    can be string (format YYYY-MM-DD), int (unixtimestamp) or DateTime - object
337
     */
338
    public function setDateOfBirth($DateOfBirth) : void
339
    {
340
        $uxts = 0;
341
        if (!isset($this['birthdays'][0])) {
342
            $this['birthdays'][0] = [];
343
        }
344
        if (!isset($this['birthdays'][0]['date'])) {
345
            $this['birthdays'][0]['date'] = [];
346
        }
347
        if (is_object($DateOfBirth)) {
348
            // DateTime -object
349
            $uxts = $DateOfBirth->getTimestamp();
350
        } else if (is_string($DateOfBirth)) {
351
            $oBirth = new \DateTime($DateOfBirth);
352
            $uxts = $oBirth->getTimestamp();
353
        } else {
354
            $uxts = $DateOfBirth;
355
        }
356
        if ($uxts > 0) {
357
            $this['birthdays'][0]['date']['month'] = intval(date('m', $uxts));
358
            $this['birthdays'][0]['date']['day'] = intval(date('d', $uxts));
359
            $this['birthdays'][0]['date']['year'] = intval(date('Y', $uxts));
360
        }
361
    }
362
363
    /**
364
     * Get date of birth.
365
     * The return type can be specified in the `$iType`parameter: <ul>
366
     * <li><b> self::DT_STRING (default):</b> Date as String in the format set with `$strFormat`param (default = 'Y-m-d') </li>
367
     * <li><b> self::DT_UNIX_TIMESTAMP:</b> Date as unix timestamp</li>
368
     * <li><b> self::DT_OBJECT:</b> Date as DateTime object </li></ul>
369
     *
370
     * if the property is not set in the contact method returns: <ul>
371
     * <li><b> self::DT_STRING:</b> empty string </li>
372
     * <li><b> self::DT_UNIX_TIMESTAMP:</b> integer 0</li>
373
     * <li><b> self::DT_OBJECT:</b> null </li></ul>
374
     *
375
     * @link https://datatracker.ietf.org/doc/html/rfc2426#section-3.1.5
376
     * @link https://www.php.net/manual/en/datetime.format.php
377
     * @param int $iType    self::DT_STRING (default), self::DT_UNIX_TIMESTAMP or self::DT_OBJECT
378
     * @param string $strFormat Date format compliant to DateTime::format() (default 'Y-m-d')
379
     * @return string|int|\DateTime|null
380
     */
381
    public function getDateOfBirth(int $iType = self::DT_STRING, string $strFormat = 'Y-m-d')
382
    {
383
        $result = '';
384
        $uxtsBirth = 0;
385
        if (isset($this['birthdays'][0]['date'])) {
386
            $aDate = $this['birthdays'][0]['date'];
387
            $uxtsBirth = mktime(0, 0, 0, $aDate['month'], $aDate['day'], $aDate['year']);
388
        }
389
        if ($iType == self::DT_UNIX_TIMESTAMP) {
390
            $result = $uxtsBirth;
391
        } else if ($iType ==  self::DT_OBJECT) {
392
            $dtBirth = null;
393
            if ($uxtsBirth > 0) {
394
                $dtBirth = new \DateTime();
395
                $dtBirth->setTimestamp($uxtsBirth);
396
            }
397
            $result = $dtBirth;
398
        } else if ($uxtsBirth > 0) {
399
            $result = date($strFormat, $uxtsBirth);
400
        }
401
        return $result;
402
    }
403
}