Completed
Pull Request — master (#899)
by Yassine
01:56
created

GraphNode::castItems()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 11
nc 4
nop 1
dl 0
loc 18
rs 8.8571
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A GraphNode::getField() 0 7 2
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 implements \IteratorAggregate
29
{
30
    /**
31
     * @var array maps object key names to Graph object types
32
     */
33
    protected static $graphObjectMap = [];
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 69
    public function __construct(array $data = [])
48
    {
49 69
        $this->fields = $this->castFields($data);
50 69
    }
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 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 10
        return array_map(function ($value) {
97 9
            if ($value instanceof GraphNode || $value instanceof GraphEdge) {
98
                return $value->asArray();
99
            }
100
101 9
            return $value;
102 10
        }, $this->fields);
103
    }
104
105
    /**
106
     * Get an iterator for the fields.
107
     *
108
     * @return \ArrayIterator
109
     */
110 1
    public function getIterator()
111
    {
112 1
        return new \ArrayIterator($this->fields);
113
    }
114
115
    /**
116
     * Convert the collection to its string representation.
117
     *
118
     * @return string
119
     */
120 2
    public function __toString()
121
    {
122 2
        return json_encode($this->uncastFields());
123
    }
124
125
    /**
126
     * Getter for $graphObjectMap.
127
     *
128
     * @return array
129
     */
130 19
    public static function getObjectMap()
131
    {
132 19
        return static::$graphObjectMap;
133
    }
134
135
    /**
136
     * Iterates over an array and detects the types each node
137
     * should be cast to and returns all the fields as an array.
138
     *
139
     * @TODO Add auto-casting to AccessToken entities.
140
     *
141
     * @param array $data the array to iterate over
142
     *
143
     * @return array
144
     */
145 69
    private function castFields(array $data)
146
    {
147 69
        $fields = [];
148
149 69
        foreach ($data as $k => $v) {
150 68
            if ($this->shouldCastAsDateTime($k)
151 25
                && (is_numeric($v)
152 68
                    || $this->isIso8601DateString($v))
153
            ) {
154 23
                $fields[$k] = $this->castToDateTime($v);
155 50
            } elseif ($k === 'birthday') {
156 3
                $fields[$k] = $this->castToBirthday($v);
157
            } else {
158 68
                $fields[$k] = $v;
159
            }
160
        }
161
162 69
        return $fields;
163
    }
164
165
    /**
166
     * Uncasts any auto-casted datatypes.
167
     * Basically the reverse of castFields().
168
     *
169
     * @return array
170
     */
171 2
    private function uncastFields()
172
    {
173 2
        $fields = $this->asArray();
174
175 2
        return array_map(function ($v) {
176 2
            if ($v instanceof \DateTime) {
177 1
                return $v->format(\DateTime::ISO8601);
178
            }
179
180 2
            return $v;
181 2
        }, $fields);
182
    }
183
184
    /**
185
     * Determines if a value from Graph should be cast to DateTime.
186
     *
187
     * @param string $key
188
     *
189
     * @return bool
190
     */
191 68
    private function shouldCastAsDateTime($key)
192
    {
193 68
        return in_array($key, [
194 68
            'created_time',
195
            'updated_time',
196
            'start_time',
197
            'stop_time',
198
            'end_time',
199
            'backdated_time',
200
            'issued_at',
201
            'expires_at',
202
            'publish_time'
203 68
        ], true);
204
    }
205
206
    /**
207
     * Detects an ISO 8601 formatted string.
208
     *
209
     * @param string $string
210
     *
211
     * @return bool
212
     *
213
     * @see https://developers.facebook.com/docs/graph-api/using-graph-api/#readmodifiers
214
     * @see http://www.cl.cam.ac.uk/~mgk25/iso-time.html
215
     * @see http://en.wikipedia.org/wiki/ISO_8601
216
     */
217 23
    private function isIso8601DateString($string)
218
    {
219
        // This insane regex was yoinked from here:
220
        // http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/
221
        // ...and I'm all like:
222
        // http://thecodinglove.com/post/95378251969/when-code-works-and-i-dont-know-why
223
        $crazyInsaneRegexThatSomehowDetectsIso8601 = '/^([\+-]?\d{4}(?!\d{2}\b))'
224
            . '((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?'
225
            . '|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d'
226
            . '|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])'
227
            . '((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d'
228 23
            . '([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/';
229
230 23
        return preg_match($crazyInsaneRegexThatSomehowDetectsIso8601, $string) === 1;
231
    }
232
233
    /**
234
     * Casts a date value from Graph to DateTime.
235
     *
236
     * @param int|string $value
237
     *
238
     * @return \DateTime
239
     */
240 23
    private function castToDateTime($value)
241
    {
242 23
        if (is_int($value)) {
243 2
            $dt = new \DateTime();
244 2
            $dt->setTimestamp($value);
245
        } else {
246 21
            $dt = new \DateTime($value);
247
        }
248
249 23
        return $dt;
250
    }
251
252
    /**
253
     * Casts a birthday value from Graph to Birthday.
254
     *
255
     * @param string $value
256
     *
257
     * @return Birthday
258
     */
259 3
    private function castToBirthday($value)
260
    {
261 3
        return new Birthday($value);
262
    }
263
}
264