Completed
Pull Request — master (#187)
by Norio
02:59
created

Cursor::fetchAfter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2
Metric Value
dl 0
loc 8
ccs 6
cts 6
cp 1
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
crap 2
1
<?php
2
/**
3
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
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
 */
24
25
namespace FacebookAds;
26
27
use FacebookAds\Http\RequestInterface;
28
use FacebookAds\Http\ResponseInterface;
29
use FacebookAds\Http\Util;
30
use FacebookAds\Object\AbstractObject;
31
32
class Cursor implements \Iterator, \Countable, \arrayaccess {
33
34
  /**
35
   * @var ResponseInterface
36
   */
37
  protected $response;
38
39
  /**
40
   * @var AbstractObject[]
41
   */
42
  protected $objects = array();
43
44
  /**
45
   * @var int|null
46
   */
47
  protected $indexLeft;
48
49
  /**
50
   * @var int|null
51
   */
52
  protected $indexRight;
53
54
  /**
55
   * @var int|null
56
   */
57
  protected $position;
58
59
  /**
60
   * @var AbstractObject
61
   */
62
  protected $objectPrototype;
63
64
  /**
65
   * @var bool
66
   */
67
  protected static $defaultUseImplicitFetch = false;
68
69
  /**
70
   * @var bool
71
   */
72
  protected $useImplicitFectch;
73
74 24
  public function __construct(
75
    ResponseInterface $response, AbstractObject $object_prototype) {
76
77 24
    $this->response = $response;
78 24
    $this->objectPrototype = $object_prototype;
79 24
    $this->appendResponse($response);
80 18
  }
81
82
  /**
83
   * @param array $object_data
84
   * @return AbstractObject
85
   */
86 16
  protected function createObject(array $object_data) {
87 16
    $object = clone $this->objectPrototype;
88 16
    $object->setDataWithoutValidation($object_data);
89
90 16
    return $object;
91
  }
92
93
  /**
94
   * @param ResponseInterface $response
95
   * @return array
96
   * @throws \InvalidArgumentException
97
   */
98 24
  protected function assureResponseData(ResponseInterface $response) {
99 24
    $content = $response->getContent();
100 24
    if (!isset($content['data']) || !is_array($content['data'])) {
101 6
      throw new \InvalidArgumentException("Malformed response data");
102
    }
103
104 18
    return $content['data'];
105
  }
106
107
  /**
108
   * @param ResponseInterface $response
109
   */
110 2
  protected function prependResponse(ResponseInterface $response) {
111 2
    $this->response = $response;
112 2
    $data = $this->assureResponseData($response);
113 2
    if (empty($data)) {
114 2
      return;
115
    }
116
117 2
    $left_index = $this->indexLeft;
118 2
    $count = count($data);
119 2
    $position = $count - 1;
120 2
    for ($i = $left_index - 1; $i >= $left_index - $count; $i--) {
121 2
      $this->objects[$i] = $this->createObject($data[$position--]);
122 2
      --$this->indexLeft;
123
    }
124 2
  }
125
126
  /**
127
   * @param ResponseInterface $response
128
   */
129 24
  protected function appendResponse(ResponseInterface $response) {
130 24
    $this->response = $response;
131 24
    $data = $this->assureResponseData($response);
132 18
    if (empty($data)) {
133 10
      return;
134
    }
135
136 16
    if ($this->indexRight === null) {
137 16
      $this->indexLeft = 0;
138 16
      $this->indexRight = -1;
139 16
      $this->position = 0;
140
    }
141
142 16
    $this->indexRight += count($data);
143
144 16
    foreach ($data as $object_data) {
145 16
      $this->objects[] = $this->createObject($object_data);
146
    }
147 16
  }
148
149
  /**
150
   * @return bool
151
   */
152 2
  public static function getDefaultUseImplicitFetch() {
153 2
    return static::$defaultUseImplicitFetch;
154
  }
155
156
  /**
157
   * @param bool $use_implicit_fectch
158
   */
159 2
  public static function setDefaultUseImplicitFetch($use_implicit_fectch) {
160 2
    static::$defaultUseImplicitFetch = $use_implicit_fectch;
161 2
  }
162
163
  /**
164
   * @return bool
165
   */
166 4
  public function getUseImplicitFetch() {
167 4
    return $this->useImplicitFectch !== null
168 2
      ? $this->useImplicitFectch
169 4
      : static::$defaultUseImplicitFetch;
170
  }
171
172
  /**
173
   * @param bool $use_implicit_fectch
174
   */
175 2
  public function setUseImplicitFetch($use_implicit_fectch) {
176 2
    $this->useImplicitFectch = $use_implicit_fectch;
177 2
  }
178
179
  /**
180
   * @return string|null
181
   */
182 7
  public function getBefore() {
183 7
    $content = $this->getLastResponse()->getContent();
184
185 7
    return isset($content['paging']['cursors']['before'])
186 2
      ? $content['paging']['cursors']['before']
187 7
      : null;
188
  }
189
190
  /**
191
   * @return string|null
192
   */
193 8
  public function getAfter() {
194 8
    $content = $this->getLastResponse()->getContent();
195
196 8
    return isset($content['paging']['cursors']['after'])
197 5
      ? $content['paging']['cursors']['after']
198 8
      : null;
199
  }
200
201
  /**
202
   * @return RequestInterface
203
   */
204 4
  protected function createUndirectionalizedRequest() {
205 4
    $request = $this->getLastResponse()->getRequest()->createClone();
206 4
    $params = $request->getQueryParams();
207 4
    if (array_key_exists('before', $params)) {
208 2
      unset($params['before']);
209
    }
210 4
    if (array_key_exists('after', $params)) {
211 2
      unset($params['after']);
212
    }
213
214 4
    return $request;
215
  }
216
217
  /**
218
   * @return string|null
219
   */
220 6
  public function getPrevious() {
221 6
    $content = $this->getLastResponse()->getContent();
222 6
    if (isset($content['paging']['previous'])) {
223 1
      return $content['paging']['previous'];
224
    }
225
226 5
    $before = $this->getBefore();
227 5
    if ($before !== null) {
228 1
      $request = $this->createUndirectionalizedRequest();
229 1
      $request->getQueryParams()->offsetSet('before', $before);
230 1
      return $request->getUrl();
231
    }
232
233 4
    return null;
234
  }
235
236
  /**
237
   * @return string|null
238
   */
239 10
  public function getNext() {
240 10
    $content = $this->getLastResponse()->getContent();
241 10
    if (isset($content['paging']['next'])) {
242 4
      return $content['paging']['next'];
243
    }
244
245 6
    $after = $this->getAfter();
246 6
    if ($after !== null) {
247 4
      $request = $this->createUndirectionalizedRequest();
248 4
      $request->getQueryParams()->offsetSet('after', $after);
249 4
      return $request->getUrl();
250
    }
251
252 2
    return null;
253
  }
254
255
  /**
256
   * @param string $url
257
   * @return RequestInterface
258
   */
259 8
  protected function createRequestFromUrl($url) {
260 8
    $components = parse_url($url);
261 8
    $request = $this->getLastResponse()->getRequest()->createClone();
262 8
    $request->setDomain($components['host']);
263 8
    $query = isset($components['query'])
264 8
      ? Util::parseUrlQuery($components['query'])
265 8
      : array();
266 8
    $request->getQueryParams()->enhance($query);
0 ignored issues
show
Unused Code introduced by
The call to the method FacebookAds\Http\Parameters::enhance() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
267
268 8
    return $request;
269
  }
270
271
  /**
272
   * @return RequestInterface|null
273
   */
274 6
  public function createBeforeRequest() {
275 6
    $url = $this->getPrevious();
276 6
    return $url !== null ? $this->createRequestFromUrl($url) : null;
277
  }
278
279
  /**
280
   * @return RequestInterface|null
281
   */
282 10
  public function createAfterRequest() {
283 10
    $url = $this->getNext();
284 10
    return $url !== null ? $this->createRequestFromUrl($url) : null;
285
  }
286
287 6
  public function fetchBefore() {
288 6
    $request = $this->createBeforeRequest();
289 6
    if (!$request) {
290 4
      return;
291
    }
292
293 2
    $this->prependResponse($request->execute());
294 2
  }
295
296 10
  public function fetchAfter() {
297 10
    $request = $this->createAfterRequest();
298 10
    if (!$request) {
299 2
      return;
300
    }
301
302 8
    $this->appendResponse($request->execute());
303 8
  }
304
305
  /**
306
   * @deprecated Use getArrayCopy()
307
   * @return AbstractObject[]
308
   */
309 2
  public function getObjects() {
310 2
    return $this->objects;
311
  }
312
313
  /**
314
   * @param bool $ksort
315
   * @return AbstractObject[]
316
   */
317 2
  public function getArrayCopy($ksort = false) {
318 2
    if ($ksort) {
319
      // Sort the main array to improve best case performance in future
320
      // invocations
321 2
      ksort($this->objects);
322
    }
323
324 2
    return $this->objects;
325
  }
326
327
  /**
328
   * @deprecated Use getLastResponse()
329
   * @return ResponseInterface
330
   */
331 2
  public function getResponse() {
332 2
    return $this->response;
333
  }
334
335
  /**
336
   * @return ResponseInterface
337
   */
338 12
  public function getLastResponse() {
339 12
    return $this->response;
340
  }
341
342
  /**
343
   * @return int
344
   */
345 8
  public function getIndexLeft() {
346 8
    return $this->indexLeft;
347
  }
348
349
  /**
350
   * @return int
351
   */
352 6
  public function getIndexRight() {
353 6
    return $this->indexRight;
354
  }
355
356 4
  public function rewind() {
357 4
    $this->position = $this->indexLeft;
358 4
  }
359
360 2
  public function end() {
361 2
    $this->position = $this->indexRight;
362 2
  }
363
364
  /**
365
   * @param int $position
366
   */
367 2
  public function seekTo($position) {
368 2
    $position = array_key_exists($position, $this->objects) ? $position : null;
369 2
    $this->position = $position;
370 2
  }
371
372
  /**
373
   * @return AbstractObject|bool
374
   */
375 2
  public function current() {
376 2
    return isset($this->objects[$this->position])
377 2
      ? $this->objects[$this->position]
378 2
      : false;
379
  }
380
381
  /**
382
   * @return int
383
   */
384 4
  public function key() {
385 4
    return $this->position;
386
  }
387
388 4
  public function prev() {
389 4
    if ($this->position == $this->getIndexLeft()) {
390 2
      if ($this->getUseImplicitFetch()) {
391 2
        $this->fetchBefore();
392 2
        if ($this->position == $this->getIndexLeft()) {
393 2
          $this->position = null;
394
        } else {
395 2
          --$this->position;
396
        }
397
      } else {
398 2
        $this->position = null;
399
      }
400
    } else {
401 4
      --$this->position;
402
    }
403 4
  }
404
405 6
  public function next() {
406 6
    if ($this->position == $this->getIndexRight()) {
407 4
      if ($this->getUseImplicitFetch()) {
408 2
        $this->fetchAfter();
409 2
        if ($this->position == $this->getIndexRight()) {
410 2
          $this->position = null;
411
        } else {
412 2
          ++$this->position;
413
        }
414
      } else {
415 4
        $this->position = null;
416
      }
417
    } else {
418 6
      ++$this->position;
419
    }
420 6
  }
421
422
  /**
423
   * @return bool
424
   */
425 4
  public function valid() {
426 4
    return isset($this->objects[$this->position]);
427
  }
428
429
  /**
430
   * @return int
431
   */
432 10
  public function count() {
433 10
    return count($this->objects);
434
  }
435
436
  /**
437
   * @param mixed $offset
438
   * @param mixed $value
439
   */
440 2
  public function offsetSet($offset, $value) {
441 2
    if ($offset === null) {
442 2
      $this->objects[] = $value;
443
    } else {
444 2
      $this->objects[$offset] = $value;
445
    }
446 2
  }
447
448
  /**
449
   * @param mixed $offset
450
   * @return bool
451
   */
452 2
  public function offsetExists($offset) {
453 2
    return isset($this->objects[$offset]);
454
  }
455
456
  /**
457
   * @param mixed $offset
458
   */
459 2
  public function offsetUnset($offset) {
460 2
    unset($this->objects[$offset]);
461 2
  }
462
463
  /**
464
   * @param mixed $offset
465
   * @return mixed
466
   */
467 2
  public function offsetGet($offset) {
468 2
    return isset($this->objects[$offset]) ? $this->objects[$offset] : null;
469
  }
470
}
471