From efb17787b69a93a2aba7e638eabf8b66825541d8 Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Wed, 19 Feb 2020 15:33:08 -0500
Subject: [PATCH] Fixed broken "on the fly debug" functionality. - Move
 functionality from Bootstrapper into LoggerFactory (more specific). - Use
 ProxyManager to build Logger as a lazy loading value holder to avoid circular
 dependencies. - Resolves VUFIND-1382.

---
 module/VuFind/src/VuFind/Bootstrapper.php     | 24 -----------
 .../VuFind/src/VuFind/Log/LoggerFactory.php   | 41 +++++++++++++++++--
 2 files changed, 37 insertions(+), 28 deletions(-)

diff --git a/module/VuFind/src/VuFind/Bootstrapper.php b/module/VuFind/src/VuFind/Bootstrapper.php
index 008b98d1f94..d2fb48d7497 100644
--- a/module/VuFind/src/VuFind/Bootstrapper.php
+++ b/module/VuFind/src/VuFind/Bootstrapper.php
@@ -124,30 +124,6 @@ class Bootstrapper
         }
     }
 
-    /**
-     * Initialize dynamic debug mode (debug initiated by a ?debug=true parameter).
-     *
-     * @return void
-     */
-    protected function initDynamicDebug()
-    {
-        // Query parameters do not apply in console mode:
-        if (Console::isConsole()) {
-            return;
-        }
-
-        $app = $this->event->getApplication();
-        $sm = $app->getServiceManager();
-        $debugOverride = $sm->get('Request')->getQuery()->get('debug');
-        if ($debugOverride) {
-            $auth = $sm->get(\ZfcRbac\Service\AuthorizationService::class);
-            if ($auth->isGranted('access.DebugMode')) {
-                $logger = $sm->get(\VuFind\Log\Logger::class);
-                $logger->addDebugWriter($debugOverride);
-            }
-        }
-    }
-
     /**
      * If the system is offline, set up a handler to override the routing output.
      *
diff --git a/module/VuFind/src/VuFind/Log/LoggerFactory.php b/module/VuFind/src/VuFind/Log/LoggerFactory.php
index 481689028f7..bd49125f1c8 100644
--- a/module/VuFind/src/VuFind/Log/LoggerFactory.php
+++ b/module/VuFind/src/VuFind/Log/LoggerFactory.php
@@ -29,6 +29,7 @@ namespace VuFind\Log;
 
 use Interop\Container\ContainerInterface;
 use Zend\Config\Config;
+use Zend\Console\Console;
 use Zend\Log\Writer\WriterInterface;
 use Zend\ServiceManager\Factory\FactoryInterface;
 
@@ -175,6 +176,27 @@ class LoggerFactory implements FactoryInterface
         $this->addWriters($logger, $writer, $filters);
     }
 
+    /**
+     * Is dynamic debug mode enabled?
+     *
+     * @param ContainerInterface $container Service manager
+     *
+     * @return bool
+     */
+    protected function hasDynamicDebug(ContainerInterface $container): bool
+    {
+        // Query parameters do not apply in console mode; if we do have a debug
+        // query parameter, and the appropriate permission is set, activate dynamic
+        // debug:
+        if (!Console::isConsole()
+            && $container->get('Request')->getQuery()->get('debug')
+        ) {
+            return $container->get(\ZfcRbac\Service\AuthorizationService::class)
+                ->isGranted('access.DebugMode');
+        }
+        return false;
+    }
+
     /**
      * Set configuration
      *
@@ -191,7 +213,7 @@ class LoggerFactory implements FactoryInterface
         $hasWriter = false;
 
         // DEBUGGER
-        if (!$config->System->debug == false) {
+        if (!$config->System->debug == false || $this->hasDynamicDebug($container)) {
             $hasWriter = true;
             $this->addDebugWriter($logger, $config->System->debug);
         }
@@ -352,8 +374,19 @@ class LoggerFactory implements FactoryInterface
         if (!empty($options)) {
             throw new \Exception('Unexpected options passed to factory.');
         }
-        $logger = new $requestedName();
-        $this->configureLogger($container, $logger);
-        return $logger;
+        // Construct the logger as a lazy loading value holder so that
+        // the object is not instantiated until it is called. This helps break
+        // potential circular dependencies with other services.
+        $callback = function (& $wrapped, $proxy) use ($container, $requestedName) {
+            // Indicate that initialization is complete to avoid reinitialization:
+            $proxy->setProxyInitializer(null);
+
+            // Now build the actual service:
+            $wrapped = new $requestedName();
+            $this->configureLogger($container, $wrapped);
+        };
+        $cfg = $container->get(\ProxyManager\Configuration::class);
+        $factory = new \ProxyManager\Factory\LazyLoadingValueHolderFactory($cfg);
+        return $factory->createProxy($requestedName, $callback);
     }
 }
-- 
GitLab