Passed
Pull Request — master (#1144)
by
unknown
01:41
created

GraphEdge   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 375
Duplicated Lines 0 %

Test Coverage

Coverage 62.79%

Importance

Changes 0
Metric Value
eloc 64
dl 0
loc 375
ccs 54
cts 86
cp 0.6279
rs 9.6
c 0
b 0
f 0
wmc 35

26 Methods

Rating   Name   Duplication   Size   Complexity  
A getTotalCount() 0 7 2
A offsetExists() 0 3 1
A getNextCursor() 0 3 1
A getPreviousCursor() 0 3 1
A getMetaData() 0 3 1
A asArray() 0 9 3
A __toString() 0 3 1
A getCursor() 0 7 2
A getIterator() 0 3 1
A getPaginationRequest() 0 11 2
A getSubClassName() 0 3 1
A offsetGet() 0 3 1
A getPaginationUrl() 0 12 2
A count() 0 3 1
A all() 0 3 1
A validateForPagination() 0 4 2
A map() 0 8 1
A getNextPageRequest() 0 3 1
A getField() 0 7 2
A asJson() 0 3 1
A offsetUnset() 0 3 1
A getFieldNames() 0 3 1
A __construct() 0 12 1
A getParentGraphEdge() 0 3 1
A getPreviousPageRequest() 0 3 1
A offsetSet() 0 6 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
use Facebook\Request;
26
use Facebook\Url\UrlManipulator;
27
use Facebook\Exception\SDKException;
28
29
/**
30
 * @package Facebook
31
 */
32
class GraphEdge implements \ArrayAccess, \Countable, \IteratorAggregate
33
{
34
    /**
35
     * @var Request the original request that generated this data
36
     */
37
    protected $request;
38
39
    /**
40
     * @var array an array of Graph meta data like pagination, etc
41
     */
42
    protected $metaData = [];
43
44
    /**
45
     * @var null|string the parent Graph edge endpoint that generated the list
46
     */
47
    protected $parentEdgeEndpoint;
48
49
    /**
50
     * @var null|string the subclass of the child GraphNode's
51
     */
52
    protected $subclassName;
53
54
    /**
55
     * The items contained in the collection.
56
     *
57
     * @var array
58
     */
59
    protected $items = [];
60
61
    /**
62
     * Init this collection of GraphNode's.
63
     *
64
     * @param Request     $request            the original request that generated this data
65
     * @param array       $data               an array of GraphNode's
66
     * @param array       $metaData           an array of Graph meta data like pagination, etc
67
     * @param null|string $parentEdgeEndpoint the parent Graph edge endpoint that generated the list
68
     * @param null|string $subclassName       the subclass of the child GraphNode's
69
     */
70 19
    public function __construct(
71
        Request $request,
72
        array $data = [],
73
        array $metaData = [],
74
        ?string $parentEdgeEndpoint = null,
75
        ?string $subclassName = null
76
    ) {
77 19
        $this->request = $request;
78 19
        $this->metaData = $metaData;
79 19
        $this->parentEdgeEndpoint = $parentEdgeEndpoint;
80 19
        $this->subclassName = $subclassName;
81 19
        $this->items = $data;
82 19
    }
83
84
    /**
85
     * Gets the value of a field from the Graph node.
86
     *
87
     * @param string $name    the field to retrieve
88
     * @param mixed  $default the default to return if the field doesn't exist
89
     *
90
     * @return mixed
91
     */
92 4
    public function getField(string $name, $default = null)
93
    {
94 4
        if (isset($this->items[$name])) {
95 1
            return $this->items[$name];
96
        }
97
98 3
        return $default;
99
    }
100
101
    /**
102
     * Returns a list of all fields set on the object.
103
     *
104
     * @return array
105
     */
106 1
    public function getFieldNames(): array
107
    {
108 1
        return array_keys($this->items);
109
    }
110
111
    /**
112
     * Get all of the items in the collection.
113
     *
114
     * @return array
115
     */
116
    public function all(): array
117
    {
118
        return $this->items;
119
    }
120
121
    /**
122
     * Get the collection of items as a plain array.
123
     *
124
     * @return array
125
     */
126
    public function asArray(): array
127
    {
128 3
        return array_map(function ($value) {
129 3
            if ($value instanceof GraphNode || $value instanceof GraphEdge) {
130 1
                return $value->asArray();
131
            }
132
133 2
            return $value;
134 3
        }, $this->items);
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140 1
    public function map(\Closure $callback)
141
    {
142 1
        return new static(
143 1
            $this->request,
144 1
            array_map($callback, $this->items, array_keys($this->items)),
145 1
            $this->metaData,
146 1
            $this->parentEdgeEndpoint,
147 1
            $this->subclassName
148
        );
149
    }
150
151
    /**
152
     * Get the collection of items as JSON.
153
     *
154
     * @param int $options
155
     *
156
     * @return string
157
     */
158 1
    public function asJson(int $options = 0): string
159
    {
160 1
        return json_encode($this->asArray(), $options);
161
    }
162
163
    /**
164
     * Count the number of items in the collection.
165
     *
166
     * @return int
167
     */
168 1
    public function count(): int
169
    {
170 1
        return count($this->items);
171
    }
172
173
    /**
174
     * Get an iterator for the items.
175
     *
176
     * @return \ArrayIterator
177
     */
178 1
    public function getIterator(): \ArrayIterator
179
    {
180 1
        return new \ArrayIterator($this->items);
181
    }
182
183
    /**
184
     * Determine if an item exists at an offset.
185
     *
186
     * @param array-key $key
0 ignored issues
show
Documentation Bug introduced by
The doc comment array-key at position 0 could not be parsed: Unknown type name 'array-key' at position 0 in array-key.
Loading history...
187
     *
188
     * @return bool
189
     */
190
    public function offsetExists($key): bool
191
    {
192
        return array_key_exists($key, $this->items);
193
    }
194
195
    /**
196
     * Get an item at a given offset.
197
     *
198
     * @param array-key $key
0 ignored issues
show
Documentation Bug introduced by
The doc comment array-key at position 0 could not be parsed: Unknown type name 'array-key' at position 0 in array-key.
Loading history...
199
     *
200
     * @return mixed
201
     */
202 5
    public function offsetGet($key)
203
    {
204 5
        return $this->items[$key];
205
    }
206
207
    /**
208
     * Set the item at a given offset.
209
     *
210
     * @param array-key $key
0 ignored issues
show
Documentation Bug introduced by
The doc comment array-key at position 0 could not be parsed: Unknown type name 'array-key' at position 0 in array-key.
Loading history...
211
     * @param mixed $value
212
     *
213
     * @return void
214
     */
215
    public function offsetSet($key, $value): void
216
    {
217
        if (is_null($key)) {
218
            $this->items[] = $value;
219
        } else {
220
            $this->items[$key] = $value;
221
        }
222
    }
223
224
    /**
225
     * Unset the item at a given offset.
226
     *
227
     * @param array-key $key
0 ignored issues
show
Documentation Bug introduced by
The doc comment array-key at position 0 could not be parsed: Unknown type name 'array-key' at position 0 in array-key.
Loading history...
228
     *
229
     * @return void
230
     */
231
    public function offsetUnset($key): void
232
    {
233
        unset($this->items[$key]);
234
    }
235
236
    /**
237
     * Convert the collection to its string representation.
238
     *
239
     * @return string
240
     */
241
    public function __toString(): string
242
    {
243
        return $this->asJson();
244
    }
245
246
    /**
247
     * Gets the parent Graph edge endpoint that generated the list.
248
     *
249
     * @return null|string
250
     */
251 1
    public function getParentGraphEdge(): ?string
252
    {
253 1
        return $this->parentEdgeEndpoint;
254
    }
255
256
    /**
257
     * Gets the subclass name that the child GraphNode's are cast as.
258
     *
259
     * @return null|string
260
     */
261
    public function getSubClassName(): ?string
262
    {
263
        return $this->subclassName;
264
    }
265
266
    /**
267
     * Returns the raw meta data associated with this GraphEdge.
268
     *
269
     * @return array
270
     */
271
    public function getMetaData(): array
272
    {
273
        return $this->metaData;
274
    }
275
276
    /**
277
     * Returns the next cursor if it exists.
278
     *
279
     * @return null|string
280
     */
281
    public function getNextCursor(): ?string
282
    {
283
        return $this->getCursor('after');
284
    }
285
286
    /**
287
     * Returns the previous cursor if it exists.
288
     *
289
     * @return null|string
290
     */
291
    public function getPreviousCursor(): ?string
292
    {
293
        return $this->getCursor('before');
294
    }
295
296
    /**
297
     * Returns the cursor for a specific direction if it exists.
298
     *
299
     * @param string $direction The direction of the page: after|before
300
     *
301
     * @return null|string
302
     */
303
    public function getCursor(string $direction): ?string
304
    {
305
        if (isset($this->metaData['paging']['cursors'][$direction])) {
306
            return $this->metaData['paging']['cursors'][$direction];
307
        }
308
309
        return null;
310
    }
311
312
    /**
313
     * Generates a pagination URL based on a cursor.
314
     *
315
     * @param string $direction The direction of the page: next|previous
316
     *
317
     * @throws SDKException
318
     *
319
     * @return null|string
320
     */
321 2
    public function getPaginationUrl(string $direction): ?string
322
    {
323 2
        $this->validateForPagination();
324
325
        // Do we have a paging URL?
326 2
        if (!isset($this->metaData['paging'][$direction])) {
327
            return null;
328
        }
329
330 2
        $pageUrl = $this->metaData['paging'][$direction];
331
332 2
        return UrlManipulator::baseGraphUrlEndpoint($pageUrl);
333
    }
334
335
    /**
336
     * Validates whether or not we can paginate on this request.
337
     *
338
     * @throws SDKException
339
     */
340 3
    public function validateForPagination(): void
341
    {
342 3
        if ($this->request->getMethod() !== 'GET') {
343 1
            throw new SDKException('You can only paginate on a GET request.', 720);
344
        }
345 2
    }
346
347
    /**
348
     * Gets the request object needed to make a next|previous page request.
349
     *
350
     * @param string $direction The direction of the page: next|previous
351
     *
352
     * @throws SDKException
353
     *
354
     * @return null|Request
355
     */
356 1
    public function getPaginationRequest(string $direction): ?Request
357
    {
358 1
        $pageUrl = $this->getPaginationUrl($direction);
359 1
        if (!$pageUrl) {
360
            return null;
361
        }
362
363 1
        $newRequest = clone $this->request;
364 1
        $newRequest->setEndpoint($pageUrl);
365
366 1
        return $newRequest;
367
    }
368
369
    /**
370
     * Gets the request object needed to make a "next" page request.
371
     *
372
     * @throws SDKException
373
     *
374
     * @return null|Request
375
     */
376 1
    public function getNextPageRequest(): ?Request
377
    {
378 1
        return $this->getPaginationRequest('next');
379
    }
380
381
    /**
382
     * Gets the request object needed to make a "previous" page request.
383
     *
384
     * @throws SDKException
385
     *
386
     * @return null|Request
387
     */
388 1
    public function getPreviousPageRequest(): ?Request
389
    {
390 1
        return $this->getPaginationRequest('previous');
391
    }
392
393
    /**
394
     * The total number of results according to Graph if it exists.
395
     *
396
     * This will be returned if the summary=true modifier is present in the request.
397
     *
398
     * @return null|int
399
     */
400
    public function getTotalCount(): ?int
401
    {
402
        if (isset($this->metaData['summary']['total_count'])) {
403
            return $this->metaData['summary']['total_count'];
404
        }
405
406
        return null;
407
    }
408
}
409