diff --git a/composer.json b/composer.json
index a0c05119467e3eb1ef7542a68b250ad0ca4f9c49..1ba7fa8699383e9bb4a578aca5fa0d6954e33de4 100644
--- a/composer.json
+++ b/composer.json
@@ -37,7 +37,7 @@
         "zendframework/zend-db": "2.8.2",
         "zendframework/zend-dom": "2.6.0",
         "zendframework/zend-escaper": "2.5.2",
-        "zendframework/zend-eventmanager": "2.6.3",
+        "zendframework/zend-eventmanager": "3.1.0",
         "zendframework/zend-feed": "2.5.2",
         "zendframework/zend-http": "2.6.0",
         "zendframework/zend-i18n": "2.7.3",
diff --git a/composer.lock b/composer.lock
index 3c9e0c04723f80a7b07d6d6af65dc2eb746b24d9..1fc7714b26d63729d0115db849be8f2b9f84046d 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "content-hash": "7713f46c9d0c08afd51e8d33eea810b5",
+    "content-hash": "6b28ba78c0ed1a34882d7b7025c5bef7",
     "packages": [
         {
             "name": "aferrandini/phpqrcode",
@@ -1886,33 +1886,37 @@
         },
         {
             "name": "zendframework/zend-eventmanager",
-            "version": "2.6.3",
+            "version": "3.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/zendframework/zend-eventmanager.git",
-                "reference": "3d41b6129fb4916d483671cea9f77e4f90ae85d3"
+                "reference": "c3bce7b7d47c54040b9ae51bc55491c72513b75d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/3d41b6129fb4916d483671cea9f77e4f90ae85d3",
-                "reference": "3d41b6129fb4916d483671cea9f77e4f90ae85d3",
+                "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/c3bce7b7d47c54040b9ae51bc55491c72513b75d",
+                "reference": "c3bce7b7d47c54040b9ae51bc55491c72513b75d",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.5 || ^7.0",
-                "zendframework/zend-stdlib": "^2.7"
+                "php": "^5.6 || ^7.0"
             },
             "require-dev": {
-                "athletic/athletic": "dev-master",
-                "fabpot/php-cs-fixer": "1.7.*",
-                "phpunit/phpunit": "~4.0"
+                "athletic/athletic": "^0.1",
+                "container-interop/container-interop": "^1.1.0",
+                "phpunit/phpunit": "^5.6",
+                "zendframework/zend-coding-standard": "~1.0.0",
+                "zendframework/zend-stdlib": "^2.7.3 || ^3.0"
+            },
+            "suggest": {
+                "container-interop/container-interop": "^1.1.0, to use the lazy listeners feature",
+                "zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-release-2.6": "2.6-dev",
-                    "dev-master": "3.0-dev",
-                    "dev-develop": "3.1-dev"
+                    "dev-master": "3.1-dev",
+                    "dev-develop": "3.2-dev"
                 }
             },
             "autoload": {
@@ -1924,12 +1928,15 @@
             "license": [
                 "BSD-3-Clause"
             ],
+            "description": "Trigger and listen to events within a PHP application",
             "homepage": "https://github.com/zendframework/zend-eventmanager",
             "keywords": [
+                "event",
                 "eventmanager",
+                "events",
                 "zf2"
             ],
-            "time": "2016-02-18T20:49:05+00:00"
+            "time": "2016-12-19T21:47:12+00:00"
         },
         {
             "name": "zendframework/zend-feed",
@@ -6910,16 +6917,16 @@
         },
         {
             "name": "symfony/css-selector",
-            "version": "v3.2.4",
+            "version": "v3.2.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/css-selector.git",
-                "reference": "f0e628f04fc055c934b3211cfabdb1c59eefbfaa"
+                "reference": "a48f13dc83c168f1253a5d2a5a4fb46c36244c4c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/css-selector/zipball/f0e628f04fc055c934b3211cfabdb1c59eefbfaa",
-                "reference": "f0e628f04fc055c934b3211cfabdb1c59eefbfaa",
+                "url": "https://api.github.com/repos/symfony/css-selector/zipball/a48f13dc83c168f1253a5d2a5a4fb46c36244c4c",
+                "reference": "a48f13dc83c168f1253a5d2a5a4fb46c36244c4c",
                 "shasum": ""
             },
             "require": {
@@ -6959,7 +6966,7 @@
             ],
             "description": "Symfony CssSelector Component",
             "homepage": "https://symfony.com",
-            "time": "2017-01-02T20:32:22+00:00"
+            "time": "2017-02-21T09:12:04+00:00"
         },
         {
             "name": "symfony/debug",
@@ -7020,16 +7027,16 @@
         },
         {
             "name": "symfony/dependency-injection",
-            "version": "v3.2.4",
+            "version": "v3.2.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dependency-injection.git",
-                "reference": "130aa55b8ed7e6d0d75b0ed37256cec687a22f41"
+                "reference": "74e0935e414ad33d5e82074212c0eedb4681a691"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/130aa55b8ed7e6d0d75b0ed37256cec687a22f41",
-                "reference": "130aa55b8ed7e6d0d75b0ed37256cec687a22f41",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/74e0935e414ad33d5e82074212c0eedb4681a691",
+                "reference": "74e0935e414ad33d5e82074212c0eedb4681a691",
                 "shasum": ""
             },
             "require": {
@@ -7079,7 +7086,7 @@
             ],
             "description": "Symfony DependencyInjection Component",
             "homepage": "https://symfony.com",
-            "time": "2017-02-16T22:46:52+00:00"
+            "time": "2017-03-05T00:06:55+00:00"
         },
         {
             "name": "symfony/event-dispatcher",
diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php
index 7877393d05bb54da2b677b7762ddd334b6e52d5c..5a98a54a9a895096a7a5c4ed3ccf4219a920f6ae 100644
--- a/module/VuFind/config/module.config.php
+++ b/module/VuFind/config/module.config.php
@@ -216,6 +216,7 @@ $config = [
             'VuFind\RecordTabPluginManager' => 'VuFind\Service\Factory::getRecordTabPluginManager',
             'VuFind\RelatedPluginManager' => 'VuFind\Service\Factory::getRelatedPluginManager',
             'VuFind\ResolverDriverPluginManager' => 'VuFind\Service\Factory::getResolverDriverPluginManager',
+            'VuFind\Search' => 'VuFind\Service\Factory::getSearchService',
             'VuFind\Search\BackendManager' => 'VuFind\Service\Factory::getSearchBackendManager',
             'VuFind\Search\Memory' => 'VuFind\Service\Factory::getSearchMemory',
             'VuFind\SearchOptionsPluginManager' => 'VuFind\Service\Factory::getSearchOptionsPluginManager',
@@ -236,7 +237,6 @@ $config = [
         'invokables' => [
             'VuFind\HierarchicalFacetHelper' => 'VuFind\Search\Solr\HierarchicalFacetHelper',
             'VuFind\IpAddressUtils' => 'VuFind\Net\IpAddressUtils',
-            'VuFind\Search' => 'VuFindSearch\Service',
             'VuFind\Session\Settings' => 'VuFind\Session\Settings',
         ],
         'initializers' => [
diff --git a/module/VuFind/src/VuFind/Search/BackendManager.php b/module/VuFind/src/VuFind/Search/BackendManager.php
index ba350513ca1e0e360423d859e70b6810cdb61dcb..177976165141f7f4f22d38176870cf309d12774a 100644
--- a/module/VuFind/src/VuFind/Search/BackendManager.php
+++ b/module/VuFind/src/VuFind/Search/BackendManager.php
@@ -30,7 +30,6 @@ namespace VuFind\Search;
 
 use Zend\ServiceManager\ServiceLocatorInterface;
 
-use Zend\EventManager\SharedListenerAggregateInterface;
 use Zend\EventManager\SharedEventManagerInterface;
 use Zend\EventManager\EventInterface;
 
@@ -48,7 +47,7 @@ use UnexpectedValueException;
  * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
  * @link     https://vufind.org Main Site
  */
-class BackendManager implements SharedListenerAggregateInterface
+class BackendManager
 {
     /**
      * Backend registry.
@@ -159,11 +158,8 @@ class BackendManager implements SharedListenerAggregateInterface
     public function attachShared(SharedEventManagerInterface $events)
     {
         if (!$this->listeners->offsetExists($events)) {
-            $listener = $events->attach(
-                'VuFind\Search',
-                'resolve',
-                [$this, 'onResolve']
-            );
+            $listener = [$this, 'onResolve'];
+            $events->attach('VuFind\Search', 'resolve', $listener);
             $this->listeners->attach($events, $listener);
         }
     }
@@ -179,7 +175,7 @@ class BackendManager implements SharedListenerAggregateInterface
     {
         if ($this->listeners->offsetExists($events)) {
             $listener = $this->listeners->offsetGet($events);
-            $events->detach('VuFind\Search', $listener);
+            $events->detach($listener, 'VuFind\Search');
             $this->listeners->detach($events);
         }
     }
diff --git a/module/VuFind/src/VuFind/Search/SearchRunner.php b/module/VuFind/src/VuFind/Search/SearchRunner.php
index eec7df35e9549f7ebf436fcf426446bbd1d64a8f..b5044ff498116c081f705e592947eab8fd935552 100644
--- a/module/VuFind/src/VuFind/Search/SearchRunner.php
+++ b/module/VuFind/src/VuFind/Search/SearchRunner.php
@@ -75,10 +75,15 @@ class SearchRunner
      * Constructor
      *
      * @param ResultsManager $resultsManager Results manager
+     * @param EventManager   $events         Event manager (optional)
      */
-    public function __construct(ResultsManager $resultsManager)
-    {
+    public function __construct(ResultsManager $resultsManager,
+        EventManager $events = null
+    ) {
         $this->resultsManager = $resultsManager;
+        if (null !== $events) {
+            $this->setEventManager($events);
+        }
     }
 
     /**
diff --git a/module/VuFind/src/VuFind/Service/Factory.php b/module/VuFind/src/VuFind/Service/Factory.php
index 61508cd61b4151544f18bafef84941af48a33ccc..fcd2776892bcef53d56dcff333bf546ff21a69aa 100644
--- a/module/VuFind/src/VuFind/Service/Factory.php
+++ b/module/VuFind/src/VuFind/Service/Factory.php
@@ -670,7 +670,7 @@ class Factory
         );
         $registry = $sm->createScopedServiceManager();
         $smConfig->configureServiceManager($registry);
-        $manager  = new \VuFind\Search\BackendManager($registry);
+        $manager = new \VuFind\Search\BackendManager($registry);
 
         return $manager;
     }
@@ -735,7 +735,22 @@ class Factory
     public static function getSearchRunner(ServiceManager $sm)
     {
         return new \VuFind\Search\SearchRunner(
-            $sm->get('VuFind\SearchResultsPluginManager')
+            $sm->get('VuFind\SearchResultsPluginManager'),
+            new \Zend\EventManager\EventManager($sm->get('SharedEventManager'))
+        );
+    }
+
+    /**
+     * Construct the search service.
+     *
+     * @param ServiceManager $sm Service manager.
+     *
+     * @return \VuFindSearch\Service
+     */
+    public static function getSearchService(ServiceManager $sm)
+    {
+        return new \VuFindSearch\Service(
+            new \Zend\EventManager\EventManager($sm->get('SharedEventManager'))
         );
     }
 
diff --git a/module/VuFindSearch/src/VuFindSearch/Service.php b/module/VuFindSearch/src/VuFindSearch/Service.php
index 8fc4fe86b7d117c7c2868253550c91ff5025379d..775b6733a933a667f72214c5b043456799978663 100644
--- a/module/VuFindSearch/src/VuFindSearch/Service.php
+++ b/module/VuFindSearch/src/VuFindSearch/Service.php
@@ -75,10 +75,15 @@ class Service
     /**
      * Constructor.
      *
+     * @param EventManagerInterface $events Event manager (optional)
+     *
      * @return void
      */
-    public function __construct()
+    public function __construct(EventManagerInterface $events = null)
     {
+        if (null !== $events) {
+            $this->setEventManager($events);
+        }
         $this->backends = [];
     }
 
@@ -349,13 +354,13 @@ class Service
     protected function resolve($backend, $args)
     {
         if (!isset($this->backends[$backend])) {
-            $response = $this->getEventManager()->trigger(
-                self::EVENT_RESOLVE,
-                $this,
-                $args,
+            $response = $this->getEventManager()->triggerUntil(
                 function ($o) {
                     return ($o instanceof BackendInterface);
-                }
+                },
+                self::EVENT_RESOLVE,
+                $this,
+                $args
             );
             if (!$response->stopped()) {
                 throw new Exception\RuntimeException(
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/SearchServiceTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/SearchServiceTest.php
index c3b8d710aa15ef8fead3964d8100ab31bcc9e34d..7f2035071e4c896c7573a835965a8635f9d810aa 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/SearchServiceTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/SearchServiceTest.php
@@ -655,9 +655,11 @@ class SearchServiceTest extends TestCase
         $mockResponse->expects($this->any())->method('stopped')->will($this->returnValue(false));
         $em = $this->createMock('Zend\EventManager\EventManagerInterface');
         $service = new Service();
-        $em->expects($this->any())->method('trigger')
-            ->with($this->equalTo('resolve'), $this->equalTo($service))
-            ->will($this->returnValue($mockResponse));
+        $em->expects($this->any())->method('triggerUntil')
+            ->with(
+                $this->anything(), $this->equalTo('resolve'),
+                $this->equalTo($service)
+            )->will($this->returnValue($mockResponse));
         $service->setEventManager($em);
         $service->retrieve('junk', 'foo');
     }
diff --git a/module/VuFindTheme/src/VuFindTheme/Initializer.php b/module/VuFindTheme/src/VuFindTheme/Initializer.php
index c6d3c025cf0a287da29e367b9710b8bf0af324cb..161a6c7dbaf1188dbbeb7cf2a766a0d5d500a632 100644
--- a/module/VuFindTheme/src/VuFindTheme/Initializer.php
+++ b/module/VuFindTheme/src/VuFindTheme/Initializer.php
@@ -26,9 +26,10 @@
  * @link     https://vufind.org Main Site
  */
 namespace VuFindTheme;
-use Zend\Config\Config,
-    Zend\Mvc\MvcEvent,
-    Zend\Stdlib\RequestInterface as Request;
+use Zend\Config\Config;
+use Zend\Mvc\MvcEvent;
+use Zend\Mvc\View\Http\InjectTemplateListener as BaseInjectTemplateListener;
+use Zend\Stdlib\RequestInterface as Request;
 
 /**
  * VuFind Theme Initializer
@@ -140,23 +141,23 @@ class Initializer
 
         // Detach the default listener:
         $listeners = $sharedEvents->getListeners(
-            'Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH
+            ['Zend\Stdlib\DispatchableInterface'], MvcEvent::EVENT_DISPATCH
         );
-        foreach ($listeners as $listener) {
-            $metadata = $listener->getMetadata();
-            $callback = $listener->getCallback();
-            if (is_a($callback[0], 'Zend\Mvc\View\Http\InjectTemplateListener')) {
-                $priority = $metadata['priority'];
-                $sharedEvents->detach(
-                    'Zend\Stdlib\DispatchableInterface', $listener
-                );
-                break;
+        foreach ($listeners as $priority => $priorityGroup) {
+            foreach ($priorityGroup as $callback) {
+                if ($callback[0] instanceof BaseInjectTemplateListener) {
+                    $injectTemplatePriority = $priority;
+                    $sharedEvents->detach(
+                        $callback, 'Zend\Stdlib\DispatchableInterface'
+                    );
+                    break 2;
+                }
             }
         }
 
         // If we didn't successfully detach a listener above, priority will not be
         // set.  This is an unexpected situation, so we should throw an exception.
-        if (!isset($priority)) {
+        if (!isset($injectTemplatePriority)) {
             throw new \Exception('Unable to detach InjectTemplateListener');
         }
 
@@ -164,7 +165,7 @@ class Initializer
         $injectTemplateListener  = new InjectTemplateListener();
         $sharedEvents->attach(
             'Zend\Stdlib\DispatchableInterface', MvcEvent::EVENT_DISPATCH,
-            [$injectTemplateListener, 'injectTemplate'], $priority
+            [$injectTemplateListener, 'injectTemplate'], $injectTemplatePriority
         );
     }