<?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\Object\ServerSide;

use InvalidArgumentException;

/**
 * Normalizer Class
 *
 * @category    Class
 * @package     FacebookAds\Object\ServerSide
 */
class Normalizer {
  /**
   * @param string $field to be normalized.
   * @param string $data value to be normalized
   * @return string
   */
  public static function normalize($field, $data) {
    if ($data == null || strlen($data) == 0) {
      return null;
    }

    // Check if already hashed. If yes, don't try to normalize an already hashed data.
    if (Util::isHashed($data)) {
      return $data;
    }

    $data = trim(strtolower($data));
    $normalized_data = $data;

    switch ($field) {
      case 'em':
        $normalized_data = Normalizer::normalizeEmail($data);
        break;

      case 'ph':
        $normalized_data = Normalizer::normalizePhone($data);
        break;

      case 'zp':
        $normalized_data = Normalizer::normalizeZipCode($data);
        break;

      case 'ct':
        $normalized_data = Normalizer::normalizeCity($data);
        break;

      case 'st':
        $normalized_data = Normalizer::normalizeState($data);
        break;

      case 'country':
        $normalized_data = Normalizer::normalizeCountry($data);
        break;

      case 'currency':
        $normalized_data = Normalizer::normalizeCurrency($data);
        break;

      case 'f5first':
        $normalized_data = Normalizer::normalizeF5($data);
        break;

      case 'f5last':
        $normalized_data = Normalizer::normalizeF5($data);
        break;

      case 'fi':
        $normalized_data = Normalizer::normalizeFi($data);
        break;

      case 'dobd':
        $normalized_data = Normalizer::normalizeDobd($data);
        break;

      case 'dobm':
        $normalized_data = Normalizer::normalizeDobm($data);
        break;

      case 'doby':
        $normalized_data = Normalizer::normalizeDoby($data);
        break;

      case 'delivery_category':
        $normalized_data = Normalizer::normalizeDeliveryCategory($data);
        break;

      case 'action_source':
        $normalized_data = Normalizer::normalizeActionSource($data);
        break;

      default:
    }

    return $normalized_data;
  }

  /**
   * @param string $email Email address to be normalized.
   * @return string
   */
  private static function normalizeEmail($email) {
    // Validates email against RFC 822
    $result = filter_var($email, FILTER_SANITIZE_EMAIL);

    if (!filter_var($result, FILTER_VALIDATE_EMAIL)) {
      throw new InvalidArgumentException('Invalid email format for the passed email: ' . $email . 'Please check the passed email format.');
    }

    return $result;
  }

  /**
   * @param string $city city name to be normalized.
   * @return string
   */
  private static function normalizeCity($city) {
    return trim(preg_replace('/[0-9.\s\-()]/', '', $city));
  }

  /**
   * @param string $state state name to be normalized.
   * @return string
   */
  private static function normalizeState($state) {
    return preg_replace('/[^a-z]/', '', $state);
  }

  /**
   * @param string $country country code to be normalized(ISO 3166-2).
   * @return string
   */
  private static function normalizeCountry($country) {
    $result = preg_replace('/[^a-z]/i', '', $country);

    if (strlen($result) != 2) {
      throw new InvalidArgumentException('Invalid country format passed(' . $country . '). Country Code should be a two-letter ISO Country Code');
    }

    return $result;
  }

  /**
   * @param string $zip postal code to be normalized.
   * @return string
   */
  private static function normalizeZipCode($zip) {
    // Removing the spaces from the zip code. Eg:
    $zip = preg_replace('/[ ]/', '', $zip);

    // If the code has more than one part, retain the first part.
    $zip = explode('-', $zip)[0];
    return $zip;
  }

  /**
   * @param string $phone phone number to be normalized.
   * @return string
   */
  private static function normalizePhone($phone) {
    $result = trim(preg_replace('/[a-z()-]/', '', $phone));

    if (Normalizer::isInternationalNumber($result)) {
      $result = preg_replace('/[\-\s+]/', '', $result);
    }

    return $result;
  }

  /**
   * @param string $currency currency code to be normalized(ISO 4217).
   * @return string
   */
  private static function normalizeCurrency($currency) {
    $result = preg_replace('/[^a-z]/i', '', $currency);

    if (strlen($result) != 3) {
      throw new InvalidArgumentException('Invalid currency format passed(' . $currency . '). Currency Code should be a three-letter ISO Currency Code');
    }

    return $result;
  }

  /**
   *  @param string $name A first or last name to be normalized.
   *  @return string
   */
  private static function normalizeF5($name) {
    return substr($name, 0, 5);
  }

  /**
   *  @param string $fi A first initial to be normalized.
   *  @return string
   */
  private static function normalizeFi($fi) {
    return substr($fi, 0, 1);
  }

  /**
   *  @param string $dobd A date of birth day to be normalized.
   *  @return string
   */
  private static function normalizeDobd($dobd) {
    if (strlen($dobd) == 1) {
      $dobd = '0' . $dobd;
    }

    if (!preg_match('/^[0-9]{2}$/', $dobd)) {
      throw new InvalidArgumentException('Invalid dobd passed(' . $dobd . '). Date of birth day should be in format "DD".');
    }

    $dobd_int = intval($dobd);
    $in_day_range = ($dobd_int >= 1) && ($dobd_int <= 31);
    if (!$in_day_range) {
      throw new InvalidArgumentException('Invalid dobd passed(' . $dobd . '). Date of birth day should be in format "DD".');
    }

    return $dobd;
  }

  /**
   *  @param string $dobm A date of birth month to be normalized.
   *  @return string
   */
  private static function normalizeDobm($dobm) {
    if (strlen($dobm) == 1) {
      $dobm = '0' . $dobm;
    }

    if (!preg_match('/^[0-9]{2}$/', $dobm)) {
      throw new InvalidArgumentException('Invalid dobm passed(' . $dobm . '). Date of birth month should be in format "MM".');
    }

    $dobm_int = intval($dobm);
    $in_month_range = ($dobm_int >= 1) && ($dobm_int <= 12);
    if (!$in_month_range) {
      throw new InvalidArgumentException('Invalid dobm passed(' . $dobm . '). Date of birth month should be in format "MM".');
    }

    return $dobm;
  }

  /**
   *  @param string $doby A date of birth year to be normalized.
   *  @return string
   */
  private static function normalizeDoby($doby) {
    if (!preg_match('/^[0-9]{4}$/', $doby)) {
      throw new InvalidArgumentException('Invalid doby passed(' . $doby . '). Date of birth year should be in format "YYYY".');
    }

    return $doby;
  }

  /**
   * Normalizes the type of DeliveryCategory and throws error if invalid.
   * @param string $delivery_category type of DeliveryCategory.
   * @return string
   */
  private static function normalizeDeliveryCategory($delivery_category) {

    $delivery_categories = DeliveryCategory::getInstance()->getValues();
      if(!DeliveryCategory::getInstance()->isValidValue($delivery_category))
        throw new InvalidArgumentException('Invalid delivery_category passed: ' . $delivery_category .
                          '.Allowed values are one of ' . implode(",",$delivery_categories));

    return $delivery_category;
  }

  /**
   * @param string $phone_number Phone number to be normalized.
   * @return bool
   */
  private static function isInternationalNumber($phone_number) {
    // Remove spaces and hyphens
    $phone_number = preg_replace('/[\-\s]/', '', $phone_number);

    // Strip + and up to 2 leading 0s
    $phone_number = preg_replace('/^\+?0{0,2}/', '', $phone_number);

    if (substr($phone_number, 0, 1) === '0') {
      return false;
    }

    // International Phone number with country calling code.
    $international_number_regex = '/^\d{1,4}\(?\d{2,3}\)?\d{4,}$/';

    return preg_match($international_number_regex, $phone_number);
  }

  /**
   * Normalizes the action_source and throws an error if invalid.
   * @param string $action_source type of DeliveryCategory.
   * @return string
   */
  private static function normalizeActionSource($action_source) {
    $action_sources = ActionSource::getInstance()->getValues();
      if (!ActionSource::getInstance()->isValidValue($action_source)) {
        throw new InvalidArgumentException(sprintf(
          'Invalid action_source passed: %s. Allowed values are one of %s',
          $action_source,
          implode(",", $action_sources)
        ));
      }

    return $action_source;
  }
}


<?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\Object\ServerSide;

abstract class Singleton {
  /**
   * @var array
   */
  protected static $instances = array();

  private function __construct() {}

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

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


<?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\Object\ServerSide;

use ArrayAccess;
use InvalidArgumentException;

/**
 * UserData is a set of identifiers Facebook can use for targeted attribution.
 *
 * @category    Class
 */
class UserData implements ArrayAccess {
  /**
   * The original name of the model.
   * @var string
   */
  protected static $swaggerModelName = 'server_side_pixel_user_data';

  /**
   * Error message for when both singular and plural values are set via constructor.
   * @var string
  */
  private static $multiVariableConstructorError = 'Cannot set both %s and %s parameters via constructor. Please set either the singular or plural parameter, not both.';

  /**
   * Array of property to type mappings. Used for (de)serialization
   * @var string[]
   */
  protected static $param_types = array(
    'email' => 'string',
    'emails' => 'string[]',
    'phone' => 'string',
    'phones' => 'string[]',
    'gender' => 'string',
    'genders' => 'string[]',
    'date_of_birth' => 'string',
    'dates_of_birth' => 'string[]',
    'last_name' => 'string',
    'last_names' => 'string[]',
    'first_name' => 'string',
    'first_names' => 'string[]',
    'ct' => 'string',
    'cts' => 'string[]',
    'state' => 'string',
    'states' => 'string[]',
    'country_code' => 'string',
    'country_codes' => 'string[]',
    'zip_code' => 'string',
    'zip_codes' => 'string[]',
    'external_id' => 'string',
    'external_ids' => 'string[]',
    'client_ip_address' => 'string',
    'client_user_agent' => 'string',
    'fbc' => 'string',
    'fbp' => 'string',
    'subscription_id' => 'string',
    'fb_login_id' => 'string',
    'lead_id' => 'string',
    'f5first' => 'string',
    'f5last' => 'string',
    'fi' => 'string',
    'dobd' => 'string',
    'dobm' => 'string',
    'doby' => 'string',
    'madid' => 'string',
    'anon_id' => 'string'
  );
  /**
   * Array of attributes where the key is the local name, and the value is the original name
   * @var string[]
   */
  protected static $attributeMap = array(
    'email' => 'email',
    'emails' => 'emails',
    'phone' => 'phone',
    'phones' => 'phones',
    'gender' => 'gender',
    'genders' => 'genders',
    'date_of_birth' => 'date_of_birth',
    'dates_of_birth' => 'dates_of_birth',
    'last_name' => 'last_name',
    'last_names' => 'last_names',
    'first_name' => 'first_name',
    'first_names' => 'first_names',
    'ct' => 'ct',
    'cts' => 'cts',
    'state' => 'state',
    'states' => 'states',
    'country_code' => 'country_code',
    'country_codes' => 'country_codes',
    'zip_code' => 'zip_code',
    'zip_codes' => 'zip_codes',
    'external_id' => 'external_id',
    'external_ids' => 'external_ids',
    'client_ip_address' => 'client_ip_address',
    'client_user_agent' => 'client_user_agent',
    'fbc' => 'fbc',
    'fbp' => 'fbp',
    'subscription_id' => 'subscription_id',
    'fb_login_id' => 'fb_login_id',
    'lead_id' => 'lead_id',
    'f5first' => 'f5first',
    'f5last' => 'f5last',
    'fi' => 'fi',
    'dobd' => 'dobd',
    'dobm' => 'dobm',
    'doby' => 'doby',
    'madid' => 'madid',
    'anon_id' => 'anon_id'
  );
  /**
   * Array of attributes to setter functions (for deserialization of responses)
   * @var string[]
   */
  protected static $setters = array(
    'email' => 'setEmail',
    'emails' => 'setEmails',
    'phone' => 'setPhone',
    'phones' => 'setPhones',
    'gender' => 'setGender',
    'genders' => 'setGenders',
    'date_of_birth' => 'setDateOfBirth',
    'dates_of_birth' => 'setDatesOfBirth',
    'last_name' => 'setLastName',
    'last_names' => 'setLastNames',
    'first_name' => 'setFirstName',
    'first_names' => 'setFirstNames',
    'city' => 'setCity',
    'cities' => 'setCities',
    'state' => 'setState',
    'states' => 'setStates',
    'country_code' => 'setCountryCode',
    'country_codes' => 'setCountryCodes',
    'zip_code' => 'setZipCode',
    'zip_codes' => 'setZipCodes',
    'external_id' => 'setExternalId',
    'external_ids' => 'setExternalIds',
    'client_ip_address' => 'setClientIpAddress',
    'client_user_agent' => 'setClientUserAgent',
    'fbc' => 'setFbc',
    'fbp' => 'setFbp',
    'subscription_id' => 'setSubscriptionId',
    'fb_login_id' => 'setFbLoginId',
    'lead_id' => 'setLeadId',
    'f5first' => 'setF5first',
    'f5last' => 'setF5last',
    'fi' => 'setFi',
    'dobd' => 'setDobd',
    'dobm' => 'setDobm',
    'doby' => 'setDoby',
    'madid' => 'setMadid',
    'anon_id' => 'setAnonId'
  );
  /**
   * Array of attributes to getter functions (for serialization of requests)
   * @var string[]
   */
  protected static $getters = array(
    'email' => 'getEmail',
    'emails' => 'getEmails',
    'phone' => 'getPhone',
    'phones' => 'getPhones',
    'gender' => 'getGender',
    'genders' => 'getGenders',
    'date_of_birth' => 'getDateOfBirth',
    'dates_of_birth' => 'getDatesOfBirth',
    'last_name' => 'getLastName',
    'last_names' => 'getLastNames',
    'first_name' => 'getFirstName',
    'first_names' => 'getFirstNames',
    'city' => 'getCity',
    'cities' => 'getCities',
    'state' => 'getState',
    'states' => 'getStates',
    'country_code' => 'getCountryCode',
    'country_codes' => 'getCountryCodes',
    'zip_code' => 'getZipCode',
    'zip_codes' => 'getZipCodes',
    'external_id' => 'getExternalId',
    'external_ids' => 'getExternalIds',
    'client_ip_address' => 'getClientIpAddress',
    'client_user_agent' => 'getClientUserAgent',
    'fbc' => 'getFbc',
    'fbp' => 'getFbp',
    'subscription_id' => 'getSubscriptionId',
    'fb_login_id' => 'getFbLoginId',
    'lead_id' => 'getLeadId',
    'f5first' => 'getF5first',
    'f5last' => 'getF5last',
    'fi' => 'getFi',
    'dobd' => 'getDobd',
    'dobm' => 'getDobm',
    'doby' => 'getDoby',
    'madid' => 'getMadid',
    'anon_id' => 'getAnonId'
  );
  /**
   * Associative array for storing property values
   * @var mixed[]
   */
  protected $container = array();

  /**
   * Constructor
   * @param mixed[] $data Associated array of property value initalizing the model
   */
  public function __construct(array $data = null) {

    # Let's make sure not both singular and plural parameters are set
    if(isset($data['email']) And isset($data['emails'])) {
      throw new InvalidArgumentException(sprintf(self::$multiVariableConstructorError, 'email', 'emails'));
    }
    if(isset($data['phone']) And isset($data['phones'])) {
      throw new InvalidArgumentException(sprintf(self::$multiVariableConstructorError, 'phone', 'phones'));
    }
    if (isset($data['gender']) and isset($data['genders'])) {
      throw new InvalidArgumentException(sprintf(self::$multiVariableConstructorError, 'gender', 'genders'));
    }
    if (isset($data['date_of_birth']) and isset($data['dates_of_birth'])) {
      throw new InvalidArgumentException(sprintf(self::$multiVariableConstructorError, 'date_of_birth', 'dates_of_birth'));
    }
    if (isset($data['last_name']) and isset($data['last_names'])) {
      throw new InvalidArgumentException(sprintf(self::$multiVariableConstructorError, 'last_name', 'last_names'));
    }
    if (isset($data['first_name']) and isset($data['first_names'])) {
      throw new InvalidArgumentException(sprintf(self::$multiVariableConstructorError, 'first_name', 'first_names'));
    }
    if (isset($data['city']) and isset($data['cities'])) {
      throw new InvalidArgumentException(sprintf(self::$multiVariableConstructorError, 'city', 'cities'));
    }
    if (isset($data['state']) and isset($data['states'])) {
      throw new InvalidArgumentException(sprintf(self::$multiVariableConstructorError, 'state', 'states'));
    }
    if (isset($data['country_code']) and isset($data['country_codes'])) {
      throw new InvalidArgumentException(sprintf(self::$multiVariableConstructorError, 'country_code', 'country_codes'));
    }
    if (isset($data['zip_code']) and isset($data['zip_codes'])) {
      throw new InvalidArgumentException(sprintf(self::$multiVariableConstructorError, 'zip_code', 'zip_codes'));
    }
    if (isset($data['external_id']) and isset($data['external_ids'])) {
      throw new InvalidArgumentException(sprintf(self::$multiVariableConstructorError, 'external_id', 'external_ids'));
    }

    # Set the parameters depending on which one is passed in.
    if (isset($data['email'])) {
      $this->setEmail($data['email']);
    } else if(isset($data['emails'])) {
      $this->setEmails($data['emails']);
    }
    if (isset($data['phone'])) {
      $this->setPhone($data['phone']);
    } else if(isset($data['phones'])) {
      $this->setPhones($data['phones']);
    }
    if (isset($data['gender'])) {
      $this->setGender($data['gender']);
    } else if(isset($data['genders'])) {
      $this->setGenders($data['genders']);
    }
    if (isset($data['date_of_birth'])) {
      $this->setDateOfBirth($data['date_of_birth']);
    } else if(isset($data['dates_of_birth'])) {
      $this->setDatesOfBirth($data['dates_of_birth']);
    }
    if (isset($data['last_name'])) {
      $this->setLastName($data['last_name']);
    } else if(isset($data['last_names'])) {
      $this->setLastNames($data['last_names']);
    }
    if (isset($data['first_name'])) {
      $this->setFirstName($data['first_name']);
    } else if(isset($data['first_names'])) {
      $this->setFirstNames($data['first_names']);
    }
    if (isset($data['city'])) {
      $this->setCity($data['city']);
    } else if(isset($data['cities'])) {
      $this->setCities($data['cities']);
    }
    if (isset($data['state'])) {
      $this->setState($data['state']);
    } else if(isset($data['states'])) {
      $this->setStates($data['states']);
    }
    if (isset($data['country_code'])) {
      $this->setCountryCode($data['country_code']);
    } else if(isset($data['country_codes'])) {
      $this->setCountryCodes($data['country_codes']);
    }
    if (isset($data['zip_code'])) {
      $this->setZipCode($data['zip_code']);
    } else if(isset($data['zip_codes'])) {
      $this->setZipCodes($data['zip_codes']);
    }
    if (isset($data['external_id'])) {
      $this->setExternalId($data['external_id']);
    } else if(isset($data['external_ids'])) {
      $this->setExternalIds($data['external_ids']);
    }

    $this->container['client_ip_address'] = isset($data['client_ip_address']) ? $data['client_ip_address'] : null;
    $this->container['client_user_agent'] = isset($data['client_user_agent']) ? $data['client_user_agent'] : null;
    $this->container['fbc'] = isset($data['fbc']) ? $data['fbc'] : null;
    $this->container['fbp'] = isset($data['fbp']) ? $data['fbp'] : null;
    $this->container['subscription_id'] = isset($data['subscription_id']) ? $data['subscription_id'] : null;
    $this->container['fb_login_id'] = isset($data['fb_login_id']) ? $data['fb_login_id'] : null;
    $this->container['lead_id'] = isset($data['lead_id']) ? $data['lead_id'] : null;
    $this->container['f5first'] = isset($data['f5first']) ? $data['f5first'] : null;
    $this->container['f5last'] = isset($data['f5last']) ? $data['f5last'] : null;
    $this->container['fi'] = isset($data['fi']) ? $data['fi'] : null;
    $this->container['dobd'] = isset($data['dobd']) ? $data['dobd'] : null;
    $this->container['dobm'] = isset($data['dobm']) ? $data['dobm'] : null;
    $this->container['doby'] = isset($data['doby']) ? $data['doby'] : null;
    $this->container['madid'] = isset($data['madid']) ? $data['madid'] : null;
    $this->container['anon_id'] = isset($data['anon_id']) ? $data['anon_id'] : null;

  }

  /**
   * @return string[]
   */
  public static function paramTypes() {
    return self::$param_types;
  }

  /**
   * @return string[]
   */
  public static function attributeMap() {
    return self::$attributeMap;
  }

  /**
   * @return string[]
   */
  public static function setters() {
    return self::$setters;
  }

  /**
   * @return string[]
   */
  public static function getters() {
    return self::$getters;
  }

  /**
   * show all the invalid properties with reasons.
   *
   * @return array invalid properties with reasons
   */
  public function listInvalidProperties() {
    $invalid_properties = array();
    return $invalid_properties;
  }

  /**
   * validate all the properties in the model
   * return true if all passed
   *
   * @return bool True if all properteis are valid
   */
  public function valid() {
    return true;
  }

  /**
   * Sets an email address, in lowercase.
   *
   *
Example: joe@eg.com
   * @param string $email An email address, in lowercase.
   * @return $this
   */
  public function setEmail($email) {
    $this->container['emails'] = isset($email) ? array($email) : null;

    return $this;
  }

  /**
   * Sets a list of email addresses, in lowercase.
   *
   *
Example: array('joe@eg.com', 'mary@test.com')
   * @param string[] $emails A list of email addresses, in lowercase.
   * @return $this
   */
  public function setEmails($emails) {
    $this->container['emails'] = $emails;

    return $this;
  }

  /**
   * Sets a phone number. Include only digits with countryCode code, area code, and number.
   *
   *
Example: 16505551212
   * @param string $phone A phone number. Include only digits with country code, area code, and number.
   * @return $this
   */
  public function setPhone($phone) {
    $this->container['phones'] = isset($phone) ? array($phone) : null;

    return $this;
  }

  /**
   * Sets a list of phone numbers. Include only digits with countryCode code, area code, and number.
   *
   *
Example: array('16505551212', '12052062007')
   * @param string[] $phone A list of phone numbers. Include only digits with country code, area code, and number.
   * @return $this
   */
  public function setPhones($phones) {
    $this->container['phones'] = $phones;

    return $this;
  }

  /**
   * Sets Gender, in lowercase. Either f or m.
   * @param FacebookAds\Object\ServerSide\Gender $gender Gender, in lowercase. Either f or m.
   * @return $this
   */
  public function setGender($gender) {
    $this->container['genders'] = isset($gender) ? array($gender) : null;

    return $this;
  }

  /**
   * Sets a list of Genders, in lowercase.
   *
Example: array('f', 'm')
   * @param FacebookAds\Object\ServerSide\Gender[] $genders A list of Genders, in lowercase.
   * @return $this
   */
  public function setGenders($genders) {
    $this->container['genders'] = $genders;

    return $this;
  }

  /**
   * Sets a date of birth given as year, month, and day.
   *
   *
Example: 19971226 for December 26, 1997.
   * @param string $date_of_birth A date of birth given as year, month, and day.
   * @return $this
   */
  public function setDateOfBirth($date_of_birth) {
    $this->container['dates_of_birth'] = isset($date_of_birth) ? array($date_of_birth) : null;

    return $this;
  }

    /**
   * Sets a list of dates of birth given as year, month, and day.
   *
   *
Example: array('19971226', '19880102')
   * @param string[] $dates_of_birth A list of dates of birth given as year, month, and day.
   * @return $this
   */
  public function setDatesOfBirth($dates_of_birth) {
    $this->container['dates_of_birth'] = $dates_of_birth;

    return $this;
  }

  /**
   * Sets a last name in lowercase.
   *
   *
Example: smith
   * @param string $last_name A last name in lowercase.
   * @return $this
   */
  public function setLastName($last_name) {
    $this->container['last_names'] = isset($last_name) ? array($last_name) : null;

    return $this;
  }

  /**
   * Sets a list of last names in lowercase.
   *
   *
Example: array('smith', 'brown')
   * @param string[] $last_names A list of last names in lowercase.
   * @return $this
   */
  public function setLastNames($last_names) {
    $this->container['last_names'] = $last_names;

    return $this;
  }

  /**
   * Sets a first name in lowercase.
   *
   *
Example: joe
   * @param string $first_name A first name in lowercase.
   * @return $this
   */
  public function setFirstName($first_name) {
    $this->container['first_names'] = isset($first_name) ? array($first_name) : null;

    return $this;
  }

  /**
   * Sets a list of first names in lowercase.
   *
   *
Example: array('joe', 'mary')
   * @param string[] $first_names A list of first names in lowercase.
   * @return $this
   */
  public function setFirstNames($first_names) {
    $this->container['first_names'] = $first_names;

    return $this;
  }

  /**
   * Sets a city in lower-case without spaces or punctuation.
   *
   *
Example: menlopark
   * @param string $city A city in lower-case without spaces or punctuation.
   * @return $this
   */
  public function setCity($city) {
    $this->container['cities'] = isset($city) ? array($city) : null;

    return $this;
  }

  /**
   * Sets a list of cities in lower-case without spaces or punctuation.
   *
   *
Example: array('menlopark', 'seattle')
   * @param string[] $cities A list of cities in lower-case without spaces or punctuation.
   * @return $this
   */
  public function setCities($cities) {
    $this->container['cities'] = $cities;

    return $this;
  }

  /**
   * Sets a two-letter state code in lowercase.
   *
   *
Example: ca
   * @param string $state A two-letter state code in lowercase.
   * @return $this
   */
  public function setState($state) {
    $this->container['states'] = isset($state) ? array($state) : null;

    return $this;
  }

  /**
   * Sets a list of two-letter state codes in lowercase.
   *
   *
Example: array('ca', 'wa')
   * @param string[] $states A list of two-letter state codes in lowercase.
   * @return $this
   */
  public function setStates($states) {
    $this->container['states'] = $states;

    return $this;
  }

  /**
   * Sets a two-letter country code in lowercase.
   *
   *
Example: us
   * @param string $country_code two-letter country code in lowercase.
   * @return $this
   */
  public function setCountryCode($country_code) {
    $this->container['country_codes'] = isset($country_code) ? array($country_code) : null;

    return $this;
  }

  /**
   * Sets a list of two-letter country codes in lowercase.
   *
   *
Example: array('us', 'ca')
   * @param string[] $country_codes A list of two-letter country codes in lowercase.
   * @return $this
   */
  public function setCountryCodes($country_codes) {
    $this->container['country_codes'] = $country_codes;

    return $this;
  }

  /**
   * Sets a five-digit zip code.
   *
   *
Example: 94035
   * @param string $zip_code A five-digit zip code.
   * @return $this
   */
  public function setZipCode($zip_code) {
    $this->container['zip_codes'] = isset($zip_code) ? array($zip_code) : null;

    return $this;
  }

  /**
   * Sets a list of five-digit zip codes.
   *
   *
Example: array('94035', '98001')
   * @param string[] $zip_codes A list of five-digit zip codes.
   * @return $this
   */
  public function setZipCodes($zip_codes) {
    $this->container['zip_codes'] = $zip_codes;

    return $this;
  }

  /**
   * Sets any unique ID from the advertiser, such as loyalty membership IDs, user IDs, and external
   * cookie IDs. In the Offline Conversions API, this is known as extern_id. For more information,
   * see Offline Conversions, Providing External IDs. If External ID is being sent via other
   * channels, then it should be sent in the same format via the Conversions API.
   * @param string $external_id Any unique ID from the advertiser, such as loyalty membership IDs,
   *      user IDs, and external cookie IDs.
   * @return $this
   */
  public function setExternalId($external_id) {
    $this->container['external_ids'] = isset($external_id) ? array($external_id) : null;

    return $this;
  }

  /**
   * Sets a list of unique IDs from the advertiser, such as loyalty membership IDs, user IDs, and external
   * cookie IDs. In the Offline Conversions API, this is known as extern_id. For more information,
   * see Offline Conversions, Providing External IDs. If External ID is being sent via other
   * channels, then it should be sent in the same format via the Conversions API.
   * @param string[] $external_ids A list of unique IDs from the advertiser, such as loyalty membership IDs,
   *      user IDs, and external cookie IDs.
   * @return $this
   */
  public function setExternalIds($external_ids) {
    $this->container['external_ids'] = $external_ids;

    return $this;
  }

  /**
   * Sets IP address of the browser corresponding to the event.
   * @param string $client_ip_address The IP address of the browser corresponding to the event.
   * @return $this
   */
  public function setClientIpAddress($client_ip_address) {
    $this->container['client_ip_address'] = $client_ip_address;

    return $this;
  }

  /**
   * Sets user agent for the browser corresponding to the event.
   * @param string $client_user_agent The user agent for the browser corresponding to the event.
   * @return $this
   */
  public function setClientUserAgent($client_user_agent) {
    $this->container['client_user_agent'] = $client_user_agent;

    return $this;
  }

  /**
   * Sets Facebook click ID value stored in the _fbc browser cookie under your domain. See Managing
   * fbc and fbp Parameters for how to get this value
   * (https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters#fbc),
   * or generate this value from a fbclid query parameter.
   * @param string $fbc The Facebook click ID value stored in the _fbc browser cookie under your domain.
   * @return $this
   */
  public function setFbc($fbc) {
    $this->container['fbc'] = $fbc;

    return $this;
  }

  /**
   * Sets Set Facebook browser ID value stored in the _fbp browser cookie under your domain. See Managing
   * fbc and fbp Parameters for how to get this value
   * (https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/customer-information-parameters#fbc),
   * or generate this value from a fbclid query parameter.
   * @param string $fbp The Facebook browser ID value stored in the _fbp browser cookie under your domain.
   * @return $this
   */
  public function setFbp($fbp) {
    $this->container['fbp'] = $fbp;

    return $this;
  }

  /**
   * Sets subscription ID for the user in this transaction. This is similar to the order ID for an
   * individual product.
   * @param string $subscription_id The subscription ID for the user in this transaction.
   * @return $this
   */
  public function setSubscriptionId($subscription_id) {
    $this->container['subscription_id'] = $subscription_id;

    return $this;
  }

  /**
   * Sets FbLogin ID for the user in this transaction.
   * ID issued by Facebook when a person first logs into an instance of an app.
   * This is also known as App-Scoped ID.
   * @param string $fb_login_id The Fb_Login_Id for the user in this transaction.
   * @return $this
   */
  public function setFbLoginId($fb_login_id) {
    $this->container['fb_login_id'] = $fb_login_id;

    return $this;
  }

  /**
   * Sets lead_id for the user in this transaction.
   * A lead_id is associated with a lead generated by Facebook's Lead Ads.
   * @param string $lead_id The lead_id for the user in this transaction.
   * @return $this
   */
  public function setLeadId($lead_id) {
    $this->container['lead_id'] = $lead_id;

    return $this;
  }

  /**
   * Sets the first 5 letters of the first name.
   * @param string $f5first The first 5 letters of the first name.
   * @return $this
   */
  public function setF5first($f5first) {
    $this->container['f5first'] = $f5first;

    return $this;
  }

  /**
   * Sets the first 5 letters of the last name.
   * @param string $f5last The first 5 letters of the last name.
   * @return $this
   */
  public function setF5last($f5last) {
    $this->container['f5last'] = $f5last;

    return $this;
  }

  /**
   * Sets the first initial.
   * @param string $fi The first initial.
   * @return $this
   */
  public function setFi($fi) {
    $this->container['fi'] = $fi;

    return $this;
  }

  /**
   * Sets the date of birth day.
   * @param string $dobd The date of birth day.
   * @return $this
   */
  public function setDobd($dobd) {
    $this->container['dobd'] = $dobd;

    return $this;
  }

  /**
   * Sets the date of birth month.
   * @param string $dobm The date of birth month.
   * @return $this
   */
  public function setDobm($dobm) {
    $this->container['dobm'] = $dobm;

    return $this;
  }

  /**
   * Sets the date of birth year.
   * @param string $doby The date of birth year.
   * @return $this
   */
  public function setDoby($doby) {
    $this->container['doby'] = $doby;

    return $this;
  }

  /**
   * Set the mobile advertiser id which is either Apple's Advertising Identifier (IDFA) or
   * Google Android's advertising ID
   *
   * @param madid is the mobile advertiser id
   * @return $this
   */
  public function setMadid($madid) {
    $this->container['madid'] = $madid;

    return $this;
  }

  /**
   * Set the ID of a person who has installed the app anonymously
   *
   * @param anon_id the anonymous id
   * @return $this
   */
  public function setAnonId($anon_id) {
    $this->container['anon_id'] = $anon_id;

    return $this;
  }

  /**
   * Returns true if offset exists. False otherwise.
   * @param integer $offset Offset
   * @return boolean
   */
  public function offsetExists($offset) : bool {
    return isset($this->container[$offset]);
  }

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

  /**
   * Sets value based on offset.
   * @param integer $offset Offset
   * @param mixed $value Value to be set
   * @return void
   */
  public function offsetSet($offset, $value) : void {
    if (is_null($offset)) {
      $this->container[] = $value;
    } else {
      $this->container[$offset] = $value;
    }
  }

  /**
   * Unsets offset.
   * @param integer $offset Offset
   * @return void
   */
  public function offsetUnset($offset) : void {
    unset($this->container[$offset]);
  }

  public function normalize() {
    $normalized_payload = array();

    $normalized_payload['em'] = $this->normalizeHashDedup('em', $this->getEmails());
    $normalized_payload['ph'] = $this->normalizeHashDedup('ph', $this->getPhones());
    $normalized_payload['ge'] = $this->normalizeHashDedup('ge', $this->getGenders());
    $normalized_payload['db'] = $this->normalizeHashDedup('db', $this->getDatesOfBirth());
    $normalized_payload['ln'] = $this->normalizeHashDedup('ln', $this->getLastNames());
    $normalized_payload['fn'] = $this->normalizeHashDedup('fn', $this->getFirstNames());
    $normalized_payload['ct'] = $this->normalizeHashDedup('ct', $this->getCities());
    $normalized_payload['st'] = $this->normalizeHashDedup('st', $this->getStates());
    $normalized_payload['zp'] = $this->normalizeHashDedup('zp', $this->getZipCodes());
    $normalized_payload['country'] = $this->normalizeHashDedup('country', $this->getCountryCodes());
    $normalized_payload['external_id'] = $this->dedup($this->getExternalIds());
    $normalized_payload['client_ip_address'] = $this->getClientIpAddress();
    $normalized_payload['client_user_agent'] = $this->getClientUserAgent();
    $normalized_payload['fbc'] = $this->getFbc();
    $normalized_payload['fbp'] = $this->getFbp();
    $normalized_payload['subscription_id'] = $this->getSubscriptionId();
    $normalized_payload['fb_login_id'] = $this->getFbLoginId();
    $normalized_payload['lead_id'] = $this->getLeadId();
    $normalized_payload['f5first'] = Util::hash(Normalizer::normalize('f5first', $this->getF5first()));
    $normalized_payload['f5last'] = Util::hash(Normalizer::normalize('f5last', $this->getF5last()));
    $normalized_payload['fi'] = Util::hash(Normalizer::normalize('fi', $this->getFi()));
    $normalized_payload['dobd'] = Util::hash(Normalizer::normalize('dobd', $this->getDobd()));
    $normalized_payload['dobm'] = Util::hash(Normalizer::normalize('dobm', $this->getDobm()));
    $normalized_payload['doby'] = Util::hash(Normalizer::normalize('doby', $this->getDoby()));
    $normalized_payload['madid'] = Util::hash(Normalizer::normalize('madid', $this->getMadid()));
    $normalized_payload['anon_id'] = Util::hash(Normalizer::normalize('anon_id', $this->getAnonId()));
    $normalized_payload = array_filter($normalized_payload);
    return $normalized_payload;
  }

  /**
  * Simply return a deduped array for the given array, without performing any normalization or hash.
  */
  private function dedup($arr){
    if(empty($arr)) {
      return null;
    }
    $deduped = array();
    foreach($arr as $val){
      $deduped[$val] = true;
    }
    return array_keys($deduped);
  }

  /**
  * Return a normalized, hashed, and deduped array for the given array.
  */
  private function normalizeHashDedup($fieldName, $valueList){
    if(empty($valueList) || !isset($fieldName)) {
      return null;
    }
    $deduped = array();
    foreach($valueList as $val){
      $hashedVal = Util::hash(Normalizer::normalize($fieldName, $val));
      $deduped[$hashedVal] = true;
    }
    return array_keys($deduped);
  }

  /**
   * Gets an email address, in lowercase.
   * @return string
   */
  public function getEmail() {
    return empty($this->container['emails']) ? null : $this->container['emails'][0];
  }

  /**
   * Gets a list of email addresses, in lowercase.
   * @return string[]
   */
  public function getEmails() {
    return empty($this->container['emails']) ? null : $this->container['emails'];
  }

  /**
   * Gets a phone number
   * @return string
   */
  public function getPhone() {
    return empty($this->container['phones']) ? null : $this->container['phones'][0];
  }

  /**
   * Gets a list of phone numbers
   * @return string[]
   */
  public function getPhones() {
    return empty($this->container['phones']) ? null : $this->container['phones'];
  }

  /**
   * Gets gender.
   * @return string
   */
  public function getGender() {
    return empty($this->container['genders']) ? null : $this->container['genders'][0];
  }

  /**
   * Gets a list of genders.
   * @return string[]
   */
  public function getGenders() {
    return empty($this->container['genders']) ? null : $this->container['genders'];
  }

  /**
   * Gets Date Of Birth.
   * @return string
   */
  public function getDateOfBirth() {
    return empty($this->container['dates_of_birth']) ? null : $this->container['dates_of_birth'][0];
  }

  /**
   * Gets a list of dates Of Birth.
   * @return string[]
   */
  public function getDatesOfBirth() {
    return empty($this->container['dates_of_birth']) ? null : $this->container['dates_of_birth'];
  }

  /**
   * Gets Last Name.
   * @return string
   */
  public function getLastName() {
    return empty($this->container['last_names']) ? null : $this->container['last_names'][0];
  }

  /**
   * Gets a list of Last Names.
   * @return string[]
   */
  public function getLastNames() {
    return empty($this->container['last_names']) ? null : $this->container['last_names'];
  }

  /**
   * Gets First Name.
   * @return string
   */
  public function getFirstName() {
    return empty($this->container['first_names']) ? null : $this->container['first_names'][0];
  }

  /**
   * Gets a list of First Name.
   * @return string[]
   */
  public function getFirstNames() {
    return empty($this->container['first_names']) ? null : $this->container['first_names'];
  }

  /**
   * Gets city.
   * @return string
   */
  public function getCity() {
    return empty($this->container['cities']) ? null : $this->container['cities'][0];
  }

  /**
   * Gets a list of cities.
   * @return string[]
   */
  public function getCities() {
    return empty($this->container['cities']) ? null : $this->container['cities'];
  }

  /**
   * Gets state.
   * @return string
   */
  public function getState() {
    return empty($this->container['states']) ? null : $this->container['states'][0];
  }

  /**
   * Gets a list of states.
   * @return string[]
   */
  public function getStates() {
    return empty($this->container['states']) ? null : $this->container['states'];
  }

  /**
   * Gets zip code
   * @return string
   */
  public function getZipCode() {
    return empty($this->container['zip_codes']) ? null : $this->container['zip_codes'][0];
  }

  /**
   * Gets zip codes
   * @return string[]
   */
  public function getZipCodes() {
    return empty($this->container['zip_codes']) ? null : $this->container['zip_codes'];
  }

  /**
   * Gets country code.
   * @return string
   */
  public function getCountryCode() {
    return empty($this->container['country_codes']) ? null : $this->container['country_codes'][0];
  }

  /**
   * Gets country codes.
   * @return string[]
   */
  public function getCountryCodes() {
    return empty($this->container['country_codes']) ? null : $this->container['country_codes'];
  }

  /**
   * Gets Any unique ID from the advertiser, such as loyalty membership IDs, user IDs, and external cookie IDs.
   * @return string
   */
  public function getExternalId() {
    return empty($this->container['external_ids']) ? null : $this->container['external_ids'][0];
  }

  /**
   * Gets a list of unique IDs from the advertiser, such as loyalty membership IDs, user IDs, and external cookie IDs.
   * @return string[]
   */
  public function getExternalIds() {
    return empty($this->container['external_ids']) ? null : $this->container['external_ids'];
  }

  /**
   * Gets IP address of the browser corresponding to the event.
   * @return string
   */
  public function getClientIpAddress() {
    return $this->container['client_ip_address'];
  }

  /**
   * Gets user agent for the browser corresponding to the event.
   * @return string
   */
  public function getClientUserAgent() {
    return $this->container['client_user_agent'];
  }

  /**
   * Gets the Facebook click ID value stored in the _fbc browser cookie under your domain.
   * @return string
   */
  public function getFbc() {
    return $this->container['fbc'];
  }

  /**
   * Gets the Facebook browser ID value stored in the _fbp browser cookie under your domain.
   * @return string
   */
  public function getFbp() {
    return $this->container['fbp'];
  }

  /**
   * Gets the subscription ID for the user in this transaction.
   * @return string
   */
  public function getSubscriptionId() {
    return $this->container['subscription_id'];
  }

  /**
   * Gets the FbLogin ID for the user in this transaction.
   * @return string
   */
  public function getFbLoginId() {
    return $this->container['fb_login_id'];
  }

  /**
   * Gets the lead_id for the user in this transaction.
   * @return string
   */
  public function getLeadId() {
    return $this->container['lead_id'];
  }

  /**
   * Gets the first 5 letters of the first name.
   * @return string
   */
  public function getF5first() {
    return $this->container['f5first'];
  }

  /**
   * Gets the first 5 letters of the last name.
   * @return string
   */
  public function getF5last() {
    return $this->container['f5last'];
  }

  /**
   * Gets the first initial.
   * @return string
   */
  public function getFi() {
    return $this->container['fi'];
  }

  /**
   * Gets the date of birth day.
   * @return string
   */
  public function getDobd() {
    return $this->container['dobd'];
  }

  /**
   * Gets the date of birth month.
   * @return string
   */
  public function getDobm() {
    return $this->container['dobm'];
  }

  /**
   * Gets the date of birth year.
   * @return string
   */
  public function getDoby() {
    return $this->container['doby'];
  }

  /**
   * The mobile advertiser id
   * @return string
   */
  public function getMadid() {
    return $this->container['madid'];
  }

  /**
   * ID of the person who has installed the app anonymously
   * @return string
   */
  public function getAnonId() {
    return $this->container['anon_id'];
  }

  /**
   * Gets the string presentation of the object
   * @return string
   */
  public function __toString() {
    if (defined('JSON_PRETTY_PRINT')) { // use JSON pretty print
      return json_encode($this, JSON_PRETTY_PRINT);
    }

    return json_encode($this);
  }
}


<?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\Object\ServerSide;

/**
 * Util Class
 *
 * @category    Class
 * @package     FacebookAds\Object\ServerSide
 */
class Util {
  /**
   * @param string $data hash input data using SHA256 algorithm.
   * @return string
   */
  public static function hash($data) {
    if ($data == null || Util::isHashed($data)) {
      return $data;
    }
    return hash('sha256', $data, false);
  }

  /**
   * @param string $pii PII data to check if its hashed.
   * @return bool
   */
  public static function isHashed($pii) {
    // it could be sha256 or md5
    return preg_match('/^[A-Fa-f0-9]{64}$/', $pii) ||
      preg_match('/^[a-f0-9]{32}$/', $pii);
  }

  /**
   * Extracts the IP Address from the PHP Request Context.
   * @return string
   */
  public static function getIpAddress() {
    $ip_address = null;

    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
      $ip_address = $_SERVER['HTTP_CLIENT_IP'];
    } else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
      $ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } else if (!empty($_SERVER['REMOTE_ADDR'])) {
      $ip_address = $_SERVER['REMOTE_ADDR'];
    }

    return $ip_address;
  }

  /**
   * Extracts the HTTP User Agent from the PHP Request Context.
   * @return string
   */
  public static function getHttpUserAgent() {
    $user_agent = null;

    if (!empty($_SERVER['HTTP_USER_AGENT'])) {
      $user_agent = $_SERVER['HTTP_USER_AGENT'];
    }

    return $user_agent;
  }

  /**
   * Extracts the URI from the PHP Request Context.
   * @return string
   */
  public static function getRequestUri() {
    $url = "http://";
    if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
      $url = "https://";
    }

    if (!empty($_SERVER['HTTP_HOST'])) {
      $url .= $_SERVER['HTTP_HOST'];
    }

    if (!empty($_SERVER['REQUEST_URI'])) {
      $url .= $_SERVER['REQUEST_URI'];
    }

    return $url;
  }

  /**
   * Extracts the FBP cookie from the PHP Request Context.
   * @return string
   */
  public static function getFbp() {
    $fbp = null;

    if (!empty($_COOKIE['_fbp'])) {
      $fbp = $_COOKIE['_fbp'];
    }

    return $fbp;
  }

  /**
   * Extracts the FBC cookie from the PHP Request Context.
   * @return string
   */
  public static function getFbc() {
    $fbc = null;

    if (!empty($_COOKIE['_fbc'])) {
      $fbc = $_COOKIE['_fbc'];
    }

    return $fbc;
  }

  public static function getCaBundlePath() {
    return __DIR__.DIRECTORY_SEPARATOR
      .str_repeat('..'.DIRECTORY_SEPARATOR, 4)
      .'fb_ca_chain_bundle.crt';
  }

  public static function getAppsecretProof($access_token, $appsecret) {
    return hash_hmac(
      'sha256',
      $access_token,
      $appsecret
    );
  }
}


<?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\Object\Signal;

use FacebookAds\Object\BusinessDataAPI\Content as BusinessDataContent;
use FacebookAds\Object\ServerSide\Content as ServerSideContent;

class Content {
  /**
   * Associative array for storing property values for Business Data API
   * @var BusinessDataContent
   */
  protected $businessDataContent= null;

  /**
   * Associative array for storing property values for Conversion API
   * @var ServerSideContent
   */
  protected $serverSideContent = null;

  /**
   * Constructor
   * @param mixed[] $data Associated array of property value initializing the model
   */
  public function __construct(array $data = null) {
    $this->businessDataContent = new BusinessDataContent($data);
    $this->serverSideContent = new ServerSideContent($data);
  }

  /**
   * Get Product Id.
   * @return array Product Id
   */
  public function getProductId() {
    return Util::constructResponse($this->serverSideContent->getProductId(), $this->businessDataContent->getProductId());
  }

  /**
   * Sets product id.
   * @param string $product_id product id
   * @return $this
   */
  public function setProductId($product_id) {
    $this->businessDataContent->setProductId($product_id);
    $this->serverSideContent->setProductId($product_id);
    return $this;
  }

  /**
   * Get number of product.
   * @return integer quantity
   */
  public function getQuantity() {
    return Util::constructResponse($this->serverSideContent->getQuantity(), $this->businessDataContent->getQuantity());
  }

  /**
   * Set number of product.
   * @param integer $quantity number of items
   * @return $this
   */
  public function setQuantity($quantity) {
    $this->businessDataContent->setQuantity($quantity);
    $this->serverSideContent->setQuantity($quantity);
    return $this;
  }

  /**
   * Get total price.
   * @return array Price
   */
  public function getPrice() {
    return Util::constructResponse(null, $this->businessDataContent->getPrice());
  }

  /**
   * Set total price.
   * @param float Price
   * @return $this
   */
  public function setPrice($price) {
    $this->businessDataContent->setPrice($price);
    return $this;
  }

  /**
   * Get title.
   * @return array title
   */
  public function getTitle() {
    return Util::constructResponse($this->serverSideContent->getTitle(), $this->businessDataContent->getTitle());
  }

  /**
   * Sets title.
   * @param string $title title
   * @return $this
   */
  public function setTitle($title) {
    $this->businessDataContent->setTitle($title);
    $this->serverSideContent->setTitle($title);
    return $this;
  }

  /**
   * Get Item Price.
   * @return array Item Price
   */
  public function getItemPrice() {
    return Util::constructResponse($this->serverSideContent->getItemPrice(), null);
  }

  /**
   * Set Item Price.
   * @param float $item_price single item price
   * @return Content
   */
  public function setItemPrice($item_price) {
    $this->serverSideContent->setItemPrice($item_price);
    return $this;
  }

  /**
   * Get description.
   * @return array description
   */
  public function getDescription() {
    return Util::constructResponse($this->serverSideContent->getDescription(), null);
  }

  /**
   * Sets description.
   * @param string $description description
   * @return $this
   */
  public function setDescription($description) {
    $this->serverSideContent->setDescription($description);
    return $this;
  }

  /**
   * Get brand.
   * @return array brand
   */
  public function getBrand() {
    return Util::constructResponse($this->serverSideContent->getBrand(), null);
  }

  /**
   * Sets brand.
   * @param string $brand brand
   * @return $this
   */
  public function setBrand($brand) {
    $this->serverSideContent->setBrand($brand);
    return $this;
  }

  /**
   * Get category.
   * @return array category
   */
  public function getCategory() {
    return Util::constructResponse($this->serverSideContent->getCategory(), null);
  }

  /**
   * Sets category.
   * @param string $category category
   * @return $this
   */
  public function setCategory($category) {
    $this->serverSideContent->setCategory($category);
    return $this;
  }

  /**
   * Gets Type of delivery for a purchase event.
   * @return array delivery_category
   */
  public function getDeliveryCategory() {
    return Util::constructResponse($this->serverSideContent->getDeliveryCategory(), null);
  }

  /**
   * Sets Type of delivery for a purchase event.
   * @param string $delivery_category
   * @return $this
   */
  public function setDeliveryCategory($delivery_category) {
    $this->serverSideContent->setDeliveryCategory($delivery_category);
    return $this;
  }

  /**
   * Gets content for Business Data API
   * @return BusinessDataContent
   */
  public function getBusinessDataContent() {
    return $this->businessDataContent;
  }

  /**
   * Gets content for Conversion API
   * @return ServerSideContent
   */
  public function getServerSideContent() {
    return $this->serverSideContent;
  }
}


<?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\Object\Signal;

use FacebookAds\Object\BusinessDataAPI\CustomData as BusinessDataCustomData;
use FacebookAds\Object\ServerSide\CustomData as ServerSideCustomData;

class CustomData {

  /**
   * Associative array for storing property values for Business Data API
   * @var BusinessDataCustomData
   */
  protected $businessDataCustomData= null;

  /**
   * Associative array for storing property values for Conversion API
   * @var ServerSideCustomData
   */
  protected $serverSideCustomData = null;

  /**
   * Constructor
   * @param mixed[] $data Associated array of property value initializing the model
   */
  public function __construct(array $data = null) {
    $business_contents = array();
    $server_contents = array();
    if(isset($data['contents'])){
        foreach ($data['contents'] as $content) {
            array_push($business_contents, $content->getBusinessDataContent());
            array_push($server_contents, $content->getServerSideContent());
        }
    }

    $business_data = $data;
    $server_data = $data;
    $business_data['contents'] =  $business_contents;
    $server_data['contents'] = $server_contents;
    $business_data['billing_contact'] = isset($data['billing_contact']) ? $data['billing_contact']->getBusinessDataUserData() : null;
    $business_data['shipping_contact'] = isset($data['shipping_contact']) ? $data['shipping_contact']->getBusinessDataUserData() : null;
    $this->businessDataCustomData = new BusinessDataCustomData($business_data);
    $this->serverSideCustomData = new ServerSideCustomData($server_data);
  }

  /**
   * Sets value
   * @param float $value A numeric value associated with this event.
   *         This could be a monetary value or a value in some other metric.
   * @return $this
   */
  public function setValue($value) {
    $this->businessDataCustomData->setValue($value);
    $this->serverSideCustomData->setValue($value);

    return $this;
  }

  /**
   * Sets currency
   * @param string $currency The currency for the value specified, if applicable.
   *          Currency must be a valid ISO 4217 three digit currency code.
   * @return $this
   */
  public function setCurrency($currency) {
    $this->businessDataCustomData->setCurrency($currency);
    $this->serverSideCustomData->setCurrency($currency);

    return $this;
  }

  /**
   * Sets contents
   * @param Content[] $contents A list of CustomData objects that contain the product IDs associated with
   *          the event plus information about the products.
   * @return $this
   */
  public function setContents($contents) {
    $business_contents = array();
    $server_contents = array();
    foreach ($contents as $content) {
        array_push($business_contents, $content->getBusinessDataContent());
        array_push($server_contents, $content->getServerSideContent());
    }
    $this->businessDataCustomData->setContents($business_contents);
    $this->serverSideCustomData->setContents($server_contents);
    return $this;
  }

  /**
   * Sets order_id
   * @param string $order_id The order ID for this transaction as a String.
   * @return $this
   */
  public function setOrderId($order_id) {
    $this->businessDataCustomData->setOrderId($order_id);
    $this->serverSideCustomData->setOrderId($order_id);

    return $this;
  }

  /**
   * Sets status
   * @param string status of the order
   *
   * @return $this
   */
  public function setStatus($status) {
    $this->businessDataCustomData->setStatus($status);
    $this->serverSideCustomData->setStatus($status);

    return $this;
  }

  /**
   * Sets billing contact
   * @param UserData billing_contact of the order
   *
   * @return $this
   */
  public function setBillingContact($billing_contact) {
    $this->businessDataCustomData->setBillingContact($billing_contact->getBusinessDataUserData());

    return $this;
  }

  /**
   * Sets shipping contact
   * @param UserData shipping_contact of the order
   *
   * @return $this
   */
  public function setShippingContact($shipping_contact) {
    $this->businessDataCustomData->setShippingContact($shipping_contact->getBusinessDataUserData());

    return $this;
  }

  /**
   * Sets external order id
   * @param string external_order_id unique order id
   *
   * @return $this
   */
  public function setExternalOrderId($external_order_id) {
    $this->businessDataCustomData->setExternalOrderId($external_order_id);

    return $this;
  }

  /**
   * Sets original order id
   * @param string original_order_id for Refund event.
   *
   * @return $this
   */
  public function setOriginalOrderId($original_order_id) {
    $this->businessDataCustomData->setOriginalOrderId($original_order_id);

    return $this;
  }

  /**
   * Sets message for Refund event
   * @param string message for Refund event
   *
   * @return $this
   */
  public function setMessage($message) {
    $this->businessDataCustomData->setMessage($message);

    return $this;
  }

  /**
   * Sets content_name
   * @param string $content_name The name of the page or product associated with the event. Example: 'lettuce'.
   *
   * @return $this
   */
  public function setContentName($content_name) {
    $this->serverSideCustomData->setContentName($content_name);

    return $this;
  }

  /**
   * Sets content_category
   * @param string $content_category The category of the content associated with the event. Example: 'grocery'
   *
   * @return $this
   */
  public function setContentCategory($content_category) {
    $this->serverSideCustomData->setContentCategory($content_category);

    return $this;
  }

  /**
   * Sets content_ids
   * @param string[] $content_ids The content IDs associated with the event,
   *      such as product SKUs for items in an AddToCart event: ['ABC123', 'XYZ789'].
   *      If content_type is a product, then your content IDs must be an array with a single string value.
   *      Otherwise, this array can contain any number of string values.
   *
   * @return $this
   */
  public function setContentIds($content_ids) {
    $this->serverSideCustomData->setContentIds($content_ids);

    return $this;
  }

  /**
   * Sets content_type
   * @param string $content_type A String equal to either 'product' or 'product_group'.
   *      Set to product if the keys you send content_ids or contents represent products.
   *      Set to product_group if the keys you send in content_ids represent product groups.
   *
   * @return $this
   */
  public function setContentType($content_type) {
    $this->serverSideCustomData->setContentType($content_type);

    return $this;
  }

  /**
   * Sets predicted_ltv
   * @param float $predicted_ltv The predicted lifetime value of a conversion event.
   *
   * @return $this
   */
  public function setPredictedLtv($predicted_ltv) {
    $this->serverSideCustomData->setPredictedLtv($predicted_ltv);

    return $this;
  }

  /**
   * Sets num_items
   * @param string $num_items Use only with InitiateCheckout events.
   *      The number of items that a user tries to buy during checkout.
   *
   * @return $this
   */
  public function setNumItems($num_items) {
    $this->serverSideCustomData->setNumItems($num_items);

    return $this;
  }

  /**
   * Sets a search query made by a user. Use only with Search events.
   * @param string $search_string Use only with Search events.
   *      A search query made by a user.
   *
   * @return $this
   */
  public function setSearchString($search_string) {
    $this->serverSideCustomData->setSearchString($search_string);

    return $this;
  }

  /**
   * Sets Type of delivery for a purchase event.
   * @param string $delivery_category Type of delivery for a purchase event.
   *
   * @return $this
   */
  public function setDeliveryCategory($delivery_category) {
    $this->serverSideCustomData->setDeliveryCategory($delivery_category);

    return $this;
  }

  /**
   * Sets the item_number.
   * @param string $item_number The item number.
   *
   * @return $this
   */
  public function setItemNumber($item_number) {
    $this->serverSideCustomData->setItemNumber($item_number);

    return $this;
  }

  /**
   * Sets custom_properties that are not defined as the standard properties list in custom data.
   * @param array custom_properties dictionary to include custom properties that are not defined in custom data.
   *
   * @return $this
   */
  public function setCustomProperties($custom_properties) {
    $this->serverSideCustomData->setCustomProperties($custom_properties);
    return $this;
  }

  /**
   * Gets a numeric value associated with this event.
   * This could be a monetary value or a value in some other metric.
   *
   * @return array
   */
  public function getValue() {
    return Util::constructResponse($this->serverSideCustomData->getValue(), $this->businessDataCustomData->getValue());
  }

  /**
   * Gets currency for the value specified, if applicable.
   * @return array
   */
  public function getCurrency() {
    return Util::constructResponse($this->serverSideCustomData->getCurrency(), $this->businessDataCustomData->getCurrency());
  }

  /**
   * Gets a list of CustomData objects that contain the product IDs associated with
   * the event plus information about the products.
   * @return array
   */
  public function getCustomDatas() {
    return Util::constructResponse($this->serverSideCustomData->getCustomDatas(), $this->businessDataCustomData->getCustomDatas());
  }

  /**
   * Gets the order ID for this transaction as a String.
   * @return array
   */
  public function getOrderId() {
    return Util::constructResponse($this->serverSideCustomData->getOrderId(), $this->businessDataCustomData->getOrderId());
  }

  /**
   * Gets the status of the registration event
   * @return array
   */
  public function getStatus() {
    return Util::constructResponse($this->serverSideCustomData->getStatus(), $this->businessDataCustomData->getStatus());
  }

  /**
   * Gets billing contact
   *
   * @return array
   */
  public function getBillingContact() {
    return Util::constructResponse(null, $this->businessDataCustomData->getBillingContact());
  }

  /**
   * Gets shipping contact
   *
   * @return array
   */
  public function getShippingContact() {
    return Util::constructResponse(null, $this->businessDataCustomData->getShippingContact());
  }

  /**
   * Gets external order id
   *
   * @return array
   */
  public function getExternalOrderId() {
    return Util::constructResponse(null, $this->businessDataCustomData->getExternalOrderId());
  }

  /**
   * Gets original order id
   *
   * @return array
   */
  public function getOriginalOrderId() {
    return Util::constructResponse(null, $this->businessDataCustomData->getOriginalOrderId());
  }

  /**
   * Gets message
   *
   * @return array
   */
  public function getMessage() {
    return Util::constructResponse(null, $this->businessDataCustomData->getMessage());
  }

  /**
   * Gets the value of a custom property from the custom_properties bag
   * @param $key Custom property name
   * @return array
   */
  public function getCustomProperty($key) {
    return Util::constructResponse($this->serverSideCustomData->getCustomProperty($key), null);
  }

   /**
   * Gets content name of the page or product associated with the event. Example: 'lettuce'.
   * @return array
   */
  public function getContentName() {
    return Util::constructResponse($this->serverSideCustomData->getContentName(), null);
  }

  /**
   * Gets the category of the content associated with the event. Example: 'grocery'
   * @return array
   */
  public function getContentCategory() {
    return Util::constructResponse($this->serverSideCustomData->getContentCategory(), null);
  }

  /**
   * Gets the content IDs associated with the event,
   * such as product SKUs for items in an AddToCart event: ['ABC123', 'XYZ789'].
   * @return array
   */
  public function getContentIds() {
    return Util::constructResponse($this->serverSideCustomData->getContentIds(), null);
  }

  /**
   * Gets content type 'product' or 'product_group'
   * @return array
   */
  public function getContentType() {
    return Util::constructResponse($this->serverSideCustomData->getContentType(), null);
  }

  /**
   * Gets the predicted lifetime value of a conversion event.
   * @return array
   */
  public function getPredictedLtv() {
    return Util::constructResponse($this->serverSideCustomData->getPredictedLtv(), null);
  }

  /**
   * Gets the number of items that a user tries to buy during checkout
   * @return array
   */
  public function getNumItems() {
    return Util::constructResponse($this->serverSideCustomData->getNumItems(), null);
  }

  /**
   * Gets a search query made by a user.
   * @return array
   */
  public function getSearchString() {
    return Util::constructResponse($this->serverSideCustomData->getSearchString(), null);
  }

  /**
   * Gets a delivery_category for a purchase order.
   * @return array
   */
  public function getDeliveryCategory() {
    return Util::constructResponse($this->serverSideCustomData->getDeliveryCategory(), null);
  }

  /**
   * Gets the item number.
   * @return array
   */
  public function getItemNumber() {
    return Util::constructResponse($this->serverSideCustomData->getItemNumber(), null);
  }

  /**
   * Gets Custom Properties dictionary to add properties that are not defined as part of the custom data.
   * @return array
   */
  public function getCustomProperties() {
    return Util::constructResponse($this->serverSideCustomData->getCustomProperties(), null);
  }

  /**
   * Gets custom data for Business Data API
   * @return BusinessDataCustomData
   */
  public function getBusinessDataCustomData() {
    return $this->businessDataCustomData;
  }

  /**
   * Gets custom data for Conversion API
   * @return ServerSideCustomData
   */
  public function getServerSideCustomData() {
    return $this->serverSideCustomData;
  }
}


<?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\Object\Signal;

use FacebookAds\Object\BusinessDataAPI\Event as BusinessDataEvent;
use FacebookAds\Object\ServerSide\Event as ServerSideEvent;

class Event {
   /**
   * Associative array for storing property values for Business Data API
   * @var BusinessDataEvent
   */
  protected $businessDataEvent= null;

  /**
   * Associative array for storing property values for Conversion API
   * @var ServerSideEvent
   */
  protected $serverSideEvent = null;

  /**
   * Constructor
   * @param mixed[] $data Associated array of property value initalizing the model
   */
  public function __construct(array $data = null) {
    $business_data = $data;
    $server_data = $data;
    $business_data['user_data'] = isset($data['user_data']) ? $data['user_data']->getBusinessDataUserData() : null;
    $server_data['user_data'] = isset($data['user_data']) ? $data['user_data']->getServerSideUserData() : null;
    $business_data['custom_data'] = isset($data['custom_data']) ? $data['custom_data']->getBusinessDataCustomData() : null;
    $server_data['custom_data'] = isset($data['custom_data']) ? $data['custom_data']->getServerSideCustomData() : null;

    $this->businessDataEvent = new BusinessDataEvent($business_data);
    $this->serverSideEvent = new ServerSideEvent($server_data);
  }

  /**
   * Sets a Facebook pixel Standard Event or Custom Event name
   * @param string $event_name A Facebook pixel Standard Event or Custom Event name.
   * @return $this
   */
  public function setEventName($event_name) {
    $this->businessDataEvent->setEventName($event_name);
    $this->serverSideEvent->setEventName($event_name);

    return $this;
  }

  /**
   * Sets a Unix timestamp in seconds indicating when the actual event occurred
   * @param int $event_time A Unix timestamp in seconds indicating when the actual event occurred.
   * @return $this
   */
  public function setEventTime($event_time) {
    $this->businessDataEvent->setEventTime($event_time);
    $this->serverSideEvent->setEventTime($event_time);

    return $this;
  }

  /**
   * Sets an ID used by Facebook to deduplicate the same event sent from both server and browser.
   * @param string $event_id This ID can be any unique string chosen by the advertiser.
   * event_id is used to deduplicate events sent by both Facebook Pixel and Server-Side API.
   * event_name is also used in the deduplication process.
   * For deduplication, the eventID from Facebook pixel must match the
   * event_id in the corresponding Server-Side API event.
   * @return $this
   */
  public function setEventId($event_id) {
    $this->businessDataEvent->setEventId($event_id);
    $this->serverSideEvent->setEventId($event_id);

    return $this;
  }

  /**
   * Sets UserData object that contains user data.
   * @param FacebookAds\Object\Signal\UserData $user_data
   * @return $this
   */
  public function setUserData($user_data) {
    $this->businessDataEvent->setUserData($user_data->getBusinessDataUserData());
    $this->serverSideEvent->setUserData($user_data->getServerSideUserData());

    return $this;
  }

  /**
   * Sets CustomData object that includes additional business data about the event.
   * @param FacebookAds\Object\Signal\CustomData $custom_data
   * @return $this
   */
  public function setCustomData($custom_data) {
    $this->businessDataEvent->setCustomData($custom_data->getBusinessDataCustomData());
    $this->serverSideEvent->setCustomData($custom_data->getServerSideCustomData());

    return $this;
  }

 /**
   * Sets the browser URL where the event happened
   * @param string $event_source_url The browser URL where the event happened.
   * @return $this
   */
  public function setEventSourceUrl($event_source_url) {
    $this->serverSideEvent->setEventSourceUrl($event_source_url);

    return $this;
  }

  /**
   * Sets a flag that indicates Facebook should or should not use this event for ads delivery optimization
   * @param bool $opt_out A flag that indicates Facebook should or should not
   *      use this event for ads delivery optimization.
   *      If set to true, Facebook only use the event for attribution.
   * @return $this
   */
  public function setOptOut($opt_out) {
    $this->serverSideEvent->setOptOut($opt_out);

    return $this;
  }

  /**
   * Sets the processing options you would like to enable for a specific event.
   * For more details see: https://developers.facebook.com/docs/marketing-apis/data-processing-options
   * @param string[], e.g. [] or ['LDU']
   * @return $this
   */
  public function setDataProcessingOptions($data_processing_options) {
    $this->businessDataEvent->setDataProcessingOptions($data_processing_options);
    $this->serverSideEvent->setDataProcessingOptions($data_processing_options);

    return $this;
  }

  /**
   * Sets a country that you want to associate to this data processing option. If you set a country, you must also set a state.
   * For more details see: https://developers.facebook.com/docs/marketing-apis/data-processing-options
   * @param int
   * @return $this
   */
  public function setDataProcessingOptionsCountry($data_processing_options_country) {
    $this->businessDataEvent->setDataProcessingOptionsCountry($data_processing_options_country);
    $this->serverSideEvent->setDataProcessingOptionsCountry($data_processing_options_country);

    return $this;
  }

  /**
   * Sets a state that you want to associate with this data processing option.
   * For more details see: https://developers.facebook.com/docs/marketing-apis/data-processing-options
   * @param int
   * @return $this
   *
   */
  public function setDataProcessingOptionsState($data_processing_options_state) {
    $this->businessDataEvent->setDataProcessingOptionsState($data_processing_options_state);
    $this->serverSideEvent->setDataProcessingOptionsState($data_processing_options_state);

    return $this;
  }

  /**
   * Gets Facebook pixel Standard Event or Custom Event name.
   * @return array
   */
  public function getEventName() {
    return Util::constructResponse($this->serverSideEvent->getEventName(), $this->businessDataEvent->getEventName());
  }

  /**
   * Gets Unix timestamp in seconds indicating when the actual event occurred.
   * @return array
   */
  public function getEventTime() {
    return Util::constructResponse($this->serverSideEvent->getEventTime(), $this->businessDataEvent->getEventTime());
  }

  /**
   * Gets Event ID can be any string chosen by the advertiser. It is used by Facebook to deduplicate
   * the same event sent from both server and browser.
   *@return array
   */
  public function getEventId() {
    return Util::constructResponse($this->serverSideEvent->getEventId(), $this->businessDataEvent->getEventId());
  }

  /**
   * Gets UserData object that contains user data
   * @return array
   */
  public function getUserData() {
    return Util::constructResponse($this->serverSideEvent->getUserData(), $this->businessDataEvent->getUserData());
  }

  /**
   * Gets customData object that includes additional business data about the event.
   * @return array
   */
  public function getCustomData() {
    return Util::constructResponse($this->serverSideEvent->getCustomData(), $this->businessDataEvent->getCustomData());
  }

  /**
   * Gets DataProcessionOptions value of Processing options you would like to enable for a specific event.
   *@return array
   */
  public function getDataProcessingOptions() {
    return Util::constructResponse($this->serverSideEvent->getDataProcessingOptions(), $this->businessDataEvent->getDataProcessingOptions());
  }

  /**
   * Gets DataProcessionOptionsState value that represents the state that you want to associate with this data processing option.
   *@return array
   */
  public function getDataProcessingOptionsState() {
    return Util::constructResponse($this->serverSideEvent->getDataProcessingOptionsState(), $this->businessDataEvent->getDataProcessingOptionsState());
  }

  /**
   * Gets DataProcessionOptionsCountry value that represents the country that you want to associate to this data processing option.
   *@return array
   */
  public function getDataProcessingOptionsCountry() {
    return Util::constructResponse($this->serverSideEvent->getDataProcessingOptionsCountry(), $this->businessDataEvent->getDataProcessingOptionsCountry());
  }

 /**
   * Gets event for Business Data API
   * @return BusinessDataEvent
   */
  public function getBusinessDataEvent() {
    return $this->businessDataEvent;
  }

  /**
   * Gets event for Conversion API
   * @return ServerSideEvent
   */
  public function getServerSideEvent() {
    return $this->serverSideEvent;
  }

}


<?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\Object\Signal;

use FacebookAds\Api;
use FacebookAds\Object\AdsPixel;
use FacebookAds\Object\Page;
use FacebookAds\Object\BusinessDataAPI\EventRequest as BusinessDataEventRequest;
use FacebookAds\Object\ServerSide\EventRequest as ServerSideEventRequest;

/**
 * Event Request
 *
 * @category    Class
 */
class EventRequest {
  /**
   * Associative array for storing property values for Business Data API
   * @var BusinessDataEventRequest
   */
  protected $businessDataEventRequest = null;

  /**
   * Associative array for storing property values for Conversion API
   * @var ServerSideEventRequest
   */
  protected $serverSideEventRequest = null;

  /**
   * Constructor
   * @param string $pixel_id pixel id
   * @param string $page_id page id
   * @param mixed[] $data Associated array of property value initializing the model
   */
  public function __construct(string $pixel_id, string $page_id, array $data = null) {
    $business_data = $data;
    $server_data = $data;

    $business_events = array();
    $server_events = array();
    if(isset($data['events'])){
        foreach ($events as $event) {
            array_push($business_events, $event->getBusinessDataEvent());
            array_push($server_events, $event->getServerSideEvent());
        }
    }
    $business_data['events'] = $business_events;
    $server_data['events'] =  $server_data;

    $this->serverSideEventRequest = new ServerSideEventRequest($pixel_id, $server_data);
    $this->businessDataEventRequest = new BusinessDataEventRequest($page_id, $business_data);
  }

  /**
   * Sets an array of Signal Event objects
   * @param FacebookAds\Object\Signal\Event[] $events An array of Signal Event objects
   * @return $this
   */
  public function setEvents($events) {
    $business_events = array();
    $server_events = array();
    foreach ($events as $event) {
        array_push($business_events, $event->getBusinessDataEvent());
        array_push($server_events, $event->getServerSideEvent());
    }
    $this->businessDataEventRequest->setEvents($business_events);
    $this->serverSideEventRequest->setEvents($server_events);

    return $this;
  }

  /**
   * Sets code used to verify that your server events are received correctly by Facebook. Use this
   * code to test your server events in the Test Events feature in Events Manager.
   * See Test Events Tool
   * (https://developers.facebook.com/docs/marketing-api/facebook-pixel/server-side-api/using-the-api#testEvents)
   * for an example.
   * @param string $test_event_code Code used to verify that your server events are received correctly by Facebook.
   * Use this code to test your server events in the Test Events feature in Events Manager. See Test Events Tool
   * (https://developers.facebook.com/docs/marketing-api/facebook-pixel/server-side-api/using-the-api#testEvents)
   * for an example.
   * @return $this
   */
  public function setTestEventCode($test_event_code) {
    $this->serverSideEventRequest->setTestEventCode($test_event_code);
    return $this;
  }

  /**
   * Sets Partner Agent, which specifies who is sending the event.
   * @param string $partner_agent The partner agent who is sending the event
   * @return $this
   */
  public function setPartnerAgent($partner_agent) {
    $this->businessDataEventRequest->setPartnerAgent($partner_agent);
    $this->serverSideEventRequest->setPartnerAgent($partner_agent);

    return $this;
  }

   /**
   * Sets namespace_id, a scope used to resolve extern_id or Third-party ID.
   * Can be another data set or data partner ID.
   * @return $this
   */
  public function setNamespaceId($namespace_id) {
    $this->serverSideEventRequest->setNamespaceId($namespace_id);
    return $this;
  }

    /**
   * Sets upload_tag, a tag string added to track your Offline event uploads.
   * @return $this
   */
  public function setUploadTag($upload_tag) {
    $this->serverSideEventRequest->setUploadTag($upload_tag);
    return $this;
  }

  /**
   * Sets upload_id, a unique id used to denote the current set being uploaded.
   * @return $this
   */
  public function setUploadId($upload_id) {
    $this->serverSideEventRequest->setUploadId($upload_id);
    return $this;
  }

  /**
   * Sets upload_source, the origin/source of data for the dataset to be uploaded.
   * @return $this
   */
  public function setUploadSource($upload_source) {
    $this->serverSideEventRequest->setUploadSource($upload_source);
    return $this;
  }

  /**
   * Execute the request
   * @return array
   */
  public function execute() {
      return Util::constructResponse(
          $this->serverSideEventRequest->execute(),
          $this->businessDataEventRequest->execute()
        );
  }

  /**
   * Gets an array of Server Event objects
   * @return array
   */
  public function getEvents() {
    return Util::constructResponse($this->serverSideEvent->getEvents(), $this->businessDataEventRequest->getEvents());
  }

  /**
   * Gets Partner Agent, which specifies who is sending the event.
   * @return array
   */
  public function getPartnerAgent() {
    return Util::constructResponse($this->serverSideEvent->getPartnerAgent(), $this->businessDataEventRequest->getPartnerAgent());
  }

  /**
   * Gets namespace_id, a scope used to resolve extern_id or Third-party ID.
   * Can be another data set or data partner ID.
   * @return array
   */
  public function getNamespaceId() {
    return Util::constructResponse($this->serverSideEvent->getNamespaceId(), null);
  }

  /**
   * Gets upload_id, a unique id used to denote the current set being uploaded.
   * @return array
   */
  public function getUploadId() {
    return Util::constructResponse($this->serverSideEvent->getUploadId(), null);
  }

 /**
   * Gets code used to verify that your server events are received correctly by Facebook. Use this
   * code to test your server events in the Test Events feature in Events Manager.
   * See Test Events Tool
   * (https://developers.facebook.com/docs/marketing-api/facebook-pixel/server-side-api/using-the-api#testEvents)
   * for an example.
   * @return array
   */
  public function getTestEventCode() {
    return Util::constructResponse($this->serverSideEvent->getTestEventCode(), null);
  }

  /**
   * Gets upload_tag, a tag string added to track your Offline event uploads.
   * @return array
   */
  public function getUploadTag() {
    return Util::constructResponse($this->serverSideEvent->getUploadTag(), null);
  }

  /**
   * Gets upload_source, the origin/source of data for the dataset to be uploaded.
   * @return array
   */
  public function getUploadSource() {
    return Util::constructResponse($this->serverSideEvent->getUploadSource(), null);
  }

}