diff --git a/CustomerData/Customer/CustomerPlugin.php b/CustomerData/Customer/CustomerPlugin.php
new file mode 100644
index 0000000..206fbfe
--- /dev/null
+++ b/CustomerData/Customer/CustomerPlugin.php
@@ -0,0 +1,112 @@
+.
+ */
+
+namespace Henhed\Piwik\CustomerData\Customer;
+
+/**
+ * Plugin for \Magento\Customer\CustomerData\Customer
+ *
+ */
+class CustomerPlugin
+{
+
+ /**
+ * Current customer helper
+ *
+ * @var \Magento\Customer\Helper\Session\CurrentCustomer $_currentCustomer
+ */
+ protected $_currentCustomer;
+
+ /**
+ * Piwik data helper
+ *
+ * @var \Henhed\Piwik\Helper\Data $_dataHelper
+ */
+ protected $_dataHelper;
+
+ /**
+ * User ID provider pool
+ *
+ * @var \Henhed\Piwik\UserId\Provider\Pool $_uidProviderPool
+ */
+ protected $_uidProviderPool;
+
+ /**
+ * Constructor
+ *
+ * @param \Magento\Customer\Helper\Session\CurrentCustomer $currentCustomer
+ * @param \Henhed\Piwik\Helper\Data $dataHelper
+ * @param \Henhed\Piwik\UserId\Provider\Pool $uidProviderPool
+ */
+ public function __construct(
+ \Magento\Customer\Helper\Session\CurrentCustomer $currentCustomer,
+ \Henhed\Piwik\Helper\Data $dataHelper,
+ \Henhed\Piwik\UserId\Provider\Pool $uidProviderPool
+ ) {
+ $this->_currentCustomer = $currentCustomer;
+ $this->_dataHelper = $dataHelper;
+ $this->_uidProviderPool = $uidProviderPool;
+ }
+
+ /**
+ * Get configured Piwik User ID provider or NULL
+ *
+ * @return \Henhed\Piwik\UserId\Provider\ProviderInterface|null
+ */
+ protected function _getUserIdProvider()
+ {
+ $code = $this->_dataHelper->getUserIdProviderCode();
+ return $code ? $this->_uidProviderPool->getProviderByCode($code) : null;
+ }
+
+ /**
+ * Get Piwik User ID for current customer
+ *
+ * @return string
+ */
+ protected function _getUserId()
+ {
+ $provider = $this->_getUserIdProvider();
+ $customerId = $this->_currentCustomer->getCustomerId();
+ return ($provider && $customerId)
+ ? (string) $provider->getUserId($customerId)
+ : '';
+ }
+
+ /**
+ * Add visitor related tracker information to customer section data.
+ *
+ * @param \Magento\Customer\CustomerData\Customer $subject
+ * @param array $result
+ * @return array
+ */
+ public function afterGetSectionData(
+ \Magento\Customer\CustomerData\Customer $subject,
+ $result
+ ) {
+ if ($this->_dataHelper->isTrackingEnabled()) {
+ $userId = $this->_getUserId();
+ if ($userId !== '') {
+ $result['piwikUserId'] = $userId;
+ }
+ }
+ return $result;
+ }
+}
diff --git a/Helper/Data.php b/Helper/Data.php
index d00122d..d192691 100644
--- a/Helper/Data.php
+++ b/Helper/Data.php
@@ -40,6 +40,7 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
const XML_PATH_SITE_ID = 'piwik/tracking/site_id';
const XML_PATH_LINK_ENABLED = 'piwik/tracking/link_enabled';
const XML_PATH_LINK_DELAY = 'piwik/tracking/link_delay';
+ const XML_PATH_UID_PROVIDER = 'piwik/tracking/uid_provider';
/**
* Check if Piwik is enabled
@@ -233,4 +234,19 @@ public function getLinkTrackingDelay($store = null)
$store
);
}
+
+ /**
+ * Get provider code for Piwik user ID tracking
+ *
+ * @param null|string|bool|int|Store $store
+ * @return string
+ */
+ public function getUserIdProviderCode($store = null)
+ {
+ return $this->scopeConfig->getValue(
+ self::XML_PATH_UID_PROVIDER,
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
+ $store
+ );
+ }
}
diff --git a/Model/Config/Source/UserId/Provider.php b/Model/Config/Source/UserId/Provider.php
new file mode 100644
index 0000000..10fef6a
--- /dev/null
+++ b/Model/Config/Source/UserId/Provider.php
@@ -0,0 +1,63 @@
+.
+ */
+
+namespace Henhed\Piwik\Model\Config\Source\UserId;
+
+/**
+ * User ID provider config source model
+ *
+ */
+class Provider implements \Magento\Framework\Option\ArrayInterface
+{
+
+ /**
+ * User ID provider pool
+ *
+ * @var \Henhed\Piwik\UserId\Provider\Pool $_pool
+ */
+ protected $_pool;
+
+ /**
+ * Constructor
+ *
+ * @param \Henhed\Piwik\UserId\Provider\Pool $pool
+ */
+ public function __construct(\Henhed\Piwik\UserId\Provider\Pool $pool)
+ {
+ $this->_pool = $pool;
+ }
+
+ /**
+ * Return array of user ID providers as value-label pairs
+ *
+ * @return array
+ */
+ public function toOptionArray()
+ {
+ $options = [['value' => '', 'label' => __('No')]];
+ foreach ($this->_pool->getAllProviders() as $code => $provider) {
+ $options[] = [
+ 'value' => $code,
+ 'label' => sprintf('%s (%s)', __('Yes'), $provider->getTitle())
+ ];
+ }
+ return $options;
+ }
+}
diff --git a/Test/Unit/CustomerData/Customer/CustomerPluginTest.php b/Test/Unit/CustomerData/Customer/CustomerPluginTest.php
new file mode 100644
index 0000000..79b0918
--- /dev/null
+++ b/Test/Unit/CustomerData/Customer/CustomerPluginTest.php
@@ -0,0 +1,175 @@
+.
+ */
+
+namespace Henhed\Piwik\Test\Unit\CustomerData\Customer;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+/**
+ * Test for \Henhed\Piwik\CustomerData\Customer\CustomerPlugin
+ *
+ */
+class CustomerPluginTest extends \PHPUnit_Framework_TestCase
+{
+
+ /**
+ * Customer data plugin (test subject) instance
+ *
+ * @var \Henhed\Piwik\CustomerData\Customer\CustomerPlugin $_customerPlugin
+ */
+ protected $_customerPlugin;
+
+ /**
+ * Current customer helper mock object
+ *
+ * @var \PHPUnit_Framework_MockObject_MockObject $_currentCustomerMock
+ */
+ protected $_currentCustomerMock;
+
+ /**
+ * Piwik data helper mock object
+ *
+ * @var \PHPUnit_Framework_MockObject_MockObject $_dataHelperMock
+ */
+ protected $_dataHelperMock;
+
+ /**
+ * Piwik user ID provider pool mock object
+ *
+ * @var \PHPUnit_Framework_MockObject_MockObject $_uidProviderPoolMock
+ */
+ protected $_uidProviderPoolMock;
+
+ /**
+ * Piwik user ID provider mock object
+ *
+ * @var \PHPUnit_Framework_MockObject_MockObject $_uidProviderMock
+ */
+ protected $_uidProviderMock;
+
+ /**
+ * Customer data mock object
+ *
+ * @var \PHPUnit_Framework_MockObject_MockObject $_customerDataMock
+ */
+ protected $_customerDataMock;
+
+ /**
+ * Set up
+ *
+ * @return void
+ */
+ public function setUp()
+ {
+ $className = 'Henhed\Piwik\CustomerData\Customer\CustomerPlugin';
+ $objectManager = new ObjectManager($this);
+ $args = $objectManager->getConstructArguments($className);
+ $this->_customerPlugin = $objectManager->getObject($className, $args);
+ $this->_currentCustomerMock = $args['currentCustomer'];
+ $this->_dataHelperMock = $args['dataHelper'];
+ $this->_uidProviderPoolMock = $args['uidProviderPool'];
+ $this->_uidProviderMock = $this->getMock(
+ 'Henhed\Piwik\UserId\Provider\ProviderInterface',
+ ['getUserId', 'getTitle'], [], '', false
+ );
+ $this->_customerDataMock = $this->getMock(
+ 'Magento\Customer\CustomerData\Customer', [], [], '', false
+ );
+ }
+
+ /**
+ * Data provider for `testafterGetSectionData'
+ *
+ * @return array
+ */
+ public function testafterGetSectionDataDataProvider()
+ {
+ return [
+ [false, 1, 'p', 'UID1'],
+ [true, null, 'p', 'UID2'],
+ [true, 3, 'p', ''],
+ [true, 4, null, 'UID4'],
+ [true, 5, 'p', 'UID5']
+ ];
+ }
+
+ /**
+ * Test `afterGetSectionData'
+ *
+ * @param boolean $enabled
+ * @param int $customerId
+ * @param string|null $provider
+ * @param string $userId
+ * @return void
+ * @dataProvider testafterGetSectionDataDataProvider
+ */
+ public function testafterGetSectionData(
+ $enabled, $customerId, $provider, $userId
+ ) {
+ $expectedResult = [];
+ if ($enabled && $customerId && $provider && $userId) {
+ $expectedResult['piwikUserId'] = $userId;
+ }
+
+ $this->_dataHelperMock
+ ->expects($this->once())
+ ->method('isTrackingEnabled')
+ ->willReturn($enabled);
+
+ $this->_dataHelperMock
+ ->expects($enabled ? $this->once() : $this->never())
+ ->method('getUserIdProviderCode')
+ ->willReturn($provider);
+
+ $this->_currentCustomerMock
+ ->expects($enabled ? $this->once() : $this->never())
+ ->method('getCustomerId')
+ ->willReturn($customerId);
+
+ $this->_uidProviderPoolMock
+ ->expects(
+ ($enabled && $provider)
+ ? $this->once()
+ : $this->never()
+ )
+ ->method('getProviderByCode')
+ ->with($provider)
+ ->willReturn($this->_uidProviderMock);
+
+ $this->_uidProviderMock
+ ->expects(
+ ($enabled && $customerId && $provider)
+ ? $this->once()
+ : $this->never()
+ )
+ ->method('getUserId')
+ ->with($customerId)
+ ->willReturn($userId);
+
+ // Assert that result of plugin equals expected result
+ $this->assertEquals(
+ $expectedResult,
+ $this->_customerPlugin->afterGetSectionData(
+ $this->_customerDataMock,
+ []
+ )
+ );
+ }
+}
diff --git a/UserId/Provider/EmailProvider.php b/UserId/Provider/EmailProvider.php
new file mode 100644
index 0000000..068bce5
--- /dev/null
+++ b/UserId/Provider/EmailProvider.php
@@ -0,0 +1,68 @@
+.
+ */
+
+namespace Henhed\Piwik\UserId\Provider;
+
+use Magento\Customer\Api\CustomerRepositoryInterface;
+
+/**
+ * Customer email provider
+ *
+ */
+class EmailProvider implements ProviderInterface
+{
+
+ /**
+ * Customer repository
+ *
+ * @var CustomerRepositoryInterface $_customerRepository
+ */
+ protected $_customerRepository;
+
+ /**
+ * Constructor
+ *
+ * @param CustomerRepositoryInterface $customerRepository
+ */
+ public function __construct(CustomerRepositoryInterface $customerRepository)
+ {
+ $this->_customerRepository = $customerRepository;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getUserId($customerId)
+ {
+ try {
+ return $this->_customerRepository->getById($customerId)->getEmail();
+ } catch (\Exception $e) {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getTitle()
+ {
+ return __('Customer E-mail');
+ }
+}
diff --git a/UserId/Provider/EntityIdProvider.php b/UserId/Provider/EntityIdProvider.php
new file mode 100644
index 0000000..5bce075
--- /dev/null
+++ b/UserId/Provider/EntityIdProvider.php
@@ -0,0 +1,45 @@
+.
+ */
+
+namespace Henhed\Piwik\UserId\Provider;
+
+/**
+ * Customer entity ID provider
+ *
+ */
+class EntityIdProvider implements ProviderInterface
+{
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getUserId($customerId)
+ {
+ return (string) $customerId;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getTitle()
+ {
+ return __('Customer Entity ID');
+ }
+}
diff --git a/UserId/Provider/Pool.php b/UserId/Provider/Pool.php
new file mode 100644
index 0000000..1e84b86
--- /dev/null
+++ b/UserId/Provider/Pool.php
@@ -0,0 +1,79 @@
+.
+ */
+
+namespace Henhed\Piwik\UserId\Provider;
+
+/**
+ * User ID provider pool
+ *
+ */
+class Pool
+{
+
+ /**
+ * User ID providers
+ *
+ * @var ProviderInterface[] $_providers
+ */
+ protected $_providers = [];
+
+ /**
+ * Constructor
+ *
+ * @param ProviderInterface[] $providers
+ * @throws \LogicException
+ */
+ public function __construct(array $providers = [])
+ {
+ foreach ($providers as $code => $provider) {
+ if ($provider instanceof ProviderInterface) {
+ $this->_providers[$code] = $provider;
+ } else {
+ throw new \LogicException(sprintf(
+ '%s must implement %s',
+ get_class($provider), ProviderInterface::class
+ ));
+ }
+ }
+ }
+
+ /**
+ * Get User ID provider by code
+ *
+ * @param string $code
+ * @return ProviderInterface|null
+ */
+ public function getProviderByCode($code)
+ {
+ return isset($this->_providers[$code])
+ ? $this->_providers[$code]
+ : null;
+ }
+
+ /**
+ * Get all User ID providers added to this pool
+ *
+ * @return ProviderInterface[]
+ */
+ public function getAllProviders()
+ {
+ return $this->_providers;
+ }
+}
diff --git a/UserId/Provider/ProviderInterface.php b/UserId/Provider/ProviderInterface.php
new file mode 100644
index 0000000..604279a
--- /dev/null
+++ b/UserId/Provider/ProviderInterface.php
@@ -0,0 +1,44 @@
+.
+ */
+
+namespace Henhed\Piwik\UserId\Provider;
+
+/**
+ * User ID provider interface
+ *
+ */
+interface ProviderInterface
+{
+
+ /**
+ * Returns Piwik user ID for given Magento customer ID
+ *
+ * @param int $customerId
+ * @return string
+ */
+ public function getUserId($customerId);
+
+ /**
+ * Get User ID provider title
+ *
+ * @return string
+ */
+ public function getTitle();
+}
diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml
index 84db54b..51f5e59 100644
--- a/etc/adminhtml/system.xml
+++ b/etc/adminhtml/system.xml
@@ -107,10 +107,24 @@
validate-digits validate-zero-or-greater
+
+
+ Henhed\Piwik\Model\Config\Source\UserId\Provider
+ Send logged in customers ID to Piwik
+
+ 1
+
+
diff --git a/etc/config.xml b/etc/config.xml
index 2e487d1..e37b7ce 100644
--- a/etc/config.xml
+++ b/etc/config.xml
@@ -29,6 +29,7 @@
1
1
500
+
piwik.php
piwik.js
diff --git a/etc/di.xml b/etc/di.xml
new file mode 100644
index 0000000..2299d2c
--- /dev/null
+++ b/etc/di.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+ - Henhed\Piwik\UserId\Provider\EntityIdProvider
+ - Henhed\Piwik\UserId\Provider\EmailProvider
+
+
+
+
+
diff --git a/etc/frontend/di.xml b/etc/frontend/di.xml
index dcb878f..8d0a059 100644
--- a/etc/frontend/di.xml
+++ b/etc/frontend/di.xml
@@ -21,9 +21,17 @@
-->
+
+
+
+
+
+
diff --git a/i18n/en_US.csv b/i18n/en_US.csv
index 702209f..ab4e326 100644
--- a/i18n/en_US.csv
+++ b/i18n/en_US.csv
@@ -11,6 +11,10 @@
"Enable tracking of outlinks and downloads","Enable tracking of outlinks and downloads"
"Link Tracking Timer","Link Tracking Timer"
"Delay for link tracking in milliseconds","Delay for link tracking in milliseconds"
+"Enable User ID Tracking","Enable User ID Tracking"
+"Customer Entity ID","Customer Entity ID"
+"Customer E-mail","Customer E-mail"
+"Send logged in customers ID to Piwik","Send logged in customers ID to Piwik"
"Advanced Options","Advanced Options"
"Javascript Path","Javascript Path"
"Path to the Piwik tracker Javascript. Usually ""piwik.js"".","Path to the Piwik tracker Javascript. Usually ""piwik.js""."
diff --git a/i18n/sv_SE.csv b/i18n/sv_SE.csv
index c2dd210..540e575 100644
--- a/i18n/sv_SE.csv
+++ b/i18n/sv_SE.csv
@@ -11,6 +11,10 @@
"Enable tracking of outlinks and downloads","Aktivera spårning av utlänkar och nedladdningar"
"Link Tracking Timer","Länkspårningstimer"
"Delay for link tracking in milliseconds","Fördröjning av länkspårning i millisekunder"
+"Enable User ID Tracking","Aktivera spårning av användar-ID"
+"Customer Entity ID","Kundens entitets-ID"
+"Customer E-mail","Kundens E-postadress"
+"Send logged in customers ID to Piwik","Skicka inloggade kunders ID till Piwik"
"Advanced Options","Avancerade inställningar"
"Javascript Path","Sökväg till javascript"
"Path to the Piwik tracker Javascript. Usually ""piwik.js"".","Sökväg till Piwik-spårarens javascript. Vanligtvis ""piwik.js""."
diff --git a/view/frontend/web/js/tracker.js b/view/frontend/web/js/tracker.js
index fd13593..774ff94 100644
--- a/view/frontend/web/js/tracker.js
+++ b/view/frontend/web/js/tracker.js
@@ -74,6 +74,20 @@ define([
*/
var storage = $.initNamespaceStorage('henhed-piwik').localStorage;
+ /**
+ * Cart data access
+ *
+ * @type {Object}
+ */
+ var cartObservable = customerData.get('cart');
+
+ /**
+ * Customer data access
+ *
+ * @type {Object}
+ */
+ var customerObservable = customerData.get('customer');
+
/**
* Append Piwik tracker script URL to head
*
@@ -182,13 +196,30 @@ define([
* @param {Tracker|undefined} tracker
*/
function pushAction(action, tracker) {
+
if (!_.isArray(action) || _.isEmpty(action)) {
return;
} else if (_.isArray(_.first(action))) {
_.each(action, function (subAction) {
pushAction(subAction, tracker);
});
- } else if (_.isObject(tracker)) {
+ return;
+ }
+
+ if (/^track/.test(_.first(action))) {
+ // Trigger event before tracking
+ var event = $.Event('piwik:beforeTrack');
+ $(exports).triggerHandler(event, [action, tracker]);
+ if (event.isDefaultPrevented()) {
+ // Skip tracking if event listener prevented default
+ return;
+ } else if (_.isArray(event.result)) {
+ // Replace track action if event listener returned an array
+ action = event.result;
+ }
+ }
+
+ if (_.isObject(tracker)) {
var actionName = action.shift();
if (_.isFunction(tracker[actionName])) {
tracker[actionName].apply(tracker, action);
@@ -225,6 +256,23 @@ define([
}
}
+ /**
+ * Event listener for `piwik:beforeTrack'. Adds visitor data to tracker.
+ *
+ * @param {jQuery.Event} event
+ * @param {Array} action
+ * @param {Tracker|undefined} tracker
+ * @see \Henhed\Piwik\CustomerData\Customer\CustomerPlugin
+ */
+ function addVisitorDataBeforeTrack(event, action, tracker) {
+
+ var customer = customerObservable();
+
+ if (_.has(customer, 'piwikUserId')) {
+ pushAction(['setUserId', customer.piwikUserId], tracker);
+ }
+ };
+
/**
* Initialzie this component with given options
*
@@ -252,7 +300,9 @@ define([
// Listen for when the Piwik asynchronous tracker is ready
exports.piwikAsyncInit = onPiwikLoaded;
// Subscribe to cart updates
- customerData.get('cart').subscribe(cartUpdated);
+ cartObservable.subscribe(cartUpdated);
+ // Listen for track actions to inject visitor data
+ $(exports).on('piwik:beforeTrack', addVisitorDataBeforeTrack);
return {
// Public component API