<?php
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

require __DIR__ . '/vendor/autoload.php';

use FacebookAds\Object\Lead;
use FacebookAds\Api;
use FacebookAds\Logger\CurlLogger;

$access_token = '<ACCESS_TOKEN>';
$app_secret = '<APP_SECRET>';
$app_id = '<APP_ID>';
$id = '<LEAD_ID>';

$api = Api::init($app_id, $app_secret, $access_token);
$api->setLogger(new CurlLogger());

$fields = array(
);
$params = array(
);
echo json_encode((new Lead($id))->getSelf(
  $fields,
  $params
)->exportAllData(), JSON_PRETTY_PRINT);


<?php
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

require __DIR__ . '/vendor/autoload.php';

use FacebookAds\Object\User;
use FacebookAds\Api;
use FacebookAds\Logger\CurlLogger;

$access_token = '<ACCESS_TOKEN>';
$app_secret = '<APP_SECRET>';
$app_id = '<APP_ID>';
$id = '<USER_ID>';

$api = Api::init($app_id, $app_secret, $access_token);
$api->setLogger(new CurlLogger());

$fields = array(
);
$params = array(
);
echo json_encode((new User($id))->getSelf(
  $fields,
  $params
)->exportAllData(), JSON_PRETTY_PRINT);


<?php
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 * All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

require __DIR__ . '/vendor/autoload.php';

use FacebookAds\Object\AdVideo;
use FacebookAds\Object\VideoThumbnail;
use FacebookAds\Api;
use FacebookAds\Logger\CurlLogger;

$access_token = '<ACCESS_TOKEN>';
$app_secret = '<APP_SECRET>';
$app_id = '<APP_ID>';
$id = '<VIDEO_ID>';

$api = Api::init($app_id, $app_secret, $access_token);
$api->setLogger(new CurlLogger());

$fields = array(
);
$params = array(
);
echo json_encode((new AdVideo($id))->getThumbnails(
  $fields,
  $params
)->getResponse()->getContent(), JSON_PRETTY_PRINT);


<?php
/**
 * Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

use FacebookAds\Api;
use FacebookAds\Logger\CurlLogger;
use FacebookAds\Object\AbstractObject;
use FacebookAds\Object\AbstractCrudObject;
use FacebookAds\Object\AdAccount;
use FacebookAds\Object\Campaign;
use FacebookAds\Object\Fields\AdAccountFields;
use FacebookAds\Object\Fields\CampaignFields;
use FacebookAds\ApiRequest;
use FacebookAds\Http\RequestInterface;
use FacebookAds\Object\Targeting;
use FacebookAds\Object\Fields\TargetingFields;
use FacebookAds\Object\AdSet;
use FacebookAds\Object\Fields\AdSetFields;
use FacebookAds\Object\Values\AdSetBillingEventValues;
use FacebookAds\Object\Values\AdSetOptimizationGoalValues;
use FacebookAds\Object\Ad;
use FacebookAds\Object\Fields\AdFields;
use FacebookAds\Object\AdImage;
use FacebookAds\Object\Fields\AdImageFields;
use FacebookAds\Object\AdCreative;
use FacebookAds\Object\Values\AdCreativeCallToActionTypeValues;
use FacebookAds\Object\AdCreativeLinkData;
use FacebookAds\Object\Fields\AdCreativeLinkDataCallToActionValueFields;
use FacebookAds\Object\Fields\AdCreativeLinkDataFields;
use FacebookAds\Object\AdCreativeObjectStorySpec;
use FacebookAds\Object\Fields\AdCreativeObjectStorySpecFields;
use FacebookAds\Object\Fields\AdCreativeFields;
use FacebookAds\Object\Values\PageCallToActionWebDestinationTypeValues;

use FacebookAds\Object\Business;
use FacebookAds\Object\Fields\BusinessFields;
use FacebookAds\Object\ExtendedCredit;

// Run with command: php -S localhost:8000

// *** Replace the constants below ***
// Aggregator Info:
$app_id = '';
$app_secret = '';
$aggregator_access_token = '';
$aggregator_bm_id = 0;
$bm_loc_id = 0;
// Clients Info
$page_id = 0;

define('SDK_DIR', __DIR__); // Path to the SDK directory
$loader = include SDK_DIR.'/vendor/autoload.php';
// Configurations - End
if (
  is_null($aggregator_access_token) || is_null($app_id) || is_null($app_secret)
) {
  throw new Exception(
    'You must set your access token, app id and app secret before executing'
  );
}

// Initialize a new Session and instanciate an Api object
Api::init($app_id, $app_secret, $aggregator_access_token);

// The Api object is now available through singleton
$api = Api::instance();
$logger = new CurlLogger();
$api->setLogger($logger);

function getEdges($api, $params, $fields, $node_id, $edge) {
  if ($fields) {
    $fields = implode(',', $fields);
    $params['fields'] = $fields;
  }
  $response =
    $api->call('/'.$node_id.'/'.$edge, RequestInterface::METHOD_GET, $params);
  return $response->getContent();
}

function postEdges($api, $params, $node_id, $edge) {
  $response =
    $api->call('/'.$node_id.'/'.$edge, RequestInterface::METHOD_POST, $params);
  return $response->getContent();
}

function setAccessToken($access_token) {
  global $app_secret, $app_id;
  Api::init($app_id, $app_secret, $access_token);
  $api = Api::instance();
  $logger = new CurlLogger();
  $api->setLogger($logger);
  return $api;
}

function create_client_business($access_token) {
  global
    $app_id,
    $app_secret,
    $aggregator_bm_id,
    $page_id,
    $bm_loc_id,
    $aggregator_access_token;

  $api = setAccessToken($access_token);
  $me = getEdges($api, array(), array(), 'me', '');
  $app_scoped_user_id = $me['id'];

  $api = setAccessToken($aggregator_access_token);
  $child_business = (new Business($aggregator_bm_id))->getOwnedBusinesses(
    array(),
    array(
      'client_user_id' => $app_scoped_user_id,
    ),
  );

  if (!is_null($child_business) && !is_null($child_business[0])) {
    $child_business_id = $child_business[0]->id;
    // A partner can only create one child business manager on behalf
    // of the user. Exit to avoid erroring.
    $accounts =
      (new Business($child_business_id))->getOwnedAdAccounts(array(), array());
    $existing_account = '';
    if (!is_null($accounts) && !is_null($accounts[0])) {
      $existing_account = $accounts[0]->id;
    }
    return $child_business_id.','.$existing_account;
  }

  /**
   * Step 1 Create the child BM under the Aggregator BM
   */
  $child_business = (new Business($aggregator_bm_id))->createOwnedBusiness(
    array(),
    array(
      'id' => $aggregator_bm_id,
      BusinessFields::NAME => 'Advertisers Name Child BM',
      BusinessFields::VERTICAL => 'OTHER',
      'shared_page_id' => $page_id,
      'page_permitted_roles' => ['ADVERTISER'],
      'timezone_id' => 1,
    ),
  );
  $child_business_id = $child_business->id;

  /**
   * Step 2 Share credit line from Aggregator BM to client BM.
   * This uses the Aggregators access token.
   */
  $api = setAccessToken($aggregator_access_token);
  (new ExtendedCredit($bm_loc_id))->createOwningCreditAllocationConfig(
    array(),
    array(
      'receiving_business_id' => $child_business_id,
      'amount' => 10,
    ),
  );

  /**
   * Step 3 Create access token System user under child BM.
   * This uses the Aggregators access token.
   */
  $api = setAccessToken($aggregator_access_token);
  $child_business_token = (new Business($child_business_id))->createAccessToken(
    array(),
    array(
      'id' => $child_business_id,
      'app_id' => $app_id,
      'scope' => 'manage_pages,ads_management,business_management',
    ),
  );
  $child_bm_system_user_access_token = $child_business_token->access_token;

  /**
   * Step 4 Fetch funding source shared with BM
   * This uses the Child BMs access token.
   */
  $api = setAccessToken($child_bm_system_user_access_token);
  $params = array();
  $fields = array();
  $response =
    getEdges($api, $params, $fields, $child_business_id, 'extendedcredits');
  $child_bm_payment_method_id = $response['data'][0]['id'];

  /**
   * Step 5 Create Ad Account
   * This uses the Child BMs access token. The Admin System user for their
   * child BM is the owner of the Ad Account.
   */
  $api = setAccessToken($child_bm_system_user_access_token);
  $account = (new Business($child_business_id))->createAdAccount(
    array(),
    array(
      'name' => 'MyAdAccount',
      'currency' => 'USD',
      'timezone_id' => 1,
      'end_advertiser' => $page_id,
      'media_agency' => 'NONE',
      'partner' => 'NONE',
      'funding_id' => $child_bm_payment_method_id,
    ),
  );
  $account_id = $account->id;

  /**
   * Step 6 Fetch the System user for the client business.
   * This uses the Child BMs access token. This system user id is used in the api calls below.
   */
  $api = setAccessToken($child_bm_system_user_access_token);
  $system_user_id =
    (new Business($child_business_id))->getSystemUsers(array(), array())[0]->id;

  /**
   * Step 7 Add System user as Admin to Ad Account.
   * This uses the Child BMs access token.
   */
  $api = setAccessToken($child_bm_system_user_access_token);
  (new AdAccount($account_id))->createAssignedUser(
    array(),
    array(
      'user' => $system_user_id,
      'role' => 'ADMIN',
      'business' => $child_business_id,
    ),
  );

  return $child_business_id.','.$account_id;
}

function create_click_to_messenger_ad(
  $account_id,
  $bmid,
  $ad_message,
  $page_welcome_message,
) {
  global $aggregator_access_token, $app_id, $page_id;
  $api = setAccessToken($aggregator_access_token);
  $child_business_token = (new Business($bmid))->createAccessToken(
    array(),
    array(
      'app_id' => $app_id,
      'scope' => 'manage_pages,ads_management,business_management',
    ),
  );
  $child_bm_system_user_access_token = $child_business_token->access_token;
  $api = setAccessToken($child_bm_system_user_access_token);
  $account = new AdAccount($account_id);
  $campaign = $account->createCampaign(
    array(),
    array(
      CampaignFields::NAME => 'First test Campaign',
      CampaignFields::OBJECTIVE => 'MESSAGES',
    ),
  );

  /**
   * Step 2 Search Targeting
   */
  $targeting = new Targeting();
  $targeting->setData(array(
    TargetingFields::GEO_LOCATIONS => array(
      'countries' => array('JP'),
      'regions' => array(array('key' => '3886')),
      'cities' => array(
        array(
          'key' => '2420605',
          'radius' => 10,
          'distance_unit' => 'mile',
        ),
      ),
    ),
  ));

  /**
   * Step 3 Create the AdSet
   */
  $start_time = (new \DateTime("+1 week"))->format(DateTime::ISO8601);
  $end_time = (new \DateTime("+2 week"))->format(DateTime::ISO8601);
  $fields = array();
  $params = array(
    AdSetFields::NAME => 'First Ad Set',
    AdSetFields::OPTIMIZATION_GOAL => AdSetOptimizationGoalValues::REPLIES,
    AdSetFields::BILLING_EVENT => AdSetBillingEventValues::IMPRESSIONS,
    AdSetFields::BID_AMOUNT => 2,
    AdSetFields::DAILY_BUDGET => 1000,
    AdSetFields::CAMPAIGN_ID => $campaign->id,
    AdSetFields::TARGETING => $targeting,
    AdSetFields::START_TIME => $start_time,
    AdSetFields::END_TIME => $end_time,
  );
  $ad_set = $account->createAdSet($fields, $params);
  $ad_set_id = $ad_set->id;

  /**
   * Step 4 Create an AdImage
   */

  $image = new AdImage();
  $image->setParentId($account->id);
  $image->{AdImageFields::FILENAME} = SDK_DIR.'<YOUR-IMAGE-PATH>';

  $image->create();
  $image_hash = $image->hash;

  /**
   * Step 5 Create an AdCreative
   */

  $link_data = new AdCreativeLinkData();
  $link_data->setData(array(
    AdCreativeLinkDataFields::CALL_TO_ACTION => array(
      'type' => AdCreativeCallToActionTypeValues::LEARN_MORE,
      'value' => array(
        AdCreativeLinkDataCallToActionValueFields::APP_DESTINATION =>
          PageCallToActionWebDestinationTypeValues::MESSENGER,
      ),
    ),
    AdCreativeLinkDataFields::LINK => '<YOUR-LINK>',
    AdCreativeLinkDataFields::IMAGE_HASH => $image->hash,
    AdCreativeLinkDataFields::MESSAGE => $ad_message,
    AdCreativeLinkDataFields::PAGE_WELCOME_MESSAGE => $page_welcome_message,
  ));

  $object_story_spec = new AdCreativeObjectStorySpec();
  $object_story_spec->setData(array(
    AdCreativeObjectStorySpecFields::PAGE_ID => $page_id,
    AdCreativeObjectStorySpecFields::LINK_DATA => $link_data,
  ));

  $creative = $account->createAdCreative(
    array(),
    array(
      AdCreativeFields::NAME => 'Sample Creative',
      AdCreativeFields::OBJECT_STORY_SPEC => $object_story_spec,
    ),
  );

  $ad = $account->createAd(
    array(),
    array(
      'status' => 'ACTIVE',
      'adset_id' => $ad_set_id,
      'name' => 'My Ad',
      'creative' => array('creative_id' => $creative->id),
    ),
  );
  $ad_id = $ad->id;
  return 'Ad ID: '.$ad_id;
}

$possible_url = array("create_client_business", "create_click_to_messenger_ad");

$value = "An error has occurred";

if (isset($_GET["action"]) && in_array($_GET["action"], $possible_url)) {
  switch ($_GET["action"]) {
    case "create_client_business":
      if (isset($_GET["access_token"]))
        $value = create_client_business($_GET["access_token"]);
      else
        $value = "Missing argument";
      break;
    case "create_click_to_messenger_ad":
      if (
        isset($_GET["adaccount"]) &&
        isset($_GET["bmid"]) &&
        isset($_GET["ad_message"]) &&
        isset($_GET["page_welcome_message"])
      )
        $value = create_click_to_messenger_ad(
          $_GET["adaccount"],
          $_GET["bmid"],
          $_GET["ad_message"],
          $_GET["page_welcome_message"],
        );
      else
        $value = "Missing argument";
      break;
  }
}

//return JSON array
exit(json_encode($value));
?>


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds;

class AnonymousSession implements SessionInterface {

  /**
   * @return array
   */
  public function getRequestParameters() {
    return array();
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds;

use FacebookAds\Http\Client;
use FacebookAds\Http\RequestInterface;
use FacebookAds\Http\ResponseInterface;
use FacebookAds\Logger\LoggerInterface;
use FacebookAds\Logger\NullLogger;
use FacebookAds\CrashReporter;

class Api {

  /**
   * @var string
   */
  const VERSION = ApiConfig::APIVersion;

  /**
   * @var Api
   */
  protected static $instance;

  /**
   * @var SessionInterface
   */
  private $session;

  /**
   * @var LoggerInterface
   */
  protected $logger;

  /**
   * @var Client
   */
  protected $httpClient;

  /**
   * @var string
   */
  protected $defaultGraphVersion;

  /**
   * @param Client $http_client
   * @param SessionInterface $session A Facebook API session
   */
  public function __construct(
    Client $http_client,
    SessionInterface $session) {
    $this->httpClient = $http_client;
    $this->session = $session;
  }

  /**
   * @param string $app_id
   * @param string $app_secret
   * @param string $access_token
   * @return static
   */
  public static function init($app_id, $app_secret, $access_token, $log_crash=true) {
    $session = new Session($app_id, $app_secret, $access_token);
    $api = new static(new Client(), $session);
    static::setInstance($api);
    if ($log_crash) {
      CrashReporter::enable();
    }
    return $api;
  }

  /**
   * @return Api|null
   */
  public static function instance() {
    return static::$instance;
  }

  /**
   * @param Api $instance
   */
  public static function setInstance(Api $instance) {
    static::$instance = $instance;
  }

  /**
   * @param SessionInterface $session
   * @return Api
   */
  public function getCopyWithSession(SessionInterface $session) {
    $api = new self($this->getHttpClient(), $session);
    $api->setDefaultGraphVersion($this->getDefaultGraphVersion());
    $api->setLogger($this->getLogger());
    return $api;
  }

  /**
   * @param string $string
   * @return string
   */
  public static function base64UrlEncode($string) {
    $str = strtr(base64_encode($string), '+/', '-_');
    $str = str_replace('=', '', $str);
    return $str;
  }

  /**
   * @param string $path
   * @param string $method
   * @param array $params
   * @return RequestInterface
   */
  public function prepareRequest(
    $path,
    $method = RequestInterface::METHOD_GET,
    array $params = array()) {

    $request = $this->getHttpClient()->createRequest();
    $request->setMethod($method);
    $request->setGraphVersion($this->getDefaultGraphVersion());
    $request->setPath($path);

    if ($method === RequestInterface::METHOD_GET) {
      $params_ref = $request->getQueryParams();
    } else {
      $params_ref = $request->getBodyParams();
    }

    if (!empty($params)) {
      $params_ref->enhance($params);
    }

    $params_ref->enhance($this->getSession()->getRequestParameters());

    return $request;
  }

  /**
   * @param RequestInterface $request
   * @return ResponseInterface
   */
  public function executeRequest(RequestInterface $request) {
    $this->getLogger()->logRequest('debug', $request);
    $response = $request->execute();
    $this->getLogger()->logResponse('debug', $response);

    return $response;
  }

  /**
   * @return string
   */
  public function getDefaultGraphVersion() {
    if ($this->defaultGraphVersion === null) {
      $match = array();
      if (preg_match("/^\d+\.\d+/", static::VERSION, $match)) {
        $this->defaultGraphVersion = $match[0];
      }
    }

    return $this->defaultGraphVersion;
  }

  /**
   * @param string $version
   */
  public function setDefaultGraphVersion($version) {
    $this->defaultGraphVersion = $version;
  }

  /**
   * Make graph api calls
   *
   * @param string $path Ads API endpoint
   * @param string $method Ads API request type
   * @param array $params Assoc of request parameters
   * @return ResponseInterface Graph API responses
   */
  public function call(
    $path,
    $method = RequestInterface::METHOD_GET,
    array $params = array(),
    array $file_params = array()) {

    $request = $this->prepareRequest($path, $method, $params);

    if (!empty($file_params)) {
      foreach($file_params as $key => $value) {
        $request->getFileParams()->offsetSet($key, $value);
      }
    }

    return $this->executeRequest($request);
  }

  /**
   * @return SessionInterface
   */
  public function getSession() {
    return $this->session;
  }

  /**
   * @param LoggerInterface $logger
   */
  public function setLogger(LoggerInterface $logger) {
    $this->logger = $logger;
  }

  /**
   * @return LoggerInterface
   */
  public function getLogger() {
    if ($this->logger === null) {
      $this->logger = new NullLogger();
    }
    return $this->logger;
  }

  /**
   * @return Client
   */
  public function getHttpClient() {
    return $this->httpClient;
  }
}


<?php
/**
 * Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */
namespace FacebookAds;
class ApiConfig {
  const APIVersion = '17.0';
  const SDKVersion = '17.0.1';
  const TYPE_CHECKER_STRICT_MODE = false;
}


<?php
/**
 * Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds;

use FacebookAds\Cursor;
use FacebookAds\AbstractObject;

class ApiRequest {
  protected $api;
  protected $id;
  protected $method;
  protected $endpoint;
  protected $return_prototype;
  protected $accepted_fields;
  protected $param_checker;
  protected $api_type;
  protected $use_graph_video_endpoint;
  private $fields;
  private $params;
  private $file_params;
  private $allow_file_upload;
  private $file_counter;

  public function __construct(
    Api $api,
    $id,
    $method,
    $endpoint,
    $return_prototype = null,
    $api_type = null,
    $accepted_fields = array(),
    TypeChecker $param_checker = null,
    $allow_file_upload = false,
    $use_graph_video_endpoint = false) {
    $this->fields = [];
    $this->params = [];
    $this->file_params = [];
    $this->file_counter = 0;
    $this->api = $api;
    $this->id = $id;
    $this->method = $method;
    $this->endpoint = $endpoint;
    $this->return_prototype = $return_prototype;
    $this->api_type = $api_type;
    $this->accepted_fields = $accepted_fields;
    $this->param_checker = $param_checker;
    $this->allow_file_upload = $allow_file_upload;
    $this->use_graph_video_endpoint = $use_graph_video_endpoint;
  }

  public function addParam($param, $value) {
    $extracted_value = $this->extractValue($value);
    if (!ApiConfig::TYPE_CHECKER_STRICT_MODE
      || !$this->param_checker->isValidParam($param)
    ) {
      if ($this->param_checker->isFileParam($param)) {
          $this->file_params[$param] = $extracted_value;
      } else {
        $this->params[$param] = $extracted_value;
      }
    } else {
      if ($this->param_checker->isValidParamPair($param, $value)) {
        if ($this->param_checker->isFileParam($param)) {
          $this->file_params[$param] = $extracted_value;
        } else {
          $this->params[$param] = $extracted_value;
        }
      } elseif ($this->param_checker->isPrimitiveType($param)) {
        $param_type = $this->param_checker->getType($param);
        $this->params[$param] = $this->param_checker->convertStringToPrimType(
          $param_type, $value);
      } else {
        throw new \LogicException('The value for '.$param.' is not compatible');
      }
    }
    return $this;
  }

  public function addParams($params) {
    foreach ($params as $key => $value) {
      $this->addParam($key, $value);
    }
    return $this;
  }

  public function removeParam($param) {
    if (array_key_exists($param, $this->params)) {
      unset($this->params[$param]);
    } elseif (array_key_exists($param, $this->params)) {
      unset($this->file_params[$param]);
    }
    return $this;
  }

  public function clearParams() {
    $this->params = [];
    $this->file_params = [];
    return $this;
  }

  public function getParams() {
    $all_params = array_merge($this->params, $this->file_params);
    return $all_params;
  }

  public function addField($field) {
    if (ApiConfig::TYPE_CHECKER_STRICT_MODE
      && !in_array($field, $this->accepted_fields)
    ) {
      throw new \LogicException('Field '.$field.' is not supported');
    }
    if (!(in_array($field, $this->fields))) {
      $this->fields[] = $field;
    }
    return $this;
  }

  public function addFields($fields) {
    foreach ($fields as $field) {
      $this->addField($field);
    }
    return $this;
  }

  public function removeField($field) {
    if (in_array($field, $this->fields)) {
      $index_to_remove = array_search($field, $this->fields);
      unset($this->fields[$index_to_remove]);
    }
    return $this;
  }

  public function clearFields() {
    $this->fields = [];
    return $this;
  }

  public function getFields() {
    return $this->fields;
  }

  public function addFile($filename) {
    if (ApiConfig::TYPE_CHECKER_STRICT_MODE && !$this->allow_file_upload) {
      throw new \LogicException("This api cannot upload files");
    }
    $file_key = 'source'.$this->file_counter;
    if (file_exists($filename)) {
      $this->file_params[$file_key] = $filename;
      $this->file_counter++;
    }
    return $this;
  }

  /**
   * Execute the request
   */
  public function execute() {
    $url_path = '/'.$this->id.$this->endpoint;
    $updated_params = $this->params;
    if (!empty($this->fields)) {
      $fields = implode(',', $this->fields);
      $updated_params['fields'] = $fields;
    }
    $response = $this->api->call(
      $url_path, $this->method, $updated_params, $this->file_params);
    if ($this->api_type === "EDGE" && $this->method === "GET") {
      return new Cursor($response, $this->return_prototype, $this->api);
    } else if ($this->method === "DELETE") {
      return $response;
    } else {
      return $this->createObject($response->getContent());
    }
  }

  protected function extractValue($value) {
    if ($this->param_checker->isAbstractObject($value)) {
      return $value->exportAllData();
    } else if (is_array($value)) {
      $extracted_value = [];
      foreach ($value as $key => $sub_value) {
        $extracted_value[$key] = $this->extractValue($sub_value);
      }
      return $extracted_value;
    } else {
      return $value;
    }
  }

  protected function createObject(array $object_data) {
    $object = clone $this->return_prototype;
    $object->setDataWithoutValidation($object_data);
    if ($object instanceof AbstractCrudObject) {
      $object->setApi($this->api);
    }
    return $object;
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds;

use FacebookAds\Api;
use FacebookAds\Exception\Exception;
use FacebookAds\Http\RequestInterface;
use FacebookAds\Http\Exception\RequestException;

/**
 * Class CrashReasons
 * @package FacebookAds
 */
class CrashReasons {
    const SDK = 'SDK';
    const API = 'API';
}

/**
 * Class CrashReporter
 * @package FacebookAds
 */
class CrashReporter {
    const E_FATAL =
      E_ERROR |
      E_USER_ERROR |
      E_PARSE |
      E_CORE_ERROR |
      E_COMPILE_ERROR |
      E_RECOVERABLE_ERROR;

    /**
     * @var CrashReporter
     */
    private static $instance;

    /**
     * @var resource
     */
    private static $handle;

    /**
     * @var int
     */
    private $app_id;

    /**
     * CrashReporter constructor.
     * @param int $app_id
     * @return void
     */
    private function __construct(
      $app_id
    ) {
        $this->app_id = $app_id;
    }

    /**
     * @return void
     */
    public static function enable() {
        if (!static::$handle) {
          static::$handle = fopen('php://stdout', 'w');
        }
        if (!static::$instance) {
            $api = Api::instance();
            if ($api == null) {
              self::log('Could not initialize API' . PHP_EOL);
            }
            static::$instance = new static($api->getSession()->getAppId());
            static::$instance->registerExceptionHandler();
            self::log('Enabled' . PHP_EOL);
        }
    }

    /**
     * @return void
     */
    public static function disable() {
        if (static::$instance) {
            static::$instance = null;
            restore_exception_handler();
            restore_error_handler();
            self::log('Disabled');
        }
    }

    /**
     * @param $handle
     */
    public static function setLogger($handle) {
        if(is_resource($handle)) {
          static::$handle  = $handle;
        }
    }

    /**
     * @return void
     */
    private function registerExceptionHandler() {
        $lastHandler = set_exception_handler(
            function (\Throwable $e) use (&$lastHandler) {
                self::log('Exception detected!');
                $params = $this->buildParamsFromException($e);
                if ($params != null) {
                    $this->sendReport(array(
                        'bizsdk_crash_report' => $params
                    ));
                }
                // restore the previous exception
                if (is_callable($lastHandler)) {
                    return call_user_func_array($lastHandler, [$e]);
                } else {
                    throw $e;
                }
            }
        );

        $lastError = set_error_handler(
            function ($errno, $errstr, $errfile, $errline) use (&$lastError) {
                if (($errno & self::E_FATAL) && strpos($errfile, 'FacebookAds') != false) {
                    self::log('Error detected!');
                    $e = new \ErrorException($errstr, 0, $errno, $errfile, $errline);
                    $params = $this->buildParamsFromException($e);
                    if ($params != null) {
                        $this->sendReport(array(
                            'bizsdk_crash_report' => $params
                        ));
                    }
                }
                if (is_callable($lastError)) {
                    return call_user_func_array($lastError, [$errno, $errstr, $errfile, $errline]);
                } else {
                    // fall through to the standard PHP error handler
                    return false;
                }
            }
        );
    }

    /**
     * @param \Throwable $e
     * @return array|null
     */
    private function buildParamsFromException(\Throwable $e) {
        if (!($e instanceof Exception || $e instanceof \ErrorException)) {
            return NULL;
        }
        $reason = CrashReasons::SDK;
        if ($e instanceof RequestException) {
            $reason = CrashReasons::API;
        }
        $reason .= ' : ' . $e->getMessage();
        $callstack = explode(PHP_EOL, $e->getTraceAsString());
        return array(
            'reason' => $reason,
            'callstack' => $callstack,
            'platform' => phpversion()
        );
    }

    /**
     * @param $params
     */
    private function sendReport($params) {
        try {
            $session = new AnonymousSession();
            $api = new Api(Api::instance()->getHttpClient(), $session);
            $request = $api->prepareRequest(
                '/' . $this->app_id . '/instruments',
                RequestInterface::METHOD_POST,
                $params
            );

            $response = $api->executeRequest($request);
            $data = $response->getContent();
            if ($data && $data['success']) {
                self::log('Successfully sent report' . PHP_EOL);
            } else {
                self::log('Failed to send report' . PHP_EOL);
            }
        } catch (\Exception $e) {
            self::log('Exception on sending report' . PHP_EOL);
        }
    }

    /**
     * @param $message
     */
    private static function log($message) {
      $content = sprintf("%s : %s%s",static::class, $message, PHP_EOL);
      fwrite(static::$handle, $content);
    }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds;

use FacebookAds\Http\RequestInterface;
use FacebookAds\Http\ResponseInterface;
use FacebookAds\Http\Util;
use FacebookAds\Object\AbstractObject;

class Cursor implements \Iterator, \Countable, \ArrayAccess {
  /**
   * @var ResponseInterface
   */
  protected $response;

  /**
   * @var Api
   */
  protected $api;

  /**
   * @var AbstractObject[]
   */
  protected $objects = array();

  /**
   * @var int|null
   */
  protected $indexLeft;

  /**
   * @var int|null
   */
  protected $indexRight;

  /**
   * @var int|null
   */
  protected $position;

  /**
   * @var AbstractObject
   */
  protected $objectPrototype;

  /**
   * @var bool
   */
  protected static $defaultUseImplicitFetch = false;

  /**
   * @var bool
   */
  protected $useImplicitFetch;

  public function __construct(
    ResponseInterface $response,
    AbstractObject $object_prototype,
    Api $api = null) {
    $this->response = $response;
    $this->objectPrototype = $object_prototype;
    $this->api = $api !== null ? $api : Api::instance();
    $this->appendResponse($response);
  }

  /**
   * @param array $object_data
   * @return AbstractObject
   */
  protected function createObject(array $object_data) {
    $object = clone $this->objectPrototype;
    $object->setDataWithoutValidation($object_data);
    if ($object instanceof AbstractCrudObject) {
      $object->setApi($this->api);
    }
    return $object;
  }

  /**
   * @param ResponseInterface $response
   * @return array
   * @throws \InvalidArgumentException
   */
  protected function assureResponseData(ResponseInterface $response) {
    $content = $response->getContent();

    // First, check if the content contains data
    if (isset($content['data']) && is_array($content['data'])) {
      $data = $content['data'];

      // If data is an object wrap the object into an array
      if ($this->isJsonObject($data)) {
        $data = array($data);
      }
      return $data;
    }

    // Second, check if the content contains special entries
    if (isset($content['targetingsentencelines'])) {
      return $content['targetingsentencelines'];
    }
    if (isset($content['adaccounts'])) {
      return $content['adaccounts'];
    }
    if (isset($content['users'])) {
      return $content['users'];
    }

    // Third, check if the content is an array of objects indexed by id
    $is_id_indexed_array = true;
    $objects = array();
    if (is_array($content) && count($content) >= 1) {
      foreach ($content as $key => $value) {
        if ($key === '__fb_trace_id__') {
          continue;
        }

        if ($value !== null &&
            $this->isJsonObject($value) &&
            isset($value['id']) &&
            $value['id'] !== null &&
            $value['id'] === $key) {
          $objects[] = $value;
        } else {
          $is_id_indexed_array = false;
          break;
        }
      }
    } else {
      $is_id_indexed_array = false;
    }
    if ($is_id_indexed_array) {
      return $objects;
    }

    throw new \InvalidArgumentException("Malformed response data");
  }

  private function isJsonObject($object) {
    if (!is_array($object)) {
      return false;
    }

    // Consider an empty array as not object
    if (empty($object)) {
      return false;
    }

    // A json object is represented by a map instead of a pure list
    return array_keys($object) !== range(0, count($object) - 1);
  }

  /**
   * @param ResponseInterface $response
   */
  protected function prependResponse(ResponseInterface $response) {
    $this->response = $response;
    $data = $this->assureResponseData($response);
    if (empty($data)) {
      return;
    }

    $left_index = $this->indexLeft;
    $count = count($data);
    $position = $count - 1;
    for ($i = $left_index - 1; $i >= $left_index - $count; $i--) {
      $this->objects[$i] = $this->createObject($data[$position--]);
      --$this->indexLeft;
    }
  }

  /**
   * @param ResponseInterface $response
   */
  protected function appendResponse(ResponseInterface $response) {
    $this->response = $response;
    $data = $this->assureResponseData($response);
    if (empty($data)) {
      return;
    }

    if ($this->indexRight === null) {
      $this->indexLeft = 0;
      $this->indexRight = -1;
      $this->position = 0;
    }

    $this->indexRight += count($data);

    foreach ($data as $object_data) {
      $this->objects[] = $this->createObject($object_data);
    }
  }

  /**
   * @return bool
   */
  public static function getDefaultUseImplicitFetch() {
    return static::$defaultUseImplicitFetch;
  }

  /**
   * @param bool $use_implicit_fetch
   */
  public static function setDefaultUseImplicitFetch($use_implicit_fetch) {
    static::$defaultUseImplicitFetch = $use_implicit_fetch;
  }

  /**
   * @return bool
   */
  public function getUseImplicitFetch() {
    return $this->useImplicitFetch !== null
      ? $this->useImplicitFetch
      : static::$defaultUseImplicitFetch;
  }

  /**
   * @param bool $use_implicit_fetch
   */
  public function setUseImplicitFetch($use_implicit_fetch) {
    $this->useImplicitFetch = $use_implicit_fetch;
  }

  /**
   * @return string|null
   */
  public function getBefore() {
    $content = $this->getLastResponse()->getContent();
    return isset($content['paging']['cursors']['before'])
      ? $content['paging']['cursors']['before']
      : null;
  }

  /**
   * @return string|null
   */
  public function getAfter() {
    $content = $this->getLastResponse()->getContent();
    return isset($content['paging']['cursors']['after'])
      ? $content['paging']['cursors']['after']
      : null;
  }

  /**
   * @return RequestInterface
   */
  protected function createUndirectionalizedRequest() {
    $request = $this->getLastResponse()->getRequest()->createClone();
    $params = $request->getQueryParams();
    if (isset($params['before'])) {
      unset($params['before']);
    }
    if (isset($params['after'])) {
      unset($params['after']);
    }

    return $request;
  }

  /**
   * @return string|null
   */
  public function getPrevious() {
    $content = $this->getLastResponse()->getContent();
    if (isset($content['paging']['previous'])) {
      return $content['paging']['previous'];
    }

    $before = $this->getBefore();
    if ($before !== null) {
      $request = $this->createUndirectionalizedRequest();
      $request->getQueryParams()->offsetSet('before', $before);
      return $request->getUrl();
    }

    return null;
  }

  /**
   * @return string|null
   */
  public function getNext() {
    $content = $this->getLastResponse()->getContent();
    if (isset($content['paging']['next'])) {
      return $content['paging']['next'];
    }

    $after = $this->getAfter();
    if ($after !== null) {
      $request = $this->createUndirectionalizedRequest();
      $request->getQueryParams()->offsetSet('after', $after);
      return $request->getUrl();
    }

    return null;
  }

  /**
   * @param string $url
   * @return RequestInterface
   */
  protected function createRequestFromUrl($url) {
    $components = parse_url($url);
    $request = $this->getLastResponse()->getRequest()->createClone();
    $request->setDomain($components['host']);
    $query = isset($components['query'])
      ? Util::parseUrlQuery($components['query'])
      : array();
    $request->getQueryParams()->enhance($query);

    return $request;
  }

  /**
   * @return RequestInterface|null
   */
  public function createBeforeRequest() {
    $url = $this->getPrevious();
    return $url !== null ? $this->createRequestFromUrl($url) : null;
  }

  /**
   * @return RequestInterface|null
   */
  public function createAfterRequest() {
    $url = $this->getNext();
    return $url !== null ? $this->createRequestFromUrl($url) : null;
  }

  public function fetchBefore() {
    $request = $this->createBeforeRequest();
    if (!$request) {
      return;
    }

    $this->prependResponse($request->execute());
  }

  public function fetchAfter() {
    $request = $this->createAfterRequest();
    if (!$request) {
      return;
    }

    $this->appendResponse($request->execute());
  }

  /**
   * @deprecated Use getArrayCopy()
   * @return AbstractObject[]
   */
  public function getObjects() {
    return $this->objects;
  }

  /**
   * @param bool $ksort
   * @return AbstractObject[]
   */
  public function getArrayCopy($ksort = false) {
    if ($ksort) {
      // Sort the main array to improve best case performance in future
      // invocations
      ksort($this->objects);
    }

    return $this->objects;
  }

  /**
   * @deprecated Use getLastResponse()
   * @return ResponseInterface
   */
  public function getResponse() {
    return $this->response;
  }

  /**
   * @return ResponseInterface
   */
  public function getLastResponse() {
    return $this->response;
  }

  /**
   * @return int
   */
  public function getIndexLeft() {
    return $this->indexLeft;
  }

  /**
   * @return int
   */
  public function getIndexRight() {
    return $this->indexRight;
  }

  public function rewind() : void {
    $this->position = $this->indexLeft;
  }

  public function end() {
    $this->position = $this->indexRight;
  }

  /**
   * @param int $position
   */
  public function seekTo($position) {
    $position = array_key_exists($position, $this->objects) ? $position : null;
    $this->position = $position;
  }

  public function current() : AbstractObject|bool {
    return isset($this->objects[$this->position])
      ? $this->objects[$this->position]
      : false;
  }

  public function key() : ?int {
    return $this->position;
  }

  public function prev() {
    if ($this->position == $this->getIndexLeft()) {
      if ($this->getUseImplicitFetch()) {
        $this->fetchBefore();
        if ($this->position == $this->getIndexLeft()) {
          $this->position = null;
        } else {
          --$this->position;
        }
      } else {
        $this->position = null;
      }
    } else {
      --$this->position;
    }
  }

  public function next() : void {
    if ($this->position == $this->getIndexRight()) {
      if ($this->getUseImplicitFetch()) {
        $this->fetchAfter();
        if ($this->position == $this->getIndexRight()) {
          $this->position = null;
        } else {
          ++$this->position;
        }
      } else {
        $this->position = null;
      }
    } else {
      ++$this->position;
    }
  }

  public function valid() : bool {
    return isset($this->objects[$this->position]);
  }

  public function count() : int {
    return count($this->objects);
  }

  /**
   * @param mixed $offset
   * @param mixed $value
   */
  public function offsetSet($offset, $value) : void {
    if ($offset === null) {
      $this->objects[] = $value;
    } else {
      $this->objects[$offset] = $value;
    }
  }

  /**
   * @param mixed $offset
   * @return bool
   */
  public function offsetExists($offset) : bool {
    return isset($this->objects[$offset]);
  }

  /**
   * @param mixed $offset
   */
  public function offsetUnset($offset) : void {
    unset($this->objects[$offset]);
  }

  /**
   * @param mixed $offset
   * @return mixed
   */
  public function offsetGet($offset) : mixed {
    return isset($this->objects[$offset]) ? $this->objects[$offset] : null;
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds;

class Session implements SessionInterface {

  /**
   * @var string
   */
  protected $appId;

  /**
   * @var string
   */
  protected $appSecret;

  /**
   * @var string
   */
  protected $accessToken;

  /**
   * @var string
   */
  protected $appSecretProof;

  /**
   * @param string $app_id
   * @param string $app_secret
   * @param string $access_token
   */
  public function __construct($app_id, $app_secret, $access_token) {
    $this->appId = $app_id;
    $this->appSecret = $app_secret;
    $this->accessToken = $access_token;
  }

  /**
   * @return string
   */
  public function getAppId() {
    return $this->appId;
  }

  /**
   * @return string
   */
  public function getAppSecret() {
    return $this->appSecret;
  }

  /**
   * @return string
   */
  public function getAccessToken() {
    return $this->accessToken;
  }

  /**
   * @return string
   */
  public function getAppSecretProof() {
    if ($this->getAppSecret() === null) {
      return null;
    }
    if ($this->appSecretProof === null) {
      $this->appSecretProof
        = hash_hmac('sha256', $this->getAccessToken(), $this->getAppSecret());
    }
    return $this->appSecretProof;
  }

  /**
   * @return array
   */
  public function getRequestParameters() {
    if ($this->getAppSecretProof() !== null) {
      return array(
        'access_token' => $this->getAccessToken(),
        'appsecret_proof' => $this->getAppSecretProof(),
      );
    } else {
      return array(
        'access_token' => $this->getAccessToken(),
      );
    }
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds;

interface SessionInterface {

  /**
   * @return array
   */
  public function getRequestParameters();
}


<?php
/**
 * Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds;

class TypeChecker {

  const ABSTRACT_OBJECT_PREFIX = "FacebookAds\\Object\\";
  private $type_data;
  private $enum_data;
  private $primitive_types = ["unsigned int", "int", "bool", "string",
    "Object", "datetime", "float"];

  public function __construct($type_check_info, $type_check_enum) {
    $this->type_data = $type_check_info;
    $this->enum_data = $type_check_enum;
  }

  public function isPrimitiveType($param) {
    return (in_array($param, $this->primitive_types) ||
      array_key_exists($param, $this->enum_data));
  }

  public function convertStringToPrimType($primitive_type, $value) {
    if (array_key_exists($primitive_type, $this->enum_data)) {
      return $value;
    } elseif (in_array($primitive_type, array("unsigned int", "int"))) {
      return intval($value);
    } elseif ($primitive_type === "bool") {
      return boolval($value);
    } elseif ($primitive_type === "float") {
      return floatval($value);
    } elseif ($primitive_type === "datetime") {
      return $value;
    } elseif ($primitive_type === "string") {
      return $value;
    } elseif ($primitive_type === "Object") {
      return $value;
    } else {
      if (ApiConfig::TYPE_CHECKER_STRICT_MODE) {
        throw new \Exception("Not a primitive type");
      } else {
        return $value;
      }
    }
  }

  public function getType($param) {
    if (array_key_exists($param, $this->type_data)) {
      return $this->type_data[$param];
    } else {
      return null;
    }
  }

  public function isValidParam($param) {
    return array_key_exists($param, $this->type_data);
  }

  public function isValidParamPair($param, $value) {
    if ($this->isValidParam($param)) {
      $type = $this->type_data[$param];
      return $this->checkType($type, $value);
    }
    return false;
  }

  public function checkType($type, $value, $allow_array_for_obj = true) {
    if ($value === null || $type === null || $type === "Object") {
      return true;
    } else if (array_key_exists($type, $this->enum_data)) {
      return in_array($value, $this->enum_data[$type]);
    } else if ($type === "file") {
      return file_exists($value);
    } else if ($type === "list" || $type === "map") {
      return is_array($value);
    } else if ($type === "bool") {
      return is_bool($value);
    } else if ($type === "int" || $type === "unsigned int" || $type === "float") {
      return is_numeric($value);
    } else if ($type === "string" || $type === "datetime") {
      return is_string($value) || is_numeric($value) || is_bool($value);
    } else if ($this->isTypeCollection($type, "list")) {
      $sub_types = $this->getTypeFromCollection($type, "list");
      $sub_type = $sub_types[0];
      if (is_array($value)) {
        if (empty($value)) {
          return true;
        }
        $all_object_same_type = true;
        foreach ($value as $key => $sub_value) {
          $all_object_same_type = ($all_object_same_type &&
            $this->checkType($sub_type, $sub_value));
        }
        return $all_object_same_type;
      } else {
        return $this->checkType($sub_type, $value);
      }
    } else if ($this->isTypeCollection($type, "map")) {
      if (is_array($value)) {
        $sub_types = $this->getTypeFromCollection($type, "map");
        if (count($sub_types) === 1) {
          $sub_key_type = 'string';
          $sub_value_type = $sub_types[0];
        } else {
          $sub_key_type = $sub_types[0];
          $sub_value_type = $sub_types[1];
        }
        $all_object_same_type = true;
        foreach ($value as $key => $sub_value) {
          $all_object_same_type = ($all_object_same_type &&
            $this->checkType($sub_key_type, $key) &&
            $this->checkType($sub_value_type, $sub_value));
        }
        return $all_object_same_type;
      }
    } else {
      // the type is an object
      if ($allow_array_for_obj && is_array($value)) {
        return true;
      }
      if (!$this->startsWith($type, self::ABSTRACT_OBJECT_PREFIX)) {
        $type = self::ABSTRACT_OBJECT_PREFIX.$type;
      }
      return is_a($value, $type);
    }
    return false;
  }

  public function isAbstractObject($value) {
    if (is_object($value)) {
      $cls_name = get_class($value);
      return $this->startsWith($cls_name, self::ABSTRACT_OBJECT_PREFIX);
    }
    return false;
  }

  private function startsWith($string, $prefix) {
    return $prefix === "" ||
      strrpos($string, $prefix, -strlen($string)) !== false;
  }

  public function isListParam($param) {
    if ($this->isValidParam($param)) {
      return $this->isTypeCollection($this->type_data[$param], "list");
    }
    return false;
  }

  public function isMapParam($param) {
    if ($this->isValidParam($param)) {
      return $this->isTypeCollection($this->type_data[$param], "map");
    }
    return false;
  }

  public function isFileParam($param) {
    if ($this->isValidParam($param)) {
      return ($this->type_data[$param] === "file");
    }
    return false;
  }

  public function isTypeCollection($type, $collection) {
    $len_of_collection = strlen($collection);
    $typeCollection = substr($type, 0, $len_of_collection);
    return ($collection === $typeCollection);
  }

  public function getTypeFromCollection($type, $collection) {
    return explode(",", trim(substr($type, strlen($collection)), "<>"));
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Enum;

abstract class AbstractEnum implements EnumInstanceInterface {

  /**
   * @var array|null
   */
  protected $map = null;

  /**
   * @var array|null
   */
  protected $names = null;

  /**
   * @var array|null
   */
  protected $values = null;

  /**
   * @var array|null
   */
  protected $valuesMap = null;

  /**
   * @var AbstractEnum[]
   */
  protected static $instances = array();

  /**
   * @return string
   */
  static function className() {
    return get_called_class();
  }

  /**
   * @return AbstractEnum
   */
  public static function getInstance() {
    $fqn = get_called_class();
    if (!array_key_exists($fqn, static::$instances)) {
      static::$instances[$fqn] = new static();
    }

    return static::$instances[$fqn];
  }

  /**
   * @return array
   */
  public function getArrayCopy() {
    if ($this->map === null) {
      $this->map = (new \ReflectionClass(get_called_class()))
        ->getConstants();
    }

    return $this->map;
  }

  /**
   * @return array
   */
  public function getNames() {
    if ($this->names === null) {
      $this->names = array_keys($this->getArrayCopy());
    }

    return $this->names;
  }

  /**
   * @return array
   */
  public function getValues() {
    if ($this->values === null) {
      $this->values = array_values($this->getArrayCopy());
    }

    return $this->values;
  }

  /**
   * @return array
   */
  public function getValuesMap() {
    if ($this->valuesMap === null) {
      $this->valuesMap = array_fill_keys($this->getValues(), null);
    }

    return $this->valuesMap;
  }

  /**
   * @param string|int|float $name
   * @return mixed
   */
  public function getValueForName($name) {
    $copy = $this->getArrayCopy();
    return array_key_exists($name, $copy)
      ? $copy[$name]
      : null;
  }

  /**
   * @param string|int|float $name
   * @return mixed
   * @throws \InvalidArgumentException
   */
  public function assureValueForName($name) {
    $value = $this->getValueForName($name);
    if ($value === null) {
      throw new \InvalidArgumentException(
        'Unknown name "'.$name.'" in '.static::className());
    }

    return $value;
  }

  /**
   * @param string|int|float $name
   * @return bool
   */
  public function isValid($name) {
    return array_key_exists($name, $this->getArrayCopy());
  }

  /**
   * @param string|int|float $name
   * @throws \InvalidArgumentException
   */
  public function assureIsValid($name) {
    if (!array_key_exists($name, $this->getArrayCopy())) {
      throw new \InvalidArgumentException(
        'Unknown name "'.$name.'" in '.static::className());
    }
  }

  /**
   * @param string|int|float $value
   * @return bool
   */
  public function isValidValue($value) {
    return array_key_exists($value, $this->getValuesMap());
  }

  /**
   * @param mixed $value
   * @throws \InvalidArgumentException
   */
  public function assureIsValidValue($value) {
    if (!$this->isValidValue($value)) {
      throw new \InvalidArgumentException(
        '"'.$value.'", not a valid value in '.static::className());
    }
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Enum;

class EmptyEnum extends AbstractEnum {

  /**
   * @return array
   */
  public function getArrayCopy() {
    return array();
  }

  /**
   * @return array
   */
  public function getNames() {
    return array();
  }

  /**
   * @return array
   */
  public function getValues() {
    return array();
  }

  /**
   * @return array
   */
  public function getValuesMap() {
    return array();
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Enum;

interface EnumInstanceInterface {

  /**
   * @return EnumInstanceInterface
   */
  public static function getInstance();

  /**
   * @return array
   */
  public function getArrayCopy();

  /**
   * @return array
   */
  public function getNames();

  /**
   * @return array
   */
  public function getValues();

  /**
   * @return array
   */
  public function getValuesMap();

  /**
   * @param string|int|float $name
   * @return mixed
   */
  public function getValueForName($name);

  /**
   * @param string|int|float $name
   * @return mixed
   * @throws \InvalidArgumentException
   */
  public function assureValueForName($name);

  /**
   * @param string|int|float $name
   * @return bool
   */
  public function isValid($name);

  /**
   * @param string|int|float $name
   * @return void
   * @throws \InvalidArgumentException
   */
  public function assureIsValid($name);

  /**
   * @param mixed $value
   * @return bool
   */
  public function isValidValue($value);

  /**
   * @param mixed $value
   * @throws \InvalidArgumentException
   */
  public function assureIsValidValue($value);
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Exception;

class Exception extends \Exception {

}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Http;

use FacebookAds\ApiConfig;
use FacebookAds\Http\Adapter\AdapterInterface;
use FacebookAds\Http\Adapter\CurlAdapter;
use FacebookAds\Http\Exception\EmptyResponseException;
use FacebookAds\Http\Exception\RequestException;

class Client {

  /**
   * @var string
   */
  const DEFAULT_GRAPH_BASE_DOMAIN = 'facebook.com';

  /**
   * @var string
   */
  const DEFAULT_LAST_LEVEL_DOMAIN = 'graph';

  /**
   * @var RequestInterface
   */
  protected $requestPrototype;

  /**
   * @var ResponseInterface
   */
  protected $responsePrototype;

  /**
   * @var Headers
   */
  protected $defaultRequestHeaders;

  /**
   * @var AdapterInterface
   */
  protected $adapter;

  /**
   * @var string
   */
  protected $caBundlePath;

  /**
   * @var string
   */
  protected $defaultGraphBaseDomain = self::DEFAULT_GRAPH_BASE_DOMAIN;

  /**
   * @return RequestInterface
   */
  public function getRequestPrototype() {
    if ($this->requestPrototype === null) {
      $this->requestPrototype = new Request($this);
    }

    return $this->requestPrototype;
  }

  /**
   * @param RequestInterface $prototype
   */
  public function setRequestPrototype(RequestInterface $prototype) {
    $this->requestPrototype = $prototype;
  }

  /**
   * @return RequestInterface
   */
  public function createRequest() {
    return $this->getRequestPrototype()->createClone();
  }

  /**
   * @return ResponseInterface
   */
  public function getResponsePrototype() {
    if ($this->responsePrototype === null) {
      $this->responsePrototype = new Response();
    }

    return $this->responsePrototype;
  }

  /**
   * @param ResponseInterface $prototype
   */
  public function setResponsePrototype(ResponseInterface $prototype) {
    $this->responsePrototype = $prototype;
  }

  /**
   * @return ResponseInterface
   */
  public function createResponse() {
    return clone $this->getResponsePrototype();
  }

  /**
   * @return Headers
   */
  public function getDefaultRequestHeaders() {
    if ($this->defaultRequestHeaders === null) {
      $this->defaultRequestHeaders = new Headers(array(
        'User-Agent' => 'fbbizsdk-php-v'.ApiConfig::SDKVersion,
        'Accept-Encoding' => '*',
      ));
    }

    return $this->defaultRequestHeaders;
  }

  /**
   * @deprecated use getDefaultRequestHeaders() instead
   *
   * @return Headers
   */
  public function getDefaultRequestHeaderds() {
    @trigger_error(sprintf('%s deprecated, use getDefaultRequestHeaders() instead.', __METHOD__), \E_USER_DEPRECATED);

    return $this->getDefaultRequestHeaders();
  }

  /**
   * @param Headers $headers
   */
  public function setDefaultRequestHeaders(Headers $headers) {
    $this->defaultRequestHeaders = $headers;
  }

  /**
   * @return string
   */
  public function getDefaultGraphBaseDomain() {
    return $this->defaultGraphBaseDomain;
  }

  /**
   * @param string $domain
   */
  public function setDefaultGraphBaseDomain($domain) {
    $this->defaultGraphBaseDomain = $domain;
  }

  /**
   * @return AdapterInterface
   */
  public function getAdapter() {
    if ($this->adapter === null) {
      $this->adapter = new CurlAdapter($this);
    }

    return $this->adapter;
  }

  /**
   * @param AdapterInterface $adapter
   */
  public function setAdapter(AdapterInterface $adapter) {
    $this->adapter = $adapter;
  }

  /**
   * @return string
   */
  public function getCaBundlePath() {
    if ($this->caBundlePath === null) {
      $this->caBundlePath = __DIR__.DIRECTORY_SEPARATOR
        .str_repeat('..'.DIRECTORY_SEPARATOR, 3)
        .'fb_ca_chain_bundle.crt';
    }

    return $this->caBundlePath;
  }

  /**
   * @param string $path
   */
  public function setCaBundlePath($path) {
    $this->caBundlePath = $path;
  }

  /**
   * @param RequestInterface $request
   * @return ResponseInterface
   * @throws RequestException
   */
  public function sendRequest(RequestInterface $request) {
    $response = $this->getAdapter()->sendRequest($request);
    $response->setRequest($request);
    $response_content = $response->getContent();

    if ($response_content === null) {
      throw new EmptyResponseException($response);
    }

    if (is_array($response_content)
      && array_key_exists('error', $response_content)) {

      throw RequestException::create($response);
    }

    return $response;
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Http;

class FileParameter {

  /**
   * @var string
   */
  protected $path;

  /**
   * @var string|null
   */
  protected $mimeType;

  /**
   * @var string|null
   */
  protected $name;

  /**
   * @param string $path
   */
  public function __construct($path) {
    $this->path = $path;
  }

  /**
   * @return string
   */
  public function getPath() {
    return $this->path;
  }

  /**
   * @return null|string
   */
  public function getMimeType() {
    return $this->mimeType;
  }

  /**
   * @param null|string $mime_type
   * @return $this
   */
  public function setMimeType($mime_type) {
    $this->mimeType = $mime_type;
    return $this;
  }

  /**
   * @return null|string
   */
  public function getName() {
    return $this->name;
  }

  /**
   * @param null|string $name
   * @return $this
   */
  public function setName($name) {
    $this->name = $name;
    return $this;
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Http;

class Headers extends \ArrayObject {

  /**
   * @return array
   */
  public function export() {
    $data = array();
    foreach ($this as $key => $value) {
      $data[$key] = is_null($value) || is_scalar($value)
        ? $value
        : $this->exportNonScalar($value);
    }

    return $data;
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Http;

class Parameters extends \ArrayObject {

  /**
   * @param array $data
   */
  public function enhance(array $data) {
    foreach ($data as $key => $value) {
      $this[$key] = $value;
    }
  }

  /**
   * @param mixed $value
   * @return string
   */
  protected function exportNonScalar($value) {
    return json_encode($value);
  }

  /**
   * @return array
   */
  public function export() {
    $data = array();
    foreach ($this as $key => $value) {
      $data[$key] = is_null($value) || is_scalar($value)
        ? $value
        : $this->exportNonScalar($value);
    }

    return $data;
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Http;

class Request implements RequestInterface {

  /**
   * @var string
   */
  const PROTOCOL_HTTP = 'http://';

  /**
   * @var string
   */
  const PROTOCOL_HTTPS = 'https://';

  /**
   * @var Client
   */
  protected $client;

  /**
   * @var Headers
   */
  protected $headers;

  /**
   * @var string
   */
  protected $method = self::METHOD_GET;

  /**
   * @var string
   */
  protected $protocol = self::PROTOCOL_HTTPS;

  /**
   * @var string
   */
  protected $domain;

  /**
   * @var string
   */
  protected $path;

  /**
   * @var string
   */
  protected $graphVersion;

  /**
   * @var Parameters
   */
  protected $queryParams;

  /**
   * @var Parameters
   */
  protected $bodyParams;

  /**
   * @var Parameters
   */
  protected $fileParams;

  /**
   * @param Client $client
   */
  public function __construct(Client $client) {
    $this->client = $client;
  }

  public function __clone() {
    $this->queryParams && $this->queryParams = clone $this->queryParams;
    $this->bodyParams && $this->bodyParams = clone $this->bodyParams;
    $this->fileParams && $this->fileParams = clone $this->fileParams;
  }

  /**
   * @return Client
   */
  public function getClient() {
    return $this->client;
  }

  /**
   * @return string
   */
  public function getProtocol() {
    return $this->protocol;
  }

  /**
   * @param string $protocol
   */
  public function setProtocol($protocol) {
    $this->protocol = $protocol;
  }

  /**
   * @return string
   */
  public function getDomain() {
    if ($this->domain === null) {
      $this->domain = sprintf(
        "%s.%s",
        Client::DEFAULT_LAST_LEVEL_DOMAIN,
        $this->client->getDefaultGraphBaseDomain());
    }

    return $this->domain;
  }

  /**
   * @param string $domain
   */
  public function setDomain($domain) {
    $this->domain = $domain;
  }

  /**
   * @param string $last_level_domain
   */
  public function setLastLevelDomain($last_level_domain) {
    $this->domain = sprintf(
      "%s.%s",
      $last_level_domain,
      $this->client->getDefaultGraphBaseDomain());
  }

  /**
   * @return Headers
   */
  public function getHeaders() {
    if ($this->headers === null) {
      $this->headers = clone $this->getClient()->getDefaultRequestHeaders();
    }

    return $this->headers;
  }

  /**
   * @param Headers $headers
   */
  public function setHeaders(Headers $headers) {
    $this->headers = $headers;
  }

  /**
   * @return string
   */
  public function getMethod() {
    return $this->method;
  }

  /**
   * @param string $method
   */
  public function setMethod($method) {
    $this->method = $method;
  }

  /**
   * @return string
   */
  public function getPath() {
    return $this->path;
  }

  /**
   * @param string $path
   */
  public function setPath($path) {
    $this->path = $path;
  }

  /**
   * @return string
   */
  public function getGraphVersion() {
    return $this->graphVersion;
  }

  /**
   * @param string $version
   */
  public function setGraphVersion($version) {
    $this->graphVersion = $version;
  }

  /**
   * @return Parameters
   */
  public function getQueryParams() {
    if ($this->queryParams === null) {
      $this->queryParams = new Parameters();
    }

    return $this->queryParams;
  }

  /**
   * @param Parameters $params
   */
  public function setQueryParams(Parameters $params) {
    $this->queryParams = $params;
  }

  /**
   * @return string
   */
  public function getUrl() {
    $delimiter = null;
    if ($this->getQueryParams()->count() ) {
      $delimiter = strpos($this->getPath(), '?') ? '&' : '?';
    }
    return $this->getProtocol().$this->getDomain()
      .'/v'.$this->getGraphVersion().$this->getPath()
      .$delimiter
      .http_build_query($this->getQueryParams()->export(), '', '&');
  }

  /**
   * @return Parameters
   */
  public function getBodyParams() {
    if ($this->bodyParams === null) {
      $this->bodyParams = new Parameters();
    }

    return $this->bodyParams;
  }

  /**
   * @param Parameters $params
   */
  public function setBodyParams(Parameters $params) {
    $this->bodyParams = $params;
  }

  /**
   * @return Parameters
   */
  public function getFileParams() {
    if ($this->fileParams === null) {
      $this->fileParams = new Parameters();
    }

    return $this->fileParams;
  }

  /**
   * @param Parameters $params
   */
  public function setFileParams(Parameters $params) {
    $this->fileParams = $params;
  }

  /**
   * @return ResponseInterface
   */
  public function execute() {
    return $this->getClient()->sendRequest($this);
  }

  /**
   * @return Request
   * @see RequestInterface::createClone()
   */
  public function createClone() {
    return clone $this;
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Http;

interface RequestInterface {

  /**
   * @var string
   */
  const METHOD_DELETE = 'DELETE';

  /**
   * @var string
   */
  const METHOD_GET = 'GET';

  /**
   * @var string
   */
  const METHOD_POST = 'POST';

  /**
   * @var string
   */
  const METHOD_PUT = 'PUT';

  /**
   * @param Client $client
   */
  public function __construct(Client $client);

  /**
   * @return Client
   */
  public function getClient();

  /**
   * @return Headers
   */
  public function getHeaders();

  /**
   * @param Headers $headers
   */
  public function setHeaders(Headers $headers);

  /**
   * @return string
   */
  public function getProtocol();

  /**
   * @param string $protocol
   */
  public function setProtocol($protocol);

  /**
   * @return string
   */
  public function getDomain();

  /**
   * @param string $domain
   */
  public function setDomain($domain);

  /**
   * @param string $last_level_domain
   */
  public function setLastLevelDomain($last_level_domain);

  /**
   * @return string
   */
  public function getMethod();

  /**
   * @param string $method
   */
  public function setMethod($method);

  /**
   * @return string
   */
  public function getPath();

  /**
   * @param string $version
   */
  public function setGraphVersion($version);

  /**
   * @return mixed
   */
  public function getGraphVersion();

  /**
   * @param string $path
   */
  public function setPath($path);

  /**
   * @return Parameters
   */
  public function getQueryParams();

  /**
   * @param Parameters $params
   */
  public function setQueryParams(Parameters $params);

  /**
   * @return string
   */
  public function getUrl();

  /**
   * @return Parameters
   */
  public function getBodyParams();

  /**
   * @param Parameters $params
   */
  public function setBodyParams(Parameters $params);

  /**
   * @return Parameters
   */
  public function getFileParams();

  /**
   * @param Parameters $params
   */
  public function setFileParams(Parameters $params);

  /**
   * @return ResponseInterface
   */
  public function execute();

  /**
   * Required for Mocking request/response chaining
   * @return RequestInterface
   */
  public function createClone();
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Http;

class Response implements ResponseInterface {

  /**
   * @var RequestInterface
   */
  protected $request;

  /**
   * @var int
   */
  protected $statusCode;

  /**
   * @var Headers
   */
  protected $headers;

  /**
   * @var string
   */
  protected $body;

  /**
   * @var mixed
   */
  protected $content;

  /**
   * @return RequestInterface
   */
  public function getRequest() {
    return $this->request;
  }

  /**
   * @param RequestInterface $request
   */
  public function setRequest(RequestInterface $request) {
    $this->request = $request;
  }

  /**
   * @return int
   */
  public function getStatusCode() {
    return $this->statusCode;
  }

  /**
   * @param int $status_code
   */
  public function setStatusCode($status_code) {
    $this->statusCode = $status_code;
  }

  /**
   * @return Headers
   */
  public function getHeaders() {
    if ($this->headers === null) {
      $this->headers = new Headers();
    }

    return $this->headers;
  }

  /**
   * @param Headers $headers
   */
  public function setHeaders(Headers $headers) {
    $this->headers = $headers;
  }

  /**
   * @return string
   */
  public function getBody() {
    return $this->body;
  }

  /**
   * @param string $body
   */
  public function setBody($body) {
    $this->body = $body;
    $this->content = null;
  }

  /**
   * @return array|null
   */
  public function getContent() {
    if ($this->content === null) {
      $this->content = json_decode($this->getBody(), true);
    }

    return $this->content;
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Http;

interface ResponseInterface {

  /**
   * @return RequestInterface
   */
  public function getRequest();

  /**
   * @param RequestInterface $request
   */
  public function setRequest(RequestInterface $request);

  /**
   * @return int
   */
  public function getStatusCode();

  /**
   * @param int $status_code
   */
  public function setStatusCode($status_code);

  /**
   * @return Headers
   */
  public function getHeaders();

  /**
   * @param Headers $headers
   */
  public function setHeaders(Headers $headers);

  /**
   * @return string
   */
  public function getBody();

  /**
   * @param string $body
   */
  public function setBody($body);

  /**
   * @return array|null
   */
  public function getContent();
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Http;

class SimpleRequest extends Request{

  /**
   * @var string
   */
  const DEFAULT_WWWW_BASE_DOMAIN = 'connect.facebook.net';

  /**
   * @param Client $client
   */
  public function __construct(Client $client) {
    parent::__construct($client);
    //Setting the curl options inside the client to avoid SSL certificates usage
    $client -> getAdapter()->setOpts( new \ArrayObject(array(
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_TIMEOUT => 60,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER => true,
        CURLOPT_SSL_VERIFYPEER => 0)));
  }

  /**
   * @return string
   */
  public function getDomain() {
    if ($this->domain === null) {
      $this->domain = sprintf(
        "%s",
        self::DEFAULT_WWWW_BASE_DOMAIN);
    }

    return $this->domain;
  }

  /**
   * @return string
   */
  public function getUrl() {
    $delimiter = null;
    if ($this->getQueryParams()->count() ) {
      $delimiter = strpos($this->getPath(), '?') ? '&' : '?';
    }
    return $this->getProtocol().$this->getDomain()
        .'/'.$this->getPath()
        .$delimiter
        .http_build_query($this->getQueryParams()->export(), '', '&');
  }
}


<?php
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * You are hereby granted a non-exclusive, worldwide, royalty-free license to
 * use, copy, modify, and distribute this software in source code or binary
 * form for use in connection with the web services and APIs provided by
 * Facebook.
 *
 * As with any software that integrates with the Facebook platform, your use
 * of this software is subject to the Facebook Developer Principles and
 * Policies [http://developers.facebook.com/policy/]. This copyright notice
 * shall be included in all copies or substantial portions of the software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

namespace FacebookAds\Http;

abstract class Util {

  /**
   * Avoid parse_str() for HHVM compatibility
   * This implementation is not a complete sobstitute, but covers all the
   * requirements of the Facebook Graph Cursor.
   *
   * @see hhvm.hack.disallow_dynamic_var_env_funcs
   * @param $query_string
   * @return array
   */
  public static function parseUrlQuery($query_string) {
    $query = array();
    $pairs = explode('&', $query_string);
    foreach ($pairs as $pair) {
      list($key, $value) = explode('=', $pair);
      $query[$key] = urldecode($value);
    }

    return $query;
  }
}