first commit
This commit is contained in:
553
modules/ps_facebook/classes/Provider/EventDataProvider.php
Normal file
553
modules/ps_facebook/classes/Provider/EventDataProvider.php
Normal file
@@ -0,0 +1,553 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright since 2007 PrestaShop SA and Contributors
|
||||
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License version 3.0
|
||||
* that is bundled with this package in the file LICENSE.md.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* https://opensource.org/licenses/AFL-3.0
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
|
||||
*/
|
||||
|
||||
namespace PrestaShop\Module\PrestashopFacebook\Provider;
|
||||
|
||||
use Cart;
|
||||
use Context;
|
||||
use Order;
|
||||
use PrestaShop\Module\PrestashopFacebook\Adapter\ConfigurationAdapter;
|
||||
use PrestaShop\Module\PrestashopFacebook\Adapter\ToolsAdapter;
|
||||
use PrestaShop\Module\PrestashopFacebook\Repository\GoogleCategoryRepository;
|
||||
use PrestaShop\Module\PrestashopFacebook\Repository\ProductRepository;
|
||||
use PrestaShop\Module\Ps_facebook\Utility\CustomerInformationUtility;
|
||||
use PrestaShop\Module\Ps_facebook\Utility\ProductCatalogUtility;
|
||||
use PrestaShopException;
|
||||
use Product;
|
||||
use Ps_facebook;
|
||||
|
||||
class EventDataProvider
|
||||
{
|
||||
public const PRODUCT_TYPE = 'product';
|
||||
|
||||
public const CATEGORY_TYPE = 'product_group';
|
||||
|
||||
/**
|
||||
* @var Context
|
||||
*/
|
||||
private $context;
|
||||
|
||||
private $locale;
|
||||
|
||||
/**
|
||||
* @var ToolsAdapter
|
||||
*/
|
||||
private $toolsAdapter;
|
||||
|
||||
/**
|
||||
* @var ConfigurationAdapter
|
||||
*/
|
||||
private $configurationAdapter;
|
||||
|
||||
/**
|
||||
* @var ProductRepository
|
||||
*/
|
||||
private $productRepository;
|
||||
|
||||
/**
|
||||
* @var ps_facebook
|
||||
*/
|
||||
private $module;
|
||||
|
||||
/**
|
||||
* @var ProductAvailabilityProviderInterface
|
||||
*/
|
||||
private $availabilityProvider;
|
||||
|
||||
/**
|
||||
* @var GoogleCategoryRepository
|
||||
*/
|
||||
private $googleCategoryRepository;
|
||||
|
||||
/**
|
||||
* @var GoogleCategoryProvider
|
||||
*/
|
||||
private $googleCategoryProvider;
|
||||
|
||||
public function __construct(
|
||||
ToolsAdapter $toolsAdapter,
|
||||
ConfigurationAdapter $configurationAdapter,
|
||||
ProductRepository $productRepository,
|
||||
Context $context,
|
||||
ps_facebook $module,
|
||||
ProductAvailabilityProviderInterface $availabilityProvider,
|
||||
GoogleCategoryRepository $googleCategoryRepository,
|
||||
GoogleCategoryProvider $googleCategoryProvider
|
||||
) {
|
||||
$this->toolsAdapter = $toolsAdapter;
|
||||
$this->context = $context;
|
||||
$this->locale = \Tools::strtoupper($this->context->language->iso_code);
|
||||
$this->configurationAdapter = $configurationAdapter;
|
||||
$this->productRepository = $productRepository;
|
||||
$this->module = $module;
|
||||
$this->availabilityProvider = $availabilityProvider;
|
||||
$this->googleCategoryRepository = $googleCategoryRepository;
|
||||
$this->googleCategoryProvider = $googleCategoryProvider;
|
||||
}
|
||||
|
||||
public function generateEventData($name, array $params)
|
||||
{
|
||||
switch ($name) {
|
||||
case 'hookDisplayHeader':
|
||||
if (true === \Tools::isSubmit('submitCustomizedData')) {
|
||||
return $this->getCustomEventData();
|
||||
}
|
||||
if ($this->context->controller instanceof \ProductControllerCore) {
|
||||
return $this->getProductPageData();
|
||||
}
|
||||
if ($this->context->controller instanceof \CategoryControllerCore) {
|
||||
return $this->getCategoryPageData();
|
||||
}
|
||||
if ($this->context->controller instanceof \CmsControllerCore) {
|
||||
return $this->getCMSPageData();
|
||||
}
|
||||
break;
|
||||
case 'hookActionSearch':
|
||||
return $this->getSearchEventData($params);
|
||||
case 'hookActionObjectCustomerMessageAddAfter':
|
||||
return $this->getContactEventData();
|
||||
case 'hookDisplayOrderConfirmation':
|
||||
return $this->getOrderConfirmationEvent($params);
|
||||
case 'InitiateCheckout':
|
||||
return $this->getInitiateCheckoutEvent();
|
||||
case 'hookActionCartSave':
|
||||
return $this->getAddToCartEventData();
|
||||
case 'hookActionNewsletterRegistrationAfter':
|
||||
return $this->getShopSubscriptionEvent($params);
|
||||
case 'hookActionCustomerAccountAdd':
|
||||
return $this->getCompleteRegistrationEventData();
|
||||
case 'customizeProduct':
|
||||
return $this->getCustomisationEventData($params);
|
||||
case 'hookActionFacebookCallPixel':
|
||||
return $this->getCustomEvent($params);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getProductPageData()
|
||||
{
|
||||
$type = 'ViewContent';
|
||||
|
||||
/** @var \ProductControllerCore $controller */
|
||||
$controller = $this->context->controller;
|
||||
$product = $controller->getTemplateVarProduct();
|
||||
|
||||
$fbProductId = ProductCatalogUtility::makeProductId(
|
||||
$product['id_product'],
|
||||
$product['id_product_attribute']
|
||||
);
|
||||
|
||||
$productUrl = $this->context->link->getProductLink($product['id']);
|
||||
|
||||
$categoryPath = $this->googleCategoryProvider->getCategoryPaths(
|
||||
$product['id_category_default'],
|
||||
$this->context->language->id,
|
||||
$this->context->shop->id
|
||||
);
|
||||
$content = [
|
||||
'id' => $fbProductId,
|
||||
'title' => \Tools::replaceAccentedChars($product['name']),
|
||||
'category' => $categoryPath['category_path'],
|
||||
'item_price' => $product['price_tax_exc'],
|
||||
'brand' => (new \Manufacturer($product['id_manufacturer']))->name,
|
||||
];
|
||||
$customData = [
|
||||
'currency' => $this->getCurrency(),
|
||||
'content_ids' => [$fbProductId],
|
||||
'contents' => [$content],
|
||||
'content_type' => self::PRODUCT_TYPE,
|
||||
'value' => $product['price_tax_exc'],
|
||||
];
|
||||
|
||||
$category = $this->googleCategoryRepository->getGoogleCategoryIdByCategoryId(
|
||||
$product['id_category_default'],
|
||||
$this->context->shop->id
|
||||
) ?: '';
|
||||
|
||||
$this->context->smarty->assign(
|
||||
[
|
||||
'retailer_item_id' => $fbProductId,
|
||||
'product_availability' => $this->availabilityProvider->getProductAvailability(
|
||||
(int) $product['id_product'],
|
||||
(int) $product['id_product_attribute']
|
||||
),
|
||||
'item_group_id' => $category,
|
||||
]
|
||||
);
|
||||
|
||||
return [
|
||||
'custom_data' => $customData,
|
||||
'event_source_url' => $productUrl,
|
||||
] + $this->getCommonData($type);
|
||||
}
|
||||
|
||||
private function getCategoryPageData()
|
||||
{
|
||||
$type = 'ViewCategory';
|
||||
|
||||
/** @var \CategoryControllerCore $controller */
|
||||
$controller = $this->context->controller;
|
||||
$category = $controller->getCategory();
|
||||
|
||||
$page = $this->toolsAdapter->getValue('page');
|
||||
$resultsPerPage = $this->configurationAdapter->get('PS_PRODUCTS_PER_PAGE');
|
||||
|
||||
$prods = $category->getProducts($this->context->language->id, $page, $resultsPerPage);
|
||||
$categoryUrl = $this->context->link->getCategoryLink($category->id);
|
||||
|
||||
$breadcrumbs = $controller->getBreadcrumbLinks();
|
||||
$breadcrumb = implode(' > ', array_column($breadcrumbs['links'], 'title'));
|
||||
|
||||
$contentIds = [];
|
||||
if ($prods) {
|
||||
foreach ($prods as $product) {
|
||||
$contentIds[] = ProductCatalogUtility::makeProductId(
|
||||
$product['id_product'],
|
||||
$product['id_product_attribute']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$customData = [
|
||||
'content_name' => \Tools::replaceAccentedChars($category->name) . ' ' . $this->locale,
|
||||
'content_category' => \Tools::replaceAccentedChars($breadcrumb),
|
||||
'content_type' => self::CATEGORY_TYPE,
|
||||
'content_ids' => $contentIds ?: null,
|
||||
];
|
||||
|
||||
return [
|
||||
'custom_data' => $customData,
|
||||
'event_source_url' => $categoryUrl,
|
||||
] + $this->getCommonData($type);
|
||||
}
|
||||
|
||||
private function getCMSPageData()
|
||||
{
|
||||
$type = 'ViewCMS';
|
||||
$cms = new \CMS((int) $this->toolsAdapter->getValue('id_cms'), $this->context->language->id);
|
||||
|
||||
/** @var \CmsControllerCore $controller */
|
||||
$controller = $this->context->controller;
|
||||
$breadcrumbs = $controller->getBreadcrumbLinks();
|
||||
|
||||
$breadcrumb = implode(' > ', array_column($breadcrumbs['links'], 'title'));
|
||||
|
||||
$customData = [
|
||||
'content_name' => \Tools::replaceAccentedChars($cms->meta_title) . ' ' . $this->locale,
|
||||
'content_category' => \Tools::replaceAccentedChars($breadcrumb),
|
||||
'content_type' => self::PRODUCT_TYPE,
|
||||
];
|
||||
|
||||
return [
|
||||
'custom_data' => $customData,
|
||||
] + $this->getCommonData($type);
|
||||
}
|
||||
|
||||
private function getAddToCartEventData()
|
||||
{
|
||||
$action = $this->toolsAdapter->getValue('action');
|
||||
$quantity = $this->toolsAdapter->getValue('qty');
|
||||
$idProduct = $this->toolsAdapter->getValue('id_product');
|
||||
$op = $this->toolsAdapter->getValue('op');
|
||||
$isDelete = $this->toolsAdapter->getValue('delete');
|
||||
$idProductAttribute = $this->toolsAdapter->getValue('id_product_attribute');
|
||||
$attributeGroups = $this->toolsAdapter->getValue('group');
|
||||
|
||||
if ($attributeGroups) {
|
||||
try {
|
||||
$idProductAttribute = $this->productRepository->getIdProductAttributeByIdAttributes(
|
||||
$idProduct,
|
||||
$attributeGroups
|
||||
);
|
||||
} catch (PrestaShopException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($action !== 'update') {
|
||||
return false;
|
||||
}
|
||||
$type = 'AddToCart';
|
||||
if ($op) {
|
||||
$type = $op === 'up' ? 'IncreaseProductQuantityInCart' : 'DecreaseProductQuantityInCart';
|
||||
} elseif ($isDelete) {
|
||||
//todo: when removing product from cart this hook gets called twice
|
||||
$type = 'RemoveProductFromCart';
|
||||
$quantity = null;
|
||||
}
|
||||
|
||||
$productName = Product::getProductName($idProduct, $idProductAttribute);
|
||||
|
||||
$customData = [
|
||||
'content_name' => pSQL($productName),
|
||||
'content_type' => self::PRODUCT_TYPE,
|
||||
'content_ids' => [
|
||||
ProductCatalogUtility::makeProductId(
|
||||
$idProduct,
|
||||
$idProductAttribute
|
||||
),
|
||||
],
|
||||
'num_items' => pSQL($quantity),
|
||||
];
|
||||
|
||||
return [
|
||||
'custom_data' => $customData,
|
||||
] + $this->getCommonData($type);
|
||||
}
|
||||
|
||||
private function getCompleteRegistrationEventData()
|
||||
{
|
||||
$type = 'CompleteRegistration';
|
||||
|
||||
$customData = [
|
||||
'content_name' => 'authentication',
|
||||
];
|
||||
|
||||
return [
|
||||
'custom_data' => $customData,
|
||||
] + $this->getCommonData($type);
|
||||
}
|
||||
|
||||
private function getContactEventData()
|
||||
{
|
||||
return $this->getCommonData('Contact');
|
||||
}
|
||||
|
||||
private function getCustomisationEventData($params)
|
||||
{
|
||||
$type = 'CombinationProduct';
|
||||
|
||||
$idLang = (int) $this->context->language->id;
|
||||
$productId = $this->toolsAdapter->getValue('id_product');
|
||||
$attributeIds = $params['attributeIds'];
|
||||
$customData = $this->getCustomAttributeData($productId, $idLang, $attributeIds);
|
||||
|
||||
return [
|
||||
'custom_data' => $customData,
|
||||
] + $this->getCommonData($type);
|
||||
}
|
||||
|
||||
private function getCustomEventData()
|
||||
{
|
||||
return $this->getCommonData('CustomizeProduct');
|
||||
}
|
||||
|
||||
private function getSearchEventData($params)
|
||||
{
|
||||
$searchQuery = $params['searched_query'];
|
||||
$quantity = $params['total'];
|
||||
|
||||
$type = 'Search';
|
||||
|
||||
$customData = [
|
||||
'content_name' => 'searchQuery',
|
||||
'search_string' => $searchQuery,
|
||||
];
|
||||
|
||||
if ($quantity) {
|
||||
$customData['num_items'] = $quantity;
|
||||
}
|
||||
|
||||
return [
|
||||
'custom_data' => $customData,
|
||||
] + $this->getCommonData($type);
|
||||
}
|
||||
|
||||
private function getOrderConfirmationEvent($params)
|
||||
{
|
||||
/** @var Order $order */
|
||||
$order = $this->module->psVersionIs17 ? $params['order'] : $params['objOrder'];
|
||||
$productList = [];
|
||||
foreach ($order->getCartProducts() as $product) {
|
||||
$productList[] = ProductCatalogUtility::makeProductId(
|
||||
$product['id_product'],
|
||||
$product['id_product_attribute']
|
||||
);
|
||||
}
|
||||
|
||||
$type = 'Purchase';
|
||||
|
||||
$customData = [
|
||||
'content_name' => 'purchased',
|
||||
'order_id' => $order->id,
|
||||
'currency' => $this->getCurrency(),
|
||||
'content_ids' => $productList,
|
||||
'content_type' => self::PRODUCT_TYPE,
|
||||
'value' => (float) ($order->total_paid_tax_excl),
|
||||
];
|
||||
|
||||
return [
|
||||
'custom_data' => $customData,
|
||||
] + $this->getCommonData($type);
|
||||
}
|
||||
|
||||
private function getInitiateCheckoutEvent()
|
||||
{
|
||||
$type = 'InitiateCheckout';
|
||||
|
||||
$cart = $this->context->cart;
|
||||
$contents = $this->getProductContent($cart);
|
||||
|
||||
$customData = [
|
||||
'contents' => $contents,
|
||||
'content_type' => 'product',
|
||||
'currency' => $this->getCurrency(),
|
||||
'value' => $cart->getOrderTotal(false),
|
||||
];
|
||||
|
||||
return [
|
||||
'custom_data' => $customData,
|
||||
] + $this->getCommonData($type);
|
||||
}
|
||||
|
||||
private function getShopSubscriptionEvent($params)
|
||||
{
|
||||
$type = 'Subscribe';
|
||||
|
||||
$customData = [
|
||||
'content_name' => pSQL($params['email']),
|
||||
];
|
||||
|
||||
return [
|
||||
'custom_data' => $customData,
|
||||
] + $this->getCommonData($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Cart $cart
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getProductContent(Cart $cart)
|
||||
{
|
||||
$contents = [];
|
||||
foreach ($cart->getProducts() as $product) {
|
||||
$categoryPath = $this->googleCategoryProvider->getCategoryPaths(
|
||||
$product['id_category_default'],
|
||||
$this->context->language->id,
|
||||
$this->context->shop->id
|
||||
);
|
||||
$content = [
|
||||
'id' => ProductCatalogUtility::makeProductId($product['id_product'], $product['id_product_attribute']),
|
||||
'quantity' => $product['quantity'],
|
||||
'item_price' => $product['price'],
|
||||
'title' => \Tools::replaceAccentedChars($product['name']),
|
||||
'brand' => (new \Manufacturer($product['id_manufacturer']))->name,
|
||||
'category' => $categoryPath['category_path'],
|
||||
];
|
||||
$contents[] = $content;
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function getCustomEvent($params)
|
||||
{
|
||||
if (!isset($params['eventName']) || !isset($params['module'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$type = pSQL($params['eventName']);
|
||||
|
||||
$customData = [
|
||||
'custom_properties' => [
|
||||
'module' => pSQL($params['module']),
|
||||
],
|
||||
];
|
||||
|
||||
if (isset($params['id_product'])) {
|
||||
$fbProductId = ProductCatalogUtility::makeProductId(
|
||||
$params['id_product'],
|
||||
isset($params['id_product_attribute']) ? $params['id_product_attribute'] : 0
|
||||
);
|
||||
$customData['content_ids']['module'] = $fbProductId;
|
||||
}
|
||||
|
||||
return [
|
||||
'custom_data' => $customData,
|
||||
] + $this->getCommonData($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $productId
|
||||
* @param int $idLang
|
||||
* @param int[] $attributeIds
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \PrestaShopException
|
||||
*/
|
||||
private function getCustomAttributeData($productId, $idLang, $attributeIds)
|
||||
{
|
||||
$attributes = [];
|
||||
foreach ($attributeIds as $attributeId) {
|
||||
$attributes[] = (new \AttributeCore($attributeId, $idLang))->name;
|
||||
}
|
||||
|
||||
try {
|
||||
$idProductAttribute = $this->productRepository->getIdProductAttributeByIdAttributes(
|
||||
$productId,
|
||||
$attributeIds
|
||||
);
|
||||
} catch (PrestaShopException $e) {
|
||||
$idProductAttribute = 0;
|
||||
}
|
||||
|
||||
return [
|
||||
'content_type' => self::PRODUCT_TYPE,
|
||||
'content_ids' => [
|
||||
ProductCatalogUtility::makeProductId($productId, $idProductAttribute),
|
||||
],
|
||||
'custom_properties' => [
|
||||
'custom_attributes' => $attributes,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the array with data that are used for all events
|
||||
*
|
||||
* @see https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events
|
||||
*
|
||||
* @param string $eventType
|
||||
*/
|
||||
private function getCommonData($eventType)
|
||||
{
|
||||
$time = time();
|
||||
|
||||
return [
|
||||
'event_type' => $eventType,
|
||||
'event_time' => $time,
|
||||
'user' => CustomerInformationUtility::getCustomerInformationForPixel($this->context->customer),
|
||||
'eventID' => uniqid($eventType . '_' . $time . '_', true),
|
||||
];
|
||||
}
|
||||
|
||||
private function getCurrency()
|
||||
{
|
||||
return \Tools::strtolower($this->context->currency->iso_code);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user