169 lines
6.2 KiB
PHP
169 lines
6.2 KiB
PHP
<?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 FacebookPixelPlugin\FacebookAds\Object\ServerSide;
|
|
|
|
use Exception;
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Exception\GuzzleException;
|
|
use GuzzleHttp\Exception\RequestException;
|
|
use GuzzleHttp\Promise\PromiseInterface;
|
|
use GuzzleHttp\Utils;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
|
|
/**
|
|
* Implementation of Custom Endpoint Request that sends events to CAPIG /events endpoint
|
|
*
|
|
* @category Class
|
|
*/
|
|
class CAPIGatewayEndpoint implements CustomEndpointRequest {
|
|
private Client $client;
|
|
private string $access_key;
|
|
private string $endpoint_URL;
|
|
private bool $sendToEndpointOnly;
|
|
private ?Filter $filter = null;
|
|
|
|
/**
|
|
* Constructor
|
|
* @param string $endpoint_URL endpoint_URL
|
|
* @param string $access_key access_key
|
|
* @throws Exception
|
|
*/
|
|
public function __construct(string $endpoint_URL, string $access_key) {
|
|
$this->validateEndpoint($endpoint_URL);
|
|
$this->endpoint_URL = $endpoint_URL;
|
|
$this->access_key = $access_key;
|
|
$this->client= new Client(['headers' => ['Content-Type' => 'application/json; charset=utf-8']]);
|
|
$this->sendToEndpointOnly = false;
|
|
}
|
|
|
|
/**
|
|
* Validates URL
|
|
* @param string $endpoint_URL
|
|
* @throws Exception
|
|
*/
|
|
private function validateEndpoint(string $endpoint_URL):void {
|
|
if (!filter_var($endpoint_URL, FILTER_VALIDATE_URL)) {
|
|
throw new Exception('URL is in invalid format ');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Synchronously send events to specified CAPIG /events endpoint
|
|
* @throws GuzzleException
|
|
* @throws Exception
|
|
*/
|
|
public function sendEvent(string $pixel_id, array $events): CustomEndpointResponse
|
|
{
|
|
try {
|
|
if (!is_null($this->filter)) {
|
|
$events = array_filter($events, function(Event $var){
|
|
return $this->filter->shouldSendEvent($var);
|
|
});
|
|
}
|
|
if (count($events) == 0) {
|
|
return new CustomEndpointResponse(array('message' => 'No events to send'));
|
|
}
|
|
$response = $this->client->request('POST', $this->endpoint_URL.'/capi/'.$pixel_id.'/events', ['http_errors'=> false, 'body' => $this->createRequestBody($events)]);
|
|
if ($response->getStatusCode() != '202') {
|
|
// a HTTP response code of 202 means the events were accepted
|
|
throw new Exception('Server response code is '.$response->getStatusCode().' expect: 202');
|
|
} else {
|
|
return new CustomEndpointResponse(array('message' => $response->getBody()->getContents(), 'response_code'=> $response->getStatusCode()));
|
|
}
|
|
} catch (Exception $e) {
|
|
throw new Exception('Server failed to accept events. '.$e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Asynchronously send events to specified CAPIG /events endpoint
|
|
* @throws Exception
|
|
* returns PromiseInterface
|
|
*/
|
|
public function sendEventAsync(string $pixel_id, array $events): PromiseInterface
|
|
{
|
|
if (!is_null($this->filter)) {
|
|
$events = array_filter($events, function (Event $var) {
|
|
return $this->filter->shouldSendEvent($var);
|
|
});
|
|
}
|
|
$promise = $this->client->requestAsync('POST', $this->endpoint_URL.'/capi/'.$pixel_id.'/events', ['http_errors'=> false, 'body' => $this->createRequestBody($events)]);
|
|
$promise->then(
|
|
function (ResponseInterface $response) {
|
|
if ($response->getStatusCode() != '202') {
|
|
// a HTTP response code of 202 means the events were accepted
|
|
throw new Exception('Server response code is '.$response->getStatusCode().' expect: 202');
|
|
} else {
|
|
return new CustomEndpointResponse(array('message' => $response->getBody()->getContents(), 'response_code'=> $response->getStatusCode()));
|
|
}
|
|
},
|
|
function (RequestException $e) {
|
|
throw new Exception('Server failed to accept events. '.$e->getMessage());
|
|
}
|
|
);
|
|
return $promise;
|
|
}
|
|
|
|
private function createRequestBody($events): string
|
|
{
|
|
$events = $this->normalize($events);
|
|
$body = array();
|
|
$body['data'] = $events;
|
|
$body['accessKey'] = $this->access_key;
|
|
return Utils::jsonEncode($body);
|
|
}
|
|
|
|
private function normalize(array $events): array
|
|
{
|
|
// we need to normalize the event fields before sending
|
|
$normalized_events = array();
|
|
foreach ($events as $event) {
|
|
$normalized_event = $event->normalize();
|
|
$normalized_events[] = $normalized_event;
|
|
}
|
|
return $normalized_events;
|
|
}
|
|
|
|
public function setFilter(Filter $filter)
|
|
{
|
|
$this->filter = $filter;
|
|
}
|
|
|
|
public function setSendToEndpointOnly(bool $setSendToEndpointOnly)
|
|
{
|
|
$this->sendToEndpointOnly = $setSendToEndpointOnly;
|
|
}
|
|
|
|
public function isSendToEndpointOnly(): bool
|
|
{
|
|
return $this->sendToEndpointOnly;
|
|
}
|
|
|
|
public function getEndpoint(): string
|
|
{
|
|
return $this->endpoint_URL;
|
|
}
|
|
}
|