Completed
Push — master ( a962f3...470970 )
by
unknown
05:06
created

Cursor::getIndexLeft()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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
   * @var ResponseInterface
35
   */
36
  protected $response;
37
38
  /**
39
   * @var Api
40
   */
41
  protected $api;
42
43
  /**
44
   * @var AbstractObject[]
45
   */
46
  protected $objects = array();
47
48
  /**
49
   * @var int|null
50
   */
51
  protected $indexLeft;
52
53
  /**
54
   * @var int|null
55
   */
56
  protected $indexRight;
57
58
  /**
59
   * @var int|null
60
   */
61
  protected $position;
62
63
  /**
64
   * @var AbstractObject
65
   */
66
  protected $objectPrototype;
67
68
  /**
69
   * @var bool
70
   */
71
  protected static $defaultUseImplicitFetch = false;
72
73
  /**
74
   * @var bool
75
   */
76
  protected $useImplicitFectch;
77
78 24
  public function __construct(
79
    ResponseInterface $response,
80
    AbstractObject $object_prototype,
81
    Api $api = null) {
82 24
    $this->response = $response;
83 24
    $this->objectPrototype = $object_prototype;
84 24
    $this->api = $api !== null ? $api : Api::instance();
85 24
    $this->appendResponse($response);
86 22
  }
87
88
  /**
89
   * @param array $object_data
90
   * @return AbstractObject
91
   */
92 20
  protected function createObject(array $object_data) {
93 20
    $object = clone $this->objectPrototype;
94 20
    $object->setDataWithoutValidation($object_data);
95 20
    if ($object instanceof AbstractCrudObject) {
0 ignored issues
show
Bug introduced by
The class FacebookAds\AbstractCrudObject does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
96
      $object->setApi($this->api);
97
    }
98 20
    return $object;
99
  }
100
101
  /**
102
   * @param ResponseInterface $response
103
   * @return array
104
   * @throws \InvalidArgumentException
105
   */
106 24
  protected function assureResponseData(ResponseInterface $response) {
107 24
    $content = $response->getContent();
108
109
    // First, check if the content contains data
110 24
    if (isset($content['data'])) {
111 20
      $data = $content['data'];
112
113
      // If data is an object (represented by a map instead of a pure list),
114
      // wrap the object into an array
115 20
      if (array_keys($data) !== range(0, count($data) - 1)) {
116 10
        $data = array($data);
117 10
      }
118 18
      return $data;
119
    }
120
121
    // Second, check if the content contains targetingsentencelines
122 4
    if (isset($content['targetingsentencelines'])) {
123
      return $content['targetingsentencelines'];
124
    }
125
126
    // Third, check if the content is an array of objects indexed by id
127 4
    $is_id_indexed_array = true;
128 4
    $objects = array();
129 4
    foreach ($content as $key => $value) {
130 2
      if ($key === '__fb_trace_id__') {
131
        continue;
132
      }
133
134 2
      if ($value !== null &&
135 2
          array_keys($value) !== range(0, count($value) - 1) &&
136 2
          isset($value['id']) &&
137 2
          $value['id'] !== null &&
138 2
          $value['id'] === $key) {
139
        $objects[] = $value;
140
      } else {
141 2
        $is_id_indexed_array = false;
142 2
        break;
143
      }
144 4
    }
145 4
    if ($is_id_indexed_array) {
146 2
      return $objects;
147
    }
148
149
    // Fourth, check if the content itself is an object (represented by a map
150
    // instead of a pure list)
151 2
    if (array_keys($content) !== range(0, count($content) - 1)) {
152 2
      return array($content);
153
    }
154
155
    throw new \InvalidArgumentException("Malformed response data");
156
  }
157
158
  /**
159
   * @param ResponseInterface $response
160
   */
161 2
  protected function prependResponse(ResponseInterface $response) {
162 2
    $this->response = $response;
163 2
    $data = $this->assureResponseData($response);
164 2
    if (empty($data)) {
165
      return;
166
    }
167
168 2
    $left_index = $this->indexLeft;
169 2
    $count = count($data);
170 2
    $position = $count - 1;
171 2
    for ($i = $left_index - 1; $i >= $left_index - $count; $i--) {
172 2
      $this->objects[$i] = $this->createObject($data[$position--]);
173 2
      --$this->indexLeft;
174 2
    }
175 2
  }
176
177
  /**
178
   * @param ResponseInterface $response
179
   */
180 24
  protected function appendResponse(ResponseInterface $response) {
181 24
    $this->response = $response;
182 24
    $data = $this->assureResponseData($response);
183 22
    if (empty($data)) {
184 2
      return;
185
    }
186
187 20
    if ($this->indexRight === null) {
188 20
      $this->indexLeft = 0;
189 20
      $this->indexRight = -1;
190 20
      $this->position = 0;
191 20
    }
192
193 20
    $this->indexRight += count($data);
194
195 20
    foreach ($data as $object_data) {
196 20
      $this->objects[] = $this->createObject($object_data);
197 20
    }
198 20
  }
199
200
  /**
201
   * @return bool
202
   */
203 2
  public static function getDefaultUseImplicitFetch() {
204 2
    return static::$defaultUseImplicitFetch;
205
  }
206
207
  /**
208
   * @param bool $use_implicit_fectch
209
   */
210 2
  public static function setDefaultUseImplicitFetch($use_implicit_fectch) {
211 2
    static::$defaultUseImplicitFetch = $use_implicit_fectch;
212 2
  }
213
214
  /**
215
   * @return bool
216
   */
217 4
  public function getUseImplicitFetch() {
218 4
    return $this->useImplicitFectch !== null
219 4
      ? $this->useImplicitFectch
220 4
      : static::$defaultUseImplicitFetch;
221
  }
222
223
  /**
224
   * @param bool $use_implicit_fectch
225
   */
226 2
  public function setUseImplicitFetch($use_implicit_fectch) {
227 2
    $this->useImplicitFectch = $use_implicit_fectch;
228 2
  }
229
230
  /**
231
   * @return string|null
232
   */
233 8
  public function getBefore() {
234 8
    $content = $this->getLastResponse()->getContent();
235 8
    return isset($content['paging']['cursors']['before'])
236 8
      ? $content['paging']['cursors']['before']
237 8
      : null;
238
  }
239
240
  /**
241
   * @return string|null
242
   */
243 9
  public function getAfter() {
244 9
    $content = $this->getLastResponse()->getContent();
245 9
    return isset($content['paging']['cursors']['after'])
246 9
      ? $content['paging']['cursors']['after']
247 9
      : null;
248
  }
249
250
  /**
251
   * @return RequestInterface
252
   */
253 4
  protected function createUndirectionalizedRequest() {
254 4
    $request = $this->getLastResponse()->getRequest()->createClone();
255 4
    $params = $request->getQueryParams();
256 4
    if (array_key_exists('before', $params)) {
257 2
      unset($params['before']);
258 2
    }
259 4
    if (array_key_exists('after', $params)) {
260 2
      unset($params['after']);
261 2
    }
262
263 4
    return $request;
264
  }
265
266
  /**
267
   * @return string|null
268
   */
269 6
  public function getPrevious() {
270 6
    $content = $this->getLastResponse()->getContent();
271 6
    if (isset($content['paging']['previous'])) {
272 1
      return $content['paging']['previous'];
273
    }
274
275 6
    $before = $this->getBefore();
276 6
    if ($before !== null) {
277 1
      $request = $this->createUndirectionalizedRequest();
278 1
      $request->getQueryParams()->offsetSet('before', $before);
279 1
      return $request->getUrl();
280
    }
281
282 6
    return null;
283
  }
284
285
  /**
286
   * @return string|null
287
   */
288 10
  public function getNext() {
289 10
    $content = $this->getLastResponse()->getContent();
290 10
    if (isset($content['paging']['next'])) {
291 4
      return $content['paging']['next'];
292
    }
293
294 7
    $after = $this->getAfter();
295 7
    if ($after !== null) {
296 4
      $request = $this->createUndirectionalizedRequest();
297 4
      $request->getQueryParams()->offsetSet('after', $after);
298 4
      return $request->getUrl();
299
    }
300
301 4
    return null;
302
  }
303
304
  /**
305
   * @param string $url
306
   * @return RequestInterface
307
   */
308 8
  protected function createRequestFromUrl($url) {
309 8
    $components = parse_url($url);
310 8
    $request = $this->getLastResponse()->getRequest()->createClone();
311 8
    $request->setDomain($components['host']);
312 8
    $query = isset($components['query'])
313 8
      ? Util::parseUrlQuery($components['query'])
314 8
      : array();
315 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...
316
317 8
    return $request;
318
  }
319
320
  /**
321
   * @return RequestInterface|null
322
   */
323 6
  public function createBeforeRequest() {
324 6
    $url = $this->getPrevious();
325 6
    return $url !== null ? $this->createRequestFromUrl($url) : null;
326
  }
327
328
  /**
329
   * @return RequestInterface|null
330
   */
331 10
  public function createAfterRequest() {
332 10
    $url = $this->getNext();
333 10
    return $url !== null ? $this->createRequestFromUrl($url) : null;
334
  }
335
336 6
  public function fetchBefore() {
337 6
    $request = $this->createBeforeRequest();
338 6
    if (!$request) {
339 6
      return;
340
    }
341
342 2
    $this->prependResponse($request->execute());
343 2
  }
344
345 10
  public function fetchAfter() {
346 10
    $request = $this->createAfterRequest();
347 10
    if (!$request) {
348 4
      return;
349
    }
350
351 8
    $this->appendResponse($request->execute());
352 8
  }
353
354
  /**
355
   * @deprecated Use getArrayCopy()
356
   * @return AbstractObject[]
357
   */
358 2
  public function getObjects() {
359 2
    return $this->objects;
360
  }
361
362
  /**
363
   * @param bool $ksort
364
   * @return AbstractObject[]
365
   */
366 2
  public function getArrayCopy($ksort = false) {
367 2
    if ($ksort) {
368
      // Sort the main array to improve best case performance in future
369
      // invocations
370 2
      ksort($this->objects);
371 2
    }
372
373 2
    return $this->objects;
374
  }
375
376
  /**
377
   * @deprecated Use getLastResponse()
378
   * @return ResponseInterface
379
   */
380 2
  public function getResponse() {
381 2
    return $this->response;
382
  }
383
384
  /**
385
   * @return ResponseInterface
386
   */
387 12
  public function getLastResponse() {
388 12
    return $this->response;
389
  }
390
391
  /**
392
   * @return int
393
   */
394 8
  public function getIndexLeft() {
395 8
    return $this->indexLeft;
396
  }
397
398
  /**
399
   * @return int
400
   */
401 6
  public function getIndexRight() {
402 6
    return $this->indexRight;
403
  }
404
405 4
  public function rewind() {
406 4
    $this->position = $this->indexLeft;
407 4
  }
408
409 2
  public function end() {
410 2
    $this->position = $this->indexRight;
411 2
  }
412
413
  /**
414
   * @param int $position
415
   */
416 2
  public function seekTo($position) {
417 2
    $position = array_key_exists($position, $this->objects) ? $position : null;
418 2
    $this->position = $position;
419 2
  }
420
421
  /**
422
   * @return AbstractObject|bool
423
   */
424 2
  public function current() {
425 2
    return isset($this->objects[$this->position])
426 2
      ? $this->objects[$this->position]
427 2
      : false;
428
  }
429
430
  /**
431
   * @return int
432
   */
433 4
  public function key() {
434 4
    return $this->position;
435
  }
436
437 4
  public function prev() {
438 4
    if ($this->position == $this->getIndexLeft()) {
439 2
      if ($this->getUseImplicitFetch()) {
440 2
        $this->fetchBefore();
441 2
        if ($this->position == $this->getIndexLeft()) {
442 2
          $this->position = null;
443 2
        } else {
444 2
          --$this->position;
445
        }
446 2
      } else {
447 2
        $this->position = null;
448
      }
449 2
    } else {
450 4
      --$this->position;
451
    }
452 4
  }
453
454 6
  public function next() {
455 6
    if ($this->position == $this->getIndexRight()) {
456 4
      if ($this->getUseImplicitFetch()) {
457 2
        $this->fetchAfter();
458 2
        if ($this->position == $this->getIndexRight()) {
459 2
          $this->position = null;
460 2
        } else {
461 2
          ++$this->position;
462
        }
463 2
      } else {
464 2
        $this->position = null;
465
      }
466 4
    } else {
467 6
      ++$this->position;
468
    }
469 6
  }
470
471
  /**
472
   * @return bool
473
   */
474 4
  public function valid() {
475 4
    return isset($this->objects[$this->position]);
476
  }
477
478
  /**
479
   * @return int
480
   */
481 10
  public function count() {
482 10
    return count($this->objects);
483
  }
484
485
  /**
486
   * @param mixed $offset
487
   * @param mixed $value
488
   */
489 2
  public function offsetSet($offset, $value) {
490 2
    if ($offset === null) {
491 2
      $this->objects[] = $value;
492 2
    } else {
493 2
      $this->objects[$offset] = $value;
494
    }
495 2
  }
496
497
  /**
498
   * @param mixed $offset
499
   * @return bool
500
   */
501 2
  public function offsetExists($offset) {
502 2
    return isset($this->objects[$offset]);
503
  }
504
505
  /**
506
   * @param mixed $offset
507
   */
508 2
  public function offsetUnset($offset) {
509 2
    unset($this->objects[$offset]);
510 2
  }
511
512
  /**
513
   * @param mixed $offset
514
   * @return mixed
515
   */
516 2
  public function offsetGet($offset) {
517 2
    return isset($this->objects[$offset]) ? $this->objects[$offset] : null;
518
  }
519
}
520