From b4fd7e1a30c0182dae3a2df69388fe5877877c8b Mon Sep 17 00:00:00 2001 From: indykoning <15870933+indykoning@users.noreply.github.com> Date: Thu, 12 Dec 2024 11:46:34 +0100 Subject: [PATCH] Allow override of some configuration per store (#155) Co-authored-by: Bruno Fache --- Helper/Data.php | 93 +++++++++++++++++++++++-------------- Model/SentryInteraction.php | 45 ++++++++++++------ etc/adminhtml/system.xml | 46 +++++++++--------- 3 files changed, 110 insertions(+), 74 deletions(-) diff --git a/Helper/Data.php b/Helper/Data.php index c6603c7..9e0966d 100644 --- a/Helper/Data.php +++ b/Helper/Data.php @@ -13,10 +13,11 @@ use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\App\State; use Magento\Framework\DB\Adapter\TableNotFoundException; +use Magento\Framework\Exception\FileSystemException; +use Magento\Framework\Exception\RuntimeException; use Magento\Framework\Serialize\Serializer\Json; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; -use RuntimeException; use Throwable; class Data extends AbstractHelper @@ -83,7 +84,7 @@ public function __construct( */ public function getDSN() { - return $this->config['dsn']; + return $this->collectModuleConfig()['dsn']; } /** @@ -91,7 +92,7 @@ public function getDSN() */ public function isTracingEnabled(): bool { - return $this->config['tracing_enabled'] ?? false; + return $this->collectModuleConfig()['tracing_enabled'] ?? false; } /** @@ -99,7 +100,7 @@ public function isTracingEnabled(): bool */ public function getTracingSampleRate(): float { - return (float) ($this->config['tracing_sample_rate'] ?? 0.2); + return (float) ($this->collectModuleConfig()['tracing_sample_rate'] ?? 0.2); } /** @@ -117,19 +118,21 @@ public function getDisabledDefaultIntegrations(): array */ public function getIgnoreJsErrors() { - $list = $this->config['ignore_js_errors']; + $list = $this->collectModuleConfig()['ignore_js_errors']; if ($list === null) { return null; } try { - $list = is_array($this->config['ignore_js_errors']) - ? $this->config['ignore_js_errors'] - : $this->serializer->unserialize($this->config['ignore_js_errors']); + $config = $this->collectModuleConfig(); + $list = is_array($config['ignore_js_errors']) + ? $config['ignore_js_errors'] + : $this->serializer->unserialize($config['ignore_js_errors']); } catch (InvalidArgumentException $e) { throw new RuntimeException( - 'Sentry configuration error: `ignore_js_errors` has to be an array or `null`. Given type: '.gettype($list) // phpcs:ignore + __('Sentry configuration error: `ignore_js_errors` has to be an array or `null`. Given type: %s', gettype($list)), // phpcs:ignore + $e ); } @@ -143,7 +146,7 @@ public function getIgnoreJsErrors() */ public function getJsSdkVersion(): string { - return $this->config['js_sdk_version'] ?: SentryScript::CURRENT_VERSION; + return $this->collectModuleConfig()['js_sdk_version'] ?: SentryScript::CURRENT_VERSION; } /** @@ -153,7 +156,7 @@ public function getJsSdkVersion(): string */ public function getEnvironment() { - return $this->config['environment']; + return $this->collectModuleConfig()['environment'] ?? 'default'; } /** @@ -186,6 +189,16 @@ public function getGeneralConfig($code, $storeId = null) return $this->getConfigValue(static::XML_PATH_SRS.$code, $storeId); } + /** + * Get the store id of the current store. + * + * @return int + */ + public function getStoreId(): int + { + return $this->getStore()?->getId() ?? 0; + } + /** * Gather all configuration. * @@ -193,27 +206,28 @@ public function getGeneralConfig($code, $storeId = null) */ public function collectModuleConfig(): array { - if (isset($this->config['enabled'])) { - return $this->config; + $storeId = $this->getStoreId(); + if (isset($this->config[$storeId]['enabled'])) { + return $this->config[$storeId]; } try { - $this->config['enabled'] = $this->scopeConfig->getValue('sentry/environment/enabled') + $this->config[$storeId]['enabled'] = $this->scopeConfig->getValue('sentry/environment/enabled', ScopeInterface::SCOPE_STORE) ?? $this->deploymentConfig->get('sentry') !== null; - } catch (TableNotFoundException $e) { - $this->config['enabled'] = null; + } catch (TableNotFoundException|FileSystemException|RuntimeException $e) { + $this->config[$storeId]['enabled'] = null; } foreach ($this->configKeys as $value) { try { - $this->config[$value] = $this->scopeConfig->getValue('sentry/environment/'.$value) + $this->config[$storeId][$value] = $this->scopeConfig->getValue('sentry/environment/'.$value, ScopeInterface::SCOPE_STORE) ?? $this->deploymentConfig->get('sentry/'.$value); - } catch (TableNotFoundException $e) { - $this->config[$value] = null; + } catch (TableNotFoundException|FileSystemException|RuntimeException $e) { + $this->config[$storeId][$value] = null; } } - return $this->config; + return $this->config[$storeId]; } /** @@ -234,8 +248,9 @@ public function isActive(): bool public function isActiveWithReason(): array { $reasons = []; - $emptyConfig = empty($this->config); - $configEnabled = array_key_exists('enabled', $this->config) && $this->config['enabled']; + $config = $this->collectModuleConfig(); + $emptyConfig = empty($config); + $configEnabled = isset($config['enabled']) && $config['enabled']; $dsnNotEmpty = $this->getDSN(); $productionMode = ($this->isProductionMode() || $this->isOverwriteProductionMode()); @@ -282,11 +297,13 @@ public function getAppState(): string */ public function isOverwriteProductionMode(): bool { - return array_key_exists('mage_mode_development', $this->config) && $this->config['mage_mode_development']; + $config = $this->collectModuleConfig(); + + return isset($config['mage_mode_development']) && $config['mage_mode_development']; } /** - * Get the current magento version. + * Get the current magento version. * * @return string */ @@ -310,7 +327,7 @@ public function getStore() */ public function isPhpTrackingEnabled(): bool { - return $this->scopeConfig->isSetFlag(static::XML_PATH_SRS.'enable_php_tracking'); + return $this->scopeConfig->isSetFlag(static::XML_PATH_SRS.'enable_php_tracking', ScopeInterface::SCOPE_STORE); } /** @@ -320,7 +337,7 @@ public function isPhpTrackingEnabled(): bool */ public function useScriptTag(): bool { - return $this->scopeConfig->isSetFlag(static::XML_PATH_SRS.'enable_script_tag'); + return $this->scopeConfig->isSetFlag(static::XML_PATH_SRS.'enable_script_tag', ScopeInterface::SCOPE_STORE); } /** @@ -328,7 +345,7 @@ public function useScriptTag(): bool */ public function useSessionReplay(): bool { - return $this->scopeConfig->isSetFlag(static::XML_PATH_SRS.'enable_session_replay'); + return $this->scopeConfig->isSetFlag(static::XML_PATH_SRS.'enable_session_replay', ScopeInterface::SCOPE_STORE); } /** @@ -390,7 +407,7 @@ public function showScriptTagInThisBlock($blockName): bool */ public function getLogrocketKey() { - return $this->config['logrocket_key']; + return $this->collectModuleConfig()['logrocket_key']; } /** @@ -401,7 +418,7 @@ public function getLogrocketKey() public function useLogrocket(): bool { return $this->scopeConfig->isSetFlag(static::XML_PATH_SRS.'use_logrocket') && - array_key_exists('logrocket_key', $this->config) && + isset($this->collectModuleConfig()['logrocket_key']) && $this->getLogrocketKey() !== null; } @@ -413,7 +430,8 @@ public function useLogrocket(): bool public function useLogrocketIdentify(): bool { return $this->scopeConfig->isSetFlag( - static::XML_PATH_SRS.'logrocket_identify' + static::XML_PATH_SRS.'logrocket_identify', + ScopeInterface::SCOPE_STORE ); } @@ -425,7 +443,8 @@ public function useLogrocketIdentify(): bool public function stripStaticContentVersion(): bool { return $this->scopeConfig->isSetFlag( - static::XML_PATH_SRS_ISSUE_GROUPING.'strip_static_content_version' + static::XML_PATH_SRS_ISSUE_GROUPING.'strip_static_content_version', + ScopeInterface::SCOPE_STORE ); } @@ -437,7 +456,8 @@ public function stripStaticContentVersion(): bool public function stripStoreCode(): bool { return $this->scopeConfig->isSetFlag( - static::XML_PATH_SRS_ISSUE_GROUPING.'strip_store_code' + static::XML_PATH_SRS_ISSUE_GROUPING.'strip_store_code', + ScopeInterface::SCOPE_STORE ); } @@ -448,7 +468,7 @@ public function stripStoreCode(): bool */ public function getErrorExceptionReporting(): int { - return (int) ($this->config['errorexception_reporting'] ?? E_ALL); + return (int) ($this->collectModuleConfig()['errorexception_reporting'] ?? E_ALL); } /** @@ -458,12 +478,13 @@ public function getErrorExceptionReporting(): int */ public function getIgnoreExceptions(): array { - if (is_array($this->config['ignore_exceptions'])) { - return $this->config['ignore_exceptions']; + $config = $this->collectModuleConfig(); + if (is_array($config['ignore_exceptions'])) { + return $config['ignore_exceptions']; } try { - return $this->serializer->unserialize($this->config['ignore_exceptions']); + return $this->serializer->unserialize($config['ignore_exceptions']); } catch (InvalidArgumentException $e) { return []; } diff --git a/Model/SentryInteraction.php b/Model/SentryInteraction.php index 2d152cb..0bb3f9b 100644 --- a/Model/SentryInteraction.php +++ b/Model/SentryInteraction.php @@ -12,6 +12,7 @@ use Magento\Framework\App\Area; use Magento\Framework\App\State; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\ObjectManager\ConfigInterface; use ReflectionClass; use Sentry\State\Scope; @@ -29,10 +30,12 @@ class SentryInteraction /** * SentryInteraction constructor. * - * @param State $appState + * @param State $appState + * @param ConfigInterface $omConfigInterface */ public function __construct( - private State $appState + private State $appState, + private ConfigInterface $omConfigInterface ) { } @@ -61,6 +64,26 @@ public function canGetUserContext() } } + /** + * Get a class instance, but only if it is already available within the objectManager. + * + * @param string $class The classname of the type you want from the objectManager. + */ + public function getObjectIfInitialized($class): ?object + { + $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); + $reflectionClass = new ReflectionClass($objectManager); + $sharedInstances = $reflectionClass->getProperty('_sharedInstances'); + $sharedInstances->setAccessible(true); + $class = $this->omConfigInterface->getPreference($class); + + if (!array_key_exists(ltrim($class, '\\'), $sharedInstances->getValue($objectManager))) { + return null; + } + + return $objectManager->get($class); + } + /** * Attempt to get userContext from the objectManager, so we don't request it too early. */ @@ -70,9 +93,7 @@ public function getUserContext(): ?UserContextInterface return $this->userContext; } - $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); - - return $this->userContext = $objectManager->get(UserContextInterface::class); + return $this->userContext = $this->getObjectIfInitialized(UserContextInterface::class); } /** @@ -97,17 +118,11 @@ private function getSessionUserData() return []; } - $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); - $reflectionClass = new ReflectionClass($objectManager); - $sharedInstances = $reflectionClass->getProperty('_sharedInstances'); - $sharedInstances->setAccessible(true); - if ($this->appState->getAreaCode() === Area::AREA_ADMINHTML) { - if (!array_key_exists(ltrim(AdminSession::class, '\\'), $sharedInstances->getValue($objectManager))) { - // Don't intitialise session if it has not already been started, this causes problems with dynamic resources. + $adminSession = $this->getObjectIfInitialized(AdminSession::class); + if ($adminSession === null) { return []; } - $adminSession = $objectManager->get(AdminSession::class); if ($adminSession->isLoggedIn()) { return [ @@ -119,10 +134,10 @@ private function getSessionUserData() } if ($this->appState->getAreaCode() === Area::AREA_FRONTEND) { - if (!array_key_exists(ltrim(CustomerSession::class, '\\'), $sharedInstances->getValue($objectManager))) { + $customerSession = $this->getObjectIfInitialized(CustomerSession::class); + if ($customerSession === null) { return []; } - $customerSession = $objectManager->get(CustomerSession::class); if ($customerSession->isLoggedIn()) { return [ diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 02a14ec..9e75046 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -9,65 +9,65 @@ justbetter JustBetter_Sentry::configuration - + - + JustBetter\Sentry\Block\Adminhtml\System\Config\DeploymentConfigInfo - + Magento\Config\Model\Config\Source\Yesno - + Magento\Config\Model\Config\Source\Yesno - + JustBetter\Sentry\Model\Config\Source\ScriptTagPlacement 1 - + Magento\Config\Model\Config\Source\Yesno - + 1 - + 1 - + Magento\Config\Model\Config\Source\Yesno 1 - + Magento\Config\Model\Config\Source\Yesno 1 - + Magento\Config\Model\Config\Source\Yesno 1 - + Include user ID, name and email to identify logged in users in LogRocket Magento\Config\Model\Config\Source\Yesno @@ -82,46 +82,46 @@ JustBetter\Sentry\Block\Adminhtml\System\Config\Button - + - + Magento\Config\Model\Config\Source\Yesno - + 1 - + 1 - + 1 - + JustBetter\Sentry\Model\Config\Source\LogLevel 1 - + Magento\Config\Model\Config\Source\Yesno 1 - + validate-not-negative-number validate-number @@ -129,14 +129,14 @@ - + - + Magento\Config\Model\Config\Source\Yesno - + Magento\Config\Model\Config\Source\Yesno