Completed
Push — master ( fd3679...f7d236 )
by
unknown
171:43 queued 171:39
created

GraphNode::getFields()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Copyright 2017 Facebook, Inc.
4
 *
5
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
6
 * use, copy, modify, and distribute this software in source code or binary
7
 * form for use in connection with the web services and APIs provided by
8
 * Facebook.
9
 *
10
 * As with any software that integrates with the Facebook platform, your use
11
 * of this software is subject to the Facebook Developer Principles and
12
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
13
 * shall be included in all copies or substantial portions of the software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
 * DEALINGS IN THE SOFTWARE.
22
 */
23
namespace Facebook\GraphNode;
24
25
/**
26
 * @package Facebook
27
 */
28
class GraphNode
29
{
30
    /**
31
     * @var array maps object key names to Graph object types
32
     */
33
    protected static $graphNodeMap = [];
34
35
    /**
36
     * The fields contained in the node.
37
     *
38
     * @var array
39
     */
40
    private $fields = [];
41
42
    /**
43
     * Init this Graph object.
44
     *
45
     * @param array $data
46
     */
47 66
    public function __construct(array $data = [])
48
    {
49 66
        $this->fields = $this->castFields($data);
50 66
    }
51
52
    /**
53
     * Gets the value of a field from the Graph node.
54
     *
55
     * @param string $name    the field to retrieve
56
     * @param mixed  $default the default to return if the field doesn't exist
57
     *
58
     * @return mixed
59
     */
60 52
    public function getField($name, $default = null)
61
    {
62 52
        if (isset($this->fields[$name])) {
63 49
            return $this->fields[$name];
64
        }
65
66 3
        return $default;
67
    }
68
69
    /**
70
     * Returns a list of all fields set on the object.
71
     *
72
     * @return array
73
     */
74 1
    public function getFieldNames()
75
    {
76 1
        return array_keys($this->fields);
77
    }
78
79
    /**
80
     * Get all of the fields in the node.
81
     *
82
     * @return array
83
     */
84
    public function getFields()
85
    {
86
        return $this->fields;
87
    }
88
89
    /**
90
     * Get all fields as a plain array.
91
     *
92
     * @return array
93
     */
94
    public function asArray()
95
    {
96 8
        return array_map(function ($value) {
97 7
            if ($value instanceof GraphNode || $value instanceof GraphEdge) {
98
                return $value->asArray();
99
            }
100
101 7
            return $value;
102 8
        }, $this->fields);
103
    }
104
105
    /**
106
     * Convert the collection to its string representation.
107
     *
108
     * @return string
109
     */
110 2
    public function __toString()
111
    {
112 2
        return json_encode($this->uncastFields());
113
    }
114
115
    /**
116
     * Getter for $graphNodeMap.
117
     *
118
     * @return array
119
     */
120 19
    public static function getNodeMap()
121
    {
122 19
        return static::$graphNodeMap;
123
    }
124
125
    /**
126
     * Iterates over an array and detects the types each node
127
     * should be cast to and returns all the fields as an array.
128
     *
129
     * @TODO Add auto-casting to AccessToken entities.
130
     *
131
     * @param array $data the array to iterate over
132
     *
133
     * @return array
134
     */
135 66
    private function castFields(array $data)
136
    {
137 66
        $fields = [];
138
139 66
        foreach ($data as $k => $v) {
140 65
            if ($this->shouldCastAsDateTime($k)
141 25
                && (is_numeric($v)
142 65
                    || $this->isIso8601DateString($v))
143
            ) {
144 23
                $fields[$k] = $this->castToDateTime($v);
145 47
            } elseif ($k === 'birthday') {
146 4
                $fields[$k] = $this->castToBirthday($v);
147
            } else {
148 65
                $fields[$k] = $v;
149
            }
150
        }
151
152 66
        return $fields;
153
    }
154
155
    /**
156
     * Uncasts any auto-casted datatypes.
157
     * Basically the reverse of castFields().
158
     *
159
     * @return array
160
     */
161 2
    private function uncastFields()
162
    {
163 2
        $fields = $this->asArray();
164
165 2
        return array_map(function ($v) {
166 2
            if ($v instanceof \DateTime) {
167 1
                return $v->format(\DateTime::ISO8601);
168
            }
169
170 2
            return $v;
171 2
        }, $fields);
172
    }
173
174
    /**
175
     * Determines if a value from Graph should be cast to DateTime.
176
     *
177
     * @param string $key
178
     *
179
     * @return bool
180
     */
181 65
    private function shouldCastAsDateTime($key)
182
    {
183 65
        return in_array($key, [
184 65
            'created_time',
185
            'updated_time',
186
            'start_time',
187
            'stop_time',
188
            'end_time',
189
            'backdated_time',
190
            'issued_at',
191
            'expires_at',
192
            'publish_time'
193 65
        ], true);
194
    }
195
196
    /**
197
     * Detects an ISO 8601 formatted string.
198
     *
199
     * @param string $string
200
     *
201
     * @return bool
202
     *
203
     * @see https://developers.facebook.com/docs/graph-api/using-graph-api/#readmodifiers
204
     * @see http://www.cl.cam.ac.uk/~mgk25/iso-time.html
205
     * @see http://en.wikipedia.org/wiki/ISO_8601
206
     */
207 23
    private function isIso8601DateString($string)
208
    {
209
        // This insane regex was yoinked from here:
210
        // http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/
211
        // ...and I'm all like:
212
        // http://thecodinglove.com/post/95378251969/when-code-works-and-i-dont-know-why
213
        $crazyInsaneRegexThatSomehowDetectsIso8601 = '/^([\+-]?\d{4}(?!\d{2}\b))'
214
            . '((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?'
215
            . '|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d'
216
            . '|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])'
217
            . '((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d'
218 23
            . '([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/';
219
220 23
        return preg_match($crazyInsaneRegexThatSomehowDetectsIso8601, $string) === 1;
221
    }
222
223
    /**
224
     * Casts a date value from Graph to DateTime.
225
     *
226
     * @param int|string $value
227
     *
228
     * @return \DateTime
229
     */
230 23
    private function castToDateTime($value)
231
    {
232 23
        if (is_int($value)) {
233 2
            $dt = new \DateTime();
234 2
            $dt->setTimestamp($value);
235
        } else {
236 21
            $dt = new \DateTime($value);
237
        }
238
239 23
        return $dt;
240
    }
241
242
    /**
243
     * Casts a birthday value from Graph to Birthday.
244
     *
245
     * @param string $value
246
     *
247
     * @return Birthday
248
     */
249 4
    private function castToBirthday($value)
250
    {
251 4
        return new Birthday($value);
252
    }
253
}
254