├── .editorconfig
├── .github
└── workflows
│ └── phpunit-test.yml
├── .gitignore
├── Block
└── Matomo.php
├── CustomerData
├── Checkout
│ └── CartPlugin.php
└── Customer
│ └── CustomerPlugin.php
├── Helper
├── Data.php
└── Tracker.php
├── LICENSE
├── Model
├── Config
│ └── Source
│ │ └── UserId
│ │ └── Provider.php
├── Tracker.php
└── Tracker
│ └── Action.php
├── Observer
├── BeforeTrackPageViewObserver.php
├── CartViewObserver.php
├── CategoryViewObserver.php
├── CheckoutSuccessObserver.php
├── ProductViewObserver.php
└── SearchResultObserver.php
├── README.md
├── Test
└── Unit
│ ├── CustomerData
│ ├── Checkout
│ │ └── CartPluginTest.php
│ └── Customer
│ │ └── CustomerPluginTest.php
│ ├── Helper
│ ├── DataTest.php
│ └── TrackerTest.php
│ ├── Model
│ └── TrackerTest.php
│ └── Observer
│ ├── BeforeTrackPageViewObserverTest.php
│ ├── CartViewObserverTest.php
│ ├── CategoryViewObserverTest.php
│ ├── CheckoutSuccessObserverTest.php
│ ├── ProductViewObserverTest.php
│ └── SearchResultObserverTest.php
├── UserId
└── Provider
│ ├── EmailProvider.php
│ ├── EntityIdProvider.php
│ ├── Pool.php
│ └── ProviderInterface.php
├── composer.json
├── dev
└── ci
│ ├── BUILDVARS.conf.dist
│ └── build.sh
├── etc
├── acl.xml
├── adminhtml
│ └── system.xml
├── config.xml
├── di.xml
├── frontend
│ ├── di.xml
│ └── events.xml
└── module.xml
├── i18n
├── en_US.csv
├── it_IT.csv
└── sv_SE.csv
├── registration.php
└── view
└── frontend
├── layout
└── default.xml
├── templates
└── matomo.phtml
└── web
└── js
└── tracker.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | insert_final_newline = true
7 | trim_trailing_whitespace = true
8 | indent_style = space
9 | indent_size = 4
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
14 | [.travis.yml]
15 | indent_size = 2
16 |
--------------------------------------------------------------------------------
/.github/workflows/phpunit-test.yml:
--------------------------------------------------------------------------------
1 | name: PHPUnit Test
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches: [ main ]
7 | pull_request:
8 | branches: [ main ]
9 |
10 | jobs:
11 | build:
12 |
13 | runs-on: ubuntu-latest
14 |
15 | strategy:
16 | matrix:
17 | include:
18 | - magento-version: '2.4.5-p1'
19 | php-version: '8.1'
20 | - magento-version: '2.4.4-p2'
21 | php-version: '8.1'
22 | - magento-version: '2.4.3-p3'
23 | php-version: '7.4'
24 | - magento-version: '2.4.2-p2'
25 | php-version: '7.4'
26 | - magento-version: '2.4.1-p1'
27 | php-version: '7.4'
28 | composer-version: '1'
29 | - magento-version: '2.4.0-p1'
30 | php-version: '7.3'
31 | composer-version: '1'
32 | - magento-version: '2.3.6-p1'
33 | php-version: '7.3'
34 | composer-version: '1'
35 |
36 | steps:
37 | - name: Checkout Code
38 | uses: actions/checkout@v3
39 |
40 | - name: Set PHP Version
41 | uses: shivammathur/setup-php@v2
42 | with:
43 | php-version: ${{ matrix.php-version }}
44 |
45 | - name: Set composer Version
46 | if: ${{ matrix.composer-version == '1' }}
47 | run: |
48 | composer --verbose self-update --${{ matrix.composer-version }}
49 |
50 | - name: Run PHPUnit Test
51 | run: |
52 | ./dev/ci/build.sh
53 | env:
54 | M2_VERSION: ${{ matrix.magento-version }}
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /dev/ci/BUILDVARS.conf
2 |
--------------------------------------------------------------------------------
/Block/Matomo.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Block;
23 |
24 | /**
25 | * Matomo page block
26 | *
27 | */
28 | class Matomo extends \Magento\Framework\View\Element\Template
29 | {
30 |
31 | /**
32 | * JSON encoder
33 | *
34 | * @var \Magento\Framework\Json\EncoderInterface
35 | */
36 | protected $_jsonEncoder;
37 |
38 | /**
39 | * Matomo tracker model
40 | *
41 | * @var \Chessio\Matomo\Model\Tracker $_tracker
42 | */
43 | protected $_tracker;
44 |
45 | /**
46 | * Matomo data helper
47 | *
48 | * @var \Chessio\Matomo\Helper\Data
49 | */
50 | protected $_dataHelper = null;
51 |
52 | /**
53 | * Constructor
54 | *
55 | * @param \Magento\Framework\View\Element\Template\Context $context
56 | * @param \Magento\Framework\Json\EncoderInterface $jsonEncoder
57 | * @param \Chessio\Matomo\Model\Tracker $tracker
58 | * @param \Chessio\Matomo\Helper\Data $dataHelper
59 | * @param array $data
60 | */
61 | public function __construct(
62 | \Magento\Framework\View\Element\Template\Context $context,
63 | \Magento\Framework\Json\EncoderInterface $jsonEncoder,
64 | \Chessio\Matomo\Model\Tracker $tracker,
65 | \Chessio\Matomo\Helper\Data $dataHelper,
66 | array $data = []
67 | ) {
68 | $this->_jsonEncoder = $jsonEncoder;
69 | $this->_tracker = $tracker;
70 | $this->_dataHelper = $dataHelper;
71 | parent::__construct($context, $data);
72 | }
73 |
74 | /**
75 | * Get Matomo tracker actions
76 | *
77 | * @return \Chessio\Matomo\Model\Tracker
78 | */
79 | public function getTracker()
80 | {
81 | return $this->_tracker;
82 | }
83 |
84 | /**
85 | * Populate tracker with actions before rendering
86 | *
87 | * @return void
88 | */
89 | protected function _prepareTracker()
90 | {
91 | $tracker = $this->getTracker();
92 |
93 | $this->_eventManager->dispatch(
94 | 'matomo_track_page_view_before',
95 | ['block' => $this, 'tracker' => $tracker]
96 | );
97 |
98 | if (!$this->getSkipTrackPageView()) {
99 | $tracker->trackPageView();
100 | }
101 |
102 | $this->_eventManager->dispatch(
103 | 'matomo_track_page_view_after',
104 | ['block' => $this, 'tracker' => $tracker]
105 | );
106 | }
107 |
108 | /**
109 | * Get javascript tracker options
110 | *
111 | * @return array
112 | */
113 | public function getJsOptions()
114 | {
115 | return [
116 | 'scriptUrl' => $this->getScriptUrl(),
117 | 'trackerUrl' => $this->getTrackerUrl(),
118 | 'siteId' => $this->getSiteId(),
119 | 'actions' => $this->getTracker()->toArray()
120 | ];
121 | }
122 |
123 | /**
124 | * Get Matomo JS URL
125 | *
126 | * @return string
127 | */
128 | public function getScriptUrl()
129 | {
130 | return $this->_dataHelper->getJsScriptUrl();
131 | }
132 |
133 | /**
134 | * Get Matomo tracker URL
135 | *
136 | * @return string
137 | */
138 | public function getTrackerUrl()
139 | {
140 | return $this->_dataHelper->getPhpScriptUrl();
141 | }
142 |
143 | /**
144 | * Get Matomo site ID
145 | *
146 | * @return int
147 | */
148 | public function getSiteId()
149 | {
150 | return $this->_dataHelper->getSiteId();
151 | }
152 |
153 | /**
154 | * Get tracking pixel URL
155 | *
156 | * @return string
157 | */
158 | public function getTrackingPixelUrl()
159 | {
160 | $params = [
161 | 'idsite' => $this->getSiteId(),
162 | 'rec' => 1,
163 | 'url' => $this->_urlBuilder->getCurrentUrl()
164 | ];
165 | return $this->getTrackerUrl() . '?' . http_build_query($params);
166 | }
167 |
168 | /**
169 | * Encode data to a JSON string
170 | *
171 | * @param mixed $data
172 | * @return string
173 | */
174 | public function jsonEncode($data)
175 | {
176 | return $this->_jsonEncoder->encode($data);
177 | }
178 |
179 | /**
180 | * Generate Matomo tracking script
181 | *
182 | * @return string
183 | */
184 | protected function _toHtml()
185 | {
186 | if ($this->_dataHelper->isTrackingEnabled()) {
187 | $this->_prepareTracker();
188 | return parent::_toHtml();
189 | }
190 | return '';
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/CustomerData/Checkout/CartPlugin.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\CustomerData\Checkout;
23 |
24 | /**
25 | * Plugin for \Magento\Checkout\CustomerData\Cart
26 | *
27 | */
28 | class CartPlugin
29 | {
30 |
31 | /**
32 | * Checkout session instance
33 | *
34 | * @var \Magento\Checkout\Model\Session $_checkoutSession
35 | */
36 | protected $_checkoutSession;
37 |
38 | /**
39 | * Matomo data helper
40 | *
41 | * @var \Chessio\Matomo\Helper\Data $_dataHelper
42 | */
43 | protected $_dataHelper;
44 |
45 | /**
46 | * Tracker helper
47 | *
48 | * @var \Chessio\Matomo\Helper\Tracker $_trackerHelper
49 | */
50 | protected $_trackerHelper;
51 |
52 | /**
53 | * Tracker factory
54 | *
55 | * @var \Chessio\Matomo\Model\TrackerFactory $_trackerFactory
56 | */
57 | protected $_trackerFactory;
58 |
59 | /**
60 | * Constructor
61 | *
62 | * @param \Magento\Checkout\Model\Session\Proxy $checkoutSession
63 | * @param \Chessio\Matomo\Helper\Data $dataHelper
64 | * @param \Chessio\Matomo\Helper\Tracker $trackerHelper
65 | * @param \Chessio\Matomo\Model\TrackerFactory $trackerFactory
66 | */
67 | public function __construct(
68 | \Magento\Checkout\Model\Session\Proxy $checkoutSession,
69 | \Chessio\Matomo\Helper\Data $dataHelper,
70 | \Chessio\Matomo\Helper\Tracker $trackerHelper,
71 | \Chessio\Matomo\Model\TrackerFactory $trackerFactory
72 | ) {
73 | $this->_checkoutSession = $checkoutSession;
74 | $this->_dataHelper = $dataHelper;
75 | $this->_trackerHelper = $trackerHelper;
76 | $this->_trackerFactory = $trackerFactory;
77 | }
78 |
79 | /**
80 | * Add `trackEcommerceCartUpdate' checkout cart customer data
81 | *
82 | * @param \Magento\Checkout\CustomerData\Cart $subject
83 | * @param array $result
84 | * @return array
85 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
86 | */
87 | public function afterGetSectionData(
88 | \Magento\Checkout\CustomerData\Cart $subject,
89 | $result
90 | ) {
91 | if ($this->_dataHelper->isTrackingEnabled()) {
92 | $quote = $this->_checkoutSession->getQuote();
93 | if ($quote->getId()) {
94 | $tracker = $this->_trackerFactory->create();
95 | $this->_trackerHelper->addQuote($quote, $tracker);
96 | $result['matomoActions'] = $tracker->toArray();
97 | }
98 | }
99 | return $result;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/CustomerData/Customer/CustomerPlugin.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\CustomerData\Customer;
23 |
24 | /**
25 | * Plugin for \Magento\Customer\CustomerData\Customer
26 | *
27 | */
28 | class CustomerPlugin
29 | {
30 |
31 | /**
32 | * Current customer helper
33 | *
34 | * @var \Magento\Customer\Helper\Session\CurrentCustomer $_currentCustomer
35 | */
36 | protected $_currentCustomer;
37 |
38 | /**
39 | * Matomo data helper
40 | *
41 | * @var \Chessio\Matomo\Helper\Data $_dataHelper
42 | */
43 | protected $_dataHelper;
44 |
45 | /**
46 | * User ID provider pool
47 | *
48 | * @var \Chessio\Matomo\UserId\Provider\Pool $_uidProviderPool
49 | */
50 | protected $_uidProviderPool;
51 |
52 | /**
53 | * Constructor
54 | *
55 | * @param \Magento\Customer\Helper\Session\CurrentCustomer $currentCustomer
56 | * @param \Chessio\Matomo\Helper\Data $dataHelper
57 | * @param \Chessio\Matomo\UserId\Provider\Pool $uidProviderPool
58 | */
59 | public function __construct(
60 | \Magento\Customer\Helper\Session\CurrentCustomer $currentCustomer,
61 | \Chessio\Matomo\Helper\Data $dataHelper,
62 | \Chessio\Matomo\UserId\Provider\Pool $uidProviderPool
63 | ) {
64 | $this->_currentCustomer = $currentCustomer;
65 | $this->_dataHelper = $dataHelper;
66 | $this->_uidProviderPool = $uidProviderPool;
67 | }
68 |
69 | /**
70 | * Get configured Matomo User ID provider or NULL
71 | *
72 | * @return \Chessio\Matomo\UserId\Provider\ProviderInterface|null
73 | */
74 | protected function _getUserIdProvider()
75 | {
76 | $code = $this->_dataHelper->getUserIdProviderCode();
77 | return $code ? $this->_uidProviderPool->getProviderByCode($code) : null;
78 | }
79 |
80 | /**
81 | * Get Matomo User ID for current customer
82 | *
83 | * @return string
84 | */
85 | protected function _getUserId()
86 | {
87 | $provider = $this->_getUserIdProvider();
88 | $customerId = $this->_currentCustomer->getCustomerId();
89 | return ($provider && $customerId)
90 | ? (string) $provider->getUserId($customerId)
91 | : '';
92 | }
93 |
94 | /**
95 | * Add visitor related tracker information to customer section data.
96 | *
97 | * @param \Magento\Customer\CustomerData\Customer $subject
98 | * @param array $result
99 | * @return array
100 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
101 | */
102 | public function afterGetSectionData(
103 | \Magento\Customer\CustomerData\Customer $subject,
104 | $result
105 | ) {
106 | if ($this->_dataHelper->isTrackingEnabled()) {
107 | $userId = $this->_getUserId();
108 | if ($userId !== '') {
109 | $result['matomoUserId'] = $userId;
110 | }
111 | }
112 | return $result;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/Helper/Data.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Helper;
23 |
24 | use Magento\Store\Model\Store;
25 |
26 | /**
27 | * Matomo data helper
28 | *
29 | */
30 | class Data extends \Magento\Framework\App\Helper\AbstractHelper
31 | {
32 |
33 | /**
34 | * System config XML paths
35 | * Prefix "piwik/" left for compatibility with Henhed_Piwik
36 | */
37 | const XML_PATH_ENABLED = 'piwik/tracking/enabled';
38 | const XML_PATH_HOSTNAME = 'piwik/tracking/hostname';
39 | const XML_PATH_CDN_HOSTNAME = 'piwik/tracking/cdn_hostname';
40 | const XML_PATH_JS_SCRIPT_PATH = 'piwik/tracking/js_script_path';
41 | const XML_PATH_PHP_SCRIPT_PATH = 'piwik/tracking/php_script_path';
42 | const XML_PATH_SITE_ID = 'piwik/tracking/site_id';
43 | const XML_PATH_LINK_ENABLED = 'piwik/tracking/link_enabled';
44 | const XML_PATH_LINK_DELAY = 'piwik/tracking/link_delay';
45 | const XML_PATH_UID_PROVIDER = 'piwik/tracking/uid_provider';
46 |
47 | /**
48 | * Check if Matomo is enabled
49 | *
50 | * @param null|string|bool|int|Store $store
51 | * @return bool
52 | */
53 | public function isTrackingEnabled($store = null)
54 | {
55 | $hostname = $this->getHostname($store);
56 | $siteId = $this->getSiteId($store);
57 | return $hostname && $siteId && $this->scopeConfig->isSetFlag(
58 | self::XML_PATH_ENABLED,
59 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
60 | $store
61 | );
62 | }
63 |
64 | /**
65 | * Retrieve Matomo hostname
66 | *
67 | * @param null|string|bool|int|Store $store
68 | * @return string
69 | */
70 | public function getHostname($store = null)
71 | {
72 | return trim($this->scopeConfig->getValue(
73 | self::XML_PATH_HOSTNAME,
74 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
75 | $store
76 | ) ?? "");
77 | }
78 |
79 | /**
80 | * Retrieve Matomo CDN hostname
81 | *
82 | * @param null|string|bool|int|Store $store
83 | * @return string
84 | */
85 | public function getCdnHostname($store = null)
86 | {
87 | return trim($this->scopeConfig->getValue(
88 | self::XML_PATH_CDN_HOSTNAME,
89 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
90 | $store
91 | ) ?? "");
92 | }
93 |
94 | /**
95 | * Retrieve base URL for given hostname
96 | *
97 | * @param string $host
98 | * @param null|bool $secure
99 | * @return string
100 | */
101 | protected function _getBaseUrl($host, $secure = null)
102 | {
103 | if ($secure === null) {
104 | $secure = $this->_getRequest()->isSecure();
105 | }
106 | if (false !== ($scheme = strpos($host, '://'))) {
107 | $host = substr($host, $scheme + 3);
108 | }
109 | return ($secure ? 'https://' : 'http://') . rtrim($host, '/') . '/';
110 | }
111 |
112 | /**
113 | * Retrieve Matomo base URL
114 | *
115 | * @param null|string|bool|int|Store $store
116 | * @param null|bool $secure
117 | * @return string
118 | */
119 | public function getBaseUrl($store = null, $secure = null)
120 | {
121 | return $this->_getBaseUrl($this->getHostname($store), $secure);
122 | }
123 |
124 | /**
125 | * Retrieve Matomo CDN URL
126 | *
127 | * @param null|string|bool|int|Store $store
128 | * @param null|bool $secure
129 | * @return string
130 | */
131 | public function getCdnBaseUrl($store = null, $secure = null)
132 | {
133 | $host = $this->getCdnHostname($store);
134 | return ('' !== $host)
135 | ? $this->_getBaseUrl($host, $secure)
136 | : $this->getBaseUrl($store, $secure);
137 | }
138 |
139 | /**
140 | * Retrieve Matomo tracker JS script path
141 | *
142 | * @param null|string|bool|int|Store $store
143 | * @return string
144 | */
145 | public function getJsScriptPath($store = null)
146 | {
147 | return ltrim(trim($this->scopeConfig->getValue(
148 | self::XML_PATH_JS_SCRIPT_PATH,
149 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
150 | $store
151 | ) ?? ""), '/') ?: 'matomo.js';
152 | }
153 |
154 | /**
155 | * Retrieve Matomo tracker JS script URL
156 | *
157 | * @param null|string|bool|int|Store $store
158 | * @param null|bool $secure
159 | * @return string
160 | */
161 | public function getJsScriptUrl($store = null, $secure = null)
162 | {
163 | return $this->getCdnBaseUrl($store, $secure)
164 | . $this->getJsScriptPath($store);
165 | }
166 |
167 | /**
168 | * Retrieve Matomo tracker PHP script path
169 | *
170 | * @param null|string|bool|int|Store $store
171 | * @return string
172 | */
173 | public function getPhpScriptPath($store = null)
174 | {
175 | return ltrim(trim($this->scopeConfig->getValue(
176 | self::XML_PATH_PHP_SCRIPT_PATH,
177 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
178 | $store
179 | ) ?? ""), '/') ?: 'matomo.php';
180 | }
181 |
182 | /**
183 | * Retrieve Matomo tracker PHP script URL
184 | *
185 | * @param null|string|bool|int|Store $store
186 | * @param null|bool $secure
187 | * @return string
188 | */
189 | public function getPhpScriptUrl($store = null, $secure = null)
190 | {
191 | return $this->getBaseUrl($store, $secure)
192 | . $this->getPhpScriptPath($store);
193 | }
194 |
195 | /**
196 | * Retrieve Matomo site ID
197 | *
198 | * @param null|string|bool|int|Store $store
199 | * @return int
200 | */
201 | public function getSiteId($store = null)
202 | {
203 | return (int) $this->scopeConfig->getValue(
204 | self::XML_PATH_SITE_ID,
205 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
206 | $store
207 | );
208 | }
209 |
210 | /**
211 | * Check if Matomo link tracking is enabled
212 | *
213 | * @param null|string|bool|int|Store $store
214 | * @return bool
215 | */
216 | public function isLinkTrackingEnabled($store = null)
217 | {
218 | return $this->scopeConfig->isSetFlag(
219 | self::XML_PATH_LINK_ENABLED,
220 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
221 | $store
222 | ) && $this->isTrackingEnabled($store);
223 | }
224 |
225 | /**
226 | * Retrieve Matomo link tracking delay in milliseconds
227 | *
228 | * @param null|string|bool|int|Store $store
229 | * @return int
230 | */
231 | public function getLinkTrackingDelay($store = null)
232 | {
233 | return (int) $this->scopeConfig->getValue(
234 | self::XML_PATH_LINK_DELAY,
235 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
236 | $store
237 | );
238 | }
239 |
240 | /**
241 | * Get provider code for Matomo user ID tracking
242 | *
243 | * @param null|string|bool|int|Store $store
244 | * @return string
245 | */
246 | public function getUserIdProviderCode($store = null)
247 | {
248 | return $this->scopeConfig->getValue(
249 | self::XML_PATH_UID_PROVIDER,
250 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
251 | $store
252 | );
253 | }
254 | }
255 |
--------------------------------------------------------------------------------
/Helper/Tracker.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Helper;
23 |
24 | use Chessio\Matomo\Model\Tracker as TrackerModel;
25 | use Magento\Quote\Model\Quote;
26 | use Magento\Sales\Api\Data\OrderInterface;
27 | use Magento\Sales\Api\Data\OrderItemInterface;
28 |
29 | /**
30 | * Matomo tracker helper
31 | *
32 | * @see http://matomo.org/docs/ecommerce-analytics/
33 | */
34 | class Tracker extends \Magento\Framework\App\Helper\AbstractHelper
35 | {
36 |
37 | /**
38 | * Push `addEcommerceItem' with quote item data to given tracker
39 | *
40 | * @param \Magento\Quote\Model\Quote\Item $item
41 | * @param \Chessio\Matomo\Model\Tracker $tracker
42 | * @return \Chessio\Matomo\Helper\Tracker
43 | */
44 | public function addQuoteItem(Quote\Item $item, TrackerModel $tracker)
45 | {
46 | $tracker->addEcommerceItem(
47 | $item->getSku(),
48 | $item->getName(),
49 | false,
50 | $item->hasCustomPrice()
51 | ? (float) $item->getCustomPrice()
52 | : (float) $item->getBasePriceInclTax(),
53 | (float) $item->getQty()
54 | );
55 | return $this;
56 | }
57 |
58 | /**
59 | * Push `trackEcommerceCartUpdate' with quote data to given tracker
60 | *
61 | * @param \Magento\Quote\Model\Quote $quote
62 | * @param \Chessio\Matomo\Model\Tracker $tracker
63 | * @return \Chessio\Matomo\Helper\Tracker
64 | */
65 | public function addQuoteTotal(Quote $quote, TrackerModel $tracker)
66 | {
67 | $tracker->trackEcommerceCartUpdate((float) $quote->getBaseGrandTotal());
68 | return $this;
69 | }
70 |
71 | /**
72 | * Push quote contents to given tracker
73 | *
74 | * @param \Magento\Quote\Model\Quote $quote
75 | * @param \Chessio\Matomo\Model\Tracker $tracker
76 | * @return \Chessio\Matomo\Helper\Tracker
77 | */
78 | public function addQuote(Quote $quote, TrackerModel $tracker)
79 | {
80 | foreach ($quote->getAllVisibleItems() as $item) {
81 | $this->addQuoteItem($item, $tracker);
82 | }
83 | $this->addQuoteTotal($quote, $tracker);
84 | return $this;
85 | }
86 |
87 | /**
88 | * Push order contents to given tracker
89 | *
90 | * @param \Magento\Sales\Api\Data\OrderInterface[]|\Traversable $orders
91 | * @param \Chessio\Matomo\Model\Tracker $tracker
92 | * @return \Chessio\Matomo\Helper\Tracker
93 | */
94 | public function addOrders($orders, TrackerModel $tracker)
95 | {
96 | $matomoItems = [];
97 | $matomoOrder = [];
98 |
99 | // Collect tracking data
100 | foreach ($orders as $order) {
101 | foreach ($order->getItems() as $item) {
102 | if (!$item->getParentItemId()) {
103 | $this->_appendOrderItemData($item, $matomoItems);
104 | }
105 | }
106 | $this->_appendOrderData($order, $matomoOrder);
107 | }
108 |
109 | // Push `addEcommerceItem'
110 | foreach ($matomoItems as $matomoItem) {
111 | list($sku, $name, $rowTotal, $qty) = $matomoItem;
112 |
113 | $tracker->addEcommerceItem(
114 | $sku,
115 | $name,
116 | false,
117 | ($qty > 0) // div-by-zero protection
118 | ? $rowTotal / $qty // restore to unit price
119 | : 0,
120 | $qty
121 | );
122 | }
123 |
124 | // Push `trackEcommerceOrder'
125 | if (!empty($matomoOrder)) {
126 | list($orderId, $grandTotal, $subTotal, $tax, $shipping, $discount)
127 | = $matomoOrder;
128 |
129 | $tracker->trackEcommerceOrder(
130 | $orderId,
131 | $grandTotal,
132 | $subTotal,
133 | $tax,
134 | $shipping,
135 | ($discount > 0)
136 | ? $discount
137 | : false
138 | );
139 | }
140 |
141 | return $this;
142 | }
143 |
144 | /**
145 | * @param OrderItemInterface $item
146 | * @param array &$data
147 | * @return void
148 | */
149 | protected function _appendOrderItemData(OrderItemInterface $item, &$data)
150 | {
151 | $sku = $item->getSku();
152 | $name = $item->getName();
153 | $price = (float) $item->getBasePriceInclTax();
154 | $qty = (float) $item->getQtyOrdered();
155 |
156 | // Group order items by SKU since Matomo doesn't seem to handle multiple
157 | // `addEcommerceItem' with the same SKU.
158 | if (!isset($data[$sku])) {
159 | $data[$sku] = [$sku, $name, $price * $qty, $qty];
160 | } else {
161 | // Aggregate row total instead of unit price in case there
162 | // are different prices for the same SKU.
163 | $data[$sku][2] += $price * $qty;
164 | $data[$sku][3] += $qty;
165 | }
166 | }
167 |
168 | /**
169 | * @param OrderInterface $order
170 | * @param array &$data
171 | * @return void
172 | */
173 | protected function _appendOrderData(OrderInterface $order, &$data)
174 | {
175 | $orderId = $order->getIncrementId();
176 | $grandTotal = (float) $order->getBaseGrandTotal();
177 | $subTotal = (float) $order->getBaseSubtotalInclTax();
178 | $tax = (float) $order->getBaseTaxAmount();
179 | $shipping = (float) $order->getBaseShippingInclTax();
180 | $discount = abs((float) $order->getBaseDiscountAmount());
181 |
182 | // Aggregate all placed orders into one since Matomo seems to only
183 | // register one `trackEcommerceOrder' per request. (For multishipping)
184 | if (empty($data)) {
185 | $data = [
186 | $orderId, $grandTotal, $subTotal, $tax, $shipping, $discount
187 | ];
188 | } else {
189 | $data[0] .= ', ' . $orderId;
190 | $data[1] += $grandTotal;
191 | $data[2] += $subTotal;
192 | $data[3] += $tax;
193 | $data[4] += $shipping;
194 | $data[5] += $discount;
195 | }
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/Model/Config/Source/UserId/Provider.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Model\Config\Source\UserId;
23 |
24 | /**
25 | * User ID provider config source model
26 | *
27 | */
28 | class Provider implements \Magento\Framework\Option\ArrayInterface
29 | {
30 |
31 | /**
32 | * User ID provider pool
33 | *
34 | * @var \Chessio\Matomo\UserId\Provider\Pool $_pool
35 | */
36 | protected $_pool;
37 |
38 | /**
39 | * Constructor
40 | *
41 | * @param \Chessio\Matomo\UserId\Provider\Pool $pool
42 | */
43 | public function __construct(\Chessio\Matomo\UserId\Provider\Pool $pool)
44 | {
45 | $this->_pool = $pool;
46 | }
47 |
48 | /**
49 | * Return array of user ID providers as value-label pairs
50 | *
51 | * @return array
52 | */
53 | public function toOptionArray()
54 | {
55 | $options = [['value' => '', 'label' => __('No')]];
56 | foreach ($this->_pool->getAllProviders() as $code => $provider) {
57 | $options[] = [
58 | 'value' => $code,
59 | 'label' => sprintf('%s (%s)', __('Yes'), $provider->getTitle())
60 | ];
61 | }
62 | return $options;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Model/Tracker.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Model;
23 |
24 | /**
25 | * Matomo tracker model
26 | *
27 | * @method Tracker trackEvent(string $category, string $action,
28 | * string $name = null, int $value = null)
29 | * Logs an event with an event category (Videos, Music, Games...), an event
30 | * action (Play, Pause, Duration, Add Playlist, Downloaded, Clicked...), and an
31 | * optional event name and optional numeric value.
32 | *
33 | * @method Tracker trackPageView(string $customTitle = null)
34 | * Logs a visit to this page
35 | *
36 | * @method Tracker trackSiteSearch(string $keyword, string $category = null,
37 | * int $resultsCount = null)
38 | * Log an internal site search for a specific keyword, in an optional category,
39 | * specifying the optional count of search results in the page.
40 | *
41 | * @method Tracker trackGoal(int $idGoal, float $customRevenue = null)
42 | * Manually log a conversion for the numeric goal ID, with an optional numeric
43 | * custom revenue customRevenue.
44 | *
45 | * @method Tracker trackLink(string $url, string $linkType)
46 | * Manually log a click from your own code. url is the full URL which is to be
47 | * tracked as a click. linkType can either be 'link' for an outlink or
48 | * 'download' for a download.
49 | *
50 | * @method Tracker trackAllContentImpressions()
51 | * Scans the entire DOM for all content blocks and tracks all impressions once
52 | * the DOM ready event has been triggered.
53 | *
54 | * @method Tracker trackVisibleContentImpressions(bool $checkOnSroll,
55 | * int $timeIntervalInMs)
56 | * Scans the entire DOM for all content blocks as soon as the page is loaded.
57 | * It tracks an impression only if a content block is actually visible.
58 | *
59 | * @method Tracker trackContentImpression(string $contentName,
60 | * string $contentPiece,
61 | * string $contentTarget)
62 | * Tracks a content impression using the specified values.
63 | *
64 | * @method Tracker trackContentInteraction(string $contentInteraction,
65 | * string $contentName,
66 | * string $contentPiece,
67 | * string $contentTarget)
68 | * Tracks a content interaction using the specified values.
69 | *
70 | * @method Tracker logAllContentBlocksOnPage()
71 | * Log all found content blocks within a page to the console. This is useful to
72 | * debug / test content tracking.
73 | *
74 | * @method Tracker enableLinkTracking(bool $enable = null)
75 | * Install link tracking on all applicable link elements. Set the enable
76 | * parameter to true to use pseudo click-handler (treat middle click and open
77 | * contextmenu as left click). A right click (or any click that opens the
78 | * context menu) on a link will be tracked as clicked even if "Open in new tab"
79 | * is not selected. If "false" (default), nothing will be tracked on open
80 | * context menu or middle click.
81 | *
82 | * @method Tracker enableHeartBeatTimer(int $delayInSeconds)
83 | * Install a Heart beat timer that will regularly send requests to Matomo (every
84 | * delayInSeconds seconds) in order to better measure the time spent on the
85 | * page. These requests will be sent only when the user is actively viewing the
86 | * page (when the tab is active and in focus). These requests will not track
87 | * additional actions or pageviews.
88 | *
89 | * @method Tracker setDocumentTitle(string $title)
90 | * Override document.title
91 | *
92 | * @method Tracker setDomains(array $domains)
93 | * Set array of hostnames or domains to be treated as local. For wildcard
94 | * subdomains, you can use: '.example.com' or '*.example.com'. You can also
95 | * specify a path along a domain: '*.example.com/subsite1'
96 | *
97 | * @method Tracker setCustomUrl(string $customUrl)
98 | * Override the page's reported URL
99 | *
100 | * @method Tracker setReferrerUrl(string $referrerUrl)
101 | * Override the detected Http-Referer
102 | *
103 | * @method Tracker setSiteId(int $siteId)
104 | * Specify the website ID
105 | *
106 | * @method Tracker setApiUrl(string $apiUrl)
107 | * Specify the Matomo HTTP API URL endpoint. Points to the root directory of
108 | * matomo, e.g. http://matomo.example.org/ or https://example.org/matomo/. This
109 | * function is only useful when the 'Overlay' report is not working. By default
110 | * you do not need to use this function.
111 | *
112 | * @method Tracker setTrackerUrl(string $trackerUrl)
113 | * Specify the Matomo server URL.
114 | *
115 | * @method Tracker setDownloadClasses(string|array $downloadClasses)
116 | * Set classes to be treated as downloads (in addition to matomo_download)
117 | *
118 | * @method Tracker setDownloadExtensions(string|array $downloadExtensions)
119 | * Set list of file extensions to be recognized as downloads. Example: 'doc' or
120 | * ['doc', 'xls']
121 | *
122 | * @method Tracker addDownloadExtensions(string|array $downloadExtensions)
123 | * Specify additional file extensions to be recognized as downloads. Example:
124 | * 'doc' or ['doc', 'xls']
125 | *
126 | * @method Tracker removeDownloadExtensions(string|array $downloadExtensions)
127 | * Specify file extensions to be removed from the list of download file
128 | * extensions. Example: 'doc' or ['doc', 'xls']
129 | *
130 | * @method Tracker setIgnoreClasses(string|array $ignoreClasses)
131 | * Set classes to be ignored if present in link (in addition to matomo_ignore)
132 | *
133 | * @method Tracker setLinkClasses(string|array $linkClasses)
134 | * Set classes to be treated as outlinks (in addition to matomo_link)
135 | *
136 | * @method Tracker setLinkTrackingTimer(int $linkTrackingTimer)
137 | * Set delay for link tracking in milliseconds.
138 | *
139 | * @method Tracker discardHashTag(bool $flag)
140 | * Set to true to not record the hash tag (anchor) portion of URLs
141 | *
142 | * @method Tracker setGenerationTimeMs(int $generationTime)
143 | * By default Matomo uses the browser DOM Timing API to accurately determine the
144 | * time it takes to generate and download the page. You may overwrite the value
145 | * by specifying a milliseconds value here.
146 | *
147 | * @method Tracker appendToTrackingUrl(string $appendToUrl)
148 | * Appends a custom string to the end of the HTTP request to matomo.php?
149 | *
150 | * @method Tracker setDoNotTrack(bool $flag)
151 | * Set to true to not track users who opt out of tracking using Mozilla's
152 | * (proposed) Do Not Track setting.
153 | *
154 | * @method Tracker disableCookies()
155 | * Disables all first party cookies. Existing Matomo cookies for this websites
156 | * will be deleted on the next page view.
157 | *
158 | * @method Tracker deleteCookies()
159 | * Deletes the tracking cookies currently set (this is useful when creating new
160 | * visits)
161 | *
162 | * @method Tracker killFrame()
163 | * Enables a frame-buster to prevent the tracked web page from being
164 | * framed/iframed.
165 | *
166 | * @method Tracker redirectFile(string $url)
167 | * Forces the browser load the live URL if the tracked web page is loaded from a
168 | * local file (e.g., saved to someone's desktop).
169 | *
170 | * @method Tracker setHeartBeatTimer(int $minimumVisitLength,
171 | * int $heartBeatDelay)
172 | * Records how long the page has been viewed if the $minimumVisitLength (in
173 | * seconds) is attained; the $heartBeatDelay determines how frequently to update
174 | * the server.
175 | *
176 | * @method Tracker setUserId(string $userId)
177 | * Sets a User ID to this user (such as an email address or a username).
178 | *
179 | * @method Tracker setCustomVariable(int $index, string $name, string $value,
180 | * string $scope)
181 | * Set a custom variable.
182 | *
183 | * @method Tracker deleteCustomVariable(int $index, string $scope)
184 | * Delete a custom variable.
185 | *
186 | * @method Tracker storeCustomVariablesInCookie()
187 | * When called then the Custom Variables of scope "visit" will be stored
188 | * (persisted) in a first party cookie for the duration of the visit. This is
189 | * useful if you want to call getCustomVariable later in the visit. (by default
190 | * custom variables are not stored on the visitor's computer.)
191 | *
192 | * @method Tracker setCustomDimension(int $customDimensionId,
193 | * string $customDimensionValue)
194 | * Set a custom dimension. (requires Matomo 2.15.1 + Custom Dimensions plugin)
195 | *
196 | * @method Tracker deleteCustomDimension(int customDimensionId)
197 | * Delete a custom dimension. (requires Matomo 2.15.1 + Custom Dimensions plugin)
198 | *
199 | * @method Tracker setCampaignNameKey(string $name)
200 | * Set campaign name parameter(s).
201 | *
202 | * @method Tracker setCampaignKeywordKey(string $keyword)
203 | * Set campaign keyword parameter(s).
204 | *
205 | * @method Tracker setConversionAttributionFirstReferrer(bool $flag)
206 | * Set to true to attribute a conversion to the first referrer. By default,
207 | * conversion is attributed to the most recent referrer.
208 | *
209 | * @method Tracker setEcommerceView(string $sku, string $productName,
210 | * string $categoryName, float $price)
211 | * Sets the current page view as a product or category page view. When you call
212 | * setEcommerceView it must be followed by a call to trackPageView to record the
213 | * product or category page view.
214 | *
215 | * @method Tracker addEcommerceItem(string $sku, string $productName = null,
216 | * string $categoryName = null,
217 | * float $price = null, float $quantity = null)
218 | * Adds a product into the ecommerce order. Must be called for each product in
219 | * the order.
220 | *
221 | * @method Tracker trackEcommerceCartUpdate(float $grandTotal)
222 | * Tracks a shopping cart. Call this function every time a user is adding,
223 | * updating or deleting a product from the cart.
224 | *
225 | * @method Tracker trackEcommerceOrder(string $orderId, float $grandTotal,
226 | * float $subTotal = null,
227 | * float $tax = null,
228 | * float $shipping = null,
229 | * float $discount = null)
230 | * Tracks an Ecommerce order, including any ecommerce item previously added to
231 | * the order. orderId and grandTotal (ie. revenue) are required parameters.
232 | *
233 | * @method Tracker setCookieNamePrefix(string $prefix)
234 | * The default prefix is 'pk'.
235 | *
236 | * @method Tracker setCookieDomain(string $domain)
237 | * The default is the document domain; if your web site can be visited at both
238 | * www.example.com and example.com, you would use: '.example.com' or
239 | * '*.example.com'
240 | *
241 | * @method Tracker setCookiePath(string $path)
242 | * The default is '/'.
243 | *
244 | * @method Tracker setVisitorCookieTimeout(int $seconds)
245 | * The default is 13 months
246 | *
247 | * @method Tracker setReferralCookieTimeout(int $seconds)
248 | * The default is 6 months
249 | *
250 | * @method Tracker setSessionCookieTimeout(int $seconds)
251 | * The default is 30 minutes
252 | *
253 | * @see http://developer.matomo.org/api-reference/tracking-javascript
254 | */
255 | class Tracker
256 | {
257 |
258 | /**
259 | * Action items
260 | *
261 | * @var \Chessio\Matomo\Model\Tracker\Action[] $_actions
262 | */
263 | protected $_actions = [];
264 |
265 | /**
266 | * Tracker action factory instance
267 | *
268 | * @var \Chessio\Matomo\Model\Tracker\ActionFactory $_actionFactory
269 | */
270 | protected $_actionFactory;
271 |
272 | /**
273 | * Constructor
274 | *
275 | * @param \Chessio\Matomo\Model\Tracker\ActionFactory $actionFactory
276 | */
277 | public function __construct(
278 | \Chessio\Matomo\Model\Tracker\ActionFactory $actionFactory
279 | ) {
280 | $this->_actionFactory = $actionFactory;
281 | }
282 |
283 | /**
284 | * Push an action to this tracker
285 | *
286 | * @param \Chessio\Matomo\Model\Tracker\Action $action
287 | * @return \Chessio\Matomo\Model\Tracker
288 | */
289 | public function push(Tracker\Action $action)
290 | {
291 | $this->_actions[] = $action;
292 | return $this;
293 | }
294 |
295 | /**
296 | * Get all actions in this tracker
297 | *
298 | * @return \Chessio\Matomo\Model\Tracker\Action[]
299 | */
300 | public function getActions()
301 | {
302 | return $this->_actions;
303 | }
304 |
305 | /**
306 | * Get an array representation of this tracker
307 | *
308 | * @return array
309 | */
310 | public function toArray()
311 | {
312 | $array = [];
313 | foreach ($this->getActions() as $action) {
314 | $array[] = $action->toArray();
315 | }
316 | return $array;
317 | }
318 |
319 | /**
320 | * Magic action push function
321 | *
322 | * @param string $name
323 | * @param array $arguments
324 | * @return \Chessio\Matomo\Model\Tracker
325 | */
326 | public function __call($name, $arguments)
327 | {
328 | return $this->push($this->_actionFactory->create([
329 | 'name' => $name,
330 | 'args' => $arguments
331 | ]));
332 | }
333 | }
334 |
--------------------------------------------------------------------------------
/Model/Tracker/Action.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Model\Tracker;
23 |
24 | /**
25 | * Matomo tracker action
26 | *
27 | */
28 | class Action
29 | {
30 |
31 | /**
32 | * Action name
33 | *
34 | * @var string $_name
35 | */
36 | protected $_name;
37 |
38 | /**
39 | * Action arguments
40 | *
41 | * @var array $_args
42 | */
43 | protected $_args;
44 |
45 | /**
46 | * Constructor
47 | *
48 | * @param string $name
49 | * @param array $args
50 | */
51 | public function __construct($name, array $args = [])
52 | {
53 | $this->_name = $name;
54 | $this->_args = $args;
55 | }
56 |
57 | /**
58 | * Get action name
59 | *
60 | * @return string
61 | */
62 | public function getName()
63 | {
64 | return $this->_name;
65 | }
66 |
67 | /**
68 | * Get action arguments
69 | *
70 | * @return array
71 | */
72 | public function getArgs()
73 | {
74 | return $this->_args;
75 | }
76 |
77 | /**
78 | * Get an array representation of this action
79 | *
80 | * @return array
81 | */
82 | public function toArray()
83 | {
84 | $array = $this->getArgs();
85 | array_unshift($array, $this->getName());
86 | return $array;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Observer/BeforeTrackPageViewObserver.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Observer;
23 |
24 | use Magento\Framework\Event\ObserverInterface;
25 |
26 | /**
27 | * Observer for `matomo_track_page_view_before'
28 | *
29 | */
30 | class BeforeTrackPageViewObserver implements ObserverInterface
31 | {
32 |
33 | /**
34 | * Matomo data helper
35 | *
36 | * @var \Chessio\Matomo\Helper\Data
37 | */
38 | protected $_dataHelper;
39 |
40 | /**
41 | * Constructor
42 | *
43 | * @param \Chessio\Matomo\Helper\Data $dataHelper
44 | */
45 | public function __construct(\Chessio\Matomo\Helper\Data $dataHelper)
46 | {
47 | $this->_dataHelper = $dataHelper;
48 | }
49 |
50 | /**
51 | * Push additional actions to tracker before `trackPageView' is added
52 | *
53 | * @param \Magento\Framework\Event\Observer $observer
54 | * @return \Chessio\Matomo\Observer\BeforeTrackPageViewObserver
55 | */
56 | public function execute(\Magento\Framework\Event\Observer $observer)
57 | {
58 | $tracker = $observer->getEvent()->getTracker();
59 | /** @var \Chessio\Matomo\Model\Tracker $tracker */
60 |
61 | $this->_pushLinkTracking($tracker);
62 |
63 | return $this;
64 | }
65 |
66 | /**
67 | * Push link tracking options to given tracker
68 | *
69 | * @param \Chessio\Matomo\Model\Tracker $tracker
70 | * @return \Chessio\Matomo\Observer\BeforeTrackPageViewObserver
71 | */
72 | protected function _pushLinkTracking(\Chessio\Matomo\Model\Tracker $tracker)
73 | {
74 | if ($this->_dataHelper->isLinkTrackingEnabled()) {
75 | $tracker->enableLinkTracking(true);
76 | $delay = $this->_dataHelper->getLinkTrackingDelay();
77 | if ($delay > 0) {
78 | $tracker->setLinkTrackingTimer($delay);
79 | }
80 | }
81 | return $this;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Observer/CartViewObserver.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Observer;
23 |
24 | use Magento\Framework\Event\ObserverInterface;
25 |
26 | /**
27 | * Observer for `controller_action_predispatch_checkout_cart_index'
28 | *
29 | */
30 | class CartViewObserver implements ObserverInterface
31 | {
32 |
33 | /**
34 | * Matomo tracker instance
35 | *
36 | * @var \Chessio\Matomo\Model\Tracker
37 | */
38 | protected $_matomoTracker;
39 |
40 | /**
41 | * Tracker helper
42 | *
43 | * @var \Chessio\Matomo\Helper\Tracker $_trackerHelper
44 | */
45 | protected $_trackerHelper;
46 |
47 | /**
48 | * Matomo data helper
49 | *
50 | * @var \Chessio\Matomo\Helper\Data $_dataHelper
51 | */
52 | protected $_dataHelper;
53 |
54 | /**
55 | * Checkout session instance
56 | *
57 | * @var \Magento\Checkout\Model\Session $_checkoutSession
58 | */
59 | protected $_checkoutSession;
60 |
61 | /**
62 | * Constructor
63 | *
64 | * @param \Chessio\Matomo\Model\Tracker $matomoTracker
65 | * @param \Chessio\Matomo\Helper\Tracker $trackerHelper
66 | * @param \Chessio\Matomo\Helper\Data $dataHelper
67 | * @param \Magento\Checkout\Model\Session\Proxy $checkoutSession
68 | */
69 | public function __construct(
70 | \Chessio\Matomo\Model\Tracker $matomoTracker,
71 | \Chessio\Matomo\Helper\Tracker $trackerHelper,
72 | \Chessio\Matomo\Helper\Data $dataHelper,
73 | \Magento\Checkout\Model\Session\Proxy $checkoutSession
74 | ) {
75 | $this->_matomoTracker = $matomoTracker;
76 | $this->_trackerHelper = $trackerHelper;
77 | $this->_dataHelper = $dataHelper;
78 | $this->_checkoutSession = $checkoutSession;
79 | }
80 |
81 | /**
82 | * Push trackEcommerceCartUpdate to tracker on cart view page
83 | *
84 | * @param \Magento\Framework\Event\Observer $observer
85 | * @return \Chessio\Matomo\Observer\CartViewObserver
86 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
87 | */
88 | public function execute(\Magento\Framework\Event\Observer $observer)
89 | {
90 | if ($this->_dataHelper->isTrackingEnabled()) {
91 | $this->_trackerHelper->addQuote(
92 | $this->_checkoutSession->getQuote(),
93 | $this->_matomoTracker
94 | );
95 | }
96 | return $this;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Observer/CategoryViewObserver.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Observer;
23 |
24 | use Magento\Framework\Event\ObserverInterface;
25 |
26 | /**
27 | * Observer for `catalog_controller_category_init_after'
28 | *
29 | */
30 | class CategoryViewObserver implements ObserverInterface
31 | {
32 |
33 | /**
34 | * Matomo tracker instance
35 | *
36 | * @var \Chessio\Matomo\Model\Tracker
37 | */
38 | protected $_matomoTracker;
39 |
40 | /**
41 | * Matomo data helper
42 | *
43 | * @var \Chessio\Matomo\Helper\Data $_dataHelper
44 | */
45 | protected $_dataHelper;
46 |
47 | /**
48 | * Constructor
49 | *
50 | * @param \Chessio\Matomo\Model\Tracker $matomoTracker
51 | * @param \Chessio\Matomo\Helper\Data $dataHelper
52 | */
53 | public function __construct(
54 | \Chessio\Matomo\Model\Tracker $matomoTracker,
55 | \Chessio\Matomo\Helper\Data $dataHelper
56 | ) {
57 | $this->_matomoTracker = $matomoTracker;
58 | $this->_dataHelper = $dataHelper;
59 | }
60 |
61 | /**
62 | * Push EcommerceView to tracker on category view page
63 | *
64 | * @param \Magento\Framework\Event\Observer $observer
65 | * @return \Chessio\Matomo\Observer\CategoryViewObserver
66 | */
67 | public function execute(\Magento\Framework\Event\Observer $observer)
68 | {
69 | if (!$this->_dataHelper->isTrackingEnabled()) {
70 | return $this;
71 | }
72 |
73 | $category = $observer->getEvent()->getCategory();
74 | /** @var \Magento\Catalog\Model\Category $category */
75 |
76 | $this->_matomoTracker->setEcommerceView(
77 | false,
78 | false,
79 | $category->getName()
80 | );
81 |
82 | return $this;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Observer/CheckoutSuccessObserver.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Observer;
23 |
24 | use Magento\Framework\Event\ObserverInterface;
25 |
26 | /**
27 | * Observer for `controller_action_predispatch_checkout_cart_index'
28 | *
29 | * @see https://matomo.org/docs/ecommerce-analytics/
30 | */
31 | class CheckoutSuccessObserver implements ObserverInterface
32 | {
33 |
34 | /**
35 | * Matomo tracker instance
36 | *
37 | * @var \Chessio\Matomo\Model\Tracker $_matomoTracker
38 | */
39 | protected $_matomoTracker;
40 |
41 | /**
42 | * Matomo data helper
43 | *
44 | * @var \Chessio\Matomo\Helper\Data $_dataHelper
45 | */
46 | protected $_dataHelper;
47 |
48 | /**
49 | * Matomo tracker helper
50 | *
51 | * @var \Chessio\Matomo\Helper\Tracker $_trackerHelper
52 | */
53 | protected $_trackerHelper;
54 |
55 | /**
56 | * Sales order repository
57 | *
58 | * @var \Magento\Sales\Api\OrderRepositoryInterface $_orderRepository
59 | */
60 | protected $_orderRepository;
61 |
62 | /**
63 | * Search criteria builder
64 | *
65 | * @var \Magento\Framework\Api\SearchCriteriaBuilder $_searchCriteriaBuilder
66 | */
67 | protected $_searchCriteriaBuilder;
68 |
69 | /**
70 | * Constructor
71 | *
72 | * @param \Chessio\Matomo\Model\Tracker $matomoTracker
73 | * @param \Chessio\Matomo\Helper\Data $dataHelper
74 | * @param \Chessio\Matomo\Helper\Tracker $trackerHelper
75 | * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository
76 | * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
77 | */
78 | public function __construct(
79 | \Chessio\Matomo\Model\Tracker $matomoTracker,
80 | \Chessio\Matomo\Helper\Data $dataHelper,
81 | \Chessio\Matomo\Helper\Tracker $trackerHelper,
82 | \Magento\Sales\Api\OrderRepositoryInterface $orderRepository,
83 | \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
84 | ) {
85 | $this->_matomoTracker = $matomoTracker;
86 | $this->_dataHelper = $dataHelper;
87 | $this->_trackerHelper = $trackerHelper;
88 | $this->_orderRepository = $orderRepository;
89 | $this->_searchCriteriaBuilder = $searchCriteriaBuilder;
90 | }
91 |
92 | /**
93 | * Push trackEcommerceOrder to tracker on checkout success page
94 | *
95 | * @param \Magento\Framework\Event\Observer $observer
96 | * @return \Chessio\Matomo\Observer\CheckoutSuccessObserver
97 | */
98 | public function execute(\Magento\Framework\Event\Observer $observer)
99 | {
100 | $orderIds = $observer->getEvent()->getOrderIds();
101 | if (!$this->_dataHelper->isTrackingEnabled()
102 | || empty($orderIds) || !is_array($orderIds)
103 | ) {
104 | return $this;
105 | }
106 |
107 | $searchCriteria = $this->_searchCriteriaBuilder
108 | ->addFilter('entity_id', $orderIds, 'in')
109 | ->create();
110 |
111 | $searchResult = $this->_orderRepository->getList($searchCriteria);
112 |
113 | $this->_trackerHelper->addOrders(
114 | $searchResult->getItems(),
115 | $this->_matomoTracker
116 | );
117 |
118 | return $this;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/Observer/ProductViewObserver.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Observer;
23 |
24 | use Magento\Framework\Event\ObserverInterface;
25 |
26 | /**
27 | * Observer for `catalog_controller_product_view'
28 | *
29 | */
30 | class ProductViewObserver implements ObserverInterface
31 | {
32 |
33 | /**
34 | * Matomo tracker instance
35 | *
36 | * @var \Chessio\Matomo\Model\Tracker
37 | */
38 | protected $_matomoTracker;
39 |
40 | /**
41 | * Matomo data helper
42 | *
43 | * @var \Chessio\Matomo\Helper\Data $_dataHelper
44 | */
45 | protected $_dataHelper;
46 |
47 | /**
48 | * Constructor
49 | *
50 | * @param \Chessio\Matomo\Model\Tracker $matomoTracker
51 | * @param \Chessio\Matomo\Helper\Data $dataHelper
52 | */
53 | public function __construct(
54 | \Chessio\Matomo\Model\Tracker $matomoTracker,
55 | \Chessio\Matomo\Helper\Data $dataHelper
56 | ) {
57 | $this->_matomoTracker = $matomoTracker;
58 | $this->_dataHelper = $dataHelper;
59 | }
60 |
61 | /**
62 | * Push EcommerceView to tracker on product view page
63 | *
64 | * @param \Magento\Framework\Event\Observer $observer
65 | * @return \Chessio\Matomo\Observer\ProductViewObserver
66 | */
67 | public function execute(\Magento\Framework\Event\Observer $observer)
68 | {
69 | if (!$this->_dataHelper->isTrackingEnabled()) {
70 | return $this;
71 | }
72 |
73 | $product = $observer->getEvent()->getProduct();
74 | /** @var \Magento\Catalog\Model\Product $product */
75 |
76 | $category = $product->getCategory();
77 | $this->_matomoTracker->setEcommerceView(
78 | $product->getSku(),
79 | $product->getName(),
80 | $category
81 | ? $category->getName()
82 | : false,
83 | $product->getFinalPrice()
84 | );
85 |
86 | return $this;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Observer/SearchResultObserver.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Observer;
23 |
24 | use Magento\Framework\Event\ObserverInterface;
25 |
26 | /**
27 | * Observer for `controller_action_layout_render_before_catalogsearch_result_index'
28 | *
29 | * @see http://developer.matomo.org/guides/tracking-javascript-guide#internal-search-tracking
30 | */
31 | class SearchResultObserver implements ObserverInterface
32 | {
33 |
34 | /**
35 | * Matomo tracker instance
36 | *
37 | * @var \Chessio\Matomo\Model\Tracker
38 | */
39 | protected $_matomoTracker;
40 |
41 | /**
42 | * Matomo data helper
43 | *
44 | * @var \Chessio\Matomo\Helper\Data $_dataHelper
45 | */
46 | protected $_dataHelper;
47 |
48 | /**
49 | * Search query factory
50 | *
51 | * @var \Magento\Search\Model\QueryFactory $_queryFactory
52 | */
53 | protected $_queryFactory;
54 |
55 | /**
56 | * Current view
57 | *
58 | * @var \Magento\Framework\App\ViewInterface $_view
59 | */
60 | protected $_view;
61 |
62 | /**
63 | * Constructor
64 | *
65 | * @param \Chessio\Matomo\Model\Tracker $matomoTracker
66 | * @param \Chessio\Matomo\Helper\Data $dataHelper
67 | * @param \Magento\Search\Model\QueryFactory $queryFactory
68 | * @param \Magento\Framework\App\ViewInterface $view
69 | */
70 | public function __construct(
71 | \Chessio\Matomo\Model\Tracker $matomoTracker,
72 | \Chessio\Matomo\Helper\Data $dataHelper,
73 | \Magento\Search\Model\QueryFactory $queryFactory,
74 | \Magento\Framework\App\ViewInterface $view
75 | ) {
76 | $this->_matomoTracker = $matomoTracker;
77 | $this->_dataHelper = $dataHelper;
78 | $this->_queryFactory = $queryFactory;
79 | $this->_view = $view;
80 | }
81 |
82 | /**
83 | * Push `trackSiteSearch' to tracker on search result page
84 | *
85 | * @param \Magento\Framework\Event\Observer $observer
86 | * @return \Chessio\Matomo\Observer\SearchResultObserver
87 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
88 | */
89 | public function execute(\Magento\Framework\Event\Observer $observer)
90 | {
91 | if (!$this->_dataHelper->isTrackingEnabled()) {
92 | return $this;
93 | }
94 |
95 | $query = $this->_queryFactory->get();
96 | $matomoBlock = $this->_view->getLayout()->getBlock('matomo.tracker');
97 | /** @var \Magento\Search\Model\Query $query */
98 | /** @var \Chessio\Matomo\Block\Matomo $matomoBlock */
99 |
100 | $keyword = $query->getQueryText();
101 | $resultsCount = $query->getNumResults();
102 |
103 | if ($resultsCount === null) {
104 | // If this is a new search query the result count hasn't been saved
105 | // yet so we have to fetch it from the search result block instead.
106 | $resultBock = $this->_view->getLayout()->getBlock('search.result');
107 | /** @var \Magento\CatalogSearch\Block\Result $resultBock */
108 | if ($resultBock) {
109 | $resultsCount = $resultBock->getResultCount();
110 | }
111 | }
112 |
113 | if ($resultsCount === null) {
114 | $this->_matomoTracker->trackSiteSearch($keyword);
115 | } else {
116 | $this->_matomoTracker->trackSiteSearch(
117 | $keyword,
118 | false,
119 | (int) $resultsCount
120 | );
121 | }
122 |
123 | if ($matomoBlock) {
124 | // Don't push `trackPageView' when `trackSiteSearch' is set
125 | $matomoBlock->setSkipTrackPageView(true);
126 | }
127 |
128 | return $this;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Matomo Integration for Magento 2
2 |
3 | *Chessio_Matomo* is a [Matomo](https://matomo.org/) web analytics module for the [Magento 2](https://magento.com/) eCommerce platform. Matomo is an extensible free/libre analytics tool that can be self-hosted, giving you complete data ownership. Chessio_Matomo lets you integrate Matomo with your Magento 2 store front.
4 |
5 | This module is the successor of [*Henhed_Piwik*](https://packagist.org/packages/henhed/module-piwik) and thus continues with its semantic versioning, beginning with version `v2.1.0` . If you're using a Magento version prior to 2.2, you'll need to stick to the 1.x releases of the original Henhed_Piwik. For manual installation, check out the [Releases archive](https://github.com/fnogatz/magento2-matomo/releases). For installation using [Composer](https://getcomposer.org/), you can use the *tilde* or *caret* version constraint operators (e.g. `~1.3` or `^1.3.1`).
6 |
7 | ## Installation
8 |
9 | To install Chessio_Matomo, download and extract the [main zip archive](https://github.com/fnogatz/magento2-matomo/archive/main.zip) and move the extracted folder to *app/code/Chessio/Matomo* in your Magento 2 installation directory.
10 |
11 | ```sh
12 | unzip magento2-matomo-main.zip
13 | mkdir app/code/Chessio
14 | mv magento2-matomo-main app/code/Chessio/Matomo
15 | ```
16 |
17 | Alternatively, you can clone the Chessio_Matomo Git repository into *app/code/Chessio_Matomo*.
18 |
19 | ```sh
20 | git clone https://github.com/fnogatz/magento2-matomo.git app/code/Chessio/Matomo
21 | ```
22 |
23 | Or, if you prefer, install it using [Composer](https://getcomposer.org/).
24 |
25 | ```sh
26 | composer require chessio/module-matomo
27 | ```
28 |
29 | Finally, enable the module with the Magento CLI tool.
30 |
31 | ```sh
32 | php bin/magento module:enable Chessio_Matomo --clear-static-content
33 | ```
34 |
35 | ## Configuration
36 |
37 | Once installed, configuration options can be found in the Magento 2 administration panel under *Stores/Configuration/Sales/Matomo API*.
38 | To start tracking, set *Enable Tracking* to *Yes*, enter the *Hostname* of your Matomo installation and click *Save Config*. If you have multiple websites in the same Matomo installation, make sure the *Site ID* configured in Magento is correct.
39 |
40 | ## Customization
41 |
42 | If you need to send some custom information to your Matomo server, Chessio_Matomo lets you do so using event observers.
43 |
44 | To set custom data on each page, use the `matomo_track_page_view_before` event. A tracker instance will be passed along with the event object to your observer's `execute` method.
45 |
46 | ```php
47 | public function execute(\Magento\Framework\Event\Observer $observer)
48 | {
49 | $tracker = $observer->getEvent()->getTracker();
50 | /** @var \Chessio\Matomo\Model\Tracker $tracker */
51 | $tracker->setDocumentTitle('My Custom Title');
52 | }
53 | ```
54 |
55 | If you only want to add data under some specific circumstance, find a suitable event and request the tracker singleton in your observer's constructor. Store the tracker in a class member variable for later use in the `execute` method.
56 |
57 | ```php
58 | public function __construct(\Chessio\Matomo\Model\Tracker $matomoTracker)
59 | {
60 | $this->_matomoTracker = $matomoTracker;
61 | }
62 | ```
63 |
64 | Beware of tracking user specific information on the server side as it will most likely cause caching problems. Instead, use Javascript to retrieve the user data from a cookie, localStorage or some Ajax request and then push the data to Matomo using either the Chessio_Matomo JS component...
65 |
66 | ```js
67 | require(['Chessio_Matomo/js/tracker'], function (trackerComponent) {
68 | trackerComponent.getTracker().done(function (tracker) {
69 | // Do something with tracker
70 | });
71 | });
72 | ```
73 |
74 | ... or the vanilla Matomo approach:
75 |
76 | ```js
77 | var _paq = _paq || [];
78 | _paq.push(['setDocumentTitle', 'My Custom Title']);
79 | ```
80 |
81 | See the [Matomo Developer Docs](https://developer.matomo.org/api-reference/tracking-javascript) or the [\Chessio\Matomo\Model\Tracker](https://github.com/fnogatz/magento2-matomo/blob/main/Model/Tracker.php) source code for a list of all methods available in the Tracking API.
82 |
--------------------------------------------------------------------------------
/Test/Unit/CustomerData/Checkout/CartPluginTest.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Test\Unit\CustomerData\Checkout;
23 |
24 | use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
25 |
26 | /**
27 | * Test for \Chessio\Matomo\CustomerData\Checkout\CartPlugin
28 | *
29 | */
30 | class CartPluginTest extends \PHPUnit\Framework\TestCase
31 | {
32 |
33 | /**
34 | * Customer data checkout cart plugin (test subject) instance
35 | *
36 | * @var \Chessio\Matomo\CustomerData\Checkout\CartPlugin $_cartPlugin
37 | */
38 | protected $_cartPlugin;
39 |
40 | /**
41 | * Cart customer data mock object
42 | *
43 | * @var \PHPUnit_Framework_MockObject_MockObject $_cartMock
44 | */
45 | protected $_cartMock;
46 |
47 | /**
48 | * Quote model mock object
49 | *
50 | * @var \PHPUnit_Framework_MockObject_MockObject $_quoteMock
51 | */
52 | protected $_quoteMock;
53 |
54 | /**
55 | * Matomo data helper mock object
56 | *
57 | * @var \PHPUnit_Framework_MockObject_MockObject $_dataHelperMock
58 | */
59 | protected $_dataHelperMock;
60 |
61 | /**
62 | * Tracker model mock object
63 | *
64 | * @var \PHPUnit_Framework_MockObject_MockObject $_trackerMock
65 | */
66 | protected $_trackerMock;
67 |
68 | /**
69 | * Tracker helper mock object
70 | *
71 | * @var \PHPUnit_Framework_MockObject_MockObject $_trackerHelperMock
72 | */
73 | protected $_trackerHelperMock;
74 |
75 | /**
76 | * Set up
77 | *
78 | * @return void
79 | */
80 | public function setUp(): void
81 | {
82 | $className = \Chessio\Matomo\CustomerData\Checkout\CartPlugin::class;
83 | $objectManager = new ObjectManager($this);
84 | $sessionProxyClass = \Magento\Checkout\Model\Session\Proxy::class;
85 | $arguments = $objectManager->getConstructArguments($className, [
86 | 'checkoutSession' => $this->getMockBuilder($sessionProxyClass)
87 | ->disableOriginalConstructor()
88 | ->setMethods(['getQuote'])
89 | ->getMock(),
90 | 'trackerFactory' => $this->createPartialMock(
91 | \Chessio\Matomo\Model\TrackerFactory::class,
92 | ['create']
93 | )
94 | ]);
95 | $this->_cartPlugin = $objectManager->getObject($className, $arguments);
96 |
97 | $this->_quoteMock = $this->createPartialMock(
98 | \Magento\Quote\Model\Quote::class,
99 | ['getId']
100 | );
101 | $arguments['checkoutSession']
102 | ->expects($this->any())
103 | ->method('getQuote')
104 | ->willReturn($this->_quoteMock);
105 |
106 | $this->_dataHelperMock = $arguments['dataHelper'];
107 | $this->_trackerMock = $this->createMock(
108 | \Chessio\Matomo\Model\Tracker::class
109 | );
110 | $arguments['trackerFactory']
111 | ->expects($this->any())
112 | ->method('create')
113 | ->willReturn($this->_trackerMock);
114 |
115 | $this->_trackerHelperMock = $arguments['trackerHelper'];
116 |
117 | $this->_cartMock = $this->createMock(
118 | \Magento\Checkout\CustomerData\Cart::class
119 | );
120 | }
121 |
122 | /**
123 | * Test \Chessio\Matomo\CustomerData\Checkout\CartPlugin::afterGetSectionData
124 | * with existing quote.
125 | *
126 | * @return void
127 | */
128 | public function testafterGetSectionData()
129 | {
130 | $expectedResult = ['matomoActions' => ['someKey' => 'someValue']];
131 |
132 | // Enable tracking
133 | $this->_dataHelperMock
134 | ->expects($this->once())
135 | ->method('isTrackingEnabled')
136 | ->willReturn(true);
137 |
138 | // Give ID to quote mock
139 | $this->_quoteMock
140 | ->expects($this->once())
141 | ->method('getId')
142 | ->willReturn(1);
143 |
144 | // Make sure tracker helpers' `addQuote' is called exactly once
145 | $this->_trackerHelperMock
146 | ->expects($this->once())
147 | ->method('addQuote')
148 | ->with($this->_quoteMock, $this->_trackerMock)
149 | ->willReturn($this->_trackerHelperMock);
150 |
151 | // Make tracker mock return expected data
152 | $this->_trackerMock
153 | ->expects($this->once())
154 | ->method('toArray')
155 | ->willReturn($expectedResult['matomoActions']);
156 |
157 | // Assert that result of plugin equals expected result
158 | $this->assertEquals(
159 | $expectedResult,
160 | $this->_cartPlugin->afterGetSectionData($this->_cartMock, [])
161 | );
162 | }
163 |
164 | /**
165 | * Test \Chessio\Matomo\CustomerData\Checkout\CartPlugin::afterGetSectionData
166 | * with empty quote.
167 | *
168 | * @return void
169 | */
170 | public function testafterGetSectionDataWithEmptyQuote()
171 | {
172 | // Enable tracking
173 | $this->_dataHelperMock
174 | ->expects($this->once())
175 | ->method('isTrackingEnabled')
176 | ->willReturn(true);
177 |
178 | // Make sure tracker methods are never called
179 | $this->_trackerHelperMock
180 | ->expects($this->never())
181 | ->method('addQuote');
182 | $this->_trackerMock
183 | ->expects($this->never())
184 | ->method('toArray');
185 |
186 | // Assert that result of plugin is same as input
187 | $result = ['someKey' => 'someValue'];
188 | $this->assertEquals(
189 | $result,
190 | $this->_cartPlugin->afterGetSectionData($this->_cartMock, $result)
191 | );
192 | }
193 |
194 | /**
195 | * Test \Chessio\Matomo\CustomerData\Checkout\CartPlugin::afterGetSectionData
196 | * with tracking disabled.
197 | *
198 | * @return void
199 | */
200 | public function testafterGetSectionDataWithTrackingDisabled()
201 | {
202 | // Disable tracking
203 | $this->_dataHelperMock
204 | ->expects($this->once())
205 | ->method('isTrackingEnabled')
206 | ->willReturn(false);
207 |
208 | // Give ID to quote mock
209 | $this->_quoteMock
210 | ->expects($this->any())
211 | ->method('getId')
212 | ->willReturn(1);
213 |
214 | // Make sure tracker methods are never called
215 | $this->_trackerHelperMock
216 | ->expects($this->never())
217 | ->method('addQuote');
218 | $this->_trackerMock
219 | ->expects($this->never())
220 | ->method('toArray');
221 |
222 | // Assert that result of plugin is same as input
223 | $result = ['someKey' => 'someValue'];
224 | $this->assertEquals(
225 | $result,
226 | $this->_cartPlugin->afterGetSectionData($this->_cartMock, $result)
227 | );
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/Test/Unit/CustomerData/Customer/CustomerPluginTest.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Test\Unit\CustomerData\Customer;
23 |
24 | use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
25 |
26 | /**
27 | * Test for \Chessio\Matomo\CustomerData\Customer\CustomerPlugin
28 | *
29 | */
30 | class CustomerPluginTest extends \PHPUnit\Framework\TestCase
31 | {
32 |
33 | /**
34 | * Customer data plugin (test subject) instance
35 | *
36 | * @var \Chessio\Matomo\CustomerData\Customer\CustomerPlugin $_customerPlugin
37 | */
38 | protected $_customerPlugin;
39 |
40 | /**
41 | * Current customer helper mock object
42 | *
43 | * @var \PHPUnit_Framework_MockObject_MockObject $_currentCustomerMock
44 | */
45 | protected $_currentCustomerMock;
46 |
47 | /**
48 | * Matomo data helper mock object
49 | *
50 | * @var \PHPUnit_Framework_MockObject_MockObject $_dataHelperMock
51 | */
52 | protected $_dataHelperMock;
53 |
54 | /**
55 | * Matomo user ID provider pool mock object
56 | *
57 | * @var \PHPUnit_Framework_MockObject_MockObject $_uidProviderPoolMock
58 | */
59 | protected $_uidProviderPoolMock;
60 |
61 | /**
62 | * Matomo user ID provider mock object
63 | *
64 | * @var \PHPUnit_Framework_MockObject_MockObject $_uidProviderMock
65 | */
66 | protected $_uidProviderMock;
67 |
68 | /**
69 | * Customer data mock object
70 | *
71 | * @var \PHPUnit_Framework_MockObject_MockObject $_customerDataMock
72 | */
73 | protected $_customerDataMock;
74 |
75 | /**
76 | * Set up
77 | *
78 | * @return void
79 | */
80 | public function setUp(): void
81 | {
82 | $className = \Chessio\Matomo\CustomerData\Customer\CustomerPlugin::class;
83 | $objectManager = new ObjectManager($this);
84 | $args = $objectManager->getConstructArguments($className);
85 | $this->_customerPlugin = $objectManager->getObject($className, $args);
86 | $this->_currentCustomerMock = $args['currentCustomer'];
87 | $this->_dataHelperMock = $args['dataHelper'];
88 | $this->_uidProviderPoolMock = $args['uidProviderPool'];
89 | $this->_uidProviderMock = $this->createPartialMock(
90 | \Chessio\Matomo\UserId\Provider\ProviderInterface::class,
91 | ['getUserId', 'getTitle']
92 | );
93 | $this->_customerDataMock = $this->createMock(
94 | \Magento\Customer\CustomerData\Customer::class
95 | );
96 | }
97 |
98 | /**
99 | * Data provider for `testafterGetSectionData'
100 | *
101 | * @return array
102 | */
103 | public function testafterGetSectionDataDataProvider()
104 | {
105 | return [
106 | [false, 1, 'p', 'UID1'],
107 | [true, null, 'p', 'UID2'],
108 | [true, 3, 'p', ''],
109 | [true, 4, null, 'UID4'],
110 | [true, 5, 'p', 'UID5']
111 | ];
112 | }
113 |
114 | /**
115 | * Test `afterGetSectionData'
116 | *
117 | * @param bool $enabled
118 | * @param int $customerId
119 | * @param string|null $provider
120 | * @param string $userId
121 | * @return void
122 | * @dataProvider testafterGetSectionDataDataProvider
123 | */
124 | public function testafterGetSectionData(
125 | $enabled,
126 | $customerId,
127 | $provider,
128 | $userId
129 | ) {
130 | $expectedResult = [];
131 | if ($enabled && $customerId && $provider && $userId) {
132 | $expectedResult['matomoUserId'] = $userId;
133 | }
134 |
135 | $this->_dataHelperMock
136 | ->expects($this->once())
137 | ->method('isTrackingEnabled')
138 | ->willReturn($enabled);
139 |
140 | $this->_dataHelperMock
141 | ->expects($enabled ? $this->once() : $this->never())
142 | ->method('getUserIdProviderCode')
143 | ->willReturn($provider);
144 |
145 | $this->_currentCustomerMock
146 | ->expects($enabled ? $this->once() : $this->never())
147 | ->method('getCustomerId')
148 | ->willReturn($customerId);
149 |
150 | $this->_uidProviderPoolMock
151 | ->expects(
152 | ($enabled && $provider)
153 | ? $this->once()
154 | : $this->never()
155 | )
156 | ->method('getProviderByCode')
157 | ->with($provider)
158 | ->willReturn($this->_uidProviderMock);
159 |
160 | $this->_uidProviderMock
161 | ->expects(
162 | ($enabled && $customerId && $provider)
163 | ? $this->once()
164 | : $this->never()
165 | )
166 | ->method('getUserId')
167 | ->with($customerId)
168 | ->willReturn($userId);
169 |
170 | // Assert that result of plugin equals expected result
171 | $this->assertEquals(
172 | $expectedResult,
173 | $this->_customerPlugin->afterGetSectionData(
174 | $this->_customerDataMock,
175 | []
176 | )
177 | );
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/Test/Unit/Helper/DataTest.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Test\Unit\Helper;
23 |
24 | use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
25 | use Magento\Store\Model\ScopeInterface;
26 |
27 | /**
28 | * Test for \Chessio\Matomo\Helper\Data
29 | *
30 | */
31 | class DataTest extends \PHPUnit\Framework\TestCase
32 | {
33 |
34 | /**
35 | * Matomo data helper (test subject) instance
36 | *
37 | * @var \Chessio\Matomo\Helper\Data $_helper
38 | */
39 | protected $_helper;
40 |
41 | /**
42 | * Scope config mock object
43 | *
44 | * @var \PHPUnit_Framework_MockObject_MockObject
45 | */
46 | protected $_scopeConfigMock;
47 |
48 | /**
49 | * Request mock object
50 | *
51 | * @var \PHPUnit_Framework_MockObject_MockObject
52 | */
53 | protected $_requestMock;
54 |
55 | /**
56 | * Setup
57 | *
58 | * @return void
59 | */
60 | public function setUp(): void
61 | {
62 | $className = \Chessio\Matomo\Helper\Data::class;
63 | $objectManager = new ObjectManager($this);
64 | $arguments = $objectManager->getConstructArguments($className);
65 | $this->_helper = $objectManager->getObject($className, $arguments);
66 | $context = $arguments['context'];
67 | /** @var \Magento\Framework\App\Helper\Context $context */
68 | $this->_scopeConfigMock = $context->getScopeConfig();
69 | $this->_requestMock = $context->getRequest();
70 | }
71 |
72 | /**
73 | * Prepare scope config mock with given values
74 | *
75 | * @param string $enabled
76 | * @param string $hostname
77 | * @param string $siteId
78 | * @param string $linkEnabled
79 | * @param string $linkDelay
80 | * @param string $phpScriptPath
81 | * @param string $jsScriptPath
82 | * @param string $cdnHostname
83 | * @param string $scope
84 | * @param null|string|bool|int|\Magento\Store\Model\Store $store
85 | */
86 | protected function _prepareScopeConfigMock(
87 | $enabled = null,
88 | $hostname = null,
89 | $siteId = null,
90 | $linkEnabled = null,
91 | $linkDelay = null,
92 | $phpScriptPath = null,
93 | $jsScriptPath = null,
94 | $cdnHostname = null,
95 | $scope = ScopeInterface::SCOPE_STORE,
96 | $store = null
97 | ) {
98 | $this->_scopeConfigMock
99 | ->expects($this->any())
100 | ->method('isSetFlag')
101 | ->will($this->returnValueMap([
102 | [
103 | \Chessio\Matomo\Helper\Data::XML_PATH_ENABLED,
104 | $scope, $store, $enabled
105 | ],
106 | [
107 | \Chessio\Matomo\Helper\Data::XML_PATH_LINK_ENABLED,
108 | $scope, $store, $linkEnabled
109 | ]
110 | ]));
111 |
112 | $this->_scopeConfigMock
113 | ->expects($this->any())
114 | ->method('getValue')
115 | ->will($this->returnValueMap([
116 | [
117 | \Chessio\Matomo\Helper\Data::XML_PATH_HOSTNAME,
118 | $scope, $store, $hostname
119 | ],
120 | [
121 | \Chessio\Matomo\Helper\Data::XML_PATH_SITE_ID,
122 | $scope, $store, $siteId
123 | ],
124 | [
125 | \Chessio\Matomo\Helper\Data::XML_PATH_LINK_DELAY,
126 | $scope, $store, $linkDelay
127 | ],
128 | [
129 | \Chessio\Matomo\Helper\Data::XML_PATH_PHP_SCRIPT_PATH,
130 | $scope, $store, $phpScriptPath
131 | ],
132 | [
133 | \Chessio\Matomo\Helper\Data::XML_PATH_JS_SCRIPT_PATH,
134 | $scope, $store, $jsScriptPath
135 | ],
136 | [
137 | \Chessio\Matomo\Helper\Data::XML_PATH_CDN_HOSTNAME,
138 | $scope, $store, $cdnHostname
139 | ]
140 | ]));
141 | }
142 |
143 | /**
144 | * Data provider for `testIsTrackingEnabled'
145 | *
146 | * @return array
147 | */
148 | public function isTrackingEnabledDataProvider()
149 | {
150 | return [
151 | [true, 'matomo.example.org', 1, true],
152 | [true, '', 1, false],
153 | [true, ' ', 1, false],
154 | [true, 'example.org/matomo', 0, false],
155 | [false, 'matomo.org', 1, false]
156 | ];
157 | }
158 |
159 | /**
160 | * Test \Chessio\Matomo\Helper\Data::isTrackingEnabled
161 | *
162 | * Also covers `getHostname' and `getSiteId'
163 | *
164 | * @param bool $enabled
165 | * @param string $hostname
166 | * @param int $siteId
167 | * @param bool $returnValue
168 | * @return void
169 | * @dataProvider isTrackingEnabledDataProvider
170 | */
171 | public function testIsTrackingEnabled(
172 | $enabled,
173 | $hostname,
174 | $siteId,
175 | $returnValue
176 | ) {
177 | $this->_prepareScopeConfigMock($enabled, $hostname, $siteId);
178 | $this->assertEquals($returnValue, $this->_helper->isTrackingEnabled());
179 | }
180 |
181 | /**
182 | * Data provider for `testGetPhpScriptUrl'
183 | *
184 | * @return array
185 | */
186 | public function phpScriptUrlDataProvider()
187 | {
188 | return [
189 | [
190 | 'matomo.org',
191 | false, // should prepend `http://'
192 | null, // should fall back on `matomo.php'
193 | // Expected result
194 | 'http://matomo.org/matomo.php'
195 | ],
196 | [
197 | 'example.com/matomo',
198 | true, // should prepend `https://'
199 | 'tracker.php', // should override `matomo.php'
200 | // Expected result
201 | 'https://example.com/matomo/tracker.php'
202 | ],
203 | [
204 | ' https://example.com/ ', // should be trimmed
205 | false, // should replace `https://' with `http://'
206 | ' /matomo/tracker.php ', // should be trimmed
207 | // Expected result
208 | 'http://example.com/matomo/tracker.php'
209 | ]
210 | ];
211 | }
212 |
213 | /**
214 | * Test \Chessio\Matomo\Helper\Data::getPhpScriptUrl
215 | *
216 | * @param string $hostname
217 | * @param bool $isSecure
218 | * @param string $phpScriptPath
219 | * @param string $returnValue
220 | * @dataProvider phpScriptUrlDataProvider
221 | */
222 | public function testGetPhpScriptUrl(
223 | $hostname,
224 | $isSecure,
225 | $phpScriptPath,
226 | $returnValue
227 | ) {
228 | $this->_prepareScopeConfigMock(
229 | null,
230 | $hostname,
231 | null,
232 | null,
233 | null,
234 | $phpScriptPath
235 | );
236 |
237 | // Test explicit `isSecure'
238 | $this->assertEquals(
239 | $returnValue,
240 | $this->_helper->getPhpScriptUrl(null, $isSecure)
241 | );
242 |
243 | // Test implicit `isSecure'
244 | $this->_requestMock
245 | ->expects($this->once())
246 | ->method('isSecure')
247 | ->will($this->returnValue($isSecure));
248 |
249 | $this->assertEquals($returnValue, $this->_helper->getPhpScriptUrl());
250 | }
251 |
252 | /**
253 | * Data provider for `testGetJsScriptUrl'
254 | *
255 | * @return array
256 | */
257 | public function jsScriptUrlDataProvider()
258 | {
259 | return [
260 | [
261 | 'matomo.org',
262 | false, // should prepend `http://'
263 | null, // should fall back on `matomo.js'
264 | null, // should fall back on regular hostname
265 | // Expected result
266 | 'http://matomo.org/matomo.js'
267 | ],
268 | [
269 | ' matomo.org/path/ ', // should be trimmed
270 | true, // should prepend `https://'
271 | 'example.js', // should override `matomo.js'
272 | null, // should fall back on hostname
273 | // Expected result
274 | 'https://matomo.org/path/example.js'
275 | ],
276 | [
277 | 'matomo.org', // should be ignored
278 | true, // should replace `http://' with `https://''
279 | ' /to/tracker.js ', // should be trimmed
280 | 'http://cdn.example.com/path/', // should override hostname
281 | // Expected result
282 | 'https://cdn.example.com/path/to/tracker.js'
283 | ]
284 | ];
285 | }
286 |
287 | /**
288 | * Test \Chessio\Matomo\Helper\Data::getJsScriptUrl
289 | *
290 | * @param string $hostname
291 | * @param bool $isSecure
292 | * @param string $jsScriptPath
293 | * @param string $cdnHostname
294 | * @param string $returnValue
295 | * @dataProvider jsScriptUrlDataProvider
296 | */
297 | public function testGetJsScriptUrl(
298 | $hostname,
299 | $isSecure,
300 | $jsScriptPath,
301 | $cdnHostname,
302 | $returnValue
303 | ) {
304 | $this->_prepareScopeConfigMock(
305 | null,
306 | $hostname,
307 | null,
308 | null,
309 | null,
310 | null,
311 | $jsScriptPath,
312 | $cdnHostname
313 | );
314 |
315 | // Test explicit `isSecure'
316 | $this->assertEquals(
317 | $returnValue,
318 | $this->_helper->getJsScriptUrl(null, $isSecure)
319 | );
320 |
321 | // Test implicit `isSecure'
322 | $this->_requestMock
323 | ->expects($this->once())
324 | ->method('isSecure')
325 | ->will($this->returnValue($isSecure));
326 |
327 | $this->assertEquals($returnValue, $this->_helper->getJsScriptUrl());
328 | }
329 |
330 | /**
331 | * Data provider for `testIsLinkTrackingEnabled'
332 | *
333 | * @return array
334 | */
335 | public function isLinkTrackingEnabledDataProvider()
336 | {
337 | return [
338 | [true, true, 'matomo.example.org', 1, true],
339 | [false, true, 'matomo.example.org', 2, false],
340 | [true, true, '', 1, false],
341 | [true, true, ' ', 1, false],
342 | [false, true, 'example.org/matomo', 0, false],
343 | [true, false, 'matomo.org', 1, false]
344 | ];
345 | }
346 |
347 | /**
348 | * Test \Chessio\Matomo\Helper\Data::isLinkTrackingEnabled
349 | *
350 | * Also covers `isTrackingEnabled'
351 | *
352 | * @param bool $linkEnabled
353 | * @param bool $enabled
354 | * @param string $hostname
355 | * @param int $siteId
356 | * @param bool $returnValue
357 | * @dataProvider isLinkTrackingEnabledDataProvider
358 | */
359 | public function testIsLinkTrackingEnabled(
360 | $linkEnabled,
361 | $enabled,
362 | $hostname,
363 | $siteId,
364 | $returnValue
365 | ) {
366 | $this->_prepareScopeConfigMock(
367 | $enabled,
368 | $hostname,
369 | $siteId,
370 | $linkEnabled
371 | );
372 |
373 | $this->assertEquals(
374 | $returnValue,
375 | $this->_helper->isLinkTrackingEnabled()
376 | );
377 | }
378 | }
379 |
--------------------------------------------------------------------------------
/Test/Unit/Helper/TrackerTest.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Test\Unit\Helper;
23 |
24 | use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
25 |
26 | /**
27 | * Test for \Chessio\Matomo\Helper\Tracker
28 | *
29 | */
30 | class TrackerTest extends \PHPUnit\Framework\TestCase
31 | {
32 |
33 | /**
34 | * Matomo tracker helper (test subject) instance
35 | *
36 | * @var \Chessio\Matomo\Helper\Tracker $_helper
37 | */
38 | protected $_helper;
39 |
40 | /**
41 | * Tracker instance
42 | *
43 | * @var \Chessio\Matomo\Model\Tracker $_tracker
44 | */
45 | protected $_tracker;
46 |
47 | /**
48 | * Setup
49 | *
50 | * @return void
51 | */
52 | public function setUp(): void
53 | {
54 | $objectManager = new ObjectManager($this);
55 |
56 | // Create test subject
57 | $this->_helper = $objectManager->getObject(
58 | \Chessio\Matomo\Helper\Tracker::class
59 | );
60 |
61 | // Create tracker instance
62 | $class = \Chessio\Matomo\Model\Tracker::class;
63 | $arguments = $objectManager->getConstructArguments($class, [
64 | 'actionFactory' => $this->createPartialMock(
65 | \Chessio\Matomo\Model\Tracker\ActionFactory::class,
66 | ['create']
67 | )
68 | ]);
69 | $arguments['actionFactory']
70 | ->expects($this->any())
71 | ->method('create')
72 | ->willReturnCallback(function ($data) {
73 | return new \Chessio\Matomo\Model\Tracker\Action(
74 | $data['name'],
75 | $data['args']
76 | );
77 | });
78 | $this->_tracker = $objectManager->getObject($class, $arguments);
79 | }
80 |
81 | /**
82 | * Quote item data provider
83 | *
84 | * @return array
85 | */
86 | public function addQuoteDataProvider()
87 | {
88 | return [
89 | [
90 | [
91 | ['SKUA', 'First product', 123.45, 1],
92 | ['SKUB', 'Second product', 6780, 2]
93 | ],
94 | 123456.78
95 | ],
96 | [
97 | [
98 | ['', '', '123.45', '0'],
99 | [null, true, 0, false],
100 | [false, 0, -123, -2]
101 | ],
102 | null
103 | ]
104 | ];
105 | }
106 |
107 | /**
108 | * Test for \Chessio\Matomo\Helper\Tracker::addQuote
109 | *
110 | * Also covers `addQuoteItem' and `addQuoteTotal'
111 | *
112 | * @param array $items
113 | * @param float $total
114 | * @dataProvider addQuoteDataProvider
115 | */
116 | public function testAddQuote($items, $total)
117 | {
118 | // Build expected tracker result from $items and $total
119 | $expectedResult = [];
120 | foreach ($items as $item) {
121 | list($sku, $name, $price, $qty) = $item;
122 | $expectedResult[] = [
123 | 'addEcommerceItem',
124 | $sku,
125 | $name,
126 | false,
127 | (float) $price,
128 | (float) $qty
129 | ];
130 | }
131 | $expectedResult[] = ['trackEcommerceCartUpdate', (float) $total];
132 |
133 | // Test `addQuote' with mock quote created from $items and $total
134 | $this->_helper->addQuote(
135 | $this->_getQuoteMock($items, $total),
136 | $this->_tracker
137 | );
138 | $this->assertSame($expectedResult, $this->_tracker->toArray());
139 | }
140 |
141 | /**
142 | * Order collection data provider
143 | *
144 | * @return array
145 | */
146 | public function addOrdersDataProvider()
147 | {
148 | return [
149 | [
150 | // Sample orders data
151 | [
152 | [
153 | '100001', 123.45, 101, 10, 15, -5,
154 | [
155 | ['sku1', 'Name 1', 50, 2, null],
156 | ['sku2', 'Name 2', 50, 3, null]
157 | ]
158 | ],
159 | [
160 | '100002', '234.56', '201', '15', '20', '-50',
161 | [
162 | ['sku2', 'Name 2 (2)', '60', '1', null],
163 | ['sku3', 'Name 3', '70', '2', null],
164 | ['sku4', 'Name 4', '0', '1', 1]
165 | ]
166 | ]
167 | ],
168 | // Expected tracker data
169 | [
170 | // Same as `sku1' from `100001'
171 | ['addEcommerceItem', 'sku1', 'Name 1', false, 50.0, 2.0],
172 |
173 | // Aggregated data for `sku2' from `100001' *and* `100002'
174 | [
175 | 'addEcommerceItem',
176 | 'sku2',
177 | 'Name 2', // Name from first occurance of `sku2'
178 | false, // No category name
179 | 52.5, // Sum of price / sum of qty (50*3 + 60)/4
180 | 4.0 // Sum of qty
181 | ],
182 |
183 | // Same as `sku3' from `100002'
184 | ['addEcommerceItem', 'sku3', 'Name 3', false, 70.0, 2.0],
185 |
186 | // `sku4' should be skipped as it's a child item
187 |
188 | // Aggregated order data from `100001' and `100002'
189 | [
190 | 'trackEcommerceOrder',
191 | '100001, 100002', // Concat increment IDs
192 | 358.01, // 123.45 + 234.56
193 | 302.0, // 101 + 201
194 | 25.0, // 10 + 15
195 | 35.0, // 15 + 20
196 | 55.0 // abs(-5 + -50)
197 | ]
198 | ]
199 | ]
200 | ];
201 | }
202 |
203 | /**
204 | * Test for \Chessio\Matomo\Helper\Tracker::addOrders
205 | *
206 | * @param array $ordersData
207 | * @param array $expectedResult
208 | * @return void
209 | * @dataProvider addOrdersDataProvider
210 | */
211 | public function testAddOrders($ordersData, $expectedResult)
212 | {
213 | $orders = [];
214 | foreach ($ordersData as $orderData) {
215 | list($incrementId, $grandTotal, $subTotal, $tax, $shipping,
216 | $discount, $itemsData) = $orderData;
217 | $orders[] = $this->_getOrderMock(
218 | $incrementId,
219 | $grandTotal,
220 | $subTotal,
221 | $tax,
222 | $shipping,
223 | $discount,
224 | $itemsData
225 | );
226 | }
227 |
228 | $this->assertSame(
229 | $this->_helper,
230 | $this->_helper->addOrders($orders, $this->_tracker)
231 | );
232 | $this->assertEquals($expectedResult, $this->_tracker->toArray());
233 | }
234 |
235 | /**
236 | * Create a mock quote object with given data
237 | *
238 | * @param array $items
239 | * @param float $total
240 | * @return \PHPUnit_Framework_MockObject_MockObject
241 | */
242 | protected function _getQuoteMock($items, $total)
243 | {
244 | $quoteItems = [];
245 | foreach ($items as $itemData) {
246 | list($sku, $name, $price, $qty) = $itemData;
247 | $item = $this->createPartialMock(
248 | \Magento\Quote\Model\Quote\Item::class,
249 | ['getData']
250 | );
251 | $item
252 | ->expects($this->any())
253 | ->method('getData')
254 | ->willReturnMap([
255 | ['sku', null, $sku],
256 | ['name', null, $name],
257 | ['base_price_incl_tax', null, $price],
258 | ['qty', null, $qty]
259 | ]);
260 | $quoteItems[] = $item;
261 | }
262 |
263 | $quote = $this->createPartialMock(
264 | \Magento\Quote\Model\Quote::class,
265 | ['getAllVisibleItems', 'getData']
266 | );
267 | $quote
268 | ->expects($this->any())
269 | ->method('getAllVisibleItems')
270 | ->willReturn($quoteItems);
271 | $quote
272 | ->expects($this->any())
273 | ->method('getData')
274 | ->with('base_grand_total')
275 | ->willReturn($total);
276 |
277 | return $quote;
278 | }
279 |
280 | /**
281 | * Create order mock object
282 | *
283 | * @param string $incrementId
284 | * @param float $grandTotal
285 | * @param float $subTotal
286 | * @param float $tax
287 | * @param float $shipping
288 | * @param float $discount
289 | * @param array $itemsData
290 | * @return \PHPUnit_Framework_MockObject_MockObject
291 | */
292 | protected function _getOrderMock(
293 | $incrementId,
294 | $grandTotal,
295 | $subTotal,
296 | $tax,
297 | $shipping,
298 | $discount,
299 | $itemsData
300 | ) {
301 | $items = [];
302 | foreach ($itemsData as $itemData) {
303 | list($sku, $name, $price, $qty, $parentId) = $itemData;
304 | $items[] = $this->createConfiguredMock(
305 | \Magento\Sales\Api\Data\OrderItemInterface::class,
306 | [
307 | 'getSku' => $sku,
308 | 'getName' => $name,
309 | 'getBasePriceInclTax' => $price,
310 | 'getQtyOrdered' => $qty,
311 | 'getParentItemId' => $parentId
312 | ]
313 | );
314 | }
315 | $orderMock = $this->createConfiguredMock(
316 | \Magento\Sales\Api\Data\OrderInterface::class,
317 | [
318 | 'getIncrementId' => $incrementId,
319 | 'getBaseGrandTotal' => $grandTotal,
320 | 'getBaseSubtotalInclTax' => $subTotal,
321 | 'getBaseTaxAmount' => $tax,
322 | 'getBaseShippingInclTax' => $shipping,
323 | 'getBaseDiscountAmount' => $discount,
324 | 'getItems' => $items
325 | ]
326 | );
327 | return $orderMock;
328 | }
329 | }
330 |
--------------------------------------------------------------------------------
/Test/Unit/Model/TrackerTest.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Test\Unit\Model;
23 |
24 | use \Chessio\Matomo\Model\Tracker;
25 | use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
26 |
27 | /**
28 | * Test for \Chessio\Matomo\Model\Tracker
29 | *
30 | */
31 | class TrackerTest extends \PHPUnit\Framework\TestCase
32 | {
33 |
34 | /**
35 | * Tracker instance
36 | *
37 | * @var \Chessio\Matomo\Model\Tracker $_tracker
38 | */
39 | protected $_tracker;
40 |
41 | /**
42 | * Action factory mock
43 | *
44 | * @var \PHPUnit_Framework_MockObject_MockObject $_actionFactory
45 | */
46 | protected $_actionFactory;
47 |
48 | /**
49 | * Setup
50 | *
51 | * @return void
52 | */
53 | public function setUp(): void
54 | {
55 | $className = \Chessio\Matomo\Model\Tracker::class;
56 | $objectManager = new ObjectManager($this);
57 | $arguments = $objectManager->getConstructArguments($className, [
58 | 'actionFactory' => $this->createPartialMock(
59 | \Chessio\Matomo\Model\Tracker\ActionFactory::class,
60 | ['create']
61 | )
62 | ]);
63 | $this->_tracker = $objectManager->getObject($className, $arguments);
64 | $this->_actionFactory = $arguments['actionFactory'];
65 | }
66 |
67 | /**
68 | * Test tracker action push
69 | *
70 | * Covers Tracker::push and Tracker::toArray
71 | *
72 | * @param string $name
73 | * @param array $args
74 | * @dataProvider trackerActionDataProvider
75 | */
76 | public function testPush($name, $args)
77 | {
78 | $this->_tracker->push(new Tracker\Action($name, $args));
79 | $this->assertEquals(
80 | [array_merge([$name], $args)],
81 | $this->_tracker->toArray()
82 | );
83 | }
84 |
85 | /**
86 | * Test magic tracker action push
87 | *
88 | * Covers Tracker::__call and Tracker::toArray
89 | *
90 | * @param string $name
91 | * @param array $args
92 | * @dataProvider trackerActionDataProvider
93 | */
94 | public function testMagicPush($name, $args)
95 | {
96 | $this->_actionFactory
97 | ->expects($this->once())
98 | ->method('create')
99 | ->with([
100 | 'name' => $name,
101 | 'args' => $args
102 | ])
103 | ->will($this->returnValue(new Tracker\Action($name, $args)));
104 |
105 | // @codingStandardsIgnoreStart
106 | call_user_func_array([$this->_tracker, $name], $args);
107 | // @codingStandardsIgnoreEnd
108 |
109 | $this->assertEquals(
110 | [array_merge([$name], $args)],
111 | $this->_tracker->toArray()
112 | );
113 | }
114 |
115 | /**
116 | * Tracker action data provider
117 | *
118 | * @return array
119 | */
120 | public function trackerActionDataProvider()
121 | {
122 | return [
123 | ['trackEvent', ['category', 'action', 'name', 1]],
124 | ['trackPageView', ['customTitle']],
125 | ['trackSiteSearch', ['keyword', 'category', 0]],
126 | ['trackGoal', [1, 1.1]],
127 | ['trackLink', ['url', 'linkType']],
128 | ['disableCookies', []]
129 | ];
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/Test/Unit/Observer/BeforeTrackPageViewObserverTest.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Test\Unit\Observer;
23 |
24 | use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
25 |
26 | /**
27 | * Test for \Chessio\Matomo\Observer\BeforeTrackPageViewObserver
28 | *
29 | */
30 | class BeforeTrackPageViewObserverTest extends \PHPUnit\Framework\TestCase
31 | {
32 |
33 | /**
34 | * Before track page view observer (test subject) instance
35 | *
36 | * @var \Chessio\Matomo\Observer\BeforeTrackPageViewObserver $_observer
37 | */
38 | protected $_observer;
39 |
40 | /**
41 | * Matomo data helper mock object
42 | *
43 | * @var \PHPUnit_Framework_MockObject_MockObject $_dataHelperMock
44 | */
45 | protected $_dataHelperMock;
46 |
47 | /**
48 | * Matomo tracker mock object
49 | *
50 | * @var \PHPUnit_Framework_MockObject_MockObject $_trackerMock
51 | */
52 | protected $_trackerMock;
53 |
54 | /**
55 | * Event mock object
56 | *
57 | * @var \PHPUnit_Framework_MockObject_MockObject $_eventMock
58 | */
59 | protected $_eventMock;
60 |
61 | /**
62 | * Event observer mock object
63 | *
64 | * @var \PHPUnit_Framework_MockObject_MockObject $_eventObserverMock
65 | */
66 | protected $_eventObserverMock;
67 |
68 | /**
69 | * Set up
70 | *
71 | * @return void
72 | */
73 | public function setUp(): void
74 | {
75 | $className = \Chessio\Matomo\Observer\BeforeTrackPageViewObserver::class;
76 | $objectManager = new ObjectManager($this);
77 | $arguments = $objectManager->getConstructArguments($className);
78 | $this->_observer = $objectManager->getObject($className, $arguments);
79 | $this->_dataHelperMock = $arguments['dataHelper'];
80 | $this->_trackerMock = $this->createPartialMock(
81 | \Chessio\Matomo\Model\Tracker::class,
82 | ['enableLinkTracking', 'setLinkTrackingTimer']
83 | );
84 | $this->_eventMock = $this->createPartialMock(
85 | \Magento\Framework\Event::class,
86 | ['getTracker']
87 | );
88 | $this->_eventObserverMock = $this->createMock(
89 | \Magento\Framework\Event\Observer::class
90 | );
91 | }
92 |
93 | /**
94 | * Data provider for `testExecute'
95 | *
96 | * @return array
97 | */
98 | public function executeDataProvider()
99 | {
100 | return [
101 | [true, 500, $this->once(), $this->once()],
102 | [true, 0, $this->once(), $this->never()],
103 | [true, -1, $this->once(), $this->never()],
104 | [false, 500, $this->never(), $this->never()],
105 | [false, 0, $this->never(), $this->never()]
106 | ];
107 | }
108 |
109 | /**
110 | * Test for \Chessio\Matomo\Observer\BeforeTrackPageViewObserver::execute
111 | *
112 | * @param bool $linkTrackingEnabled
113 | * @param int $linkTrackingDelay
114 | * @param \PHPUnit_Framework_MockObject_Matcher_Invocation $enableLinkTrackingMatcher
115 | * @param \PHPUnit_Framework_MockObject_Matcher_Invocation $setLinkTrackingTimerMatcher
116 | * @return void
117 | * @dataProvider executeDataProvider
118 | */
119 | public function testExecute(
120 | $linkTrackingEnabled,
121 | $linkTrackingDelay,
122 | $enableLinkTrackingMatcher,
123 | $setLinkTrackingTimerMatcher
124 | ) {
125 | // Prepare observer mock
126 | $this->_eventObserverMock
127 | ->expects($this->once())
128 | ->method('getEvent')
129 | ->willReturn($this->_eventMock);
130 | $this->_eventMock
131 | ->expects($this->once())
132 | ->method('getTracker')
133 | ->willReturn($this->_trackerMock);
134 |
135 | // Prepare data helper mock
136 | $this->_dataHelperMock
137 | ->expects($this->once())
138 | ->method('isLinkTrackingEnabled')
139 | ->willReturn($linkTrackingEnabled);
140 | $this->_dataHelperMock
141 | ->expects($this->any())
142 | ->method('getLinkTrackingDelay')
143 | ->willReturn($linkTrackingDelay);
144 |
145 | // Prepare tracker mock
146 | $this->_trackerMock
147 | ->expects($enableLinkTrackingMatcher)
148 | ->method('enableLinkTracking')
149 | ->with(true)
150 | ->willReturn($this->_trackerMock);
151 | $this->_trackerMock
152 | ->expects($setLinkTrackingTimerMatcher)
153 | ->method('setLinkTrackingTimer')
154 | ->with($linkTrackingDelay)
155 | ->willReturn($this->_trackerMock);
156 |
157 | // Assert that `execute' returns $this
158 | $this->assertSame(
159 | $this->_observer,
160 | $this->_observer->execute($this->_eventObserverMock)
161 | );
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/Test/Unit/Observer/CartViewObserverTest.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Test\Unit\Observer;
23 |
24 | use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
25 |
26 | /**
27 | * Test for \Chessio\Matomo\Observer\CartViewObserver
28 | *
29 | */
30 | class CartViewObserverTest extends \PHPUnit\Framework\TestCase
31 | {
32 |
33 | /**
34 | * Cart view observer (test subject) instance
35 | *
36 | * @var \Chessio\Matomo\Observer\CartViewObserver
37 | */
38 | protected $_observer;
39 |
40 | /**
41 | * Event observer mock object
42 | *
43 | * @var \PHPUnit_Framework_MockObject_MockObject $_eventObserverMock
44 | */
45 | protected $_eventObserverMock;
46 |
47 | /**
48 | * Tracker mock object
49 | *
50 | * @var \PHPUnit_Framework_MockObject_MockObject $_trackerMock
51 | */
52 | protected $_trackerMock;
53 |
54 | /**
55 | * Tracker helper mock object
56 | *
57 | * @var \PHPUnit_Framework_MockObject_MockObject $_trackerHelperMock
58 | */
59 | protected $_trackerHelperMock;
60 |
61 | /**
62 | * Matomo data helper mock object
63 | *
64 | * @var \PHPUnit_Framework_MockObject_MockObject $_dataHelperMock
65 | */
66 | protected $_dataHelperMock;
67 |
68 | /**
69 | * Checkout session mock object
70 | *
71 | * @var \PHPUnit_Framework_MockObject_MockObject $_checkoutSessionMock
72 | */
73 | protected $_checkoutSessionMock;
74 |
75 | /**
76 | * Quote mock object
77 | *
78 | * @var \PHPUnit_Framework_MockObject_MockObject $_quoteMock
79 | */
80 | protected $_quoteMock;
81 |
82 | /**
83 | * Set up
84 | *
85 | * @return void
86 | */
87 | public function setUp(): void
88 | {
89 | $className = \Chessio\Matomo\Observer\CartViewObserver::class;
90 | $objectManager = new ObjectManager($this);
91 | $sessionProxyClass = \Magento\Checkout\Model\Session\Proxy::class;
92 | $arguments = $objectManager->getConstructArguments($className, [
93 | 'checkoutSession' => $this->getMockBuilder($sessionProxyClass)
94 | ->disableOriginalConstructor()
95 | ->setMethods(['getQuote'])
96 | ->getMock()
97 | ]);
98 | $this->_observer = $objectManager->getObject($className, $arguments);
99 | $this->_trackerMock = $arguments['matomoTracker'];
100 | $this->_trackerHelperMock = $arguments['trackerHelper'];
101 | $this->_dataHelperMock = $arguments['dataHelper'];
102 | $this->_checkoutSessionMock = $arguments['checkoutSession'];
103 | $this->_eventObserverMock = $this->createMock(
104 | \Magento\Framework\Event\Observer::class
105 | );
106 | $this->_quoteMock = $this->createMock(
107 | \Magento\Quote\Model\Quote::class
108 | );
109 | }
110 |
111 | /**
112 | * Test for \Chessio\Matomo\Observer\CartViewObserver::execute where
113 | * tracking is enabled.
114 | *
115 | * @return void
116 | */
117 | public function testExecuteWithTrackingEnabled()
118 | {
119 | // Enable tracking
120 | $this->_dataHelperMock
121 | ->expects($this->once())
122 | ->method('isTrackingEnabled')
123 | ->willReturn(true);
124 |
125 | // Provide quote mock access from checkout session mock
126 | $this->_checkoutSessionMock
127 | ->expects($this->any())
128 | ->method('getQuote')
129 | ->willReturn($this->_quoteMock);
130 |
131 | // Make sure the tracker helpers `addQuote' is called exactly once with
132 | // provided quote and tracker. Actual behavior of `addQuote' is covered
133 | // by \Chessio\Matomo\Test\Unit\Helper\TrackerTest.
134 | $this->_trackerHelperMock
135 | ->expects($this->once())
136 | ->method('addQuote')
137 | ->with($this->_quoteMock, $this->_trackerMock)
138 | ->willReturn($this->_trackerHelperMock);
139 |
140 | // Assert that `execute' returns $this
141 | $this->assertSame(
142 | $this->_observer,
143 | $this->_observer->execute($this->_eventObserverMock)
144 | );
145 | }
146 |
147 | /**
148 | * Test for \Chessio\Matomo\Observer\CartViewObserver::execute where
149 | * tracking is disabled.
150 | *
151 | * @return void
152 | */
153 | public function testExecuteWithTrackingDisabled()
154 | {
155 | // Disable tracking
156 | $this->_dataHelperMock
157 | ->expects($this->once())
158 | ->method('isTrackingEnabled')
159 | ->willReturn(false);
160 |
161 | // Provide quote mock access from checkout session mock
162 | $this->_checkoutSessionMock
163 | ->expects($this->any())
164 | ->method('getQuote')
165 | ->willReturn($this->_quoteMock);
166 |
167 | // Make sure the tracker helpers `addQuote' is never called
168 | $this->_trackerHelperMock
169 | ->expects($this->never())
170 | ->method('addQuote');
171 |
172 | // Assert that `execute' returns $this
173 | $this->assertSame(
174 | $this->_observer,
175 | $this->_observer->execute($this->_eventObserverMock)
176 | );
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/Test/Unit/Observer/CategoryViewObserverTest.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Test\Unit\Observer;
23 |
24 | use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
25 |
26 | /**
27 | * Test for \Chessio\Matomo\Observer\CategoryViewObserver
28 | *
29 | */
30 | class CategoryViewObserverTest extends \PHPUnit\Framework\TestCase
31 | {
32 |
33 | /**
34 | * Category view observer (test subject) instance
35 | *
36 | * @var \Chessio\Matomo\Observer\CategoryViewObserver $_observer
37 | */
38 | protected $_observer;
39 |
40 | /**
41 | * Matomo tracker mock object
42 | *
43 | * @var \PHPUnit_Framework_MockObject_MockObject $_trackerMock
44 | */
45 | protected $_trackerMock;
46 |
47 | /**
48 | * Matomo data helper mock object
49 | *
50 | * @var \PHPUnit_Framework_MockObject_MockObject $_dataHelperMock
51 | */
52 | protected $_dataHelperMock;
53 |
54 | /**
55 | * Event mock object
56 | *
57 | * @var \PHPUnit_Framework_MockObject_MockObject $_eventMock
58 | */
59 | protected $_eventMock;
60 |
61 | /**
62 | * Event observer mock object
63 | *
64 | * @var \PHPUnit_Framework_MockObject_MockObject $_eventObserverMock
65 | */
66 | protected $_eventObserverMock;
67 |
68 | /**
69 | * Category model mock object
70 | *
71 | * @var \PHPUnit_Framework_MockObject_MockObject $_categoryMock
72 | */
73 | protected $_categoryMock;
74 |
75 | /**
76 | * Set up
77 | *
78 | * @return void
79 | */
80 | public function setUp(): void
81 | {
82 | $className = \Chessio\Matomo\Observer\CategoryViewObserver::class;
83 | $objectManager = new ObjectManager($this);
84 | $arguments = $objectManager->getConstructArguments($className);
85 | $this->_trackerMock = $this->createPartialMock(
86 | \Chessio\Matomo\Model\Tracker::class,
87 | ['setEcommerceView']
88 | );
89 | $arguments['matomoTracker'] = $this->_trackerMock;
90 | $this->_observer = $objectManager->getObject($className, $arguments);
91 | $this->_dataHelperMock = $arguments['dataHelper'];
92 | $this->_eventMock = $this->createPartialMock(
93 | \Magento\Framework\Event::class,
94 | ['getCategory']
95 | );
96 | $this->_eventObserverMock = $this->createMock(
97 | \Magento\Framework\Event\Observer::class
98 | );
99 | $this->_categoryMock = $this->createPartialMock(
100 | \Magento\Catalog\Model\Category::class,
101 | ['getName']
102 | );
103 | }
104 |
105 | /**
106 | * Test for \Chessio\Matomo\Observer\CategoryViewObserver::execute when Matomo
107 | * tracking is enabled.
108 | *
109 | * @return void
110 | */
111 | public function testExecuteWithTrackingEnabled()
112 | {
113 | $categoryName = 'Some category name';
114 |
115 | // Prepare mock objects
116 | $this->_dataHelperMock
117 | ->expects($this->once())
118 | ->method('isTrackingEnabled')
119 | ->willReturn(true);
120 | $this->_eventObserverMock
121 | ->expects($this->once())
122 | ->method('getEvent')
123 | ->willReturn($this->_eventMock);
124 | $this->_eventMock
125 | ->expects($this->once())
126 | ->method('getCategory')
127 | ->willReturn($this->_categoryMock);
128 | $this->_categoryMock
129 | ->expects($this->once())
130 | ->method('getName')
131 | ->willReturn($categoryName);
132 |
133 | // Make sure trackers' `setEcommerceView' is called exactly once
134 | $this->_trackerMock
135 | ->expects($this->once())
136 | ->method('setEcommerceView')
137 | ->with(false, false, $categoryName)
138 | ->willReturn($this->_trackerMock);
139 |
140 | // Assert that `execute' returns $this
141 | $this->assertSame(
142 | $this->_observer,
143 | $this->_observer->execute($this->_eventObserverMock)
144 | );
145 | }
146 |
147 | /**
148 | * Test for \Chessio\Matomo\Observer\CategoryViewObserver::execute when Matomo
149 | * tracking is disabled.
150 | *
151 | * @return void
152 | */
153 | public function testExecuteWithTrackingDisabled()
154 | {
155 | // Prepare mock objects
156 | $this->_dataHelperMock
157 | ->expects($this->once())
158 | ->method('isTrackingEnabled')
159 | ->willReturn(false);
160 | $this->_eventObserverMock
161 | ->expects($this->any())
162 | ->method('getEvent')
163 | ->willReturn($this->_eventMock);
164 | $this->_eventMock
165 | ->expects($this->any())
166 | ->method('getCategory')
167 | ->willReturn($this->_categoryMock);
168 |
169 | // Make sure trackers' `setEcommerceView' is never called
170 | $this->_trackerMock
171 | ->expects($this->never())
172 | ->method('setEcommerceView');
173 |
174 | // Assert that `execute' returns $this
175 | $this->assertSame(
176 | $this->_observer,
177 | $this->_observer->execute($this->_eventObserverMock)
178 | );
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/Test/Unit/Observer/CheckoutSuccessObserverTest.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Test\Unit\Observer;
23 |
24 | use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
25 |
26 | /**
27 | * Test for \Chessio\Matomo\Observer\CheckoutSuccessObserver
28 | *
29 | */
30 | class CheckoutSuccessObserverTest extends \PHPUnit\Framework\TestCase
31 | {
32 |
33 | /**
34 | * Checkout success observer (test subject) instance
35 | *
36 | * @var \Chessio\Matomo\Observer\CheckoutSuccessObserver $_testSubject
37 | */
38 | protected $_testSubject;
39 |
40 | /**
41 | * Tracker instance
42 | *
43 | * @var \PHPUnit_Framework_MockObject_MockObject $_trackerMock
44 | */
45 | protected $_trackerMock;
46 |
47 | /**
48 | * Matomo data helper mock object
49 | *
50 | * @var \PHPUnit_Framework_MockObject_MockObject $_dataHelperMock
51 | */
52 | protected $_dataHelperMock;
53 |
54 | /**
55 | * Matomo tracker helper mock object
56 | *
57 | * @var \PHPUnit_Framework_MockObject_MockObject $_trackerHelperMock
58 | */
59 | protected $_trackerHelperMock;
60 |
61 | /**
62 | * Sales order repository mock object
63 | *
64 | * @var \PHPUnit_Framework_MockObject_MockObject $_orderRepositoryMock
65 | */
66 | protected $_orderRepositoryMock;
67 |
68 | /**
69 | * Search criteria builder mock object
70 | *
71 | * @var \PHPUnit_Framework_MockObject_MockObject $_searchCriteriaBuilderMock
72 | */
73 | protected $_searchCriteriaBuilderMock;
74 |
75 | /**
76 | * Event observer mock object
77 | *
78 | * @var \PHPUnit_Framework_MockObject_MockObject $_eventObserverMock
79 | */
80 | protected $_eventObserverMock;
81 |
82 | /**
83 | * Event mock object
84 | *
85 | * @var \PHPUnit_Framework_MockObject_MockObject $_eventMock
86 | */
87 | protected $_eventMock;
88 |
89 | /**
90 | * Setup
91 | *
92 | * @return void
93 | */
94 | public function setUp(): void
95 | {
96 | $objectMgr = new ObjectManager($this);
97 |
98 | // Create test subject
99 | $className = \Chessio\Matomo\Observer\CheckoutSuccessObserver::class;
100 | $arguments = $objectMgr->getConstructArguments($className);
101 | $this->_testSubject = $objectMgr->getObject($className, $arguments);
102 | $this->_trackerMock = $arguments['matomoTracker'];
103 | $this->_dataHelperMock = $arguments['dataHelper'];
104 | $this->_trackerHelperMock = $arguments['trackerHelper'];
105 | $this->_orderRepositoryMock = $arguments['orderRepository'];
106 | $this->_searchCriteriaBuilderMock = $arguments['searchCriteriaBuilder'];
107 |
108 | $this->_eventMock = $this->createPartialMock(
109 | \Magento\Framework\Event::class,
110 | ['getOrderIds']
111 | );
112 | $this->_eventObserverMock = $this->createMock(
113 | \Magento\Framework\Event\Observer::class
114 | );
115 | $this->_eventObserverMock
116 | ->expects($this->any())
117 | ->method('getEvent')
118 | ->willReturn($this->_eventMock);
119 | }
120 |
121 | /**
122 | * Test for \Chessio\Matomo\Observer\CheckoutSuccessObserver::execute where
123 | * tracking is enabled.
124 | *
125 | * @return void
126 | */
127 | public function testExecuteWithTrackingEnabled()
128 | {
129 | $orders = [
130 | 1 => new \stdClass(),
131 | 2 => new \stdClass()
132 | ];
133 |
134 | $this->_dataHelperMock
135 | ->expects($this->once())
136 | ->method('isTrackingEnabled')
137 | ->willReturn(true);
138 |
139 | $this->_eventMock
140 | ->expects($this->atLeastOnce())
141 | ->method('getOrderIds')
142 | ->willReturn(array_keys($orders));
143 |
144 | $this->_searchCriteriaBuilderMock
145 | ->expects($this->once())
146 | ->method('addFilter')
147 | ->with('entity_id', array_keys($orders), 'in')
148 | ->willReturn($this->_searchCriteriaBuilderMock);
149 |
150 | $searchCriteriaMock = $this->createMock(
151 | \Magento\Framework\Api\SearchCriteriaInterface::class
152 | );
153 |
154 | $this->_searchCriteriaBuilderMock
155 | ->expects($this->once())
156 | ->method('create')
157 | ->willReturn($searchCriteriaMock);
158 |
159 | $searchResultMock = $this->createConfiguredMock(
160 | \Magento\Sales\Api\Data\OrderSearchResultInterface::class,
161 | ['getItems' => $orders]
162 | );
163 |
164 | $this->_orderRepositoryMock
165 | ->expects($this->once())
166 | ->method('getList')
167 | ->with($searchCriteriaMock)
168 | ->willReturn($searchResultMock);
169 |
170 | $this->_trackerHelperMock
171 | ->expects($this->once())
172 | ->method('addOrders')
173 | ->with($orders, $this->_trackerMock)
174 | ->willReturn($this->_trackerHelperMock);
175 |
176 | $this->assertSame(
177 | $this->_testSubject,
178 | $this->_testSubject->execute($this->_eventObserverMock)
179 | );
180 | }
181 |
182 | /**
183 | * Test for \Chessio\Matomo\Observer\CheckoutSuccessObserver::execute where
184 | * tracking is disabled.
185 | *
186 | * @return void
187 | */
188 | public function testExecuteWithTrackingDisabled()
189 | {
190 | $this->_dataHelperMock
191 | ->expects($this->once())
192 | ->method('isTrackingEnabled')
193 | ->willReturn(false);
194 |
195 | $this->_eventMock
196 | ->expects($this->any())
197 | ->method('getOrderIds')
198 | ->willReturn([1]);
199 |
200 | $this->_searchCriteriaBuilderMock
201 | ->expects($this->never())
202 | ->method('addFilter');
203 |
204 | $this->_searchCriteriaBuilderMock
205 | ->expects($this->never())
206 | ->method('create');
207 |
208 | $this->_orderRepositoryMock
209 | ->expects($this->never())
210 | ->method('getList');
211 |
212 | $this->_trackerHelperMock
213 | ->expects($this->never())
214 | ->method('addOrders');
215 |
216 | $this->assertSame(
217 | $this->_testSubject,
218 | $this->_testSubject->execute($this->_eventObserverMock)
219 | );
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/Test/Unit/Observer/ProductViewObserverTest.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Test\Unit\Observer;
23 |
24 | use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
25 |
26 | /**
27 | * Test for \Chessio\Matomo\Observer\ProductViewObserver
28 | *
29 | */
30 | class ProductViewObserverTest extends \PHPUnit\Framework\TestCase
31 | {
32 |
33 | /**
34 | * Product view observer (test subject) instance
35 | *
36 | * @var \Chessio\Matomo\Observer\ProductViewObserver $_observer
37 | */
38 | protected $_observer;
39 |
40 | /**
41 | * Matomo tracker mock object
42 | *
43 | * @var \PHPUnit_Framework_MockObject_MockObject $_trackerMock
44 | */
45 | protected $_trackerMock;
46 |
47 | /**
48 | * Matomo data helper mock object
49 | *
50 | * @var \PHPUnit_Framework_MockObject_MockObject $_dataHelperMock
51 | */
52 | protected $_dataHelperMock;
53 |
54 | /**
55 | * Event mock object
56 | *
57 | * @var \PHPUnit_Framework_MockObject_MockObject $_eventMock
58 | */
59 | protected $_eventMock;
60 |
61 | /**
62 | * Event observer mock object
63 | *
64 | * @var \PHPUnit_Framework_MockObject_MockObject $_eventObserverMock
65 | */
66 | protected $_eventObserverMock;
67 |
68 | /**
69 | * Product model mock object
70 | *
71 | * @var \PHPUnit_Framework_MockObject_MockObject $_productMock
72 | */
73 | protected $_productMock;
74 |
75 | /**
76 | * Category model mock object
77 | *
78 | * @var \PHPUnit_Framework_MockObject_MockObject $_categoryMock
79 | */
80 | protected $_categoryMock;
81 |
82 | /**
83 | * Set up
84 | *
85 | * @return void
86 | */
87 | public function setUp(): void
88 | {
89 | $className = \Chessio\Matomo\Observer\ProductViewObserver::class;
90 | $objectManager = new ObjectManager($this);
91 | $arguments = $objectManager->getConstructArguments($className);
92 | $this->_trackerMock = $this->createPartialMock(
93 | \Chessio\Matomo\Model\Tracker::class,
94 | ['setEcommerceView']
95 | );
96 | $arguments['matomoTracker'] = $this->_trackerMock;
97 | $this->_observer = $objectManager->getObject($className, $arguments);
98 | $this->_dataHelperMock = $arguments['dataHelper'];
99 | $this->_eventMock = $this->createPartialMock(
100 | \Magento\Framework\Event::class,
101 | ['getProduct']
102 | );
103 | $this->_eventObserverMock = $this->createMock(
104 | \Magento\Framework\Event\Observer::class
105 | );
106 | $this->_productMock = $this->createPartialMock(
107 | \Magento\Catalog\Model\Product::class,
108 | ['getCategory', 'getSku', 'getName', 'getFinalPrice']
109 | );
110 | $this->_categoryMock = $this->createPartialMock(
111 | \Magento\Catalog\Model\Category::class,
112 | ['getName']
113 | );
114 | }
115 |
116 | /**
117 | * Data provicer for `testExecute'
118 | *
119 | * @return array
120 | */
121 | public function executeDataProvider()
122 | {
123 | return [
124 | ['sku1', 'Product Name #1', 123.45],
125 | ['sku2', 'Product Name #2', '234.56', 'Categor Name #1']
126 | ];
127 | }
128 |
129 | /**
130 | * Test for \Chessio\Matomo\Observer\ProductViewObserver::execute where
131 | * tracking is enabled.
132 | *
133 | * @param string $sku
134 | * @param string $name
135 | * @param float $price
136 | * @param string|null $category
137 | * @return void
138 | * @dataProvider executeDataProvider
139 | */
140 | public function testExecuteWithTrackingEnabled(
141 | $sku,
142 | $name,
143 | $price,
144 | $category = null
145 | ) {
146 | // Enable tracking
147 | $this->_dataHelperMock
148 | ->expects($this->once())
149 | ->method('isTrackingEnabled')
150 | ->willReturn(true);
151 |
152 | // Prepare event observer mock
153 | $this->_eventObserverMock
154 | ->expects($this->once())
155 | ->method('getEvent')
156 | ->willReturn($this->_eventMock);
157 | $this->_eventMock
158 | ->expects($this->once())
159 | ->method('getProduct')
160 | ->willReturn($this->_productMock);
161 |
162 | // Prepare product mock
163 | $methodMap = [
164 | 'getSku' => $sku,
165 | 'getName' => $name,
166 | 'getFinalPrice' => $price
167 | ];
168 | foreach ($methodMap as $method => $returnValue) {
169 | $this->_productMock
170 | ->expects($this->once())
171 | ->method($method)
172 | ->willReturn($returnValue);
173 | }
174 |
175 | // Prepare category mock if category name was provided
176 | if ($category !== null) {
177 | $this->_productMock
178 | ->expects($this->once())
179 | ->method('getCategory')
180 | ->willReturn($this->_categoryMock);
181 | $this->_categoryMock
182 | ->expects($this->once())
183 | ->method('getName')
184 | ->willReturn($category);
185 | }
186 |
187 | // Make sure trackers' `setEcommerceView' is called exactly once.
188 | $this->_trackerMock
189 | ->expects($this->once())
190 | ->method('setEcommerceView')
191 | ->with(
192 | $sku,
193 | $name,
194 | // Category should be FALSE if product has no category
195 | ($category === null) ? false : $category,
196 | (float) $price
197 | )
198 | ->willReturn($this->_trackerMock);
199 |
200 | // Assert that `execute' returns $this
201 | $this->assertSame(
202 | $this->_observer,
203 | $this->_observer->execute($this->_eventObserverMock)
204 | );
205 | }
206 |
207 | /**
208 | * Test for \Chessio\Matomo\Observer\ProductViewObserver::execute where
209 | * tracking is disabled.
210 | *
211 | * @return void
212 | */
213 | public function testExecuteWithTrackingDisabled()
214 | {
215 | // Disable tracking
216 | $this->_dataHelperMock
217 | ->expects($this->once())
218 | ->method('isTrackingEnabled')
219 | ->willReturn(false);
220 |
221 | // Provide access to event and product though they should preferably
222 | // never be touched when tracking is disabled.
223 | $this->_eventObserverMock
224 | ->expects($this->any())
225 | ->method('getEvent')
226 | ->willReturn($this->_eventMock);
227 | $this->_eventMock
228 | ->expects($this->any())
229 | ->method('getProduct')
230 | ->willReturn($this->_productMock);
231 |
232 | // Make sure trackers' `setEcommerceView' is never called.
233 | $this->_trackerMock
234 | ->expects($this->never())
235 | ->method('setEcommerceView');
236 |
237 | // Assert that `execute' returns $this
238 | $this->assertSame(
239 | $this->_observer,
240 | $this->_observer->execute($this->_eventObserverMock)
241 | );
242 | }
243 | }
244 |
--------------------------------------------------------------------------------
/Test/Unit/Observer/SearchResultObserverTest.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\Test\Unit\Observer;
23 |
24 | use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
25 |
26 | /**
27 | * Test for \Chessio\Matomo\Observer\SearchResultObserver
28 | *
29 | */
30 | class SearchResultObserverTest extends \PHPUnit\Framework\TestCase
31 | {
32 |
33 | /**
34 | * Search result observer (test subject) instance
35 | *
36 | * @var \Chessio\Matomo\Observer\SearchResultObserver $_observer
37 | */
38 | protected $_observer;
39 |
40 | /**
41 | * Matomo tracker mock object
42 | *
43 | * @var \PHPUnit_Framework_MockObject_MockObject $_trackerMock
44 | */
45 | protected $_trackerMock;
46 |
47 | /**
48 | * Matomo data helper mock object
49 | *
50 | * @var \PHPUnit_Framework_MockObject_MockObject $_dataHelperMock
51 | */
52 | protected $_dataHelperMock;
53 |
54 | /**
55 | * Layout mock object
56 | *
57 | * @var \PHPUnit_Framework_MockObject_MockObject $_layoutMock
58 | */
59 | protected $_layoutMock;
60 |
61 | /**
62 | * Search query mock object
63 | *
64 | * @var \PHPUnit_Framework_MockObject_MockObject $_queryMock
65 | */
66 | protected $_queryMock;
67 |
68 | /**
69 | * Matomo block mock object
70 | *
71 | * @var \PHPUnit_Framework_MockObject_MockObject $_matomoBlockMock
72 | */
73 | protected $_matomoBlockMock;
74 |
75 | /**
76 | * Search result block mock object
77 | *
78 | * @var \PHPUnit_Framework_MockObject_MockObject $_searchResultBlockMock
79 | */
80 | protected $_searchResultBlockMock;
81 |
82 | /**
83 | * Event observer mock object
84 | *
85 | * @var \PHPUnit_Framework_MockObject_MockObject $_eventObserverMock
86 | */
87 | protected $_eventObserverMock;
88 |
89 | /**
90 | * Set up
91 | *
92 | * @return void
93 | */
94 | public function setUp(): void
95 | {
96 | $className = \Chessio\Matomo\Observer\SearchResultObserver::class;
97 | $objectManager = new ObjectManager($this);
98 | $arguments = $objectManager->getConstructArguments($className);
99 |
100 | $this->_trackerMock = $this->createPartialMock(
101 | \Chessio\Matomo\Model\Tracker::class,
102 | ['trackSiteSearch']
103 | );
104 | $arguments['matomoTracker'] = $this->_trackerMock;
105 | $this->_dataHelperMock = $arguments['dataHelper'];
106 |
107 | $this->_layoutMock = $this->createMock(
108 | \Magento\Framework\View\Layout::class
109 | );
110 | $arguments['view']
111 | ->expects($this->any())
112 | ->method('getLayout')
113 | ->willReturn($this->_layoutMock);
114 |
115 | $this->_queryMock = $this->createPartialMock(
116 | \Magento\Search\Model\Query::class,
117 | ['getQueryText', 'getNumResults']
118 | );
119 | $arguments['queryFactory']
120 | ->expects($this->any())
121 | ->method('get')
122 | ->willReturn($this->_queryMock);
123 |
124 | $this->_observer = $objectManager->getObject($className, $arguments);
125 | $this->_matomoBlockMock = $this->createPartialMock(
126 | \Chessio\Matomo\Block\Matomo::class,
127 | ['setSkipTrackPageView']
128 | );
129 | $this->_searchResultBlockMock = $this->createMock(
130 | \Magento\CatalogSearch\Block\Result::class
131 | );
132 | $this->_eventObserverMock = $this->createMock(
133 | \Magento\Framework\Event\Observer::class
134 | );
135 | }
136 |
137 | /**
138 | * Prepare the search query mock object with given text and result count
139 | *
140 | * @param string $queryText
141 | * @param int|null $numResults
142 | */
143 | protected function _prepareQueryMock($queryText, $numResults)
144 | {
145 | $this->_queryMock
146 | ->expects($this->once())
147 | ->method('getQueryText')
148 | ->willReturn($queryText);
149 | $this->_queryMock
150 | ->expects($this->once())
151 | ->method('getNumResults')
152 | ->willReturn($numResults);
153 | }
154 |
155 | /**
156 | * Prepare layout mock object with given blocks
157 | *
158 | * @param array $blocks
159 | */
160 | protected function _prepareLayoutMock($blocks = [])
161 | {
162 | $blockMap = [['matomo.tracker', $this->_matomoBlockMock]];
163 | foreach ($blocks as $name => $block) {
164 | $blockMap[] = [$name, $block];
165 | }
166 | $this->_layoutMock
167 | ->expects($this->any())
168 | ->method('getBlock')
169 | ->willReturnMap($blockMap);
170 | $this->_matomoBlockMock
171 | ->expects($this->once())
172 | ->method('setSkipTrackPageView')
173 | ->with(true)
174 | ->willReturn($this->_matomoBlockMock);
175 | }
176 |
177 | /**
178 | * Test for \Chessio\Matomo\Observer\SearchResultObserver::execute where
179 | * the query object does not have a result count.
180 | *
181 | * @return void
182 | */
183 | public function testExecuteWithNewQuery()
184 | {
185 | $queryText = 'Some query text';
186 | $resultsCount = 5;
187 |
188 | // Enable tracking
189 | $this->_dataHelperMock
190 | ->expects($this->once())
191 | ->method('isTrackingEnabled')
192 | ->willReturn(true);
193 |
194 | $this->_prepareQueryMock($queryText, null);
195 | $this->_prepareLayoutMock([
196 | 'search.result' => $this->_searchResultBlockMock
197 | ]);
198 |
199 | // Make sure the search result block is called to access a result count
200 | $this->_searchResultBlockMock
201 | ->expects($this->once())
202 | ->method('getResultCount')
203 | ->willReturn($resultsCount);
204 |
205 | // Make sure the trackers' `trackSiteSearch' is called exactly once
206 | $this->_trackerMock
207 | ->expects($this->once())
208 | ->method('trackSiteSearch')
209 | ->with($queryText, false, $resultsCount)
210 | ->willReturn($this->_trackerMock);
211 |
212 | // Assert that `execute' returns $this
213 | $this->assertSame(
214 | $this->_observer,
215 | $this->_observer->execute($this->_eventObserverMock)
216 | );
217 | }
218 |
219 | /**
220 | * Test for \Chessio\Matomo\Observer\SearchResultObserver::execute where
221 | * the query object does not have a result count and there is no search
222 | * result block available.
223 | *
224 | * @return void
225 | */
226 | public function testExecuteWithNewQueryAndNoResultBlock()
227 | {
228 | $queryText = 'Some query text';
229 |
230 | // Enable tracking
231 | $this->_dataHelperMock
232 | ->expects($this->once())
233 | ->method('isTrackingEnabled')
234 | ->willReturn(true);
235 |
236 | $this->_prepareQueryMock($queryText, null);
237 | $this->_prepareLayoutMock(['search.result' => false]);
238 |
239 | // Make sure the trackers' `trackSiteSearch' is called exactly once
240 | $this->_trackerMock
241 | ->expects($this->once())
242 | ->method('trackSiteSearch')
243 | ->with($queryText) // No results count available
244 | ->willReturn($this->_trackerMock);
245 |
246 | // Assert that `execute' returns $this
247 | $this->assertSame(
248 | $this->_observer,
249 | $this->_observer->execute($this->_eventObserverMock)
250 | );
251 | }
252 |
253 | /**
254 | * Test for \Chessio\Matomo\Observer\SearchResultObserver::execute where
255 | * the query object has a result count.
256 | *
257 | * @return void
258 | */
259 | public function testExecuteWithExistingQuery()
260 | {
261 | $queryText = 'Some query text';
262 | $resultsCount = 5;
263 |
264 | // Enable tracking
265 | $this->_dataHelperMock
266 | ->expects($this->once())
267 | ->method('isTrackingEnabled')
268 | ->willReturn(true);
269 |
270 | $this->_prepareQueryMock($queryText, $resultsCount);
271 | $this->_prepareLayoutMock([
272 | 'search.result' => $this->_searchResultBlockMock
273 | ]);
274 |
275 | // Make sure the search result block is not accessed when the query
276 | // itself already has a result count.
277 | $this->_searchResultBlockMock
278 | ->expects($this->never())
279 | ->method('getResultCount');
280 |
281 | // Make sure the trackers' `trackSiteSearch' is called exactly once
282 | $this->_trackerMock
283 | ->expects($this->once())
284 | ->method('trackSiteSearch')
285 | ->with($queryText, false, $resultsCount)
286 | ->willReturn($this->_trackerMock);
287 |
288 | // Assert that `execute' returns $this
289 | $this->assertSame(
290 | $this->_observer,
291 | $this->_observer->execute($this->_eventObserverMock)
292 | );
293 | }
294 |
295 | /**
296 | * Test for \Chessio\Matomo\Observer\SearchResultObserver::execute where
297 | * tracking is disabled.
298 | *
299 | * @return void
300 | */
301 | public function testExecuteWithTrackingDisabled()
302 | {
303 | // Disable tracking
304 | $this->_dataHelperMock
305 | ->expects($this->once())
306 | ->method('isTrackingEnabled')
307 | ->willReturn(false);
308 |
309 | // Make sure the trackers' `trackSiteSearch' is never called
310 | $this->_trackerMock
311 | ->expects($this->never())
312 | ->method('trackSiteSearch');
313 |
314 | // Assert that `execute' returns $this
315 | $this->assertSame(
316 | $this->_observer,
317 | $this->_observer->execute($this->_eventObserverMock)
318 | );
319 | }
320 | }
321 |
--------------------------------------------------------------------------------
/UserId/Provider/EmailProvider.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\UserId\Provider;
23 |
24 | use Magento\Customer\Api\CustomerRepositoryInterface;
25 |
26 | /**
27 | * Customer email provider
28 | *
29 | */
30 | class EmailProvider implements ProviderInterface
31 | {
32 |
33 | /**
34 | * Customer repository
35 | *
36 | * @var CustomerRepositoryInterface $_customerRepository
37 | */
38 | protected $_customerRepository;
39 |
40 | /**
41 | * Constructor
42 | *
43 | * @param CustomerRepositoryInterface $customerRepository
44 | */
45 | public function __construct(CustomerRepositoryInterface $customerRepository)
46 | {
47 | $this->_customerRepository = $customerRepository;
48 | }
49 |
50 | /**
51 | * {@inheritDoc}
52 | */
53 | public function getUserId($customerId)
54 | {
55 | try {
56 | return $this->_customerRepository->getById($customerId)->getEmail();
57 | } catch (\Exception $e) {
58 | return false;
59 | }
60 | }
61 |
62 | /**
63 | * {@inheritDoc}
64 | */
65 | public function getTitle()
66 | {
67 | return __('Customer E-mail');
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/UserId/Provider/EntityIdProvider.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\UserId\Provider;
23 |
24 | /**
25 | * Customer entity ID provider
26 | *
27 | */
28 | class EntityIdProvider implements ProviderInterface
29 | {
30 |
31 | /**
32 | * {@inheritDoc}
33 | */
34 | public function getUserId($customerId)
35 | {
36 | return (string) $customerId;
37 | }
38 |
39 | /**
40 | * {@inheritDoc}
41 | */
42 | public function getTitle()
43 | {
44 | return __('Customer Entity ID');
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/UserId/Provider/Pool.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\UserId\Provider;
23 |
24 | /**
25 | * User ID provider pool
26 | *
27 | */
28 | class Pool
29 | {
30 |
31 | /**
32 | * User ID providers
33 | *
34 | * @var ProviderInterface[] $_providers
35 | */
36 | protected $_providers = [];
37 |
38 | /**
39 | * Constructor
40 | *
41 | * @param ProviderInterface[] $providers
42 | */
43 | public function __construct(array $providers = [])
44 | {
45 | $this->_providers = $providers;
46 | }
47 |
48 | /**
49 | * Get User ID provider by code
50 | *
51 | * @param string $code
52 | * @return ProviderInterface|null
53 | */
54 | public function getProviderByCode($code)
55 | {
56 | if (isset($this->_providers[$code])
57 | && ($this->_providers[$code] instanceof ProviderInterface)
58 | ) {
59 | return $this->_providers[$code];
60 | }
61 | return null;
62 | }
63 |
64 | /**
65 | * Get all User ID providers added to this pool
66 | *
67 | * @return ProviderInterface[]
68 | */
69 | public function getAllProviders()
70 | {
71 | return array_filter($this->_providers, function ($provider) {
72 | return $provider instanceof ProviderInterface;
73 | });
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/UserId/Provider/ProviderInterface.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Chessio\Matomo\UserId\Provider;
23 |
24 | /**
25 | * User ID provider interface
26 | *
27 | */
28 | interface ProviderInterface
29 | {
30 |
31 | /**
32 | * Returns Matomo user ID for given Magento customer ID
33 | *
34 | * @param int $customerId
35 | * @return string
36 | */
37 | public function getUserId($customerId);
38 |
39 | /**
40 | * Get User ID provider title
41 | *
42 | * @return string
43 | */
44 | public function getTitle();
45 | }
46 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chessio/module-matomo",
3 | "description": "Matomo Analytics module for Magento 2",
4 | "type": "magento2-module",
5 | "license": [
6 | "AGPL-3.0+"
7 | ],
8 | "require": {
9 | "php": "~7.0.0|~7.1.0|~7.2.0|~7.3.0|~7.4.0|~8.1.0|~8.2.0",
10 | "magento/framework": "~101.0|~102.0|~103.0",
11 | "magento/module-catalog": "~102.0|~103.0|~104.0",
12 | "magento/module-catalog-search": "~100.0|~101.0|~102.0",
13 | "magento/module-checkout": "~100.0",
14 | "magento/module-config": "~101.0",
15 | "magento/module-customer": "~101.0|~102.0|~103.0",
16 | "magento/module-quote": "~101.0",
17 | "magento/module-sales": "~101.0|~102.0|~103.0",
18 | "magento/module-search": "~100.0|~101.0",
19 | "magento/module-store": "~100.0|~101.0"
20 | },
21 | "autoload": {
22 | "files": ["registration.php"],
23 | "psr-4": {
24 | "Chessio\\Matomo\\": ""
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/dev/ci/BUILDVARS.conf.dist:
--------------------------------------------------------------------------------
1 | MODULE_NAME='Chessio_Matomo'
2 | MODULE_SRC_DIR="$(cd "$(dirname "$0")"/../.. && pwd)"
3 |
--------------------------------------------------------------------------------
/dev/ci/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Read variables from config file
4 | VARS_FILE="$(cd "$(dirname "$0")" && pwd)"'/BUILDVARS.conf'
5 | if [ -e "$VARS_FILE" ]
6 | then
7 | source "$VARS_FILE"
8 | else
9 | source "$VARS_FILE"'.dist'
10 | fi
11 |
12 | if [ -n "$TRAVIS_BUILD_DIR" ]
13 | then
14 | MODULE_SRC_DIR="$TRAVIS_BUILD_DIR"
15 | fi
16 |
17 | # Check for missing required variables
18 | for envkey in \
19 | MODULE_NAME \
20 | MODULE_SRC_DIR \
21 | M2_VERSION
22 | do
23 | if [ -z "$(eval echo \$$envkey)" ]
24 | then
25 | echo "Missing required variable: $envkey" >&2
26 | exit 1
27 | fi
28 | done
29 |
30 | set -e
31 |
32 | # Set up environment
33 | PHP_BIN="$(which php)"
34 | COMPOSER_BIN="$(which composer)"
35 | COMPOSER_VERSION="$(composer --version | cut -d " " -f3)"
36 | BUILD_DIR="$(mktemp -d /tmp/$MODULE_NAME.XXXXXX)"
37 | if [ -z "$MODULE_DST_DIR" ]
38 | then
39 | MODULE_DST_DIR="$BUILD_DIR/app/code/$(echo $MODULE_NAME | sed 's/_/\//')"
40 | fi
41 |
42 | set -x
43 |
44 | # Fetch Magento 2 source
45 | "$COMPOSER_BIN" create-project \
46 | --repository=https://repo-magento-mirror.fooman.co.nz/ \
47 | --add-repository \
48 | --quiet \
49 | --ignore-platform-reqs \
50 | --no-install \
51 | magento/project-community-edition \
52 | "$BUILD_DIR" "$M2_VERSION"
53 |
54 | cd "$BUILD_DIR"
55 | "$COMPOSER_BIN" config --unset repo.0
56 | "$COMPOSER_BIN" config repositories.foomanmirror composer https://repo-magento-mirror.fooman.co.nz/
57 |
58 | COMPOSER_MAJOR_VERSION="$(cut -d '.' -f 1 <<< "$COMPOSER_VERSION")"
59 | if [ "$COMPOSER_MAJOR_VERSION" == "2" ]
60 | then
61 | "$COMPOSER_BIN" config allow-plugins.magento/* true
62 | "$COMPOSER_BIN" config allow-plugins.laminas/laminas-dependency-plugin true
63 | "$COMPOSER_BIN" config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
64 | fi
65 |
66 | "$COMPOSER_BIN" update
67 |
68 | # Copy module into Magento
69 | mkdir -p "$(dirname "$MODULE_DST_DIR")"
70 | cp -r "$MODULE_SRC_DIR" "$MODULE_DST_DIR"
71 |
72 | # Run module unit tests
73 | "$PHP_BIN" "$BUILD_DIR/vendor/phpunit/phpunit/phpunit" \
74 | --colors \
75 | -c "$BUILD_DIR/dev/tests/unit/phpunit.xml.dist" \
76 | "$MODULE_DST_DIR/Test/Unit"
77 |
--------------------------------------------------------------------------------
/etc/acl.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/etc/adminhtml/system.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
25 |
26 |
27 |
34 |
35 | sales
36 | Chessio_Matomo::matomo
37 |
44 |
45 |
52 |
53 | Magento\Config\Model\Config\Source\Yesno
54 |
55 |
62 |
63 | Matomo hostname, optionally including a path e.g. matomo.example.com or example.com/matomo
64 |
65 | 1
66 |
67 | required-entry
68 |
69 |
76 |
77 | Listed under Settings/Website in your Matomo administration panel
78 |
79 | 1
80 |
81 | required-entry validate-digits validate-zero-or-greater
82 |
83 |
90 |
91 | Magento\Config\Model\Config\Source\Yesno
92 | Enable tracking of outlinks and downloads
93 |
94 | 1
95 |
96 |
97 |
104 |
105 | Delay for link tracking in milliseconds
106 |
107 | 1
108 | 1
109 |
110 | validate-digits validate-zero-or-greater
111 |
112 |
119 |
120 | Chessio\Matomo\Model\Config\Source\UserId\Provider
121 | Send logged in customers ID to Matomo
122 |
123 | 1
124 |
125 |
126 |
133 |
134 |
135 | 1
136 |
137 |
144 |
145 | piwik/tracking/php_script_path
146 | Path to the Matomo tracker PHP script. Usually "matomo.php".
147 | required-entry
148 |
149 |
156 |
157 | piwik/tracking/js_script_path
158 | Path to the Matomo tracker Javascript. Usually "matomo.js".
159 | required-entry
160 |
161 |
168 |
169 | piwik/tracking/cdn_hostname
170 | Hostname for serving the Matomo tracker Javascript. May be left empty in which case the regular hostname will be used.
171 |
172 |
173 |
174 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/etc/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
25 |
26 |
27 |
28 |
29 | 0
30 |
31 | 1
32 | 1
33 | 500
34 |
35 | matomo.php
36 | matomo.js
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/etc/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
25 |
26 |
27 |
28 |
29 | - Chessio\Matomo\UserId\Provider\EntityIdProvider
30 | - Chessio\Matomo\UserId\Provider\EmailProvider
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/etc/frontend/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/etc/frontend/events.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
25 |
26 |
28 |
29 |
30 |
32 |
33 |
34 |
36 |
37 |
38 |
40 |
41 |
42 |
44 |
45 |
46 |
48 |
49 |
50 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/i18n/en_US.csv:
--------------------------------------------------------------------------------
1 | "Matomo API","Matomo API"
2 | "Tracking API","Tracking API"
3 | "Enable Tracking","Enable Tracking"
4 | "Yes","Yes"
5 | "No","No"
6 | "Hostname","Hostname"
7 | "Matomo hostname, optionally including a path e.g. matomo.example.com or example.com/matomo","Matomo hostname, optionally including a path e.g. matomo.example.com or example.com/matomo"
8 | "Site ID","Site ID"
9 | "Listed under Settings/Website in your Matomo administration panel","Listed under Settings/Website in your Matomo administration panel"
10 | "Enable Link Tracking","Enable Link Tracking"
11 | "Enable tracking of outlinks and downloads","Enable tracking of outlinks and downloads"
12 | "Link Tracking Timer","Link Tracking Timer"
13 | "Delay for link tracking in milliseconds","Delay for link tracking in milliseconds"
14 | "Enable User ID Tracking","Enable User ID Tracking"
15 | "Customer Entity ID","Customer Entity ID"
16 | "Customer E-mail","Customer E-mail"
17 | "Send logged in customers ID to Matomo","Send logged in customers ID to Matomo"
18 | "Advanced Options","Advanced Options"
19 | "Javascript Path","Javascript Path"
20 | "Path to the Matomo tracker Javascript. Usually ""matomo.js"".","Path to the Matomo tracker Javascript. Usually ""matomo.js""."
21 | "PHP Script Path","PHP Script Path"
22 | "Path to the Matomo tracker PHP script. Usually ""matomo.php"".","Path to the Matomo tracker PHP script. Usually ""matomo.php""."
23 | "CDN Hostname","CDN Hostname"
24 | "Hostname for serving the Matomo tracker Javascript. May be left empty in which case the regular hostname will be used.","Hostname for serving the Matomo tracker Javascript. May be left empty in which case the regular hostname will be used."
25 |
--------------------------------------------------------------------------------
/i18n/it_IT.csv:
--------------------------------------------------------------------------------
1 | "Matomo API","Matomo API"
2 | "Tracking API","Tracking API"
3 | "Enable Tracking","Abilita Tracking"
4 | Yes,Si
5 | No,No
6 | Hostname,Hostname
7 | "Matomo hostname, optionally including a path e.g. matomo.example.com or example.com/matomo","Matomo hostname, opzionalmente include un percorso es. matomo.example.com o example.com/matomo"
8 | "Site ID","ID Sito"
9 | "Listed under Settings/Website in your Matomo administration panel","Elencati in Impostazioni/Sito nel tuo pannello di amministrazione Matomo"
10 | "Enable Link Tracking","Abilita Link Tracking"
11 | "Enable tracking of outlinks and downloads","Abilita tracking di outlinks e downloads"
12 | "Link Tracking Timer","Link Tracking Timer"
13 | "Delay for link tracking in milliseconds","Ritardo per il link tracking in millisecondi"
14 |
--------------------------------------------------------------------------------
/i18n/sv_SE.csv:
--------------------------------------------------------------------------------
1 | "Matomo API","Matomo API"
2 | "Tracking API","API för spårning"
3 | "Enable Tracking","Aktivera spårning"
4 | "Yes","Ja"
5 | "No","Nej"
6 | "Hostname","Värdnamn"
7 | "Matomo hostname, optionally including a path e.g. matomo.example.com or example.com/matomo","Matomo-värdnamn, alternativt inkluderande sökväg t.ex. matomo.example.com eller example.com/matomo"
8 | "Site ID","Webbplatsens ID"
9 | "Listed under Settings/Website in your Matomo administration panel","Finns att hitta under Inställningar/Webbplatser i Matomos administrationspanel"
10 | "Enable Link Tracking","Aktivera länkspårning"
11 | "Enable tracking of outlinks and downloads","Aktivera spårning av utlänkar och nedladdningar"
12 | "Link Tracking Timer","Länkspårningstimer"
13 | "Delay for link tracking in milliseconds","Fördröjning av länkspårning i millisekunder"
14 | "Enable User ID Tracking","Aktivera spårning av användar-ID"
15 | "Customer Entity ID","Kundens entitets-ID"
16 | "Customer E-mail","Kundens E-postadress"
17 | "Send logged in customers ID to Matomo","Skicka inloggade kunders ID till Matomo"
18 | "Advanced Options","Avancerade inställningar"
19 | "Javascript Path","Sökväg till javascript"
20 | "Path to the Matomo tracker Javascript. Usually ""matomo.js"".","Sökväg till Matomo-spårarens javascript. Vanligtvis ""matomo.js""."
21 | "PHP Script Path","Sökväg till PHP-skript"
22 | "Path to the Matomo tracker PHP script. Usually ""matomo.php"".","Sökväg till Matomo-spårarens PHP-skript. Vanligtvis ""matomo.php""."
23 | "CDN Hostname","CDN-värdnamn"
24 | "Hostname for serving the Matomo tracker Javascript. May be left empty in which case the regular hostname will be used.","Värdnamn för Matomo-spårarens javascript. Lämna tomt för att använda det allmänna värdnamnet."
25 |
--------------------------------------------------------------------------------
/registration.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | \Magento\Framework\Component\ComponentRegistrar::register(
23 | \Magento\Framework\Component\ComponentRegistrar::MODULE,
24 | 'Chessio_Matomo',
25 | __DIR__
26 | );
27 |
--------------------------------------------------------------------------------
/view/frontend/layout/default.xml:
--------------------------------------------------------------------------------
1 |
2 |
23 |
25 |
26 |
27 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/view/frontend/templates/matomo.phtml:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | ?>
23 |
24 |
31 |
37 |
51 |
60 |
87 |
94 |
--------------------------------------------------------------------------------
/view/frontend/web/js/tracker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016-2018 Henrik Hedelund
3 | * Copyright 2020 Falco Nogatz
4 | *
5 | * This file is part of Chessio_Matomo.
6 | *
7 | * Chessio_Matomo is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Affero General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * Chessio_Matomo is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Affero General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Affero General Public License
18 | * along with Chessio_Matomo. If not, see .
19 | */
20 |
21 | define([
22 | 'jquery',
23 | 'underscore',
24 | 'Magento_Customer/js/customer-data',
25 | 'jquery/jquery-storageapi'
26 | ], function ($, _, customerData) {
27 | 'use strict';
28 |
29 | /**
30 | * Object holding globally accessible properties
31 | *
32 | * @type {Object}
33 | */
34 | var exports = window;
35 |
36 | /**
37 | * Default Matomo website ID
38 | *
39 | * @type {number}
40 | */
41 | var defaultSiteId;
42 |
43 | /**
44 | * Default Matomo tracker endpoint
45 | *
46 | * @type {String}
47 | */
48 | var defaultTrackerUrl;
49 |
50 | /**
51 | * Reference to global `matomoAsyncInit' in case we overwrite something
52 | *
53 | * @type {Function|undefined}
54 | */
55 | var origMatomoAsyncInit = exports.matomoAsyncInit;
56 |
57 | /**
58 | * Matomo singleton/namespace
59 | *
60 | * @type {Object}
61 | */
62 | var matomo = exports.Matomo || null;
63 |
64 | /**
65 | * Collection of matomo promises
66 | *
67 | * @type {Array.}
68 | */
69 | var matomoPromises = [];
70 |
71 | /**
72 | * Client side cache/storage
73 | *
74 | * @type {Object}
75 | */
76 | var storage = $.initNamespaceStorage('chessio-matomo').localStorage;
77 |
78 | /**
79 | * Cart data access
80 | *
81 | * @type {Object}
82 | */
83 | var cartObservable = customerData.get('cart');
84 |
85 | /**
86 | * Customer data access
87 | *
88 | * @type {Object}
89 | */
90 | var customerObservable = customerData.get('customer');
91 |
92 | /**
93 | * Append Matomo tracker script URL to head
94 | *
95 | * @param {String} scriptUrl
96 | */
97 | function injectScript(scriptUrl) {
98 | $('