first commit

This commit is contained in:
2024-11-05 12:22:50 +01:00
commit e5682a3912
19641 changed files with 2948548 additions and 0 deletions

View File

@@ -0,0 +1 @@
service_name: travis-ci

View File

@@ -0,0 +1,14 @@
# Drupal editor configuration normalization
# @see http://editorconfig.org/
# This is the top-most .editorconfig file; do not search in parent directories.
root = true
# All files.
[*]
end_of_line = LF
indent_style = space
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

View File

@@ -0,0 +1,5 @@
composer.phar
composer.lock
/vendor/
.idea
.DS_Store

View File

@@ -0,0 +1,14 @@
# .travis.yml
language: php
php:
- 7.4
install:
- curl -s http://getcomposer.org/installer | php
- php composer.phar update --dev --no-interaction
script:
- mkdir -p build/logs
- XDEBUG_MODE=coverage vendor/bin/phpunit -c phpunit.xml.dist
after_success:
- travis_retry php vendor/bin/php-coveralls

View File

@@ -0,0 +1,249 @@
# Google Analytics 4 Measurement Protocol PHP Library
[![Coverage Status](https://coveralls.io/repos/github/br33f/php-GA4-Measurement-Protocol/badge.svg?branch=master)](https://coveralls.io/github/br33f/php-GA4-Measurement-Protocol?branch=master)
[![Latest Stable Version](https://poser.pugx.org/br33f/php-ga4-mp/v/stable.png)](https://packagist.org/packages/br33f/php-ga4-mp)
[![Total Downloads](https://poser.pugx.org/br33f/php-ga4-mp/downloads.png)](https://packagist.org/packages/br33f/php-ga4-mp)
## Overview
This is a PHP Library facilitating the use of Google Analytics 4 (GA4) Measurement Protocol. Measurement Protocol allows developers to send events directly from server-side PHP to Google Analytics.
Full documentation is available here:
https://developers.google.com/analytics/devguides/collection/protocol/ga4
## Requirements
- PHP >= 7.1
- ext-json
- guzzlehttp/guzzle: ^6.5.5 || ^7.0.0
dev:
- phpunit/phpunit: "^9.5"
- fakerphp/faker: "^1.14"
## Installation
The recommended way to install this library is via [Composer](https://getcomposer.org/ "Composer") (packagist package: [br33f/php-ga4-mp](https://packagist.org/packages/br33f/php-ga4-mp "br33f/php-ga4-mp")).
Install by composer command:
```
composer require br33f/php-ga4-mp
```
or `package.json`
```
{
"require": {
"br33f/php-ga4-mp": "^0.1.0"
}
}
```
## Usage
### Send View Item Event
```php
use Br33f\Ga4\MeasurementProtocol\Service;
use Br33f\Ga4\MeasurementProtocol\Dto\Request\BaseRequest;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\ViewItemEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemParameter;
// Create service instance
$ga4Service = new Service('MEASUREMENT_PROTOCOL_API_SECRET');
$ga4Service->setMeasurementId('MEASUREMENT_ID');
// Create base request
$baseRequest = new BaseRequest();
$baseRequest->setClientId('CLIENT_ID');
// Create Event Data
$viewItemEventData = new ViewItemEvent();
$viewItemEventData
->setValue(51.10)
->setCurrency('EUR');
// Create Item
$viewedItem = new ItemParameter();
$viewedItem
->setItemId('ITEM_ID')
->setItemName('ITEM_NAME')
->setPrice(25.55)
->setQuantity(2);
// Add this item to viewItemEventData
$viewItemEventData->addItem($viewedItem);
// Add event to base request (you can add up to 25 events to single request)
$baseRequest->addEvent($viewItemEventData);
// We have all the data we need. Just send the request.
$ga4Service->send($baseRequest);
```
### Send Purchase Event
```php
use Br33f\Ga4\MeasurementProtocol\Service;
use Br33f\Ga4\MeasurementProtocol\Dto\Request\BaseRequest;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\PurchaseEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemParameter;
// Create service instance
$ga4Service = new Service('MEASUREMENT_PROTOCOL_API_SECRET');
$ga4Service->setMeasurementId('MEASUREMENT_ID');
// Create base request
$baseRequest = new BaseRequest();
$baseRequest->setClientId('CLIENT_ID');
// Create Event Data
$purchaseEventData = new PurchaseEvent();
$purchaseEventData
->setValue(250.00)
->setCurrency('USD');
// Create Item
$purchasedItem1 = new ItemParameter();
$purchasedItem1
->setItemId('FIRST_ITEM_ID')
->setItemName('FIRST_ITEM_NAME')
->setPrice(100.00)
->setQuantity(2);
// Add this item to purchaseEventData
$purchaseEventData->addItem($purchasedItem1);
// You can also fill item data via constructor
$purchaseEventData->addItem(new ItemParameter([
'item_id' => 'SECOND_ITEM_ID',
'item_name' => 'SECOND_ITEM_NAME',
'price' => 50.00,
'quantity' => 1
]));
// Add event to base request (you can add up to 25 events to single request)
$baseRequest->addEvent($purchaseEventData);
// We have all the data we need. Just send the request.
$ga4Service->send($baseRequest);
```
At the moment, the library contains the defined structures of the following events:
| Event name | Structure | Documentation |
| ---------- | --------- | --------------|
| add_payment_info | AddPaymentInfoEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#add_payment_info)
| add_shipping_info | AddShippingInfoEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#add_shipping_info)
| add_to_cart | AddToCartEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#add_to_cart)
| begin_checkout | BeginCheckoutEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#begin_checkout)
| login | LoginEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#login)
| purchase | PurchaseEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#purchase)
| refund | RefundEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#refund)
| remove_from_cart | RemoveFromCartEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#remove_from_cart)
| search | SearchEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#search)
| select_item | SelectItemEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#select_item)
| sign_up | SignUpEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#sign_up)
| view_cart | ViewCartEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#view_cart)
| view_item | ViewItemEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#view_item)
| view_search_results | ViewSearchResultsEvent | [see documentation](https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#view_search_results)
These events are sent analogously to the examples presented above.
### Other events
In order to send any event one can use `BaseEvent` structure and add any data. Please note that specific event structure should be used instead if already defined, since BaseEvent does not force any structure or provide data validation.
```php
use Br33f\Ga4\MeasurementProtocol\Service;
use Br33f\Ga4\MeasurementProtocol\Dto\Request\BaseRequest;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\BaseEvent;
// Create Service and request same as above
// ...
// Create Base Event Data (for example: 'share' event - https://developers.google.com/analytics/devguides/collection/protocol/ga4/reference/events#share)
$eventName = 'share';
$anyEventData = new BaseEvent($eventName);
$anyEventData
->setMethod('Twitter')
->setContentType('Post')
->setItemId('example_item_id')
->setAnyParamYouWish('test'); // means 'any_param_you_wish' is set
// Add event to base request (you can add up to 25 events to single request) and send, same as above
// ...
```
### Firebase Support
It is possible to use this library to send Firebase events. To do so, just initialize Service and BaseRequest as in following example:
```php
use Br33f\Ga4\MeasurementProtocol\Service;
use Br33f\Ga4\MeasurementProtocol\Dto\Request\BaseRequest;
// Create service instance
$ga4Service = new Service('MEASUREMENT_PROTOCOL_API_SECRET');
$ga4Service->setFirebaseId('FIREBASE_APP_ID'); // instead of setMeasurementId(...)
// Create base request
$baseRequest = new BaseRequest();
$baseRequest->setAppInstanceId('APP_INSTANCE_ID'); // instead of setClientId(...)
```
## Debug event data and requests
Debuging event data is possible by sending them to debug endpoint (Measurement Protocol Validation Server), since default endpoint for Google Analytics 4 Measurement Protocol does not return any HTTP error codes or messages. In order to validate event one should use `sendDebug($request)` method instead of `send($request)`.
Method `sendDebug($request)` returns `DebugResponse` object, which is hydrated with response data such as: `status_code` and `validation_messages`.
### Example:
```php
use Br33f\Ga4\MeasurementProtocol\Service;
use Br33f\Ga4\MeasurementProtocol\Dto\Request\BaseRequest;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\AddToCartEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemParameter;
// Create service instance
$ga4Service = new Service('MEASUREMENT_PROTOCOL_API_SECRET');
$ga4Service->setMeasurementId('MEASUREMENT_ID');
// Create base request
$baseRequest = new BaseRequest();
$baseRequest->setClientId('CLIENT_ID');
// Create Invalid Event Data
$addToCartEventData = new AddToCartEvent();
$addToCartEventData
->setValue(99.99)
->setCurrency('SOME_INVALID_CURRENCY_CODE'); // invalid currency code
// addItem
$addToCartEventData->addItem(new ItemParameter([
'item_id' => 'ITEM_ID',
'item_name' => 'ITEM_NAME',
'price' => 99.99,
'quantity' => 1
]));
// Add event to base request (you can add up to 25 events to single request)
$baseRequest->addEvent($addToCartEventData);
// Instead of sending data to production Measurement Protocol endpoint
// $ga4Service->send($baseRequest);
// Send data to validation endpoint, which responds with status cude and validation messages.
$debugResponse = $ga4Service->sendDebug($baseRequest);
// Now debug response contains status code, and validation messages if request is invalid
var_dump($debugResponse->getStatusCode());
var_dump($debugResponse->getValidationMessages());
```
## Unit Testing
Unit Testing for this module is done using PHPUnit 9.
Running unit tests:
```
composer install
php vendor/bin/phpunit
```
## License
This library is released under the MIT License.

View File

@@ -0,0 +1,32 @@
{
"name": "br33f/php-ga4-mp",
"description": "PHP GoogleAnalytics4 Measurement Protocol Library",
"minimum-stability": "stable",
"license": "MIT",
"authors": [
{
"name": "Damian Zamojski",
"email": "damian.zamojski1@gmail.com"
}
],
"require": {
"php": ">=7.1",
"guzzlehttp/guzzle": "^6.5.5 || ^7.0.0",
"ext-json": "*"
},
"autoload": {
"psr-4": {
"Br33f\\Ga4\\MeasurementProtocol\\": "src/"
}
},
"require-dev": {
"phpunit/phpunit": "^9.5",
"fakerphp/faker": "^1.14",
"php-coveralls/php-coveralls": "^2.4"
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
}
}

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheResultFile=".phpunit.cache/test-results"
executionOrder="depends,defects"
forceCoversAnnotation="false"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
failOnWarning="false"
verbose="true">
<testsuites>
<testsuite name="default">
<directory>tests</directory>
</testsuite>
</testsuites>
<coverage cacheDirectory=".phpunit.cache/code-coverage"
processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
<report>
<clover outputFile="build/logs/clover.xml"></clover>
</report>
</coverage>
</phpunit>

View File

@@ -0,0 +1,78 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 13:51
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Common;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\AbstractEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\ExportableInterface;
use Br33f\Ga4\MeasurementProtocol\Dto\ValidateInterface;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use InvalidArgumentException;
class EventCollection implements ExportableInterface, ValidateInterface
{
/**
* @var AbstractEvent[]
*/
protected $eventList = [];
/**
* @param AbstractEvent $event
*/
public function addEvent(AbstractEvent $event)
{
if (count($this->eventList) >= 25) {
throw new InvalidArgumentException('Event list must not exceed 25 items', ErrorCode::MAX_EVENT_COUNT_EXCEED);
}
$this->eventList[] = $event;
}
/**
* @return array
*/
public function export(): array
{
return array_map(function ($userProperty) {
return $userProperty->export();
}, $this->getEventList());
}
/**
* @return array
*/
public function getEventList(): array
{
return $this->eventList;
}
/**
* @param array $eventList
*/
public function setEventList(array $eventList)
{
if (count($eventList) > 25) {
throw new InvalidArgumentException('Event list must not exceed 25 items', ErrorCode::MAX_EVENT_COUNT_EXCEED);
}
$this->eventList = $eventList;
}
/**
* @throws ValidationException
*/
public function validate()
{
if (count($this->getEventList()) === 0) {
throw new ValidationException('Event list must not be empty', ErrorCode::VALIDATION_EVENTS_MUST_NOT_BE_EMPTY, 'events');
}
return true;
}
}

View File

@@ -0,0 +1,62 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 12:23
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Common;
use Br33f\Ga4\MeasurementProtocol\Dto\ExportableInterface;
class UserProperties implements ExportableInterface
{
/**
* @var UserProperty[]
*/
protected $userPropertiesList;
/**
* UserProperties constructor.
* @param UserProperty[] $userPropertiesList
*/
public function __construct(array $userPropertiesList = null)
{
$this->userPropertiesList = $userPropertiesList ?? [];
}
/**
* @param UserProperty $userProperty
*/
public function addUserProperty(UserProperty $userProperty)
{
$this->userPropertiesList[] = $userProperty;
}
/**
* @return array
*/
public function export(): array
{
return array_reduce($this->getUserPropertiesList(), function ($last, UserProperty $userProperty) {
return array_merge($last, $userProperty->export());
}, []);
}
/**
* @return UserProperty[]
*/
public function getUserPropertiesList(): array
{
return $this->userPropertiesList;
}
/**
* @param UserProperty[] $userPropertiesList
*/
public function setUserPropertiesList(array $userPropertiesList)
{
$this->userPropertiesList = $userPropertiesList;
}
}

View File

@@ -0,0 +1,78 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 12:23
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Common;
use Br33f\Ga4\MeasurementProtocol\Dto\ExportableInterface;
class UserProperty implements ExportableInterface
{
/**
* User property name
* @var string
*/
protected $name;
/**
* User property value
* @var mixed
*/
protected $value;
/**
* UserProperty constructor.
* @param string|null $name
* @param mixed $value
*/
public function __construct(?string $name = null, $value = null)
{
$this->name = $name;
$this->value = $value;
}
public function export(): array
{
return [
$this->getName() => [
'value' => $this->getValue()
]
];
}
/**
* @return string|null
*/
public function getName(): ?string
{
return $this->name;
}
/**
* @param string|null $name
*/
public function setName(?string $name)
{
$this->name = $name;
}
/**
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* @param mixed $value
*/
public function setValue($value)
{
$this->value = $value;
}
}

View File

@@ -0,0 +1,102 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 12:23
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Common;
use Br33f\Ga4\MeasurementProtocol\Dto\HydratableInterface;
use Br33f\Ga4\MeasurementProtocol\Enum\ValidationCode;
use Psr\Http7\Message\ResponseInterface;
class ValidationMessage implements HydratableInterface
{
/**
* The path to the field that was invalid
* @var string|null
*/
protected $fieldPath;
/**
* A description of the error
* @var string|null
*/
protected $description;
/**
* A ValidationCode that corresponds to the error
* @var string|null
* @see ValidationCode
*/
protected $validationCode;
/**
* ValidationMessage constructor.
* @param array|null $blueprint
*/
public function __construct(?array $blueprint = null)
{
if ($blueprint !== null) {
$this->hydrate($blueprint);
}
}
/**
* @param array|ResponseInterface $blueprint
*/
public function hydrate($blueprint)
{
$this->setFieldPath(array_key_exists('fieldPath', $blueprint) ? $blueprint['fieldPath'] : null);
$this->setDescription(array_key_exists('description', $blueprint) ? $blueprint['description'] : null);
$this->setValidationCode(array_key_exists('validationCode', $blueprint) ? $blueprint['validationCode'] : null);
}
/**
* @return string|null
*/
public function getFieldPath(): ?string
{
return $this->fieldPath;
}
/**
* @param string|null $fieldPath
*/
public function setFieldPath(?string $fieldPath)
{
$this->fieldPath = $fieldPath;
}
/**
* @return string|null
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* @param string|null $description
*/
public function setDescription(?string $description)
{
$this->description = $description;
}
/**
* @return string|null
*/
public function getValidationCode(): ?string
{
return $this->validationCode;
}
/**
* @param string|null $validationCode
*/
public function setValidationCode(?string $validationCode)
{
$this->validationCode = $validationCode;
}
}

View File

@@ -0,0 +1,195 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 14:16
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use BadMethodCallException;
use Br33f\Ga4\MeasurementProtocol\Dto\ExportableInterface;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\BaseParameter;
use Br33f\Ga4\MeasurementProtocol\Dto\ValidateInterface;
use InvalidArgumentException;
abstract class AbstractEvent implements ExportableInterface, ValidateInterface
{
/**
* @var string
*/
protected $name;
/**
* @var AbstractParameter[]
*/
protected $paramList;
/**
* AbstractEvent constructor.
* @param string|null $name
* @param AbstractParameter[] $paramList
*/
public function __construct(?string $name = null, array $paramList = [])
{
$this->name = $name;
$this->paramList = $paramList ?? [];
}
/**
* @param string $methodName
* @param array $methodArguments
* @return mixed|null
*/
public function __call(string $methodName, array $methodArguments)
{
$methodPrefix = substr($methodName, 0, 3);
$paramName = $this->convertCamelCaseToSnakeCase(substr($methodName, 3));
if ($methodPrefix === "set") {
if (!isset($methodArguments[0])) {
throw new InvalidArgumentException('First argument is expected to be paramter value, none specified.');
}
return $this->setParamValue($paramName, $methodArguments[0]);
}
if ($methodPrefix === "get") {
return $this->getParamValue($paramName);
}
throw new BadMethodCallException('Method ' . $methodName . ' is not defined.');
}
/**
* @param string $input
* @return string
*/
protected function convertCamelCaseToSnakeCase(string $input)
{
preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $input, $matches);
$ret = $matches[0];
foreach ($ret as &$match) {
$match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match);
}
return implode('_', $ret);
}
/**
* @param string $paramName
* @param mixed $paramValue
* @return AbstractEvent
*/
public function setParamValue(string $paramName, $paramValue)
{
$this->findOrCreateParameter($paramName)->setValue($paramValue);
return $this;
}
/**
* @param string $paramName
* @return AbstractParameter
*/
public function findOrCreateParameter(string $paramName)
{
$foundParameter = $this->findParameter($paramName);
if ($foundParameter === null) {
$foundParameter = new BaseParameter();
$this->addParam($paramName, $foundParameter);
}
return $foundParameter;
}
/**
* @param string $paramName
* @return AbstractParameter|null
*/
public function findParameter(string $paramName)
{
if (array_key_exists($paramName, $this->getParamList())) {
return $this->getParamList()[$paramName];
} else {
return null;
}
}
/**
* @return AbstractParameter[]
*/
public function getParamList(): array
{
return $this->paramList;
}
/**
* @param AbstractParameter[] $paramList
*/
public function setParamList(array $paramList)
{
$this->paramList = $paramList;
}
/**
* @param string $parameterName
* @param AbstractParameter $parameter
*/
public function addParam(string $parameterName, AbstractParameter $parameter)
{
$this->paramList[$parameterName] = $parameter;
}
/**
* @param string $paramName
* @return mixed|null
*/
public function getParamValue(string $paramName)
{
return $this->findOrCreateParameter($paramName)->getValue();
}
/**
* @param string $paramName
*/
public function deleteParameter(string $paramName)
{
if (array_key_exists($paramName, $this->getParamList())) {
unset($this->paramList[$paramName]);
}
}
public function export(): array
{
$preparedParams = [];
foreach ($this->getParamList() as $parameterName => $parameter) {
$parameterExportedValue = $parameter->export();
if (!is_null($parameterExportedValue)) {
$preparedParams[$parameterName] = $parameterExportedValue;
}
}
return [
'name' => $this->getName(),
// Note that we need to return an \ArrayObject here. As otherwise json_encode will serialize params to `[]`. And
// Google Analytics will error on this, as it expects a map. Whereas new \ArrayObject will export correctly to `{}`.
// See https://github.com/br33f/php-GA4-Measurement-Protocol/issues/10.
'params' => new \ArrayObject($preparedParams),
];
}
/**
* @return string|null
*/
public function getName(): ?string
{
return $this->name;
}
/**
* @param string|null $name
*/
protected function setName(?string $name)
{
$this->name = $name;
}
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:33
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class AddPaymentInfoEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getCurrency()
* @method AddPaymentInfoEvent setCurrency(string $currency)
* @method float getValue()
* @method AddPaymentInfoEvent setValue(float $value)
* @method string getCoupon()
* @method AddPaymentInfoEvent setCoupon(string $coupon)
* @method string getPaymentType()
* @method AddPaymentInfoEvent setPaymentType(string $paymentType)
*/
class AddPaymentInfoEvent extends ItemBaseEvent
{
private $eventName = 'add_payment_info';
/**
* AddPaymentInfoEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
public function validate()
{
parent::validate();
if (!empty($this->getValue())) {
if (empty($this->getCurrency())) {
throw new ValidationException('Field "currency" is required if "value" is set', ErrorCode::VALIDATION_FIELD_REQUIRED, 'currency');
}
}
return true;
}
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:33
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class AddShippingInfoEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getCurrency()
* @method AddShippingInfoEvent setCurrency(string $currency)
* @method float getValue()
* @method AddShippingInfoEvent setValue(float $value)
* @method string getCoupon()
* @method AddShippingInfoEvent setCoupon(string $coupon)
* @method string getShippingTier()
* @method AddShippingInfoEvent setShippingTier(string $shippingTier)
*/
class AddShippingInfoEvent extends ItemBaseEvent
{
private $eventName = 'add_shipping_info';
/**
* AddShippingInfoEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
public function validate()
{
parent::validate();
if (!empty($this->getValue())) {
if (empty($this->getCurrency())) {
throw new ValidationException('Field "currency" is required if "value" is set', ErrorCode::VALIDATION_FIELD_REQUIRED, 'currency');
}
}
return true;
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:33
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class AddToCartEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getCurrency()
* @method AddToCartEvent setCurrency(string $currency)
* @method float getValue()
* @method AddToCartEvent setValue(float $value)
*/
class AddToCartEvent extends ItemBaseEvent
{
private $eventName = 'add_to_cart';
/**
* AddToCartEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
public function validate()
{
parent::validate();
if (!empty($this->getValue())) {
if (empty($this->getCurrency())) {
throw new ValidationException('Field "currency" is required if "value" is set', ErrorCode::VALIDATION_FIELD_REQUIRED, 'currency');
}
}
return true;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 13:52
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
class BaseEvent extends AbstractEvent
{
/**
* @param string|null $name
*/
public function setName(?string $name)
{
parent::setName($name);
}
/**
* @return bool
* @throws ValidationException
*/
public function validate()
{
foreach ($this->getParamList() as $parameter) {
$parameter->validate();
}
return true;
}
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:33
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class AddToCartEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getCurrency()
* @method BeginCheckoutEvent setCurrency(string $currency)
* @method float getValue()
* @method BeginCheckoutEvent setValue(float $value)
* @method string getCoupon()
* @method BeginCheckoutEvent setCoupon(string $coupon)
*/
class BeginCheckoutEvent extends ItemBaseEvent
{
private $eventName = 'begin_checkout';
/**
* BeginCheckoutEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
public function validate()
{
parent::validate();
if (!empty($this->getValue())) {
if (empty($this->getCurrency())) {
throw new ValidationException('Field "currency" is required if "value" is set', ErrorCode::VALIDATION_FIELD_REQUIRED, 'currency');
}
}
return true;
}
}

View File

@@ -0,0 +1,67 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:25
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemCollectionParameter;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemParameter;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class ItemBaseEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
*/
abstract class ItemBaseEvent extends AbstractEvent
{
/**
* @param ItemParameter $item
* @return self
*/
public function addItem(ItemParameter $item)
{
$this->getItems()->addItem($item);
return $this;
}
/**
* @return ItemCollectionParameter
*/
public function getItems()
{
$items = $this->findParameter('items');
if ($items === null) {
$items = new ItemCollectionParameter();
$this->setItems($items);
}
return $items;
}
/**
* @param ItemCollectionParameter|null $items
* @return self
*/
public function setItems(?ItemCollectionParameter $items)
{
$this->deleteParameter('items');
$this->addParam('items', $items);
return $this;
}
/**
* @return bool
* @throws ValidationException
*/
public function validate()
{
$this->getItems()->validate();
return true;
}
}

View File

@@ -0,0 +1,38 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:52
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
/**
* Class LoginEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getMethod()
* @method LoginEvent setMethod(string $method)
*/
class LoginEvent extends AbstractEvent
{
private $eventName = 'login';
/**
* LoginEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
/**
* @return bool
*/
public function validate()
{
return true;
}
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:33
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class PurchaseEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getCurrency()
* @method PurchaseEvent setCurrency(string $currency)
* @method string getTransactionId()
* @method PurchaseEvent setTransactionId(string $transactionId)
* @method float getValue()
* @method PurchaseEvent setValue(float $value)
* @method string getAffiliation()
* @method PurchaseEvent setAffiliation(string $affiliation)
* @method string getCoupon()
* @method PurchaseEvent setCoupon(string $coupon)
* @method float getShipping()
* @method PurchaseEvent setShipping(float $shipping)
* @method float getTax()
* @method PurchaseEvent setTax(float $tax)
*/
class PurchaseEvent extends ItemBaseEvent
{
private $eventName = 'purchase';
/**
* PurchaseEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
public function validate()
{
parent::validate();
if (empty($this->getTransactionId())) {
throw new ValidationException('Field "transaction_id" is required if "value" is set', ErrorCode::VALIDATION_FIELD_REQUIRED, 'curtransaction_idrency');
}
if (!empty($this->getValue())) {
if (empty($this->getCurrency())) {
throw new ValidationException('Field "currency" is required if "value" is set', ErrorCode::VALIDATION_FIELD_REQUIRED, 'currency');
}
}
return true;
}
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:33
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class RefundEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getCurrency()
* @method RefundEvent setCurrency(string $currency)
* @method string getTransactionId()
* @method RefundEvent setTransactionId(string $transactionId)
* @method float getValue()
* @method RefundEvent setValue(float $value)
* @method string getAffiliation()
* @method RefundEvent setAffiliation(string $affiliation)
* @method string getCoupon()
* @method RefundEvent setCoupon(string $coupon)
* @method float getShipping()
* @method RefundEvent setShipping(float $shipping)
* @method float getTax()
* @method RefundEvent setTax(float $tax)
*/
class RefundEvent extends ItemBaseEvent
{
private $eventName = 'refund';
/**
* RefundEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
public function validate()
{
parent::validate();
if (empty($this->getTransactionId())) {
throw new ValidationException('Field "transaction_id" is required if "value" is set', ErrorCode::VALIDATION_FIELD_REQUIRED, 'curtransaction_idrency');
}
if (!empty($this->getValue())) {
if (empty($this->getCurrency())) {
throw new ValidationException('Field "currency" is required if "value" is set', ErrorCode::VALIDATION_FIELD_REQUIRED, 'currency');
}
}
return true;
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:33
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class RemoveFromCartEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getCurrency()
* @method RemoveFromCartEvent setCurrency(string $currency)
* @method float getValue()
* @method RemoveFromCartEvent setValue(float $value)
*/
class RemoveFromCartEvent extends ItemBaseEvent
{
private $eventName = 'remove_from_cart';
/**
* AddToCartEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
public function validate()
{
parent::validate();
if (!empty($this->getValue())) {
if (empty($this->getCurrency())) {
throw new ValidationException('Field "currency" is required if "value" is set', ErrorCode::VALIDATION_FIELD_REQUIRED, 'currency');
}
}
return true;
}
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:52
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class SearchEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getSearchTerm()
* @method SearchEvent setSearchTerm(string $searchTerm)
*/
class SearchEvent extends AbstractEvent
{
private $eventName = 'search';
/**
* SearchEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
/**
* @return bool
* @throws ValidationException
*/
public function validate()
{
if (empty($this->getSearchTerm())) {
throw new ValidationException('Field "search_term" is required if "value" is set', ErrorCode::VALIDATION_FIELD_REQUIRED, 'search_term');
}
return true;
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:33
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
/**
* Class SelectItemEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getItemListId()
* @method SelectItemEvent setItemListId(string $itemListId)
* @method string getItemListName()
* @method SelectItemEvent setItemListName(string $itemListName)
*/
class SelectItemEvent extends ItemBaseEvent
{
private $eventName = 'select_item';
/**
* SelectItemEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
}

View File

@@ -0,0 +1,38 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:52
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
/**
* Class SignUpEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getMethod()
* @method SignUpEvent setMethod(string $method)
*/
class SignUpEvent extends AbstractEvent
{
private $eventName = 'sign_up';
/**
* SignUpEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
/**
* @return bool
*/
public function validate()
{
return true;
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:33
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class ViewCartEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getCurrency()
* @method ViewCartEvent setCurrency(string $currency)
* @method float getValue()
* @method ViewCartEvent setValue(float $value)
*/
class ViewCartEvent extends ItemBaseEvent
{
private $eventName = 'view_cart';
/**
* ViewCartEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
public function validate()
{
parent::validate();
if (!empty($this->getValue())) {
if (empty($this->getCurrency())) {
throw new ValidationException('Field "currency" is required if "value" is set', ErrorCode::VALIDATION_FIELD_REQUIRED, 'currency');
}
}
return true;
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 24.06.2021
* Time: 15:22
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
/**
* Class ViewItemEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getCurrency()
* @method ViewItemEvent setCurrency(string $currency)
* @method string getValue()
* @method ViewItemEvent setValue(string $value)
*/
class ViewItemEvent extends ItemBaseEvent
{
private $eventName = 'view_item';
/**
* ViewItemEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:33
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
/**
* Class ViewItemListEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getItemListId()
* @method ViewItemListEvent setItemListId(string $itemListId)
* @method string getItemListName()
* @method ViewItemListEvent setItemListName(string $itemListName)
*/
class ViewItemListEvent extends ItemBaseEvent
{
private $eventName = 'view_item_list';
/**
* ViewItemListEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:33
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\AbstractParameter;
/**
* Class ViewSearchResultsEvent
* @package Br33f\Ga4\MeasurementProtocol\Dto\Event
* @method string getSearchTerm()
* @method ViewSearchResultsEvent setSearchTerm(string $itemListId)
*/
class ViewSearchResultsEvent extends ItemBaseEvent
{
private $eventName = 'view_search_results';
/**
* ViewSearchResultsEvent constructor.
* @param AbstractParameter[] $paramList
*/
public function __construct(array $paramList = [])
{
parent::__construct($this->eventName, $paramList);
}
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 11:10
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto;
interface ExportableInterface
{
/**
* Method returns prepared data
* @return mixed
*/
public function export();
}

View File

@@ -0,0 +1,21 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 13:42
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto;
use Br33f\Ga4\MeasurementProtocol\Exception\HydrationException;
use Psr\Http7\Message\ResponseInterface;
interface HydratableInterface
{
/**
* Method hydrates DTO with data from blueprint
* @param ResponseInterface|array $blueprint
* @throws HydrationException
*/
public function hydrate($blueprint);
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 13:56
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Parameter;
use Br33f\Ga4\MeasurementProtocol\Dto\ExportableInterface;
use Br33f\Ga4\MeasurementProtocol\Dto\ValidateInterface;
abstract class AbstractParameter implements ExportableInterface, ValidateInterface
{
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 13:56
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Parameter;
use Br33f\Ga4\MeasurementProtocol\Dto\ExportableInterface;
class BaseParameter extends AbstractParameter
{
/**
* @var mixed
*/
protected $value;
/**
* BaseParameter constructor.
* @param mixed|null $value
*/
public function __construct($value = null)
{
$this->value = $value;
}
/**
* @return mixed
*/
public function export()
{
if ($this->getValue() instanceof ExportableInterface) {
return $this->getValue()->export();
} else {
return $this->getValue();
}
}
/**
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* @param mixed $value
*/
public function setValue($value)
{
$this->value = $value;
}
/**
* @return bool
*/
public function validate()
{
return true;
}
}

View File

@@ -0,0 +1,86 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 24.06.2021
* Time: 15:40
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Parameter;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class ItemCollectionParameter
* @package Br33f\Ga4\MeasurementProtocol\Dto\Parameter
*/
class ItemCollectionParameter extends AbstractParameter
{
/**
* @var ItemParameter[]
*/
protected $itemList;
/**
* ItemCollectionParameter constructor.
* @param ItemParameter[]|null $itemList
*/
public function __construct(?array $itemList = [])
{
$this->itemList = $itemList;
}
/**
* @param ItemParameter $item
* @return ItemCollectionParameter
*/
public function addItem(ItemParameter $item)
{
$this->itemList[] = $item;
return $this;
}
/**
* @return bool
* @throws ValidationException
*/
public function validate()
{
foreach ($this->getItemList() as $item) {
$item->validate();
}
return true;
}
/**
* @return ItemParameter[]
*/
public function getItemList(): array
{
return $this->itemList;
}
/**
* @param ItemParameter[] $itemList
* @return ItemCollectionParameter
*/
public function setItemList(array $itemList)
{
$this->itemList = $itemList;
return $this;
}
/**
* @return array
*/
public function export()
{
$exportableObject = [];
foreach ($this->getItemList() as $item) {
$exportableObject[] = $item->export();
}
return $exportableObject;
}
}

View File

@@ -0,0 +1,626 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 24.06.2021
* Time: 15:40
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Parameter;
use Br33f\Ga4\MeasurementProtocol\Dto\HydratableInterface;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
/**
* Class ItemParameter
* @package Br33f\Ga4\MeasurementProtocol\Dto\Parameter
*/
class ItemParameter extends AbstractParameter implements HydratableInterface
{
/**
* The ID of the item
* One of itemId or itemName is required.
* @var string|null
*/
protected $itemId;
/**
* The name of the item
* One of itemId or itemName is required.
* @var string|null
*/
protected $itemName;
/**
* A product affiliation to designate a supplying company or brick and mortar store location
* Not required
* @var string|null
*/
protected $affiliation;
/**
* The coupon name/code associated with the item
* Not required
* @var string|null
*/
protected $coupon;
/**
* The currency in 3-lettery ISO 4217 format
* Not required
* @var string|null
*/
protected $currency;
/**
* The monetary discount value associated with the item
* Not required
* @var float|null
*/
protected $discount;
/**
* The index/position of the item in a list
* Not required
* @var float|null
*/
protected $index;
/**
* The brand of the item
* Not required
* @var string|null
*/
protected $itemBrand;
/**
* The category of the item.
* If used as part of a category hierarchy or taxonomy then this will be the first category.
* Not required
* @var string|null
*/
protected $itemCategory;
/**
* The second category of the item.
* If used as part of a category hierarchy or taxonomy then this will be the first category.
* Not required
* @var string|null
*/
protected $itemCategory2;
/**
* The third category of the item.
* If used as part of a category hierarchy or taxonomy then this will be the first category.
* Not required
* @var string|null
*/
protected $itemCategory3;
/**
* The fourth category of the item.
* If used as part of a category hierarchy or taxonomy then this will be the first category.
* Not required
* @var string|null
*/
protected $itemCategory4;
/**
* The fifth category of the item.
* If used as part of a category hierarchy or taxonomy then this will be the first category.
* Not required
* @var string|null
*/
protected $itemCategory5;
/**
* The ID of the list in which the item was presented to the user
* Not required
* @var string|null
*/
protected $itemListId;
/**
* The name of the list in which the item was presented to the user
* Not required
* @var string|null
*/
protected $itemListName;
/**
* The item variant or unique code or description for additional item details/options.
* Not required
* @var string|null
*/
protected $itemVariant;
/**
* The location associated with the item. It's recommended to use the Google Place ID that corresponds to the associated item. A custom location ID can also be used
* Not required
* @var string|null
*/
protected $locationId;
/**
* The monetary price of the item, in units of the specified currency parameter
* Not required
* @var float|null
*/
protected $price;
/**
* Item quantity
* Not required
* @var float|null
*/
protected $quantity;
/**
* ItemParameter constructor.
* @param array|null $blueprint
*/
public function __construct(?array $blueprint = null)
{
if ($blueprint !== null) {
$this->hydrate($blueprint);
}
}
/**
* @param array $blueprint
*/
public function hydrate($blueprint)
{
if (array_key_exists('item_id', $blueprint)) {
$this->setItemId($blueprint['item_id']);
}
if (array_key_exists('item_name', $blueprint)) {
$this->setItemName($blueprint['item_name']);
}
if (array_key_exists('affiliation', $blueprint)) {
$this->setAffiliation($blueprint['affiliation']);
}
if (array_key_exists('coupon', $blueprint)) {
$this->setCoupon($blueprint['coupon']);
}
if (array_key_exists('currency', $blueprint)) {
$this->setCurrency($blueprint['currency']);
}
if (array_key_exists('discount', $blueprint)) {
$this->setDiscount($blueprint['discount']);
}
if (array_key_exists('index', $blueprint)) {
$this->setIndex($blueprint['index']);
}
if (array_key_exists('item_brand', $blueprint)) {
$this->setItemBrand($blueprint['item_brand']);
}
if (array_key_exists('item_category', $blueprint)) {
$this->setItemCategory($blueprint['item_category']);
}
if (array_key_exists('item_category2', $blueprint)) {
$this->setItemCategory2($blueprint['item_category2']);
}
if (array_key_exists('item_category3', $blueprint)) {
$this->setItemCategory3($blueprint['item_category3']);
}
if (array_key_exists('item_category4', $blueprint)) {
$this->setItemCategory4($blueprint['item_category4']);
}
if (array_key_exists('item_category5', $blueprint)) {
$this->setItemCategory5($blueprint['item_category5']);
}
if (array_key_exists('item_list_id', $blueprint)) {
$this->setItemListId($blueprint['item_list_id']);
}
if (array_key_exists('item_list_name', $blueprint)) {
$this->setItemListName($blueprint['item_list_name']);
}
if (array_key_exists('item_variant', $blueprint)) {
$this->setItemVariant($blueprint['item_variant']);
}
if (array_key_exists('location_id', $blueprint)) {
$this->setLocationId($blueprint['location_id']);
}
if (array_key_exists('price', $blueprint)) {
$this->setPrice($blueprint['price']);
}
if (array_key_exists('quantity', $blueprint)) {
$this->setQuantity($blueprint['quantity']);
}
}
/**
* @return bool
* @throws ValidationException
*/
public function validate()
{
if (empty($this->getItemId()) && empty($this->getItemName())) {
throw new ValidationException("At least one of item_id or item_name is required", ErrorCode::VALIDATION_ITEM_AT_LEAST_ITEM_ID_OR_ITEM_NAME_REQUIRED, 'item_id|item_name');
}
return true;
}
/**
* @return string|null
*/
public function getItemId(): ?string
{
return $this->itemId;
}
/**
* @param string|null $itemId
* @return ItemParameter
*/
public function setItemId(?string $itemId): ItemParameter
{
$this->itemId = $itemId;
return $this;
}
/**
* @return string|null
*/
public function getItemName(): ?string
{
return $this->itemName;
}
/**
* @param string|null $itemName
* @return ItemParameter
*/
public function setItemName(?string $itemName): ItemParameter
{
$this->itemName = $itemName;
return $this;
}
/**
* @return array
*/
public function export()
{
$exportableObject = [
'item_id' => $this->getItemId(),
'item_name' => $this->getItemName(),
'affiliation' => $this->getAffiliation(),
'coupon' => $this->getCoupon(),
'currency' => $this->getCurrency(),
'discount' => $this->getDiscount(),
'index' => $this->getIndex(),
'item_brand' => $this->getItemBrand(),
'item_category' => $this->getItemCategory(),
'item_category2' => $this->getItemCategory2(),
'item_category3' => $this->getItemCategory3(),
'item_category4' => $this->getItemCategory4(),
'item_category5' => $this->getItemCategory5(),
'item_list_id' => $this->getItemListId(),
'item_list_name' => $this->getItemListName(),
'item_variant' => $this->getItemVariant(),
'location_id' => $this->getLocationId(),
'price' => $this->getPrice(),
'quantity' => $this->getQuantity()
];
$preparedExportableObject = [];
foreach ($exportableObject as $exportableItemName => $exportableItemValue) {
if (!is_null($exportableItemValue)) {
$preparedExportableObject[$exportableItemName] = $exportableItemValue;
}
}
return $preparedExportableObject;
}
/**
* @return string|null
*/
public function getAffiliation(): ?string
{
return $this->affiliation;
}
/**
* @param string|null $affiliation
* @return ItemParameter
*/
public function setAffiliation(?string $affiliation): ItemParameter
{
$this->affiliation = $affiliation;
return $this;
}
/**
* @return string|null
*/
public function getCoupon(): ?string
{
return $this->coupon;
}
/**
* @param string|null $coupon
* @return ItemParameter
*/
public function setCoupon(?string $coupon): ItemParameter
{
$this->coupon = $coupon;
return $this;
}
/**
* @return string|null
*/
public function getCurrency(): ?string
{
return $this->currency;
}
/**
* @param string|null $currency
* @return ItemParameter
*/
public function setCurrency(?string $currency): ItemParameter
{
$this->currency = $currency;
return $this;
}
/**
* @return float|null
*/
public function getDiscount(): ?float
{
return $this->discount;
}
/**
* @param float|null $discount
* @return ItemParameter
*/
public function setDiscount(?float $discount): ItemParameter
{
$this->discount = $discount;
return $this;
}
/**
* @return float|null
*/
public function getIndex(): ?float
{
return $this->index;
}
/**
* @param float|null $index
* @return ItemParameter
*/
public function setIndex(?float $index): ItemParameter
{
$this->index = $index;
return $this;
}
/**
* @return string|null
*/
public function getItemBrand(): ?string
{
return $this->itemBrand;
}
/**
* @param string|null $itemBrand
* @return ItemParameter
*/
public function setItemBrand(?string $itemBrand): ItemParameter
{
$this->itemBrand = $itemBrand;
return $this;
}
/**
* @return string|null
*/
public function getItemCategory(): ?string
{
return $this->itemCategory;
}
/**
* @param string|null $itemCategory
* @return ItemParameter
*/
public function setItemCategory(?string $itemCategory): ItemParameter
{
$this->itemCategory = $itemCategory;
return $this;
}
/**
* @return string|null
*/
public function getItemCategory2(): ?string
{
return $this->itemCategory2;
}
/**
* @param string|null $itemCategory2
* @return ItemParameter
*/
public function setItemCategory2(?string $itemCategory2): ItemParameter
{
$this->itemCategory2 = $itemCategory2;
return $this;
}
/**
* @return string|null
*/
public function getItemCategory3(): ?string
{
return $this->itemCategory3;
}
/**
* @param string|null $itemCategory3
* @return ItemParameter
*/
public function setItemCategory3(?string $itemCategory3): ItemParameter
{
$this->itemCategory3 = $itemCategory3;
return $this;
}
/**
* @return string|null
*/
public function getItemCategory4(): ?string
{
return $this->itemCategory4;
}
/**
* @param string|null $itemCategory4
* @return ItemParameter
*/
public function setItemCategory4(?string $itemCategory4): ItemParameter
{
$this->itemCategory4 = $itemCategory4;
return $this;
}
/**
* @return string|null
*/
public function getItemCategory5(): ?string
{
return $this->itemCategory5;
}
/**
* @param string|null $itemCategory5
* @return ItemParameter
*/
public function setItemCategory5(?string $itemCategory5): ItemParameter
{
$this->itemCategory5 = $itemCategory5;
return $this;
}
/**
* @return string|null
*/
public function getItemListId(): ?string
{
return $this->itemListId;
}
/**
* @param string|null $itemListId
* @return ItemParameter
*/
public function setItemListId(?string $itemListId): ItemParameter
{
$this->itemListId = $itemListId;
return $this;
}
/**
* @return string|null
*/
public function getItemListName(): ?string
{
return $this->itemListName;
}
/**
* @param string|null $itemListName
* @return ItemParameter
*/
public function setItemListName(?string $itemListName): ItemParameter
{
$this->itemListName = $itemListName;
return $this;
}
/**
* @return string|null
*/
public function getItemVariant(): ?string
{
return $this->itemVariant;
}
/**
* @param string|null $itemVariant
* @return ItemParameter
*/
public function setItemVariant(?string $itemVariant): ItemParameter
{
$this->itemVariant = $itemVariant;
return $this;
}
/**
* @return string|null
*/
public function getLocationId(): ?string
{
return $this->locationId;
}
/**
* @param string|null $locationId
* @return ItemParameter
*/
public function setLocationId(?string $locationId): ItemParameter
{
$this->locationId = $locationId;
return $this;
}
/**
* @return float|null
*/
public function getPrice(): ?float
{
return $this->price;
}
/**
* @param float|null $price
* @return ItemParameter
*/
public function setPrice(?float $price): ItemParameter
{
$this->price = $price;
return $this;
}
/**
* @return float|null
*/
public function getQuantity(): ?float
{
return $this->quantity;
}
/**
* @param float|null $quantity
* @return ItemParameter
*/
public function setQuantity(?float $quantity): ItemParameter
{
$this->quantity = $quantity;
return $this;
}
}

View File

@@ -0,0 +1,16 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 11:10
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Request;
use Br33f\Ga4\MeasurementProtocol\Dto\ExportableInterface;
use Br33f\Ga4\MeasurementProtocol\Dto\RequestValidateInterface;
abstract class AbstractRequest implements ExportableInterface, RequestValidateInterface
{
}

View File

@@ -0,0 +1,289 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 11:22
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Request;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\EventCollection;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\UserProperties;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\UserProperty;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\AbstractEvent;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
class BaseRequest extends AbstractRequest
{
/**
* Unique identifier of user instance.
* Required
* @var string
*/
protected $clientId = null;
/**
* App Instance ID.
* @var string
*/
protected $appInstanceId = null;
/**
* Unique identifier for a user.
* Not required
* @var string
*/
protected $userId;
/**
* An unix timestamp (microseconds) for the time to associate with the event.
* Not requied
* @var int
*/
protected $timestampMicros = null;
/**
* The user properties for the measurement.
* Not required
* @var UserProperties
*/
protected $userProperties = null;
/**
* If set true - indicates that events should not be use for personalized ads.
* Default false
* @var bool
*/
protected $nonPersonalizedAds = false;
/**
* Collection of event items. Maximum 25 events.
* Required
* @var EventCollection
*/
protected $events;
/**
* BaseRequest constructor.
* @param string|null $clientId
* @param AbstractEvent|EventCollection|null $events - Single Event or EventsCollection
*/
public function __construct(?string $clientId = null, $events = null)
{
if ($clientId !== null) {
@trigger_error('Creating a request by passing a web client ID to the constructor is deprecated in v0.1.3 and removed in v0.2.0. Use ::setClientId() or ::setAppInstanceId() directly, instead.', E_USER_DEPRECATED);
$this->clientId = $clientId;
}
if ($events !== null) {
if ($events instanceof EventCollection) {
$this->events = $events;
} else if ($events instanceof AbstractEvent) {
$this->events = new EventCollection();
$this->events->addEvent($events);
}
} else {
$this->events = new EventCollection();
}
}
/**
* @param UserProperty $userProperty
* @return BaseRequest
*/
public function addUserProperty(UserProperty $userProperty)
{
if ($this->getUserProperties() === null) {
$this->setUserProperties(new UserProperties());
}
$this->getUserProperties()->addUserProperty($userProperty);
return $this;
}
/**
* @return UserProperties|null
*/
public function getUserProperties(): ?UserProperties
{
return $this->userProperties;
}
/**
* @param UserProperties|null $userProperties
* @return BaseRequest
*/
public function setUserProperties(?UserProperties $userProperties)
{
$this->userProperties = $userProperties;
return $this;
}
/**
* @param AbstractEvent $event
* @return BaseRequest
*/
public function addEvent(AbstractEvent $event)
{
$this->getEvents()->addEvent($event);
return $this;
}
/**
* @return EventCollection
*/
public function getEvents(): EventCollection
{
return $this->events;
}
/**
* @param EventCollection $events
* @return BaseRequest
*/
public function setEvents(EventCollection $events)
{
$this->events = $events;
return $this;
}
/**
* @return array
*/
public function export(): array
{
$exportBaseRequest = array_filter([
'client_id' => $this->getClientId(),
'app_instance_id' => $this->getAppInstanceId(),
'non_personalized_ads' => $this->isNonPersonalizedAds(),
'events' => $this->getEvents()->export(),
]);
if ($this->getUserId() !== null) {
$exportBaseRequest['user_id'] = $this->getUserId();
}
if ($this->getTimestampMicros() !== null) {
$exportBaseRequest['timestamp_micros'] = $this->getTimestampMicros();
}
if ($this->getUserProperties() !== null) {
$exportBaseRequest['user_properties'] = $this->getUserProperties()->export();
}
return $exportBaseRequest;
}
/**
* @return string
*/
public function getClientId(): ?string
{
return $this->clientId;
}
/**
* @param string $clientId
* @return BaseRequest
*/
public function setClientId(string $clientId): self
{
$this->clientId = $clientId;
return $this;
}
/**
* @return string|null
*/
public function getAppInstanceId(): ?string
{
return $this->appInstanceId;
}
/**
* @param string $appInstanceId
* @return BaseRequest
*/
public function setAppInstanceId(string $appInstanceId): self
{
$this->appInstanceId = $appInstanceId;
return $this;
}
/**
* @return bool
*/
public function isNonPersonalizedAds(): bool
{
return $this->nonPersonalizedAds;
}
/**
* @param bool $nonPersonalizedAds
* @return BaseRequest
*/
public function setNonPersonalizedAds(bool $nonPersonalizedAds)
{
$this->nonPersonalizedAds = $nonPersonalizedAds;
return $this;
}
/**
* @return string|null
*/
public function getUserId(): ?string
{
return $this->userId;
}
/**
* @param string|null $userId
* @return BaseRequest
*/
public function setUserId(?string $userId)
{
$this->userId = $userId;
return $this;
}
/**
* @return ?int
*/
public function getTimestampMicros(): ?int
{
return $this->timestampMicros;
}
/**
* @param ?int $timestampMicros
* @return BaseRequest
*/
public function setTimestampMicros(?int $timestampMicros)
{
$this->timestampMicros = $timestampMicros;
return $this;
}
/**
* @param string|null $context Context for request, either 'web' or 'firebase'.
* @return bool
* @throws ValidationException
*/
public function validate(?string $context = 'web')
{
if ($context === 'web' && empty($this->getClientId())) {
throw new ValidationException('Parameter "client_id" is required.', ErrorCode::VALIDATION_CLIENT_ID_REQUIRED, 'client_id');
}
if ($context === 'firebase' && empty($this->getAppInstanceId())) {
throw new ValidationException('Parameter "app_instance_id" is required.', ErrorCode::VALIDATION_APP_INSTANCE_ID_REQUIRED, 'app_instance_id');
}
if ($this->getClientId() && $this->getAppInstanceId()) {
throw new ValidationException('Cannot specify both "client_id" and "app_instance_id".', ErrorCode::VALIDATION_CLIENT_IDENTIFIER_MISCONFIGURED);
}
$this->getEvents()->validate();
return true;
}
}

View File

@@ -0,0 +1,21 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 11:10
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
interface RequestValidateInterface
{
/**
* Method validates object. Throws exception if error, returns true if valid.
* @param string|null $context
* @return boolean
* @throws ValidationException
*/
public function validate(?string $context);
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 11:10
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Response;
use Br33f\Ga4\MeasurementProtocol\Dto\HydratableInterface;
use Br33f\Ga4\MeasurementProtocol\Exception\HydrationException;
use Psr\Http7\Message\ResponseInterface;
abstract class AbstractResponse implements HydratableInterface
{
/**
* AbstractResponse constructor.
* @param ResponseInterface|null $blueprint
* @throws HydrationException
*/
public function __construct(ResponseInterface $blueprint = null)
{
if ($blueprint !== null) {
$this->hydrate($blueprint);
}
}
}

View File

@@ -0,0 +1,77 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 11:10
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Response;
use Psr\Http7\Message\ResponseInterface;
class BaseResponse extends AbstractResponse
{
/**
* @var int|null
*/
protected $statusCode;
/**
* @var string
*/
protected $body;
/**
* @return int|null
*/
public function getStatusCode(): ?int
{
return $this->statusCode;
}
/**
* @param int|null $statusCode
* @return BaseResponse
*/
public function setStatusCode(?int $statusCode)
{
$this->statusCode = $statusCode;
return $this;
}
/**
* Get parsed body
* @return array
*/
public function getData()
{
return json_decode($this->getBody(), true);
}
/**
* @return string
*/
public function getBody(): string
{
return $this->body;
}
/**
* @param string $body
* @return BaseResponse
*/
public function setBody(string $body)
{
$this->body = $body;
return $this;
}
/**
* @param array|ResponseInterface $blueprint
*/
public function hydrate($blueprint)
{
$this->setStatusCode($blueprint->getStatusCode());
$this->setBody($blueprint->getBody()->getContents());
}
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 11:10
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto\Response;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\ValidationMessage;
use Psr\Http7\Message\ResponseInterface;
class DebugResponse extends BaseResponse
{
/**
* @var ValidationMessage[]
*/
protected $validationMessages = [];
/**
* @return ValidationMessage[]
*/
public function getValidationMessages(): array
{
return $this->validationMessages;
}
/**
* @param ValidationMessage[] $validationMessages
* @return DebugResponse
*/
public function setValidationMessages(array $validationMessages)
{
$this->validationMessages = $validationMessages;
return $this;
}
/**
* @param array|ResponseInterface $blueprint
*/
public function hydrate($blueprint)
{
parent::hydrate($blueprint);
$validationMessages = [];
foreach ($this->getData()['validationMessages'] as $validationMessage) {
$validationMessages[] = new ValidationMessage($validationMessage);
}
$this->setValidationMessages($validationMessages);
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 11:10
*/
namespace Br33f\Ga4\MeasurementProtocol\Dto;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
interface ValidateInterface
{
/**
* Method validates object. Throws exception if error, returns true if valid.
* @return boolean
* @throws ValidationException
*/
public function validate();
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 15:29
*/
namespace Br33f\Ga4\MeasurementProtocol\Enum;
class ErrorCode
{
const MAX_EVENT_COUNT_EXCEED = 100001;
const VALIDATION_CLIENT_ID_REQUIRED = 1000002;
const VALIDATION_EVENTS_MUST_NOT_BE_EMPTY = 1000003;
const VALIDATION_ITEM_AT_LEAST_ITEM_ID_OR_ITEM_NAME_REQUIRED = 1000004;
const VALIDATION_FIELD_REQUIRED = 1000005;
const VALIDATION_APP_INSTANCE_ID_REQUIRED = 1000006;
const VALIDATION_CLIENT_IDENTIFIER_MISCONFIGURED = 1000007;
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 24.06.2021
* Time: 13:49
*/
namespace Br33f\Ga4\MeasurementProtocol\Enum;
class ValidationCode
{
const VALUE_INVALID = 'VALUE_INVALID';
const VALUE_REQUIRED = 'VALUE_REQUIRED';
const NAME_INVALID = 'NAME_INVALID';
const NAME_RESERVED = 'NAME_RESERVED';
const VALUE_OUT_OF_BOUNDS = 'VALUE_OUT_OF_BOUNDS';
const EXCEEDED_MAX_ENTITIES = 'EXCEEDED_MAX_ENTITIES';
const NAME_DUPLICATED = 'NAME_DUPLICATED';
}

View File

@@ -0,0 +1,5 @@
<?php
namespace Br33f\Ga4\MeasurementProtocol\Exception;
abstract class AnalyticsException extends \Exception {};

View File

@@ -0,0 +1,16 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 11:20
*/
namespace Br33f\Ga4\MeasurementProtocol\Exception;
use Exception;
class HydrationException extends AnalyticsException
{
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Br33f\Ga4\MeasurementProtocol\Exception;
use Exception;
class MisconfigurationException extends AnalyticsException
{
}

View File

@@ -0,0 +1,42 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 11:20
*/
namespace Br33f\Ga4\MeasurementProtocol\Exception;
use Exception;
use Throwable;
class ValidationException extends AnalyticsException
{
/**
* @var string|null
*/
protected $fieldName = null;
public function __construct($message = "", $code = 0, $fieldName = null, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->fieldName = $fieldName;
}
/**
* @return string|null
*/
public function getFieldName(): ?string
{
return $this->fieldName;
}
/**
* @param string|null $fieldName
*/
public function setFieldName(?string $fieldName): void
{
$this->fieldName = $fieldName;
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 10:35
*/
namespace Br33f\Ga4\MeasurementProtocol;
use GuzzleHttp7\Client;
use GuzzleHttp7\Exception\BadResponseException;
use GuzzleHttp7\RequestOptions;
use Psr\Http7\Message\ResponseInterface;
class HttpClient
{
const DEFAULT_REQUEST_TIMEOUT = 30;
/**
* Guzzle Client
* @var Client
*/
protected $client;
/**
* Sends request to Google Analytics.
*
* @param string $url
* @param array $data
* @param array|null $options
* @return ResponseInterface
*/
public function post(string $url, array $data, ?array $options = [])
{
try {
return $this->getClient()->post($url, $this->getPreparedOptions($options, $data));
} catch (BadResponseException $e) {
return $e->getResponse();
}
}
/**
* Returns guzzle client if set or creates a new instance and returns it
* @return Client
*/
public function getClient(): Client
{
if ($this->client === null) {
$this->client = new Client();
}
return $this->client;
}
/**
* @param Client $client
*/
public function setClient(Client $client)
{
$this->client = $client;
}
/**
* @param $options
* @param $data
* @return array
*/
protected function getPreparedOptions($options, $data)
{
$options[RequestOptions::JSON] = $data;
if (!isset($options['timeout'])) {
$options['timeout'] = self::DEFAULT_REQUEST_TIMEOUT;
}
if (!isset($options['connect_timeout'])) {
$options['connect_timeout'] = self::DEFAULT_REQUEST_TIMEOUT;
}
return $options;
}
}

View File

@@ -0,0 +1,331 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 21.06.2021
* Time: 16:15
*/
namespace Br33f\Ga4\MeasurementProtocol;
use Br33f\Ga4\MeasurementProtocol\Dto\Request\AbstractRequest;
use Br33f\Ga4\MeasurementProtocol\Dto\Response\BaseResponse;
use Br33f\Ga4\MeasurementProtocol\Dto\Response\DebugResponse;
use Br33f\Ga4\MeasurementProtocol\Exception\MisconfigurationException;
class Service
{
const SSL_SCHEME = 'https://';
const NOT_SSL_SCHEME = 'http://';
const PREPENDED_WWW = 'www';
/**
* Indicates if connection to endpoint should be made with HTTPS (true) or HTTP (false)
* @var bool
*/
protected $useSsl = true;
/**
* Indicates if connection to endpoint should be made with prepended WWW
* @var bool
*/
protected $useWww = false;
/**
* Collect Endpoint
* @var string
*/
protected $collectEndpoint = 'google-analytics.com/mp/collect';
/**
* Collect Debug Endpoint. Used for validating events.
* @var string
*/
protected $collectDebugEndpoint = 'google-analytics.com/debug/mp/collect';
/**
* Http Client
* @var HttpClient
*/
protected $httpClient;
/**
* An API SECRET generated in the Google Analytics UI
* @var string
*/
protected $apiSecret = null;
/**
* The measurement ID associated with a data stream
* @var string
*/
protected $measurementId = null;
/**
* The Firebase App ID associated with a data stream
* @var string
*/
protected $firebaseId = null;
/**
* The custom ip address of the visitor
* @var string
*/
protected $ipOverride;
/**
* Http Options
* @var array
*/
protected $options;
/**
* Client constructor.
* @param string $apiSecret
* @param string|null $measurementId
*/
public function __construct(string $apiSecret, ?string $measurementId = null)
{
$this->setApiSecret($apiSecret);
if ($measurementId) {
@trigger_error('Creating a measurement service instance with a measurement ID passed to the constructor is deprecated in v0.1.3 and removed in v0.2.0. Use ::setMeasurementId() or ::setFirebaseId() directly, instead.', E_USER_DEPRECATED);
$this->setMeasurementId($measurementId);
}
}
/**
* @param AbstractRequest $request
* @param bool|null $debug
* @return BaseResponse
* @throws Exception\ValidationException
* @throws Exception\HydrationException
*/
public function send(AbstractRequest $request, ?bool $debug = false)
{
$request->validate($this->measurementId ? 'web' : 'firebase');
$response = $this->getHttpClient()->post($this->getEndpoint($debug), $request->export(), $this->getOptions());
return !$debug
? new BaseResponse($response)
: new DebugResponse($response);
}
/**
* @param AbstractRequest $request
* @return BaseResponse
* @throws Exception\ValidationException
* @throws Exception\HydrationException
*/
public function sendDebug(AbstractRequest $request)
{
return $this->send($request, true);
}
/**
* Returns Http Client if set or creates a new instance and returns it
* @return HttpClient
*/
public function getHttpClient(): HttpClient
{
if ($this->httpClient === null) {
$this->httpClient = new HttpClient();
}
return $this->httpClient;
}
/**
* @param HttpClient $httpClient
*/
public function setHttpClient(HttpClient $httpClient)
{
$this->httpClient = $httpClient;
}
/**
* Returns prepared endpoint url
* @return string
*/
public function getEndpoint(?bool $isDebug = false): string
{
$protocolScheme = $this->isUseSsl() ? self::SSL_SCHEME : self::NOT_SSL_SCHEME;
$collectEndpoint = $isDebug ? $this->getCollectDebugEndpoint() : $this->getCollectEndpoint();
$prependedWww = $this->isUseWww() ? (self::PREPENDED_WWW . '.') : '';
return $protocolScheme . $prependedWww . $collectEndpoint . "?" . http_build_query($this->getQueryParameters());
}
/**
* @return bool
*/
public function isUseSsl(): bool
{
return $this->useSsl;
}
/**
* @param bool $useSsl
*/
public function setUseSsl(bool $useSsl)
{
$this->useSsl = $useSsl;
}
/**
* @return bool
*/
public function isUseWww(): bool
{
return $this->useWww;
}
/**
* @param bool $useWww
*/
public function setUseWww(bool $useWww)
{
$this->useWww = $useWww;
}
/**
* @return string
*/
public function getCollectDebugEndpoint(): string
{
return $this->collectDebugEndpoint;
}
/**
* @param string $collectDebugEndpoint
*/
public function setCollectDebugEndpoint(string $collectDebugEndpoint)
{
$this->collectDebugEndpoint = $collectDebugEndpoint;
}
/**
* @return string
*/
public function getCollectEndpoint(): string
{
return $this->collectEndpoint;
}
/**
* @param string $collectEndpoint
*/
public function setCollectEndpoint(string $collectEndpoint)
{
$this->collectEndpoint = $collectEndpoint;
}
/**
* Returns query parameters
* @return array
* @throws MisconfigurationException
*/
public function getQueryParameters(): array
{
$parameters = [
'api_secret' => $this->getApiSecret(),
'measurement_id' => $this->getMeasurementId(),
'firebase_app_id' => $this->getFirebaseId(),
];
if ($parameters['firebase_app_id'] && $parameters['measurement_id']) {
throw new MisconfigurationException("Cannot specify both 'measurement_id' and 'firebase_app_id'.");
}
$ip = $this->getIpOverride();
if (!empty($ip)) {
$parameters['uip'] = $ip;
// TODO Remove the following line when the GA4 API will support the IP override
// https://github.com/dataunlocker/save-analytics-from-content-blockers/issues/25#issuecomment-864392422
$parameters['_uip'] = $ip;
}
return array_filter($parameters);
}
/**
* @return string
*/
public function getMeasurementId(): ?string
{
return $this->measurementId;
}
/**
* @param string $measurementId
* @return self
*/
public function setMeasurementId(string $measurementId): self
{
$this->measurementId = $measurementId;
return $this;
}
/**
* @return string|null
*/
public function getFirebaseId(): ?string
{
return $this->firebaseId;
}
/**
* @param string $firebaseId
* @return self
*/
public function setFirebaseId(string $firebaseId): self
{
$this->firebaseId = $firebaseId;
return $this;
}
/**
* @return string
*/
public function getApiSecret(): string
{
return $this->apiSecret;
}
/**
* @param string $apiSecret
*/
public function setApiSecret(string $apiSecret)
{
$this->apiSecret = $apiSecret;
}
/**
* @return string
*/
public function getIpOverride(): ?string
{
return $this->ipOverride;
}
/**
* @param string $ipOverride
*/
public function setIpOverride(string $ipOverride)
{
$this->ipOverride = $ipOverride;
}
/**
* @return array|null
*/
public function getOptions(): ?array
{
return $this->options;
}
/**
* @param array|null $options
*/
public function setOptions(?array $options)
{
$this->options = $options;
}
}

View File

@@ -0,0 +1,25 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 14:49
*/
namespace Tests\Common;
use Faker\Factory;
use PHPUnit\Framework\TestCase;
class BaseTestCase extends TestCase
{
protected $faker;
/**
* BaseTestCase constructor.
*/
public function __construct()
{
parent::__construct();
$this->faker = Factory::create();
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 15:23
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Common;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\EventCollection;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\BaseEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\BaseParameter;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Tests\Common\BaseTestCase;
class EventCollectionTest extends BaseTestCase
{
/**
* @var EventCollection
*/
protected $eventCollection;
public function testEventList()
{
$setEventList = [];
for ($i = 0; $i < rand(1, 25); $i++) {
$setEventList[] = new BaseEvent();
}
$this->eventCollection->setEventList($setEventList);
$this->assertEquals($setEventList, $this->eventCollection->getEventList());
}
public function testSetEventListExceed25()
{
$setEventList = [];
for ($i = 0; $i < rand(26, 50); $i++) {
$setEventList[] = new BaseEvent();
}
$this->expectExceptionCode(ErrorCode::MAX_EVENT_COUNT_EXCEED);
$this->eventCollection->setEventList($setEventList);
}
public function testAddEvent()
{
$this->eventCollection->setEventList([]);
$newEvent = new BaseEvent();
$this->eventCollection->addEvent($newEvent);
$this->assertEquals(1, count($this->eventCollection->getEventList()));
$this->assertEquals($newEvent, $this->eventCollection->getEventList()[0]);
}
public function testAddEventExceed25()
{
$setEventList = [];
for ($i = 0; $i < 25; $i++) {
$setEventList[] = new BaseEvent();
}
$this->eventCollection->setEventList($setEventList);
$newEvent = new BaseEvent();
$this->expectExceptionCode(ErrorCode::MAX_EVENT_COUNT_EXCEED);
$this->eventCollection->addEvent($newEvent);
}
public function testExport()
{
$setEventListExport = [];
$setEventList = [];
for ($i = 0; $i < rand(1, 25); $i++) {
$event = new BaseEvent($this->faker->word);
$event->addParam($this->faker->word, new BaseParameter($this->faker->word));
$setEventList[] = $event;
$setEventListExport[] = $event->export();
}
$this->eventCollection->setEventList($setEventList);
$this->assertEquals($setEventListExport, $this->eventCollection->export());
}
public function testValidateFailed()
{
$newEventCollection = new EventCollection();
$this->expectExceptionCode(ErrorCode::VALIDATION_EVENTS_MUST_NOT_BE_EMPTY);
$newEventCollection->validate();
}
public function testValidateSuccess()
{
$newEventCollection = new EventCollection();
$event = new BaseEvent($this->faker->word);
$event->addParam($this->faker->word, new BaseParameter($this->faker->word));
$newEventCollection->addEvent($event);
$this->assertTrue($newEventCollection->validate());
}
protected function setUp(): void
{
parent::setUp();
$this->eventCollection = new EventCollection();
}
}

View File

@@ -0,0 +1,90 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 15:56
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Common;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\UserProperties;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\UserProperty;
use Tests\Common\BaseTestCase;
class UserPropertiesTest extends BaseTestCase
{
/**
* @var UserProperties
*/
protected $userProperties;
public function testDefaultConstructor()
{
$constructedUserProperties = new UserProperties();
$this->assertEquals([], $constructedUserProperties->getUserPropertiesList());
}
public function testConstructor()
{
$setUserProperties = [
new UserProperty(),
new UserProperty()
];
$constructedUserProperties = new UserProperties($setUserProperties);
$this->assertEquals($setUserProperties, $constructedUserProperties->getUserPropertiesList());
}
public function testUserPropertiesList()
{
$setUserProperties = [
new UserProperty($this->faker->word, $this->faker->word),
new UserProperty($this->faker->word, $this->faker->word),
new UserProperty($this->faker->word, $this->faker->word)
];
$this->userProperties->setUserPropertiesList($setUserProperties);
$this->assertEquals($setUserProperties, $this->userProperties->getUserPropertiesList());
}
public function testUserPropertyAdd()
{
$this->userProperties->setUserPropertiesList([]);
$addUserProperty = new UserProperty($this->faker->word, $this->faker->word);
$this->userProperties->addUserProperty($addUserProperty);
$this->assertEquals(1, count($this->userProperties->getUserPropertiesList()));
$this->assertEquals($addUserProperty, $this->userProperties->getUserPropertiesList()[0]);
}
public function testExport()
{
$setUserProperties = [
new UserProperty($this->faker->word, $this->faker->word),
new UserProperty($this->faker->word, $this->faker->word),
new UserProperty($this->faker->word, $this->faker->word)
];
$this->userProperties->setUserPropertiesList($setUserProperties);
$this->assertEquals([
$setUserProperties[0]->getName() => [
'value' => $setUserProperties[0]->getValue()
],
$setUserProperties[1]->getName() => [
'value' => $setUserProperties[1]->getValue()
],
$setUserProperties[2]->getName() => [
'value' => $setUserProperties[2]->getValue()
],
], $this->userProperties->export());
}
protected function setUp(): void
{
$this->userProperties = new UserProperties();
}
}

View File

@@ -0,0 +1,75 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 15:47
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Common;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\UserProperty;
use Tests\Common\BaseTestCase;
class UserPropertyTest extends BaseTestCase
{
/**
* @var UserProperty
*/
protected $userProperty;
public function testDefaultConstructor()
{
$constructedUserProperty = new UserProperty();
$this->assertEquals(null, $constructedUserProperty->getName());
$this->assertEquals(null, $constructedUserProperty->getValue());
}
public function testParametrizedConstructor()
{
$setName = $this->faker->word;
$setValue = $this->faker->word;
$constructedUserProperty = new UserProperty($setName, $setValue);
$this->assertEquals($setName, $constructedUserProperty->getName());
$this->assertEquals($setValue, $constructedUserProperty->getValue());
}
public function testName()
{
$setName = $this->faker->word;
$this->userProperty->setName($setName);
$this->assertEquals($setName, $this->userProperty->getName());
}
public function testValue()
{
$setValue = $this->faker->word;
$this->userProperty->setValue($setValue);
$this->assertEquals($setValue, $this->userProperty->getValue());
}
public function testExportEmpty()
{
$emptyUserProperty = new UserProperty();
$this->assertEquals([null => ['value' => null]], $emptyUserProperty->export());
}
public function testExport()
{
$setName = $this->faker->word;
$setValue = $this->faker->word;
$emptyUserProperty = new UserProperty($setName, $setValue);
$this->assertEquals([$setName => ['value' => $setValue]], $emptyUserProperty->export());
}
protected function setUp(): void
{
parent::setUp();
$this->userProperty = new UserProperty();
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 24.06.2021
* Time: 13:54
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Common;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\ValidationMessage;
use Br33f\Ga4\MeasurementProtocol\Enum\ValidationCode;
use Tests\Common\BaseTestCase;
class ValidationMessageTest extends BaseTestCase
{
/**
* @var ValidationMessage
*/
protected $validationMessage;
public function testDefaultConstructor()
{
$constructedValidationMessage = new ValidationMessage();
$this->assertNotNull($constructedValidationMessage);
}
public function testArrayBlueprintConstructor()
{
$blueprint = ['fieldPath' => $this->faker->word];
$constructedValidationMessage = new ValidationMessage($blueprint);
$this->assertNotNull($constructedValidationMessage);
$this->assertEquals($blueprint['fieldPath'], $constructedValidationMessage->getFieldPath());
$this->assertEquals(null, $constructedValidationMessage->getDescription());
$this->assertEquals(null, $constructedValidationMessage->getValidationCode());
}
public function testHydrate()
{
$blueprint = [
'fieldPath' => $this->faker->word,
'description' => $this->faker->text,
'validationCode' => $this->faker->randomElement([ValidationCode::EXCEEDED_MAX_ENTITIES, ValidationCode::NAME_DUPLICATED, ValidationCode::NAME_RESERVED])
];
$constructedValidationMessage = new ValidationMessage($blueprint);
$this->assertNotNull($constructedValidationMessage);
$this->assertEquals($blueprint['fieldPath'], $constructedValidationMessage->getFieldPath());
$this->assertEquals($blueprint['description'], $constructedValidationMessage->getDescription());
$this->assertEquals($blueprint['validationCode'], $constructedValidationMessage->getValidationCode());
}
public function testFieldPath()
{
$setFieldPath = $this->faker->word;
$this->validationMessage->setFieldPath($setFieldPath);
$this->assertEquals($setFieldPath, $this->validationMessage->getFieldPath());
}
public function testValidationCode()
{
$setValidationCode = $this->faker->randomElement([ValidationCode::EXCEEDED_MAX_ENTITIES, ValidationCode::NAME_DUPLICATED, ValidationCode::NAME_RESERVED]);
$this->validationMessage->setValidationCode($setValidationCode);
$this->assertEquals($setValidationCode, $this->validationMessage->getValidationCode());
}
public function testDescription()
{
$setDescription = $this->faker->text;
$this->validationMessage->setDescription($setDescription);
$this->assertEquals($setDescription, $this->validationMessage->getDescription());
}
protected function setUp(): void
{
parent::setUp();
$this->validationMessage = new ValidationMessage();
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\AddPaymentInfoEvent;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class AddPaymentInfoEventTest extends BaseTestCase
{
/**
* @var AddPaymentInfoEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new AddPaymentInfoEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('add_payment_info', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setCurrency($this->faker->currencyCode);
$this->assertTrue($this->event->validate());
}
public function testValidateFail()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->expectException(ValidationException::class);
$this->event->validate();
}
protected function setUp(): void
{
parent::setUp();
$this->event = new AddPaymentInfoEvent();
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\AddShippingInfoEvent;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class AddShippingInfoEventTest extends BaseTestCase
{
/**
* @var AddShippingInfoEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new AddShippingInfoEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('add_shipping_info', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setCurrency($this->faker->currencyCode);
$this->assertTrue($this->event->validate());
}
public function testValidateFail()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->expectException(ValidationException::class);
$this->event->validate();
}
protected function setUp(): void
{
parent::setUp();
$this->event = new AddShippingInfoEvent();
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\AddToCartEvent;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class AddToCartEventTest extends BaseTestCase
{
/**
* @var AddToCartEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new AddToCartEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('add_to_cart', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setCurrency($this->faker->currencyCode);
$this->assertTrue($this->event->validate());
}
public function testValidateFail()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->expectException(ValidationException::class);
$this->event->validate();
}
protected function setUp(): void
{
parent::setUp();
$this->event = new AddToCartEvent();
}
}

View File

@@ -0,0 +1,171 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 15:05
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use BadMethodCallException;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\BaseEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\BaseParameter;
use InvalidArgumentException;
use Tests\Common\BaseTestCase;
class BaseEventTest extends BaseTestCase
{
/**
* @var BaseEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new BaseEvent();
$this->assertEquals(null, $constructedEvent->getName());
$this->assertEquals([], $constructedEvent->getParamList());
}
public function testNameOnlyConstructor()
{
$setupName = $this->faker->word;
$constructedEvent = new BaseEvent($setupName);
$this->assertEquals($setupName, $constructedEvent->getName());
$this->assertEquals([], $constructedEvent->getParamList());
}
public function testParamListOnlyConstructor()
{
$baseParams = [];
for ($i = 0; $i < rand(4, 10); $i++) {
$baseParams[$this->faker->word] = new BaseParameter($this->faker->word);
}
$constructedEvent = new BaseEvent(null, $baseParams);
$this->assertEquals(null, $constructedEvent->getName());
$this->assertEquals($baseParams, $constructedEvent->getParamList());
}
public function testFullConstructor()
{
$setupName = $this->faker->word;
$baseParams = [];
for ($i = 0; $i < rand(4, 10); $i++) {
$baseParams[$this->faker->word] = new BaseParameter($this->faker->word);
}
$constructedEvent = new BaseEvent($setupName, $baseParams);
$this->assertEquals($setupName, $constructedEvent->getName());
$this->assertEquals($baseParams, $constructedEvent->getParamList());
}
public function testName()
{
$setupName = $this->faker->word;
$this->event->setName($setupName);
$this->assertEquals($setupName, $this->event->getName());
}
public function testParamList()
{
$baseParams = [];
for ($i = 0; $i < rand(4, 10); $i++) {
$baseParams[$this->faker->word] = new BaseParameter($this->faker->word);
}
$this->event->setParamList($baseParams);
$this->assertEquals($baseParams, $this->event->getParamList());
}
public function testAddParam()
{
$this->event->setParamList([]);
$paramName = $this->faker->word;
$paramToAdd = new BaseParameter($this->faker->word);
$this->event->addParam($paramName, $paramToAdd);
$this->assertEquals(1, count($this->event->getParamList()));
$this->assertEquals($paramToAdd, $this->event->getParamList()[$paramName]);
}
public function testDeleteParam()
{
$this->event->setParamList([]);
$paramName = $this->faker->word;
$paramToAdd = new BaseParameter($this->faker->word);
$this->event->addParam($paramName, $paramToAdd);
$this->assertEquals(1, count($this->event->getParamList()));
$this->event->deleteParameter($paramName);
$this->assertEquals(0, count($this->event->getParamList()));
}
public function testExportEmpty()
{
$emptyEvent = new BaseEvent();
$this->assertEquals(['name' => null, 'params' => new \ArrayObject()], $emptyEvent->export());
}
public function testExport()
{
$setupName = $this->faker->word;
$baseParamsExport = [];
$baseParams = [];
for ($i = 0; $i < rand(4, 10); $i++) {
$baseParamName = $this->faker->word;
$baseParam = new BaseParameter($this->faker->word);
$baseParams[$baseParamName] = $baseParam;
$baseParamsExport[$baseParamName] = $baseParam->export();
}
$constructedEvent = new BaseEvent($setupName, $baseParams);
$this->assertEquals(['name' => $setupName, 'params' => new \ArrayObject($baseParamsExport)], $constructedEvent->export());
}
public function testSetGetCall()
{
$this->event->setTest1('test1value');
$this->assertEquals('test1value', $this->event->getTest1());
}
public function testSetCallNoParams()
{
$this->expectException(InvalidArgumentException::class);
$this->event->setTest2();
}
public function testUnknownCallMethod()
{
$this->expectException(BadMethodCallException::class);
$this->event->invalidMethodName();
}
public function testValidate()
{
$setupName = $this->faker->word;
$baseParams = [];
for ($i = 0; $i < rand(4, 10); $i++) {
$baseParam = new BaseParameter($this->faker->word);
$baseParams[$this->faker->word] = $baseParam;
}
$constructedEvent = new BaseEvent($setupName, $baseParams);
$this->assertTrue($constructedEvent->validate());
}
protected function setUp(): void
{
$this->event = new BaseEvent();
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\BeginCheckoutEvent;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class BeginCheckoutEventTest extends BaseTestCase
{
/**
* @var BeginCheckoutEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new BeginCheckoutEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('begin_checkout', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setCurrency($this->faker->currencyCode);
$this->assertTrue($this->event->validate());
}
public function testValidateFail()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->expectException(ValidationException::class);
$this->event->validate();
}
protected function setUp(): void
{
parent::setUp();
$this->event = new BeginCheckoutEvent();
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\LoginEvent;
use Tests\Common\BaseTestCase;
class LoginEventTest extends BaseTestCase
{
/**
* @var LoginEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new LoginEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('login', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setMethod($this->faker->word);
$this->assertTrue($this->event->validate());
}
protected function setUp(): void
{
parent::setUp();
$this->event = new LoginEvent();
}
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\PurchaseEvent;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class PurchaseEventTest extends BaseTestCase
{
/**
* @var PurchaseEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new PurchaseEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('purchase', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setCurrency($this->faker->currencyCode);
$this->event->setTransactionId($this->faker->bothify('*#*#*#_transaction'));
$this->assertTrue($this->event->validate());
}
public function testValidateFailNoCurrency()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setTransactionId($this->faker->bothify('*#*#*#_transaction'));
$this->expectException(ValidationException::class);
$this->event->validate();
}
public function testValidateFailNoTransaction()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setCurrency($this->faker->currencyCode);
$this->expectException(ValidationException::class);
$this->event->validate();
}
protected function setUp(): void
{
parent::setUp();
$this->event = new PurchaseEvent();
}
}

View File

@@ -0,0 +1,61 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\RefundEvent;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class RefundEventTest extends BaseTestCase
{
/**
* @var RefundEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new RefundEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('refund', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setCurrency($this->faker->currencyCode);
$this->event->setTransactionId($this->faker->bothify('*#*#*#_transaction'));
$this->assertTrue($this->event->validate());
}
public function testValidateFailNoCurrency()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setTransactionId($this->faker->bothify('*#*#*#_transaction'));
$this->expectException(ValidationException::class);
$this->event->validate();
}
public function testValidateFailNoTransaction()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setCurrency($this->faker->currencyCode);
$this->expectException(ValidationException::class);
$this->event->validate();
}
protected function setUp(): void
{
parent::setUp();
$this->event = new RefundEvent();
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\RemoveFromCartEvent;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class RemoveFromCartEventTest extends BaseTestCase
{
/**
* @var RemoveFromCartEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new RemoveFromCartEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('remove_from_cart', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setCurrency($this->faker->currencyCode);
$this->assertTrue($this->event->validate());
}
public function testValidateFail()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->expectException(ValidationException::class);
$this->event->validate();
}
protected function setUp(): void
{
parent::setUp();
$this->event = new RemoveFromCartEvent();
}
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\SearchEvent;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class SearchEventTest extends BaseTestCase
{
/**
* @var SearchEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new SearchEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('search', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setSearchTerm($this->faker->paragraph);
$this->assertTrue($this->event->validate());
}
public function testValidateFail()
{
$this->event = new SearchEvent();
$this->expectException(ValidationException::class);
$this->event->validate();
}
protected function setUp(): void
{
parent::setUp();
$this->event = new SearchEvent();
}
}

View File

@@ -0,0 +1,55 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 10:44
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\SelectItemEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\ViewItemEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\BaseParameter;
use Tests\Common\BaseTestCase;
class SelectItemEventTest extends BaseTestCase
{
/**
* @var SelectItemEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new SelectItemEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('select_item', $constructedEvent->getName());
}
public function testParameterConstructor()
{
$setParameters = [
$this->faker->word => new BaseParameter($this->faker->word),
$this->faker->word => new BaseParameter($this->faker->word)
];
$constructedEvent = new ViewItemEvent($setParameters);
$this->assertNotNull($constructedEvent);
$this->assertEquals($setParameters, $constructedEvent->getParamList());
}
public function testValidateSuccess()
{
$newViewItemEvent = new ViewItemEvent();
$this->assertTrue($newViewItemEvent->validate());
}
protected function setUp(): void
{
parent::setUp();
$this->event = new SelectItemEvent();
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\SignUpEvent;
use Tests\Common\BaseTestCase;
class SignUpEventTest extends BaseTestCase
{
/**
* @var SignUpEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new SignUpEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('sign_up', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setMethod($this->faker->word);
$this->assertTrue($this->event->validate());
}
protected function setUp(): void
{
parent::setUp();
$this->event = new SignUpEvent();
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\ViewCartEvent;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class ViewCartEventTest extends BaseTestCase
{
/**
* @var ViewCartEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new ViewCartEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('view_cart', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->event->setCurrency($this->faker->currencyCode);
$this->assertTrue($this->event->validate());
}
public function testValidateFail()
{
$this->event->setValue($this->faker->randomFloat(2, 10, 3000));
$this->expectException(ValidationException::class);
$this->event->validate();
}
protected function setUp(): void
{
parent::setUp();
$this->event = new ViewCartEvent();
}
}

View File

@@ -0,0 +1,109 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 10:44
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\ViewItemEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\BaseParameter;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemCollectionParameter;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemParameter;
use Tests\Common\BaseTestCase;
class ViewItemEventTest extends BaseTestCase
{
protected $viewItemEvent;
public function testDefaultConstructor()
{
$constructedEvent = new ViewItemEvent();
$this->assertNotNull($constructedEvent);
}
public function testParameterConstructor()
{
$setParameters = [
$this->faker->word => new BaseParameter($this->faker->word),
$this->faker->word => new BaseParameter($this->faker->word)
];
$constructedEvent = new ViewItemEvent($setParameters);
$this->assertNotNull($constructedEvent);
$this->assertEquals($setParameters, $constructedEvent->getParamList());
}
public function testSetGetItems()
{
$setItems = new ItemCollectionParameter([
new ItemParameter(['item_name' => $this->faker->word]),
new ItemParameter(['item_name' => $this->faker->word, 'price' => $this->faker->randomFloat(2, 10, 100)])
]);
$this->viewItemEvent->setItems($setItems);
$this->assertEquals($setItems, $this->viewItemEvent->getItems());
}
public function testGetItemsEmpty()
{
$newViewItemEvent = new ViewItemEvent();
$this->assertNotNull($newViewItemEvent->getItems());
}
public function testAddItem()
{
$this->viewItemEvent->setItems(new ItemCollectionParameter());
$itemToAdd = new ItemParameter(['item_name' => $this->faker->word]);
$this->viewItemEvent->addItem($itemToAdd);
$this->assertEquals(1, count($this->viewItemEvent->getItems()->getItemList()));
$this->assertEquals($itemToAdd, $this->viewItemEvent->getItems()->getItemList()[0]);
}
public function testCurrency()
{
$setCurrency = $this->faker->currencyCode;
$this->viewItemEvent->setCurrency($setCurrency);
$this->assertEquals($setCurrency, $this->viewItemEvent->getCurrency());
}
public function testValue()
{
$setValue = $this->faker->randomFloat(2, 10, 2000);
$this->viewItemEvent->setValue($setValue);
$this->assertEquals($setValue, $this->viewItemEvent->getValue());
}
public function testValidateEmpty()
{
$newViewItemEvent = new ViewItemEvent();
$this->assertTrue($newViewItemEvent->validate());
}
public function testValidate()
{
$setItems = new ItemCollectionParameter([
new ItemParameter(['item_name' => $this->faker->word]),
new ItemParameter(['item_name' => $this->faker->word, 'price' => $this->faker->randomFloat(2, 10, 100)])
]);
$newViewItemEvent = new ViewItemEvent([$setItems]);
$this->assertTrue($newViewItemEvent->validate());
}
protected function setUp(): void
{
parent::setUp();
$this->viewItemEvent = new ViewItemEvent();
}
}

View File

@@ -0,0 +1,103 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 10:44
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\ViewItemEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\ViewItemListEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\BaseParameter;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemCollectionParameter;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemParameter;
use Tests\Common\BaseTestCase;
class ViewItemListEventTest extends BaseTestCase
{
/**
* @var ViewItemEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new ViewItemListEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('view_item_list', $constructedEvent->getName());
}
public function testParameterConstructor()
{
$setParameters = [
$this->faker->word => new BaseParameter($this->faker->word),
$this->faker->word => new BaseParameter($this->faker->word)
];
$constructedEvent = new ViewItemEvent($setParameters);
$this->assertNotNull($constructedEvent);
$this->assertEquals($setParameters, $constructedEvent->getParamList());
}
public function testSetGetItems()
{
$setItems = new ItemCollectionParameter([
new ItemParameter(['item_name' => $this->faker->word]),
new ItemParameter(['item_name' => $this->faker->word, 'price' => $this->faker->randomFloat(2, 10, 100)])
]);
$this->event->setItems($setItems);
$this->assertEquals($setItems, $this->event->getItems());
}
public function testGetItemsEmpty()
{
$newViewItemEvent = new ViewItemEvent();
$this->assertNotNull($newViewItemEvent->getItems());
}
public function testAddItem()
{
$this->event->setItems(new ItemCollectionParameter());
$itemToAdd = new ItemParameter(['item_name' => $this->faker->word]);
$this->event->addItem($itemToAdd);
$this->assertEquals(1, count($this->event->getItems()->getItemList()));
$this->assertEquals($itemToAdd, $this->event->getItems()->getItemList()[0]);
}
public function testCurrency()
{
$setCurrency = $this->faker->currencyCode;
$this->event->setCurrency($setCurrency);
$this->assertEquals($setCurrency, $this->event->getCurrency());
}
public function testValue()
{
$setValue = $this->faker->randomFloat(2, 10, 2000);
$this->event->setValue($setValue);
$this->assertEquals($setValue, $this->event->getValue());
}
public function testValidate()
{
$newViewItemEvent = new ViewItemEvent();
$this->assertTrue($newViewItemEvent->validate());
}
protected function setUp(): void
{
parent::setUp();
$this->event = new ViewItemListEvent();
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:40
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Event;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\ViewSearchResultsEvent;
use Tests\Common\BaseTestCase;
class ViewSearchResultsEventTest extends BaseTestCase
{
/**
* @var ViewSearchResultsEvent
*/
protected $event;
public function testDefaultConstructor()
{
$constructedEvent = new ViewSearchResultsEvent();
$this->assertNotNull($constructedEvent);
$this->assertEquals('view_search_results', $constructedEvent->getName());
}
public function testValidateSuccess()
{
$this->event->setSearchTerm($this->faker->paragraph);
$this->assertTrue($this->event->validate());
}
protected function setUp(): void
{
parent::setUp();
$this->event = new ViewSearchResultsEvent();
}
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 14:22
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Parameter;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\BaseParameter;
use Tests\Common\BaseTestCase;
class BaseParameterTest extends BaseTestCase
{
/**
* @var BaseParameter
*/
protected $baseParameter;
public function setUp(): void
{
$this->baseParameter = new BaseParameter();
}
public function testValueString()
{
$valueToSet = $this->faker->word;
$this->baseParameter->setValue($valueToSet);
$this->assertEquals($valueToSet, $this->baseParameter->getValue());
}
public function testValueArray()
{
$valueToSet = [];
for ($i = 0; $i < $this->faker->randomDigit; $i++) {
$valueToSet[] = $this->faker->word;
}
$this->baseParameter->setValue($valueToSet);
$this->assertEquals($valueToSet, $this->baseParameter->getValue());
}
public function testValueBaseParam()
{
$valueToSet = new BaseParameter();
$valueToSet->setValue($this->faker->word);
$this->baseParameter->setValue($valueToSet);
$this->assertEquals($valueToSet, $this->baseParameter->getValue());
}
public function testExportSimple()
{
$valueToSet = $this->faker->word;
$this->baseParameter->setValue($valueToSet);
$this->assertEquals($valueToSet, $this->baseParameter->export());
}
public function testExportBaseParameter()
{
$valueToSet = new BaseParameter();
$valueToSet->setValue($this->faker->word);
$this->baseParameter->setValue($valueToSet);
$this->assertEquals($valueToSet->getValue(), $this->baseParameter->export());
}
}

View File

@@ -0,0 +1,92 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 14:22
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Parameter;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemCollectionParameter;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemParameter;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class ItemCollectionParameterTest extends BaseTestCase
{
/**
* @var ItemCollectionParameter
*/
protected $itemCollectionParameter;
public function setUp(): void
{
$this->itemCollectionParameter = new ItemCollectionParameter();
}
public function testDefaultContructor()
{
$constructedItemCollectionParameter = new ItemCollectionParameter();
$this->assertNotNull($constructedItemCollectionParameter);
}
public function testItemList()
{
$setItemList = [
new ItemParameter(['item_name' => 'test1']),
new ItemParameter(['item_id' => '123', 'price' => 15.55])
];
$this->itemCollectionParameter->setItemList($setItemList);
$this->assertEquals($setItemList, $this->itemCollectionParameter->getItemList());
}
public function testAddItem()
{
$itemToAdd = new ItemParameter(['item_name' => $this->faker->name, 'item_id' => '123', 'price' => 15.55]);
$this->itemCollectionParameter
->setItemList([])
->addItem($itemToAdd);
$this->assertEquals(1, count($this->itemCollectionParameter->getItemList()));
$this->assertEquals($itemToAdd, $this->itemCollectionParameter->getItemList()[0]);
}
public function testExportSimple()
{
$setItemList = [
new ItemParameter(['item_name' => 'test1']),
new ItemParameter(['item_id' => '123', 'price' => 15.55])
];
$this->itemCollectionParameter->setItemList($setItemList);
$this->assertEquals([
['item_name' => 'test1'],
['item_id' => '123', 'price' => 15.55]
], $this->itemCollectionParameter->export());
}
public function testValidateSuccess()
{
$setItemList = [
new ItemParameter(['item_name' => 'test1']),
new ItemParameter(['item_id' => '123', 'price' => 15.55])
];
$this->itemCollectionParameter->setItemList($setItemList);
$this->assertTrue($this->itemCollectionParameter->validate());
}
public function testValidateError()
{
$setItemList = [
new ItemParameter(['item_name' => 'test1']),
new ItemParameter(['price' => 15.55])
];
$this->itemCollectionParameter->setItemList($setItemList);
$this->expectException(ValidationException::class);
$this->itemCollectionParameter->validate();
}
}

View File

@@ -0,0 +1,265 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 25.06.2021
* Time: 13:03
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Parameter;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\ItemParameter;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class ItemParameterTest extends BaseTestCase
{
protected $itemParameter;
public function testDefaultConstructor()
{
$constructedItemParameter = new ItemParameter();
$this->assertNotNull($constructedItemParameter);
}
public function testParametrizedConstructor()
{
$blueprint = [
'item_id' => $this->faker->name,
'price' => $this->faker->randomFloat(2, 10, 1000),
'quantity' => $this->faker->numberBetween(1, 3)
];
$constructedItemParameter = new ItemParameter($blueprint);
$this->assertNotNull($constructedItemParameter);
$this->assertEquals($blueprint['item_id'], $constructedItemParameter->getItemId());
$this->assertEquals($blueprint['price'], $constructedItemParameter->getPrice());
$this->assertEquals($blueprint['quantity'], $constructedItemParameter->getQuantity());
}
public function testIndex()
{
$setIndex = $this->faker->numberBetween(1, 9);
$this->itemParameter->setIndex($setIndex);
$this->assertEquals($setIndex, $this->itemParameter->getIndex());
}
public function testAffiliation()
{
$setAffiliation = $this->faker->word;
$this->itemParameter->setAffiliation($setAffiliation);
$this->assertEquals($setAffiliation, $this->itemParameter->getAffiliation());
}
public function testCurrency()
{
$setCurrency = $this->faker->currencyCode;
$this->itemParameter->setCurrency($setCurrency);
$this->assertEquals($setCurrency, $this->itemParameter->getCurrency());
}
public function testQuantity()
{
$setQuantity = $this->faker->numberBetween(1, 30);
$this->itemParameter->setQuantity($setQuantity);
$this->assertEquals($setQuantity, $this->itemParameter->getQuantity());
}
public function testItemName()
{
$setName = $this->faker->word . $this->faker->colorName;
$this->itemParameter->setItemName($setName);
$this->assertEquals($setName, $this->itemParameter->getItemName());
}
public function testLocationId()
{
$setLocationId = $this->faker->bothify('*_#####');
$this->itemParameter->setLocationId($setLocationId);
$this->assertEquals($setLocationId, $this->itemParameter->getLocationId());
}
public function testItemCategory()
{
$setCategory = $this->faker->word;
$this->itemParameter->setItemCategory($setCategory);
$this->itemParameter->setItemCategory2($setCategory);
$this->itemParameter->setItemCategory3($setCategory);
$this->itemParameter->setItemCategory4($setCategory);
$this->itemParameter->setItemCategory5($setCategory);
$this->assertEquals($setCategory, $this->itemParameter->getItemCategory());
$this->assertEquals($setCategory, $this->itemParameter->getItemCategory2());
$this->assertEquals($setCategory, $this->itemParameter->getItemCategory3());
$this->assertEquals($setCategory, $this->itemParameter->getItemCategory4());
$this->assertEquals($setCategory, $this->itemParameter->getItemCategory5());
}
public function testPrice()
{
$setPrice = $this->faker->randomFloat(2, 1, 10000);
$this->itemParameter->setPrice($setPrice);
$this->assertEquals($setPrice, $this->itemParameter->getPrice());
}
public function testSetItemId()
{
$setItemId = $this->faker->bothify('***_#####');
$this->itemParameter->setItemId($setItemId);
$this->assertEquals($setItemId, $this->itemParameter->getItemId());
}
public function testItemListId()
{
$setItemListId = $this->faker->bothify('ITEM_LIST_#####');
$this->itemParameter->setItemListId($setItemListId);
$this->assertEquals($setItemListId, $this->itemParameter->getItemListId());
}
public function testItemListName()
{
$setItemListName = $this->faker->word;
$this->itemParameter->setItemListName($setItemListName);
$this->assertEquals($setItemListName, $this->itemParameter->getItemListName());
}
public function testCoupon()
{
$setCoupon = $this->faker->bothify('***-#####-#####');
$this->itemParameter->setCoupon($setCoupon);
$this->assertEquals($setCoupon, $this->itemParameter->getCoupon());
}
public function testDiscount()
{
$setDiscount = $this->faker->randomFloat(2, 1, 20);
$this->itemParameter->setDiscount($setDiscount);
$this->assertEquals($setDiscount, $this->itemParameter->getDiscount());
}
public function testItemVariant()
{
$setItemVariant = $this->faker->colorName;
$this->itemParameter->setItemVariant($setItemVariant);
$this->assertEquals($setItemVariant, $this->itemParameter->getItemVariant());
}
public function testSetItemBrand()
{
$setItemBrand = $this->faker->company;
$this->itemParameter->setItemBrand($setItemBrand);
$this->assertEquals($setItemBrand, $this->itemParameter->getItemBrand());
}
public function testValidateSuccess()
{
$validatedParameter = new ItemParameter(['item_name' => 'test1']);
$this->assertTrue($validatedParameter->validate());
}
public function testValidateError()
{
$validatedParameter = new ItemParameter(['price' => 15.55]);
$this->expectException(ValidationException::class);
$validatedParameter->validate();
}
public function testHydrate()
{
$blueprint = [
'item_id' => $this->faker->name,
'item_name' => $this->faker->name,
'affiliation' => $this->faker->name,
'coupon' => $this->faker->name,
'currency' => $this->faker->currencyCode,
'discount' => $this->faker->randomFloat(2, 10, 30),
'index' => $this->faker->numberBetween(1, 5),
'item_brand' => $this->faker->company,
'item_category' => $this->faker->name,
'item_category2' => $this->faker->name,
'item_category3' => $this->faker->name,
'item_category4' => $this->faker->name,
'item_category5' => $this->faker->name,
'item_list_id' => $this->faker->name,
'item_list_name' => $this->faker->name,
'item_variant' => $this->faker->name,
'location_id' => $this->faker->name,
'price' => $this->faker->randomFloat(2, 10, 1000),
'quantity' => $this->faker->numberBetween(1, 3)
];
$constructedItemParameter = new ItemParameter();
$constructedItemParameter->hydrate($blueprint);
$this->assertEquals($blueprint['item_id'], $constructedItemParameter->getItemId());
$this->assertEquals($blueprint['item_name'], $constructedItemParameter->getItemName());
$this->assertEquals($blueprint['affiliation'], $constructedItemParameter->getAffiliation());
$this->assertEquals($blueprint['coupon'], $constructedItemParameter->getCoupon());
$this->assertEquals($blueprint['currency'], $constructedItemParameter->getCurrency());
$this->assertEquals($blueprint['discount'], $constructedItemParameter->getDiscount());
$this->assertEquals($blueprint['index'], $constructedItemParameter->getIndex());
$this->assertEquals($blueprint['item_brand'], $constructedItemParameter->getItemBrand());
$this->assertEquals($blueprint['item_category'], $constructedItemParameter->getItemCategory());
$this->assertEquals($blueprint['item_category2'], $constructedItemParameter->getItemCategory2());
$this->assertEquals($blueprint['item_category3'], $constructedItemParameter->getItemCategory3());
$this->assertEquals($blueprint['item_category4'], $constructedItemParameter->getItemCategory4());
$this->assertEquals($blueprint['item_category5'], $constructedItemParameter->getItemCategory5());
$this->assertEquals($blueprint['item_list_id'], $constructedItemParameter->getItemListId());
$this->assertEquals($blueprint['item_list_name'], $constructedItemParameter->getItemListName());
$this->assertEquals($blueprint['item_variant'], $constructedItemParameter->getItemVariant());
$this->assertEquals($blueprint['location_id'], $constructedItemParameter->getLocationId());
$this->assertEquals($blueprint['price'], $constructedItemParameter->getPrice());
$this->assertEquals($blueprint['quantity'], $constructedItemParameter->getQuantity());
}
public function testExport()
{
$blueprint = [
'item_id' => $this->faker->name,
'item_name' => $this->faker->name,
'affiliation' => $this->faker->name,
'coupon' => $this->faker->name,
'currency' => $this->faker->currencyCode,
'discount' => $this->faker->randomFloat(2, 10, 30),
'index' => $this->faker->numberBetween(1, 5),
'item_brand' => $this->faker->company,
'item_category' => $this->faker->name,
'item_category2' => $this->faker->name,
'item_category3' => $this->faker->name,
'item_category4' => $this->faker->name,
'item_category5' => $this->faker->name,
'item_list_id' => $this->faker->name,
'item_list_name' => $this->faker->name,
'item_variant' => $this->faker->name,
'location_id' => $this->faker->name,
'price' => $this->faker->randomFloat(2, 10, 1000),
'quantity' => $this->faker->numberBetween(1, 3)
];
$constructedItemParameter = new ItemParameter($blueprint);
$this->assertEquals($blueprint, $constructedItemParameter->export());
}
protected function setUp(): void
{
parent::setUp();
$this->itemParameter = new ItemParameter();
}
}

View File

@@ -0,0 +1,208 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 22.06.2021
* Time: 16:06
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Request;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\EventCollection;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\UserProperties;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\UserProperty;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\BaseEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Parameter\BaseParameter;
use Br33f\Ga4\MeasurementProtocol\Dto\Request\BaseRequest;
use Br33f\Ga4\MeasurementProtocol\Enum\ErrorCode;
use Tests\Common\BaseTestCase;
class BaseRequestTest extends BaseTestCase
{
/**
* @var BaseRequest
*/
protected $baseRequest;
public function testDefaultConstructor()
{
$constructedBaseRequest = new BaseRequest();
$this->assertNotNull($constructedBaseRequest);
}
public function testAbstractEventConstructor()
{
$event = new BaseEvent();
$constructedBaseRequest = new BaseRequest(null, $event);
$this->assertNotNull($constructedBaseRequest);
$this->assertCount(1, $constructedBaseRequest->getEvents()->getEventList());
$this->assertEquals($event, $constructedBaseRequest->getEvents()->getEventList()[0]);
}
public function testClientId()
{
$setClientId = $this->faker->asciify('********************.********************');
$this->baseRequest->setClientId($setClientId);
$this->assertEquals($setClientId, $this->baseRequest->getClientId());
}
public function testUserId()
{
$setUserId = $this->faker->asciify('*********');
$this->baseRequest->setUserId($setUserId);
$this->assertEquals($setUserId, $this->baseRequest->getUserId());
}
public function testTimestampMicros()
{
$setTimestampMicros = $this->faker->unixTime * 1000;
$this->baseRequest->setTimestampMicros($setTimestampMicros);
$this->assertEquals($setTimestampMicros, $this->baseRequest->getTimestampMicros());
}
public function testNonPersonalizedAds()
{
$this->baseRequest->setNonPersonalizedAds(true);
$this->assertEquals(true, $this->baseRequest->isNonPersonalizedAds());
$this->baseRequest->setNonPersonalizedAds(false);
$this->assertEquals(false, $this->baseRequest->isNonPersonalizedAds());
}
public function testUserProperties()
{
$setUserProperties = new UserProperties();
$this->baseRequest->setUserProperties($setUserProperties);
$this->assertEquals($setUserProperties, $this->baseRequest->getUserProperties());
}
public function testAddUserProperty()
{
$addUserProperty = new UserProperty($this->faker->word, $this->faker->word);
$this->baseRequest->addUserProperty($addUserProperty);
$this->assertEquals(1, count($this->baseRequest->getUserProperties()->getUserPropertiesList()));
$this->assertEquals($addUserProperty, $this->baseRequest->getUserProperties()->getUserPropertiesList()[0]);
}
public function testEvents()
{
$setEvents = new EventCollection();
$event = new BaseEvent($this->faker->word);
$event->addParam($this->faker->word, new BaseParameter($this->faker->word));
$setEvents->addEvent($event);
$this->baseRequest->setEvents($setEvents);
$this->assertEquals($setEvents, $this->baseRequest->getEvents());
}
public function testAddEvent()
{
$this->baseRequest->setEvents(new EventCollection());
$event = new BaseEvent($this->faker->word);
$event->addParam($this->faker->word, new BaseParameter($this->faker->word));
$this->baseRequest->addEvent($event);
$this->assertEquals(1, count($this->baseRequest->getEvents()->getEventList()));
$this->assertEquals($event, $this->baseRequest->getEvents()->getEventList()[0]);
}
public function testValidateClientIdRequiredFailed()
{
$newBaseRequest = new BaseRequest();
$this->expectExceptionCode(ErrorCode::VALIDATION_CLIENT_ID_REQUIRED);
$newBaseRequest->validate('web');
}
public function testValidateAppInstanceIdRequiredFailed()
{
$newBaseRequest = new BaseRequest();
$this->expectExceptionCode(ErrorCode::VALIDATION_APP_INSTANCE_ID_REQUIRED);
$newBaseRequest->validate('firebase');
}
public function testValidateBothClientIdAppInstanceIdRequiredFailed()
{
$newBaseRequest = new BaseRequest();
$setAppInstanceId = $this->faker->bothify('**-########');
$setFirebaseId = $this->faker->bothify('**-########');
$newBaseRequest->setAppInstanceId($setAppInstanceId);
$newBaseRequest->setClientId($setFirebaseId);
$this->expectExceptionCode(ErrorCode::VALIDATION_CLIENT_IDENTIFIER_MISCONFIGURED);
$newBaseRequest->validate();
}
public function testValidateSuccess()
{
$setClientId = $this->faker->asciify('********************.********************');
$setEventCollection = new EventCollection();
$event = new BaseEvent($this->faker->word);
$event->addParam($this->faker->word, new BaseParameter($this->faker->word));
$setEventCollection->addEvent($event);
$newBaseRequest = new BaseRequest($setClientId, $setEventCollection);
$this->assertTrue($newBaseRequest->validate());
}
public function testExportOnlyRequiredParameters()
{
$setClientId = $this->faker->asciify('********************.********************');
$setEventCollection = new EventCollection();
$event = new BaseEvent($this->faker->word);
$event->addParam($this->faker->word, new BaseParameter($this->faker->word));
$setEventCollection->addEvent($event);
$exportBaseRequest = new BaseRequest($setClientId, $setEventCollection);
$this->assertEquals([
'client_id' => $setClientId,
'events' => $setEventCollection->export(),
], $exportBaseRequest->export());
}
public function testExportAllParameters()
{
$setClientId = $this->faker->asciify('********************.********************');
$setEventCollection = new EventCollection();
$event = new BaseEvent($this->faker->word);
$event->addParam($this->faker->word, new BaseParameter($this->faker->word));
$setEventCollection->addEvent($event);
$exportBaseRequest = new BaseRequest($setClientId, $setEventCollection);
$setUserId = $this->faker->asciify('************');
$exportBaseRequest->setUserId($setUserId);
$setTimestampMicros = $this->faker->unixTime * 1000;
$exportBaseRequest->setTimestampMicros($setTimestampMicros);
$setUserProperties = new UserProperties();
$exportBaseRequest->setUserProperties($setUserProperties);
$this->assertEquals([
'client_id' => $setClientId,
'events' => $setEventCollection->export(),
'user_id' => $setUserId,
'timestamp_micros' => $setTimestampMicros,
'user_properties' => $setUserProperties->export()
], $exportBaseRequest->export());
}
protected function setUp(): void
{
parent::setUp();
$this->baseRequest = new BaseRequest();
}
}

View File

@@ -0,0 +1,68 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 24.06.2021
* Time: 14:25
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Response;
use Br33f\Ga4\MeasurementProtocol\Dto\Response\BaseResponse;
use GuzzleHttp7\Psr7\Response;
use Tests\Common\BaseTestCase;
class BaseResponseTest extends BaseTestCase
{
/**
* @var BaseResponse
*/
protected $baseResponse;
public function testDefaultConstructor()
{
$constructedBaseResponse = new BaseResponse();
$this->assertNotNull($constructedBaseResponse);
}
public function testBlueprintConstructor()
{
$response = new Response(200, [], '{"test_field": {"value": "123"}}');
$constructedBaseResponse = new BaseResponse($response);
$this->assertNotNull($constructedBaseResponse);
$this->assertEquals(200, $constructedBaseResponse->getStatusCode());
$this->assertEquals('{"test_field": {"value": "123"}}', $constructedBaseResponse->getBody());
}
public function testStatusCode()
{
$setStatusCode = 204;
$this->baseResponse->setStatusCode($setStatusCode);
$this->assertEquals(204, $this->baseResponse->getStatusCode());
}
public function testData()
{
$setBody = '{"test_field": {"value": "321"}}';
$this->baseResponse->setBody($setBody);
$this->assertEquals($setBody, $this->baseResponse->getBody());
$this->assertEquals(json_decode($setBody, true), $this->baseResponse->getData());
}
public function testBody()
{
$setBody = '{"test_field": {"value": "321"}}';
$this->baseResponse->setBody($setBody);
$this->assertEquals($setBody, $this->baseResponse->getBody());
}
protected function setUp(): void
{
parent::setUp();
$this->baseResponse = new BaseResponse();
}
}

View File

@@ -0,0 +1,66 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 24.06.2021
* Time: 14:25
*/
namespace Tests\Ga4\MeasurementProtocol\Dto\Response;
use Br33f\Ga4\MeasurementProtocol\Dto\Common\ValidationMessage;
use Br33f\Ga4\MeasurementProtocol\Dto\Response\DebugResponse;
use GuzzleHttp7\Psr7\Response;
use Tests\Common\BaseTestCase;
class DebugResponseTest extends BaseTestCase
{
/**
* @var DebugResponse
*/
protected $debugResponse;
public function testDefaultConstructor()
{
$constructedDebugResponse = new DebugResponse();
$this->assertNotNull($constructedDebugResponse);
}
public function testBlueprintConstructor()
{
$response = new Response(200, [], '{
"validationMessages": [
{
"description": "Unable to parse Measurement Protocol JSON payload. (events[0]) names: Cannot find field.",
"validationCode": "VALUE_INVALID"
}
]
}');
$parsedValidationMessage = new ValidationMessage(json_decode('{
"description": "Unable to parse Measurement Protocol JSON payload. (events[0]) names: Cannot find field.",
"validationCode": "VALUE_INVALID"
}', true));
$constructedDebugResponse = new DebugResponse($response);
$this->assertNotNull($constructedDebugResponse);
$this->assertEquals(200, $constructedDebugResponse->getStatusCode());
$this->assertEquals(1, count($constructedDebugResponse->getValidationMessages()));
$this->assertEquals($parsedValidationMessage, $constructedDebugResponse->getValidationMessages()[0]);
}
public function testBody()
{
$setValidationMessages = [new ValidationMessage(['fieldPath' => 'test123'])];
$this->debugResponse->setValidationMessages($setValidationMessages);
$this->assertEquals($setValidationMessages, $this->debugResponse->getValidationMessages());
}
protected function setUp(): void
{
parent::setUp();
$this->debugResponse = new DebugResponse();
}
}

View File

@@ -0,0 +1,24 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 23.06.2021
* Time: 12:17
*/
namespace Tests\Ga4\MeasurementProtocol\Exception;
use Br33f\Ga4\MeasurementProtocol\Exception\HydrationException;
use Tests\Common\BaseTestCase;
class HydrationExceptionTest extends BaseTestCase
{
public function test__construct()
{
$setMessage = $this->faker->word;
$setCode = $this->faker->numerify('#######');
$constructedValidationException = new HydrationException($setMessage, $setCode);
$this->assertEquals($setMessage, $constructedValidationException->getMessage());
$this->assertEquals($setCode, $constructedValidationException->getCode());
}
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 23.06.2021
* Time: 12:17
*/
namespace Tests\Ga4\MeasurementProtocol\Exception;
use Br33f\Ga4\MeasurementProtocol\Exception\ValidationException;
use Tests\Common\BaseTestCase;
class ValidationExceptionTest extends BaseTestCase
{
public function test__construct()
{
$setMessage = $this->faker->word;
$setCode = $this->faker->numerify('#######');
$setFieldName = $this->faker->word;
$constructedValidationException = new ValidationException($setMessage, $setCode, $setFieldName);
$this->assertEquals($setMessage, $constructedValidationException->getMessage());
$this->assertEquals($setCode, $constructedValidationException->getCode());
$this->assertEquals($setFieldName, $constructedValidationException->getFieldName());
}
public function testFieldName()
{
$setFieldName = $this->faker->word;
$constructedValidationException = new ValidationException();
$constructedValidationException->setFieldName($setFieldName);
$this->assertEquals($setFieldName, $constructedValidationException->getFieldName());
}
}

View File

@@ -0,0 +1,75 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 23.06.2021
* Time: 12:23
*/
namespace Tests\Ga4\MeasurementProtocol;
use Br33f\Ga4\MeasurementProtocol\HttpClient;
use GuzzleHttp7\Client;
use GuzzleHttp7\Handler\MockHandler;
use GuzzleHttp7\HandlerStack;
use GuzzleHttp7\Psr7\Response;
use Tests\Common\BaseTestCase;
class HttpClientTest extends BaseTestCase
{
/**
* @var HttpClient
*/
protected $httpClient;
public function testDefaultConstructor()
{
$constructedHttpClient = new HttpClient();
$this->assertNotNull($constructedHttpClient);
}
public function testClient()
{
$setClient = new Client();
$this->httpClient->setClient($setClient);
$this->assertEquals($setClient, $this->httpClient->getClient());
}
public function testGetClientWhenNotSet()
{
$emptyHttpClient = new HttpClient();
$this->assertNotNull($emptyHttpClient->getClient());
}
public function testPost()
{
$mock = new MockHandler([
new Response(204),
new Response(403),
new Response(500)
]);
$handlerStack = HandlerStack::create($mock);
$mockClient = new Client(['handler' => $handlerStack]);
$newHttpClient = new HttpClient();
$newHttpClient->setClient($mockClient);
$response = $newHttpClient->post($this->faker->url, []);
$this->assertEquals(204, $response->getStatusCode());
$response = $newHttpClient->post($this->faker->url, []);
$this->assertEquals(403, $response->getStatusCode());
$response = $newHttpClient->post($this->faker->url, []);
$this->assertEquals(500, $response->getStatusCode());
}
protected function setUp(): void
{
parent::setUp();
$this->httpClient = new HttpClient();
}
}

View File

@@ -0,0 +1,264 @@
<?php
/**
* User: Damian Zamojski (br33f)
* Date: 23.06.2021
* Time: 14:42
*/
namespace Tests\Ga4\MeasurementProtocol;
use Br33f\Ga4\MeasurementProtocol\Dto\Event\BaseEvent;
use Br33f\Ga4\MeasurementProtocol\Dto\Request\BaseRequest;
use Br33f\Ga4\MeasurementProtocol\Dto\Response\AbstractResponse;
use Br33f\Ga4\MeasurementProtocol\Dto\Response\DebugResponse;
use Br33f\Ga4\MeasurementProtocol\Exception\MisconfigurationException;
use Br33f\Ga4\MeasurementProtocol\HttpClient;
use Br33f\Ga4\MeasurementProtocol\Service;
use GuzzleHttp7\Client;
use GuzzleHttp7\Handler\MockHandler;
use GuzzleHttp7\HandlerStack;
use GuzzleHttp7\Psr7\Response;
use Tests\Common\BaseTestCase;
class ServiceTest extends BaseTestCase
{
/**
* @var Service
*/
protected $service;
public function testConstructor()
{
$setApiSecret = $this->faker->word;
$setMeasurementId = $this->faker->bothify('**-########');
$constructedService = new Service($setApiSecret, $setMeasurementId);
$this->assertEquals($setApiSecret, $constructedService->getApiSecret());
$this->assertEquals($setMeasurementId, $constructedService->getMeasurementId());
}
public function testUseSsl()
{
$this->service->setUseSsl(true);
$this->assertTrue($this->service->isUseSsl());
$this->service->setUseSsl(false);
$this->assertFalse($this->service->isUseSsl());
}
public function testUsewww()
{
$this->service->setUseWww(true);
$this->assertTrue($this->service->isUseWww());
$this->service->setUseWww(false);
$this->assertFalse($this->service->isUseWww());
}
public function testCollectEndpoint()
{
$setCollectEndpoint = str_replace('https://', '', $this->faker->url);
$setCollectEndpoint = str_replace('http://', '', $setCollectEndpoint);
$this->service->setCollectEndpoint($setCollectEndpoint);
$this->assertEquals($setCollectEndpoint, $this->service->getCollectEndpoint());
}
public function testCollectDebugEndpoint()
{
$setCollectDebugEndpoint = str_replace('https://', '', $this->faker->url);
$setCollectDebugEndpoint = str_replace('http://', '', $setCollectDebugEndpoint);
$this->service->setCollectDebugEndpoint($setCollectDebugEndpoint);
$this->assertEquals($setCollectDebugEndpoint, $this->service->getCollectDebugEndpoint());
}
public function testMeasurementId()
{
$setMeasurementId = $this->faker->bothify('**-########');
$this->service->setMeasurementId($setMeasurementId);
$this->assertEquals($setMeasurementId, $this->service->getMeasurementId());
}
public function testSetApiSecret()
{
$setApiSecret = $this->faker->word;
$this->service->setApiSecret($setApiSecret);
$this->assertEquals($setApiSecret, $this->service->getApiSecret());
}
public function testHttpClient()
{
$setHttpClient = new HttpClient();
$this->service->setHttpClient($setHttpClient);
$this->assertEquals($setHttpClient, $this->service->getHttpClient());
}
public function testHttpClientWhenEmpty()
{
$setApiSecret = $this->faker->word;
$setMeasurementId = $this->faker->bothify('**-########');
$constructedService = new Service($setApiSecret, $setMeasurementId);
$this->assertNotNull($constructedService->getHttpClient());
}
public function testEndpoint()
{
$setApiSecret = $this->faker->word;
$setMeasurementId = $this->faker->bothify('**-########');
$newService = new Service($setApiSecret, $setMeasurementId);
$setCollectEndpoint = str_replace('https://', '', $this->faker->url);
$setCollectEndpoint = str_replace('http://', '', $setCollectEndpoint);
$newService->setCollectEndpoint($setCollectEndpoint);
$newService->setUseSsl(true);
$getParams = '?' . http_build_query(['api_secret' => $newService->getApiSecret(), 'measurement_id' => $newService->getMeasurementId()]);
$this->assertEquals(Service::SSL_SCHEME . $setCollectEndpoint . $getParams, $newService->getEndpoint());
$newService->setUseSsl(false);
$this->assertEquals(Service::NOT_SSL_SCHEME . $setCollectEndpoint . $getParams, $newService->getEndpoint());
$setCollectDebugEndpoint = str_replace('https://', '', $this->faker->url);
$setCollectDebugEndpoint = str_replace('http://', '', $setCollectDebugEndpoint);
$newService->setCollectDebugEndpoint($setCollectDebugEndpoint);
$newService->setUseSsl(true);
$this->assertEquals(Service::SSL_SCHEME . $setCollectDebugEndpoint . $getParams, $newService->getEndpoint(true));
$newService->setUseSsl(false);
$this->assertEquals(Service::NOT_SSL_SCHEME . $setCollectDebugEndpoint . $getParams, $newService->getEndpoint(true));
}
public function testOptions()
{
$setOptions = [
'timeout' => '25',
'headers' => [
'User-Agent' => 'Test User Agent'
]
];
$this->service->setOptions($setOptions);
$this->assertEquals($setOptions, $this->service->getOptions());
}
public function testSend()
{
$mock = new MockHandler([
new Response(200)
]);
$handlerStack = HandlerStack::create($mock);
$mockClient = new Client(['handler' => $handlerStack]);
$setApiSecret = $this->faker->word;
$setMeasurementId = $this->faker->bothify('**-########');
$sendService = new Service($setApiSecret, $setMeasurementId);
$sendService->getHttpClient()->setClient($mockClient);
$setClientId = $this->faker->asciify('********************.********************');
$sentRequest = new BaseRequest($setClientId);
$event = new BaseEvent($this->faker->word);
$sentRequest->addEvent($event);
$baseResponse = $sendService->send($sentRequest);
$this->assertTrue($baseResponse instanceof AbstractResponse);
$this->assertEquals(200, $baseResponse->getStatusCode());
}
public function testSendWithIpOverride()
{
$mock = new MockHandler([
new Response(200)
]);
$handlerStack = HandlerStack::create($mock);
$mockClient = new Client(['handler' => $handlerStack]);
$setApiSecret = $this->faker->word;
$setMeasurementId = $this->faker->bothify('**-########');
$sendService = new Service($setApiSecret, $setMeasurementId);
$sendService->getHttpClient()->setClient($mockClient);
$sendService->setIpOverride($this->faker->ipv4);
$setClientId = $this->faker->asciify('********************.********************');
$sentRequest = new BaseRequest($setClientId);
$event = new BaseEvent($this->faker->word);
$sentRequest->addEvent($event);
$baseResponse = $sendService->send($sentRequest);
$this->assertTrue($baseResponse instanceof AbstractResponse);
$this->assertEquals(200, $baseResponse->getStatusCode());
}
public function testSendDebugWithError()
{
$mock = new MockHandler([
new Response(200, [], '{
"validationMessages": [
{
"description": "Unable to parse Measurement Protocol JSON payload. (events[0]) names: Cannot find field.",
"validationCode": "VALUE_INVALID"
}
]
}')
]);
$handlerStack = HandlerStack::create($mock);
$mockClient = new Client(['handler' => $handlerStack]);
$setApiSecret = $this->faker->word;
$setMeasurementId = $this->faker->bothify('**-########');
$sendService = new Service($setApiSecret, $setMeasurementId);
$sendService->getHttpClient()->setClient($mockClient);
$setClientId = $this->faker->asciify('********************.********************');
$sentRequest = new BaseRequest($setClientId);
$event = new BaseEvent($this->faker->word);
$sentRequest->addEvent($event);
$debugResponse = $sendService->sendDebug($sentRequest);
$this->assertTrue($debugResponse instanceof DebugResponse);
$this->assertEquals(200, $debugResponse->getStatusCode());
$this->assertEquals(1, count($debugResponse->getValidationMessages()));
}
public function testMisconfigBothInGetQueryParameters()
{
$setApiSecret = $this->faker->word;
$setMeasurementId = $this->faker->bothify('**-########');
$setFirebaseId = $this->faker->bothify('**-########');
$testService = new Service($setApiSecret, $setMeasurementId);
$testService->setFirebaseId($setFirebaseId);
$this->expectException(MisconfigurationException::class);
$testService->getQueryParameters();
}
public function testMisconfigApiSecretEmptyInGetQueryParameters()
{
$setApiSecret = $this->faker->word;
$setMeasurementId = $this->faker->bothify('**-########');
$setFirebaseId = $this->faker->bothify('**-########');
$testService = new Service($setApiSecret, $setMeasurementId);
$testService->setFirebaseId($setFirebaseId);
$this->expectException(MisconfigurationException::class);
$testService->getQueryParameters();
}
protected function setUp(): void
{
parent::setUp();
$this->service = new Service($this->faker->word, $this->faker->bothify('**-########'));
}
}