Passed
Pull Request — master (#899)
by Yassine
60:30
created

GraphNode::getNodeMap()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
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
    public function __construct(array $data = [])
48
    {
49
        $this->fields = $this->castFields($data);
50
    }
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
    public function getField($name, $default = null)
61
    {
62
        if (isset($this->fields[$name])) {
63
            return $this->fields[$name];
64
        }
65
66
        return $default;
67
    }
68
69
    /**
70
     * Returns a list of all fields set on the object.
71
     *
72
     * @return array
73
     */
74
    public function getFieldNames()
75
    {
76
        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 View Code Duplication
    public function asArray()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
95
    {
96
        return array_map(function ($value) {
97
            if ($value instanceof GraphNode || $value instanceof GraphEdge) {
98
                return $value->asArray();
99
            }
100
101
            return $value;
102
        }, $this->fields);
103
    }
104
105
    /**
106
     * Convert the collection to its string representation.
107
     *
108
     * @return string
109
     */
110
    public function __toString()
111
    {
112
        return json_encode($this->uncastFields());
113
    }
114
115
    /**
116
     * Getter for $graphNodeMap.
117
     *
118
     * @return array
119
     */
120
    public static function getNodeMap()
121
    {
122
        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
    private function castFields(array $data)
136
    {
137
        $fields = [];
138
139
        foreach ($data as $k => $v) {
140
            if ($this->shouldCastAsDateTime($k)
141
                && (is_numeric($v)
142
                    || $this->isIso8601DateString($v))
143
            ) {
144
                $fields[$k] = $this->castToDateTime($v);
145
            } elseif ($k === 'birthday') {
146
                $fields[$k] = $this->castToBirthday($v);
147
            } else {
148
                $fields[$k] = $v;
149
            }
150
        }
151
152
        return $fields;
153
    }
154
155
    /**
156
     * Uncasts any auto-casted datatypes.
157
     * Basically the reverse of castFields().
158
     *
159
     * @return array
160
     */
161
    private function uncastFields()
162
    {
163
        $fields = $this->asArray();
164
165
        return array_map(function ($v) {
166
            if ($v instanceof \DateTime) {
167
                return $v->format(\DateTime::ISO8601);
168
            }
169
170
            return $v;
171
        }, $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
    private function shouldCastAsDateTime($key)
182
    {
183
        return in_array($key, [
184
            '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
        ], 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
    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
            . '([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/';
219
220
        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
    private function castToDateTime($value)
231
    {
232
        if (is_int($value)) {
233
            $dt = new \DateTime();
234
            $dt->setTimestamp($value);
235
        } else {
236
            $dt = new \DateTime($value);
237
        }
238
239
        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
    private function castToBirthday($value)
250
    {
251
        return new Birthday($value);
252
    }
253
}
254