Failed Conditions
Push — master ( 81ead6...837ea5 )
by
unknown
13:08
created

Cursor::setUseImplicitFetch()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

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