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

AbstractCrudObject::getParentId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 0
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
namespace FacebookAds\Object;
25
use FacebookAds\Api;
26
use FacebookAds\Cursor;
27
use FacebookAds\Http\RequestInterface;
28
use FacebookAds\Http\ResponseInterface;
29
class AbstractCrudObject extends AbstractObject {
30
  /**
31
   * @var string
32
   */
33
  const FIELD_ID = 'id';
34
  /**
35
   * @var string[] set of fields to read by default
36
   */
37
  protected static $defaultReadFields = array();
38
  /**
39
   * @var array set of fields that have been mutated
40
   */
41
  protected $changedFields = array();
42
  /**
43
   * @var Api instance of the Api used by this object
44
   */
45
  protected $api;
46
  /**
47
   * @var string ID of the adaccount this object belongs to
48
   */
49
  protected $parentId;
50
  /**
51
   * @param string $id Optional (do not set for new objects)
52
   * @param string $parent_id Optional, needed for creating new objects.
53
   * @param Api $api The Api instance this object should use to make calls
54
   */
55
  public function __construct($id = null, $parent_id = null, Api $api = null) {
56
    parent::__construct();
57
    $this->data[static::FIELD_ID] = $id;
58
    $this->parentId = $parent_id;
59
    $this->api = static::assureApi($api);
60
  }
61
  /**
62
   * @param string $id
63
   */
64
  public function setId($id) {
65
    $this->data[static::FIELD_ID] = $id;
66
    return $this;
67
  }
68
  /**
69
   * @param string $parent_id
70
   */
71
  public function setParentId($parent_id) {
72
    $this->parentId = $parent_id;
73
  }
74
  /**
75
   * @param Api $api The Api instance this object should use to make calls
76
   */
77
  public function setApi(Api $api) {
78
    $this->api = static::assureApi($api);
79
    return $this;
80
  }
81
  /**
82
   * @return string
83
   */
84
  protected function getEndpoint() {
85
    return null;
86
  }
87
  /**
88
   * @param Api|null $instance
89
   * @return Api
90
   * @throws \InvalidArgumentException
91
   */
92
  protected static function assureApi(Api $instance = null) {
93
    $instance = $instance ?: Api::instance();
94
    if (!$instance) {
95
      throw new \InvalidArgumentException(
96
        'An Api instance must be provided as argument or '.
97
        'set as instance in the \FacebookAds\Api');
98
    }
99
    return $instance;
100
  }
101
  /**
102
   * @return string|null
103
   */
104
  public function getParentId() {
105
    return $this->parentId;
106
  }
107
  /**
108
   * @return string
109
   * @throws \Exception
110
   */
111
  protected function assureParentId() {
112
    if (!$this->parentId) {
113
      throw new \Exception("A parent ID is required.");
114
    }
115
    return $this->parentId;
116
  }
117
  /**
118
   * @return string
119
   * @throws \Exception
120
   */
121
  protected function assureId() {
122
    if (!$this->data[static::FIELD_ID]) {
123
      throw new \Exception("field '".static::FIELD_ID."' is required.");
124
    }
125
    return (string) $this->data[static::FIELD_ID];
126
  }
127
  /**
128
   * @return Api
129
   */
130
  public function getApi() {
131
    return $this->api;
132
  }
133
  /**
134
   * Get the values which have changed
135
   *
136
   * @return array Key value pairs of changed variables
137
   */
138
  public function getChangedValues() {
139
    return $this->changedFields;
140
  }
141
  /**
142
   * Get the name of the fields that have changed
143
   *
144
   * @return array Array of changed field names
145
   */
146
  public function getChangedFields() {
147
    return array_keys($this->changedFields);
148
  }
149
  /**
150
   * Get the values which have changed, converting them to scalars
151
   */
152
  public function exportData() {
153
    $data = array();
154
    foreach ($this->changedFields as $key => $val) {
155
      $data[$key] = $val instanceof AbstractObject ? $val->exportData() : $val;
156
    }
157
    return $data;
158
  }
159
  /**
160
   * @return void
161
   */
162
  protected function clearHistory() {
163
    $this->changedFields = array();
164
  }
165
  /**
166
   * @param string $name
167
   * @param mixed $value
168
   */
169
  public function __set($name, $value) {
170
    if (!array_key_exists($name, $this->data)
171
      || $this->data[$name] !== $value) {
172
      $this->changedFields[$name] = $value;
173
    }
174
    parent::__set($name, $value);
175
  }
176
  /**
177
   * @param string[] $fields
178
   */
179
  public static function setDefaultReadFields(array $fields = array()) {
180
    static::$defaultReadFields = $fields;
181
  }
182
  /**
183
   * @return string[]
184
   */
185
  public static function getDefaultReadFields() {
186
    return static::$defaultReadFields;
187
  }
188
  /**
189
   * @return string
190
   */
191
  protected function getNodePath() {
192
    return '/'.$this->assureId();
193
  }
194
  /**
195
   * Create function for the object.
196
   *
197
   * @param array $params Additional parameters to include in the request
198
   * @return $this
199
   * @throws \Exception
200
   */
201
  public function create(array $params = array()) {
202
    if ($this->data[static::FIELD_ID]) {
203
      throw new \Exception("Object has already an ID");
204
    }
205
    $response = $this->getApi()->call(
206
      '/'.$this->assureParentId().'/'.$this->getEndpoint(),
207
      RequestInterface::METHOD_POST,
208
      array_merge($this->exportData(), $params));
209
    $this->clearHistory();
210
    $data = $response->getContent();
211
    if (!isset($params['execution_options'])){
212
      $id = is_string($data) ? $data : $data[static::FIELD_ID];
213
    /** @var AbstractCrudObject $this */
214
      if ($this instanceof CanRedownloadInterface
215
        && isset($params[CanRedownloadInterface::PARAM_REDOWNLOAD])
216
        && $params[CanRedownloadInterface::PARAM_REDOWNLOAD] === true
217
        && isset($data['data'][$id])
218
        && is_array($data['data'][$id])
219
      ) {
220
        $this->setDataWithoutValidation($data['data'][$id]);
221
      }
222
      $this->data[static::FIELD_ID] = (string) $id;
223
    }
224
    return $this;
225
  }
226
  /**
227
   * Read object data from the graph
228
   *
229
   * @param string[] $fields Fields to request
230
   * @param array $params Additional request parameters
231
   * @return $this
232
   */
233
  public function read(array $fields = array(), array $params = array()) {
234
    $fields = implode(',', $fields ?: static::getDefaultReadFields());
235
    if ($fields) {
236
      $params['fields'] = $fields;
237
    }
238
    $response = $this->getApi()->call(
239
      $this->getNodePath(),
240
      RequestInterface::METHOD_GET,
241
      $params);
242
    $this->setDataWithoutValidation($response->getContent());
243
    $this->clearHistory();
244
    return $this;
245
  }
246
  /**
247
   * Update the object. Function parameters are similar with the create function
248
   *
249
   * @param array $params Update parameters in assoc
250
   * @return $this
251
   */
252
  public function update(array $params = array()) {
253
    $this->getApi()->call(
254
      $this->getNodePath(),
255
      RequestInterface::METHOD_POST,
256
      array_merge($this->exportData(), $params));
257
    $this->clearHistory();
258
    return $this;
259
  }
260
  /**
261
   * Delete this object from the graph
262
   *
263
   * @param array $params
264
   * @return void
265
   */
266
  public function delete(array $params = array()) {
267
    $this->getApi()->call(
268
      $this->getNodePath(),
269
      RequestInterface::METHOD_DELETE,
270
      $params);
271
  }
272
  /**
273
   * Perform object upsert
274
   *
275
   * Helper function which determines whether an object should be created or
276
   * updated
277
   *
278
   * @param array $params
279
   * @return $this
280
   */
281
  public function save(array $params = array()) {
282
    if ($this->data[static::FIELD_ID]) {
283
      return $this->update($params);
284
    } else {
285
      return $this->create($params);
286
    }
287
  }
288
  /**
289
   * @param string $prototype_class
290
   * @param string $endpoint
291
   * @return string
292
   * @throws \InvalidArgumentException
293
   */
294
  protected function assureEndpoint($prototype_class, $endpoint) {
295
    if (!$endpoint) {
296
      $prototype = new $prototype_class(null, null, $this->getApi());
297
      if (!$prototype instanceof AbstractCrudObject) {
298
        throw new \InvalidArgumentException('Either prototype must be instance
299
          of AbstractCrudObject or $endpoint must be given');
300
      }
301
      $endpoint = $prototype->getEndpoint();
302
    }
303
    return $endpoint;
304
  }
305
  /**
306
   * @param array $fields
307
   * @param array $params
308
   * @param string $prototype_class
309
   * @param string|null $endpoint
310
   * @return ResponseInterface
311
   */
312
  protected function fetchConnection(
313
    array $fields = array(),
314
    array $params = array(),
315
    $prototype_class,
316
    $endpoint = null) {
317
    $fields = implode(',', $fields ?: static::getDefaultReadFields());
318
    if ($fields) {
319
      $params['fields'] = $fields;
320
    }
321
    $endpoint = $this->assureEndpoint($prototype_class, $endpoint);
322
    return $this->getApi()->call(
323
      '/'.$this->assureId().'/'.$endpoint,
324
      RequestInterface::METHOD_GET,
325
      $params);
326
  }
327
  /**
328
   * Read a single connection object
329
   *
330
   * @param string $prototype_class
331
   * @param array $fields Fields to request
332
   * @param array $params Additional filters for the reading
333
   * @param string|null $endpoint
334
   * @return AbstractObject
335
   */
336
  protected function getOneByConnection(
337
    $prototype_class,
338
    array $fields = array(),
339
    array $params = array(),
340
    $endpoint = null) {
341
    $response = $this->fetchConnection(
342
      $fields, $params, $prototype_class, $endpoint);
343
    if (!$response->getContent()) {
344
      return null;
345
    }
346
    $object = new $prototype_class(
347
      null, $this->{static::FIELD_ID}, $this->getApi());
348
    /** @var AbstractCrudObject $object */
349
    $object->setDataWithoutValidation($response->getContent());
350
    return $object;
351
  }
352
  /**
353
   * Read objects from a connection
354
   *
355
   * @param string $prototype_class
356
   * @param array $fields Fields to request
357
   * @param array $params Additional filters for the reading
358
   * @param string|null $endpoint
359
   * @return Cursor
360
   */
361
  protected function getManyByConnection(
362
    $prototype_class,
363
    array $fields = array(),
364
    array $params = array(),
365
    $endpoint = null) {
366
    $response = $this->fetchConnection(
367
      $fields, $params, $prototype_class, $endpoint);
368
    return new Cursor(
369
      $response,
370
      new $prototype_class(null, $this->{static::FIELD_ID}, $this->getApi()));
371
  }
372
  /**
373
   * @param string $job_class
374
   * @param array $fields
375
   * @param array $params
376
   * @return AbstractAsyncJobObject
377
   * @throws \InvalidArgumentException
378
   */
379
  protected function createAsyncJob(
380
    $job_class,
381
    array $fields = array(),
382
    array $params = array()) {
383
    $object = new $job_class(null, $this->assureId(), $this->getApi());
384
    if (!$object instanceof AbstractAsyncJobObject) {
0 ignored issues
show
Bug introduced by
The class FacebookAds\Object\AbstractAsyncJobObject 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...
385
      throw new \InvalidArgumentException(
386
        "Class {$job_class} is not of type "
387
        .AbstractAsyncJobObject::className());
388
    }
389
    $params['fields'] = $fields;
390
    return $object->create($params);
391
  }
392
  /**
393
   * Delete objects.
394
   *
395
   * Used batch API calls to delete multiple objects at once
396
   *
397
   * @param string[] $ids Array or single Object ID to delete
398
   * @param Api $api Api Object to use
399
   * @return bool Returns true on success
400
   */
401
  public static function deleteIds(array $ids, Api $api = null) {
402
    $batch = array();
403
    foreach ($ids as $id) {
404
      $request = array(
405
        'relative_url' => '/'.$id,
406
        'method' => RequestInterface::METHOD_DELETE,
407
      );
408
      $batch[] = $request;
409
    }
410
    $api = static::assureApi($api);
411
    $response = $api->call(
412
      '/',
413
      RequestInterface::METHOD_POST,
414
      array('batch' => json_encode($batch)));
415
    foreach ($response->getContent() as $result) {
416
      if (200 != $result['code']) {
417
        return false;
418
      }
419
    }
420
    return true;
421
  }
422
  /**
423
   * Read function for the object. Convert fields and filters into the query
424
   * part of uri and return objects.
425
   *
426
   * @param mixed $ids Array or single object IDs
427
   * @param array $fields Array of field names to read
428
   * @param array $params Additional filters for the reading, in assoc
429
   * @param Api $api Api Object to use
430
   * @return Cursor
431
   */
432
  public static function readIds(
433
    array $ids,
434
    array $fields = array(),
435
    array $params = array(),
436
    Api $api = null) {
437
    if (empty($fields)) {
438
      $fields = static::getDefaultReadFields();
439
    }
440
    if (!empty($fields)) {
441
      $params['fields'] = implode(',', $fields);
442
    }
443
    $params['ids'] = implode(',', $ids);
444
    $api = static::assureApi($api);
445
    $response = $api->call('/', RequestInterface::METHOD_GET, $params);
446
    $result = array();
447
    foreach ($response->getContent() as $data) {
448
      /** @var AbstractObject $object */
449
      $object = new static(null, null, $api);
450
      $object->setDataWithoutValidation((array) $data);
451
      $result[] = $object;
452
    }
453
    return $result;
454
  }
455
}
456