Completed
Push — master ( 22ee83...d51193 )
by
unknown
03:10
created

AbstractCrudObject::exportData()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 5
nc 3
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
  /**
52
   * @deprecated deprecate constructor with null and parent_id
53
   * @param string $id Optional (do not set for new objects)
54
   * @param string $parent_id Optional, needed for creating new objects.
55
   * @param Api $api The Api instance this object should use to make calls
56
   */
57
  public function __construct($id = null, $parent_id = null, Api $api = null) {
58
    parent::__construct();
59
    $this->data[static::FIELD_ID] = $id;
60
61
    if (!is_null($parent_id)) {
62
      $warning_message = "\$parent_id as a parameter of constructor is being " .
63
        "deprecated, please try not to use this in new code.\n";
64
      error_log($warning_message);
65
    }
66
    $this->parentId = $parent_id;
67
68
    $this->api = static::assureApi($api);
69
  }
70
71
  /**
72
   * @param string $id
73
   */
74
  public function setId($id) {
75
    $this->data[static::FIELD_ID] = $id;
76
    return $this;
77
  }
78
  /**
79
   * @param string $parent_id
80
   */
81
  public function setParentId($parent_id) {
82
    $this->parentId = $parent_id;
83
  }
84
  /**
85
   * @param Api $api The Api instance this object should use to make calls
86
   */
87
  public function setApi(Api $api) {
88
    $this->api = static::assureApi($api);
89
    return $this;
90
  }
91
  /**
92
   * @deprecated getEndpoint function is deprecated
93
   * @return string
94
   */
95
  protected function getEndpoint() {
96
    return null;
97
  }
98
  /**
99
   * @param Api|null $instance
100
   * @return Api
101
   * @throws \InvalidArgumentException
102
   */
103
  protected static function assureApi(Api $instance = null) {
104
    $instance = $instance ?: Api::instance();
105
    if (!$instance) {
106
      throw new \InvalidArgumentException(
107
        'An Api instance must be provided as argument or '.
108
        'set as instance in the \FacebookAds\Api');
109
    }
110
    return $instance;
111
  }
112
  /**
113
   * @return string|null
114
   */
115
  public function getParentId() {
116
    return $this->parentId;
117
  }
118
  /**
119
   * @return string
120
   * @throws \Exception
121
   */
122
  protected function assureParentId() {
123
    if (!$this->parentId) {
124
      throw new \Exception("A parent ID is required.");
125
    }
126
    return $this->parentId;
127
  }
128
  /**
129
   * @return string
130
   * @throws \Exception
131
   */
132
  protected function assureId() {
133
    if (!$this->data[static::FIELD_ID]) {
134
      throw new \Exception("field '".static::FIELD_ID."' is required.");
135
    }
136
    return (string) $this->data[static::FIELD_ID];
137
  }
138
  /**
139
   * @return Api
140
   */
141
  public function getApi() {
142
    return $this->api;
143
  }
144
  /**
145
   * Get the values which have changed
146
   *
147
   * @return array Key value pairs of changed variables
148
   */
149
  public function getChangedValues() {
150
    return $this->changedFields;
151
  }
152
  /**
153
   * Get the name of the fields that have changed
154
   *
155
   * @return array Array of changed field names
156
   */
157
  public function getChangedFields() {
158
    return array_keys($this->changedFields);
159
  }
160
  /**
161
   * Get the values which have changed, converting them to scalars
162
   */
163
  public function exportData() {
164
    $data = array();
165
    foreach ($this->changedFields as $key => $val) {
166
      $data[$key] = $val instanceof AbstractObject ? $val->exportData() : $val;
167
    }
168
    return $data;
169
  }
170
  /**
171
   * @return void
172
   */
173
  protected function clearHistory() {
174
    $this->changedFields = array();
175
  }
176
  /**
177
   * @param string $name
178
   * @param mixed $value
179
   */
180
  public function __set($name, $value) {
181
    if (!array_key_exists($name, $this->data)
182
      || $this->data[$name] !== $value) {
183
      $this->changedFields[$name] = $value;
184
    }
185
    parent::__set($name, $value);
186
  }
187
  /**
188
   * @param string[] $fields
189
   */
190
  public static function setDefaultReadFields(array $fields = array()) {
191
    static::$defaultReadFields = $fields;
192
  }
193
  /**
194
   * @return string[]
195
   */
196
  public static function getDefaultReadFields() {
197
    return static::$defaultReadFields;
198
  }
199
  /**
200
   * @return string
201
   */
202
  protected function getNodePath() {
203
    return '/'.$this->assureId();
204
  }
205
  /**
206
   * Create function for the object.
207
   *
208
   * @param array $params Additional parameters to include in the request
209
   * @return $this
210
   * @throws \Exception
211
   */
212
  public function create(array $params = array()) {
213
    if ($this->data[static::FIELD_ID]) {
214
      throw new \Exception("Object has already an ID");
215
    }
216
    $response = $this->getApi()->call(
217
      '/'.$this->assureParentId().'/'.$this->getEndpoint(),
0 ignored issues
show
Deprecated Code introduced by
The method FacebookAds\Object\Abstr...udObject::getEndpoint() has been deprecated with message: getEndpoint function is deprecated

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
218
      RequestInterface::METHOD_POST,
219
      array_merge($this->exportData(), $params));
220
    $this->clearHistory();
221
    $data = $response->getContent();
222
    if (!isset($params['execution_options'])){
223
      $id = is_string($data) ? $data : $data[static::FIELD_ID];
224
    /** @var AbstractCrudObject $this */
225
      if ($this instanceof CanRedownloadInterface
226
        && isset($params[CanRedownloadInterface::PARAM_REDOWNLOAD])
227
        && $params[CanRedownloadInterface::PARAM_REDOWNLOAD] === true
228
        && isset($data['data'][$id])
229
        && is_array($data['data'][$id])
230
      ) {
231
        $this->setDataWithoutValidation($data['data'][$id]);
232
      }
233
      $this->data[static::FIELD_ID] = (string) $id;
234
    }
235
    return $this;
236
  }
237
  /**
238
   * Read object data from the graph
239
   *
240
   * @param string[] $fields Fields to request
241
   * @param array $params Additional request parameters
242
   * @return $this
243
   */
244
  public function read(array $fields = array(), array $params = array()) {
245
    $fields = implode(',', $fields ?: static::getDefaultReadFields());
246
    if ($fields) {
247
      $params['fields'] = $fields;
248
    }
249
    $response = $this->getApi()->call(
250
      $this->getNodePath(),
251
      RequestInterface::METHOD_GET,
252
      $params);
253
    $this->setDataWithoutValidation($response->getContent());
254
    $this->clearHistory();
255
    return $this;
256
  }
257
  /**
258
   * Update the object. Function parameters are similar with the create function
259
   *
260
   * @param array $params Update parameters in assoc
261
   * @return $this
262
   */
263
  public function update(array $params = array()) {
264
    $this->getApi()->call(
265
      $this->getNodePath(),
266
      RequestInterface::METHOD_POST,
267
      array_merge($this->exportData(), $params));
268
    $this->clearHistory();
269
    return $this;
270
  }
271
  /**
272
   * Delete this object from the graph
273
   *
274
   * @param array $params
275
   * @return void
276
   */
277
  public function deleteSelf(array $params = array()) {
278
    $this->getApi()->call(
279
      $this->getNodePath(),
280
      RequestInterface::METHOD_DELETE,
281
      $params);
282
  }
283
  /**
284
   * Perform object upsert
285
   *
286
   * Helper function which determines whether an object should be created or
287
   * updated
288
   *
289
   * @param array $params
290
   * @return $this
291
   */
292
  public function save(array $params = array()) {
293
    if ($this->data[static::FIELD_ID]) {
294
      return $this->update($params);
295
    } else {
296
      return $this->create($params);
297
    }
298
  }
299
  /**
300
   * @param string $prototype_class
301
   * @param string $endpoint
302
   * @return string
303
   * @throws \InvalidArgumentException
304
   */
305
  protected function assureEndpoint($prototype_class, $endpoint) {
306
    if (!$endpoint) {
307
      $prototype = new $prototype_class(null, null, $this->getApi());
308
      if (!$prototype instanceof AbstractCrudObject) {
309
        throw new \InvalidArgumentException('Either prototype must be instance
310
          of AbstractCrudObject or $endpoint must be given');
311
      }
312
      $endpoint = $prototype->getEndpoint();
0 ignored issues
show
Deprecated Code introduced by
The method FacebookAds\Object\Abstr...udObject::getEndpoint() has been deprecated with message: getEndpoint function is deprecated

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
313
    }
314
    return $endpoint;
315
  }
316
  /**
317
   * @param array $fields
318
   * @param array $params
319
   * @param string $prototype_class
320
   * @param string|null $endpoint
321
   * @return ResponseInterface
322
   */
323
  protected function fetchConnection(
324
    array $fields = array(),
325
    array $params = array(),
326
    $prototype_class,
327
    $endpoint = null) {
328
    $fields = implode(',', $fields ?: static::getDefaultReadFields());
329
    if ($fields) {
330
      $params['fields'] = $fields;
331
    }
332
    $endpoint = $this->assureEndpoint($prototype_class, $endpoint);
333
    return $this->getApi()->call(
334
      '/'.$this->assureId().'/'.$endpoint,
335
      RequestInterface::METHOD_GET,
336
      $params);
337
  }
338
  /**
339
   * Read a single connection object
340
   *
341
   * @param string $prototype_class
342
   * @param array $fields Fields to request
343
   * @param array $params Additional filters for the reading
344
   * @param string|null $endpoint
345
   * @return AbstractObject
346
   */
347
  protected function getOneByConnection(
348
    $prototype_class,
349
    array $fields = array(),
350
    array $params = array(),
351
    $endpoint = null) {
352
    $response = $this->fetchConnection(
353
      $fields, $params, $prototype_class, $endpoint);
354
    if (!$response->getContent()) {
355
      return null;
356
    }
357
    $object = new $prototype_class(
358
      null, $this->{static::FIELD_ID}, $this->getApi());
359
    /** @var AbstractCrudObject $object */
360
    $object->setDataWithoutValidation($response->getContent());
361
    return $object;
362
  }
363
  /**
364
   * Read objects from a connection
365
   *
366
   * @param string $prototype_class
367
   * @param array $fields Fields to request
368
   * @param array $params Additional filters for the reading
369
   * @param string|null $endpoint
370
   * @return Cursor
371
   */
372
  protected function getManyByConnection(
373
    $prototype_class,
374
    array $fields = array(),
375
    array $params = array(),
376
    $endpoint = null) {
377
    $response = $this->fetchConnection(
378
      $fields, $params, $prototype_class, $endpoint);
379
    return new Cursor(
380
      $response,
381
      new $prototype_class(null, $this->{static::FIELD_ID}, $this->getApi()));
382
  }
383
  /**
384
   * @param string $job_class
385
   * @param array $fields
386
   * @param array $params
387
   * @return AbstractAsyncJobObject
388
   * @throws \InvalidArgumentException
389
   */
390
  protected function createAsyncJob(
391
    $job_class,
392
    array $fields = array(),
393
    array $params = array()) {
394
    $object = new $job_class(null, $this->assureId(), $this->getApi());
395
    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...
396
      throw new \InvalidArgumentException(
397
        "Class {$job_class} is not of type "
398
        .AbstractAsyncJobObject::className());
399
    }
400
    $params['fields'] = $fields;
401
    return $object->create($params);
402
  }
403
  /**
404
   * Delete objects.
405
   *
406
   * Used batch API calls to delete multiple objects at once
407
   *
408
   * @param string[] $ids Array or single Object ID to delete
409
   * @param Api $api Api Object to use
410
   * @return bool Returns true on success
411
   */
412
  public static function deleteIds(array $ids, Api $api = null) {
413
    $batch = array();
414
    foreach ($ids as $id) {
415
      $request = array(
416
        'relative_url' => '/'.$id,
417
        'method' => RequestInterface::METHOD_DELETE,
418
      );
419
      $batch[] = $request;
420
    }
421
    $api = static::assureApi($api);
422
    $response = $api->call(
423
      '/',
424
      RequestInterface::METHOD_POST,
425
      array('batch' => json_encode($batch)));
426
    foreach ($response->getContent() as $result) {
427
      if (200 != $result['code']) {
428
        return false;
429
      }
430
    }
431
    return true;
432
  }
433
  /**
434
   * Read function for the object. Convert fields and filters into the query
435
   * part of uri and return objects.
436
   *
437
   * @param mixed $ids Array or single object IDs
438
   * @param array $fields Array of field names to read
439
   * @param array $params Additional filters for the reading, in assoc
440
   * @param Api $api Api Object to use
441
   * @return Cursor
442
   */
443
  public static function readIds(
444
    array $ids,
445
    array $fields = array(),
446
    array $params = array(),
447
    Api $api = null) {
448
    if (empty($fields)) {
449
      $fields = static::getDefaultReadFields();
450
    }
451
    if (!empty($fields)) {
452
      $params['fields'] = implode(',', $fields);
453
    }
454
    $params['ids'] = implode(',', $ids);
455
    $api = static::assureApi($api);
456
    $response = $api->call('/', RequestInterface::METHOD_GET, $params);
457
    $result = array();
458
    foreach ($response->getContent() as $data) {
459
      /** @var AbstractObject $object */
460
      $object = new static(null, null, $api);
461
      $object->setDataWithoutValidation((array) $data);
462
      $result[] = $object;
463
    }
464
    return $result;
465
  }
466
}
467