diff --git a/classes/Endpoint.php b/classes/Endpoint.php
index d8b6744a1d41f6dc1be5f95c774957e50ecb177d..dc6f488bfae37c23cb529cc380f68c5b4240cf70 100644
--- a/classes/Endpoint.php
+++ b/classes/Endpoint.php
@@ -8,7 +8,7 @@ class Endpoint
     private $sparqlUrl;
     private $params;
 
-    public function __construct($sparqlUrl, $params)
+    public function __construct($sparqlUrl, array $params)
     {
         $this->sparqlUrl = $sparqlUrl;
         $this->params = $params;
@@ -29,7 +29,7 @@ class Endpoint
         } elseif ($output == 'rdf') {
             $accept = 'application/rdf+xml';
         }
-        $aux = "";
+
         $modified = 0;
         $now = time();
         $cacheFile = "";
diff --git a/classes/Exporter.php b/classes/Exporter.php
index 89084dcd72524a74f3fdc3427c84ce0bda060f10..97b9eaf26dcf5b467387942da27054086798d4ae 100644
--- a/classes/Exporter.php
+++ b/classes/Exporter.php
@@ -39,7 +39,7 @@ class Exporter
         array_push($triples, $t);
         $t['o'] = LS . 'Application';
         array_push($triples, $t);
-        if ($conf['parentApp'] != null) {
+        if (isset($conf['parentApp']) && $conf['parentApp'] !== null) {
             $t['p'] = OPMV . 'wasDerivedFrom';
             $t['o'] = $conf['parentApp'];
             array_push($triples, $t);
diff --git a/classes/Importer.php b/classes/Importer.php
index 7ace900372e2a1004e0acfc3c31653498b811ebb..90226c1a53cdc75da23659b0bc094c16d6146b86 100644
--- a/classes/Importer.php
+++ b/classes/Importer.php
@@ -156,8 +156,8 @@ class Importer
 
     private function createEndpoints($ep)
     {
-        require('common.inc.php');
         $endpoints = "";
+
         try {
             foreach ($ep as $k => $v) {
                 if ($conf['endpoint'][$k] != $v) {
@@ -169,13 +169,16 @@ class Importer
             echo 'Caught exception while importing endpoints: ', $e->getMessage(), "\n";
             exit(1);
         }
+
         return $endpoints;
     }
 
     private function createNamespaces($ns)
     {
-        require('namespaces.php');
+        require_once LOADSPEAKR_ROOT . '/namespaces.php';
+        global $conf;
         $namespaces = "";
+
         try {
             foreach ($ns as $k => $v) {
                 if ($conf["ns"][$k] != $v) {
@@ -192,6 +195,7 @@ class Importer
             echo 'Caught exception while importing namespaces: ', $e->getMessage(), "\n";
             exit(1);
         }
+
         return $namespaces;
     }
 
diff --git a/classes/LoadModules.php b/classes/LoadModules.php
new file mode 100644
index 0000000000000000000000000000000000000000..b15ccbd0845b982fb4b64f1005870fde6898129d
--- /dev/null
+++ b/classes/LoadModules.php
@@ -0,0 +1,72 @@
+<?php declare(strict_types=1);
+
+namespace uib\ub\loadspeakr;
+
+use uib\ub\loadspeakr\modules\ModuleInterface;
+use uib\ub\loadspeakr\modules\UnknownModule;
+
+final class LoadModules
+{
+    private array $conf;
+
+    public function __construct($conf)
+    {
+        $this->conf = $conf;
+    }
+
+  public function loadModule(string $uri): ModuleInterface
+  {
+      $className =  $this->loadClass($uri);
+      $unknown = new UnknownModule();
+
+      switch ($uri) {
+          case 'admin':
+              return new $className();
+          case 'redirect':
+              return new $className();
+          case 'service':
+              return new $className();
+          case 'session':
+              return new $className();
+          case 'sparqlfilter':
+              return new $className();
+          case 'type':
+              return new $className();
+          case 'uri':
+              return new $className();
+          case 'export':
+              return new $className();
+          case 'static':
+              return new $className();
+          case 'default':
+              break;
+      }
+
+      return $unknown;
+  }
+
+    private function loadClass($module): string
+    {
+        if (!$this->moduleAvailable($module)) {
+            HTTPStatus::send500('Module: ' . $module . ' not found.');
+        }
+
+        $className = ucfirst($module) . 'Module';
+
+        if (file_exists(__DIR__ . '/modules/' . $className . '.php')) {
+            return __NAMESPACE__ . '\\modules\\' . $className;
+        }
+
+        return '';
+    }
+
+    private function moduleAvailable(string $module): bool
+    {
+        if (!in_array($module, $this->conf['modules']['available'], true)) {
+            return false;
+        }
+
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/classes/Utils.php b/classes/Utils.php
index 80eda140140c11c176ae099bcb1bd1be16a76096..186b938128d5403ffe3cb5e71cbfd192120643cc 100644
--- a/classes/Utils.php
+++ b/classes/Utils.php
@@ -215,7 +215,7 @@ class Utils
             $t = $parser->getTriples();
             $triples = array_merge($triples, $t);
         }
-        if ($lodspk['mirror_external_uris']) {
+            if (self::mirror_external_uris($lodspk)) {
             global $uri;
             global $localUri;
             $t = array();
@@ -492,7 +492,6 @@ class Utils
         $data = array();
         $strippedModelFile = str_replace('endpoint.', '', str_replace('.query', '', $modelFile));
         if (!is_dir($modelFile)) {
-            require_once __DIR__ . '/../vendor/ubbdst/haanga/lib/Haanga.php';
             Haanga::configure(array(
               'cache_dir' => $conf['home'] . 'cache/',
               'autoescape' => false,
@@ -708,7 +707,6 @@ class Utils
         if (isset($lodspk['queryTimes'])) {
             $lodspk['queryTimes'] = Convert::array_to_object($lodspk['queryTimes']);
         }
-        require_once __DIR__ . '/../vendor/ubbdst/haanga/lib/Haanga.php';
         $viewAux = explode("/", $view);
         $viewFile = array_pop($viewAux);
         //$viewFile = $view;
@@ -805,38 +803,54 @@ class Utils
         return $result;
     }
 
-    public static function getMirroredUri($localUri)
+    public static function mirror_external_uris($conf): bool
     {
-        global $conf;
-        $uri = $localUri;
-        if (isset($conf['mirror_external_uris']) && $conf['mirror_external_uris'] != false) {
-            if (is_bool($conf['mirror_external_uris'])) {
-                $uri = preg_replace("|^" . $conf['basedir'] . "|", $conf['ns']['base'], $localUri);
-            } elseif (is_string($conf['mirror_external_uris'])) {
-                $uri = preg_replace("|^" . $conf['basedir'] . "|", $conf['mirror_external_uris'], $localUri);
-            } elseif (is_array($conf['mirror_external_uris'])) {
-                $defaultKey = ""; //Default namespace is empty string ""
-                $namespaceFragment = array_shift(split("/", str_replace($conf['basedir'], "", $localUri)));
+        return isset($conf['mirror_external_uris']) && $conf['mirror_external_uris'] !== false;
+    }
+
+    private static function multiple_mirror_external_uris($conf)
+    {
+        HTTPStatus::send500("Mirroring multiple external uris currently not supported in PHP 7 and 8 by Loadspeakr");
+
+        $defaultKey = ""; //Default namespace is empty string ""
+        $namespaceFragment = array_shift(split("/", str_replace($conf['basedir'], "", $localUri)));
+        $uri = preg_replace(
+          "|^" . $conf['basedir'] . "|",
+          $conf['mirror_external_uris'][$defaultKey],
+          $localUri
+        );
+        foreach ($conf['mirror_external_uris'] as $k => $v) {
+            if ($namespaceFragment == $k) {
                 $uri = preg_replace(
-                  "|^" . $conf['basedir'] . "|",
-                  $conf['mirror_external_uris'][$defaultKey],
+                  "|^" . $conf['basedir'] . $k . "/" . "|",
+                  $conf['mirror_external_uris'][$k],
                   $localUri
                 );
-                foreach ($conf['mirror_external_uris'] as $k => $v) {
-                    if ($namespaceFragment == $k) {
-                        $uri = preg_replace(
-                          "|^" . $conf['basedir'] . $k . "/" . "|",
-                          $conf['mirror_external_uris'][$k],
-                          $localUri
-                        );
-                        break;
-                    }
-                }
-            } else {
-                HTTPStatus::send500("Error in mirroring configuration");
-                exit(1);
+                break;
             }
         }
+
+    }
+
+    public static function getMirroredUri($localUri)
+    {
+        global $conf;
+        $uri = '';
+
+        if (!self::mirror_external_uris($conf)) {
+            return $localUri;
+        }
+
+        if (is_bool($conf['mirror_external_uris'])) {
+            $uri = preg_replace("|^" . $conf['basedir'] . "|", $conf['ns']['base'], $localUri);
+        } elseif (is_string($conf['mirror_external_uris'])) {
+            $uri = preg_replace("|^" . $conf['basedir'] . "|", $conf['mirror_external_uris'], $localUri);
+        } elseif (is_array($conf['mirror_external_uris'])) {
+            self::multiple_mirror_external_uris($conf);
+        } else {
+            HTTPStatus::send500("Error in mirroring configuration");
+        }
+
         return $uri;
     }
 
diff --git a/classes/modules/adminModule.php b/classes/modules/AdminModule.php
similarity index 99%
rename from classes/modules/adminModule.php
rename to classes/modules/AdminModule.php
index 9fa787286d81c038765d472f7a4e4695131c1901..36d1a209625db5e354d1d94c14dca0d61604d6c7 100644
--- a/classes/modules/adminModule.php
+++ b/classes/modules/AdminModule.php
@@ -2,13 +2,12 @@
 
 namespace uib\ub\loadspeakr\modules;
 
+use ARC2;
 use uib\ub\loadspeakr\Endpoint;
 use uib\ub\loadspeakr\HTTPStatus;
 use uib\ub\loadspeakr\Utils;
 
-require_once('abstractModule.php');
-
-class AdminModule extends abstractModule
+class AdminModule implements ModuleInterface
 {
     //Service module
     private $head = "<!DOCTYPE html>
@@ -332,8 +331,6 @@ class AdminModule extends abstractModule
                     HTTPStatus::send409("No file was included in the request");
                 } else {
                     $ng = (isset($_POST['namedgraph'])) ? $_POST['namedgraph'] : 'default';
-
-                    require_once __DIR__ . '/../../vendor/semsol/arc2/ARC2.php';
                     $parser = ARC2::getRDFParser();
                     $parser->parse($_FILES["file"]["tmp_name"]);
                     $triples = $parser->getTriples();
diff --git a/classes/modules/exportModule.php b/classes/modules/ExportModule.php
similarity index 98%
rename from classes/modules/exportModule.php
rename to classes/modules/ExportModule.php
index 162b71f0e0ba942af781c4291ec7053be5e4e428..9abe8e131ad5111bbfddb0aecbe605601bf428bb 100644
--- a/classes/modules/exportModule.php
+++ b/classes/modules/ExportModule.php
@@ -2,9 +2,9 @@
 
 namespace uib\ub\loadspeakr\modules;
 
-require_once('abstractModule.php');
+use ARC2;
 
-class ExportModule extends abstractModule
+class ExportModule implements ModuleInterface
 {
     private $serialization;
     private $graph;
@@ -32,7 +32,6 @@ class ExportModule extends abstractModule
         define("RDFS", "http://www.w3.org/2000/01/rdf-schema#");
         define("OPMV", "http://openprovenance.org/ontology#");
         define("SKOS", "http://www.w3.org/2004/02/skos/core#");
-        require __DIR__ . '/../../vendor/semsol/arc2/ARC2.php';
         $ser = ARC2::getTurtleSerializer();
 
         $triples = array();
diff --git a/classes/modules/ModuleInterface.php b/classes/modules/ModuleInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..12614e20934d78bbb9990b81e2f6ccfe93491f49
--- /dev/null
+++ b/classes/modules/ModuleInterface.php
@@ -0,0 +1,9 @@
+<?php declare(strict_types=1);
+
+namespace uib\ub\loadspeakr\modules;
+
+interface ModuleInterface
+{
+    public function match($uri);
+    public function execute($params);
+}
diff --git a/classes/modules/redirectModule.php b/classes/modules/RedirectModule.php
similarity index 83%
rename from classes/modules/redirectModule.php
rename to classes/modules/RedirectModule.php
index a72d6672ec5f0bc0a34866bee8c1e52f9db30672..57e17d1c927bf22f96272e3c693292088fac2b10 100644
--- a/classes/modules/redirectModule.php
+++ b/classes/modules/RedirectModule.php
@@ -1,11 +1,10 @@
 <?php declare(strict_types=1);
 
 namespace uib\ub\loadspeakr\modules;
-use uib\ub\loadspeakr\MetaDb;
 
-require_once('abstractModule.php');
+use uib\ub\loadspeakr\MetaDb;
 
-class RedirectModule extends abstractModule
+class RedirectModule implements ModuleInterface
 {
     public function match($uri)
     {
@@ -16,7 +15,6 @@ class RedirectModule extends abstractModule
         global $endpoints;
         global $lodspk;
 
-        require_once($conf['home'] . 'classes/MetaDb.php');
         $metaDb = new MetaDb($conf['metadata']['db']['location']);
 
         return true;
diff --git a/classes/modules/serviceModule.php b/classes/modules/ServiceModule.php
similarity index 92%
rename from classes/modules/serviceModule.php
rename to classes/modules/ServiceModule.php
index ebc3818d43dd2f351d8b2c974207d3999cd8b758..2539bad0e53228a5778986d0e2b7ed9095483dc3 100644
--- a/classes/modules/serviceModule.php
+++ b/classes/modules/ServiceModule.php
@@ -2,14 +2,14 @@
 
 namespace uib\ub\loadspeakr\modules;
 
+use ARC2;
+use Exception;
 use uib\ub\loadspeakr\Convert;
 use uib\ub\loadspeakr\HTTPStatus;
 use uib\ub\loadspeakr\Logging;
 use uib\ub\loadspeakr\Utils;
 
-require_once('abstractModule.php');
-
-class ServiceModule extends abstractModule
+class ServiceModule implements ModuleInterface
 {
     public function match($uri)
     {
@@ -138,18 +138,16 @@ class ServiceModule extends abstractModule
         $context = array();
         $context['contentType'] = $acceptContentType;
         $context['endpoints'] = $endpoints;
-        //$f = $this->getFunction($localUri);
         $params = $this->getParams($localUri);
-        //$params[] = $context;
-        //$acceptContentType = Utils::getBestContentType($_SERVER['HTTP_ACCEPT']);
         $extension = Utils::getExtension($acceptContentType, $conf['http_accept']);
         $args = array();
         list($modelFile, $viewFile) = $service;
+
         try {
             $prefixHeader = array();
 
             for ($i = 0; $i < sizeof($params); $i++) {
-                if ($conf['mirror_external_uris'] != false) {
+                if (Utils::mirror_external_uris($conf)) {
                     $altUri = Utils::curie2uri($params[$i]);
                     $altUri = preg_replace("|^" . $conf['basedir'] . "|", $conf['ns']['local'], $altUri);
                     $params[$i] = Utils::uri2curie($altUri);
@@ -159,7 +157,6 @@ class ServiceModule extends abstractModule
             $segmentConnector = "";
             for ($i = 0; $i < sizeof($params); $i++) {
                 Utils::curie2uri($params[$i]);
-                //echo $params[$i]." ".Utils::curie2uri($params[$i]);exit(0);
                 $auxPrefix = Utils::getPrefix($params[$i]);
                 if ($auxPrefix['ns'] != null) {
                     $prefixHeader[] = $auxPrefix;
@@ -185,7 +182,6 @@ class ServiceModule extends abstractModule
             $lodspk['local']['curie'] = Utils::uri2curie($localUri);
             $lodspk['contentType'] = $acceptContentType;
             $lodspk['endpoint'] = $conf['endpoint'];
-
             $lodspk['type'] = $modelFile;
             $lodspk['header'] = $prefixHeader;
             $lodspk['args'] = $args;
@@ -195,13 +191,12 @@ class ServiceModule extends abstractModule
             if ($viewFile == null) {
                 $lodspk['transform_select_query'] = true;
             }
-            //  chdir($lodspk['model']);
             Utils::queryFile($modelFile, $endpoints['local'], $results, $firstResults);
+
             if (!$lodspk['resultRdf']) {
                 $results = Utils::internalize($results);
                 $firstAux = Utils::getfirstResults($results);
 
-                //  	chdir($conf['home']);
                 if (is_array($results)) {
                     $resultsObj = Convert::array_to_object($results);
                     $results = $resultsObj;
@@ -212,9 +207,7 @@ class ServiceModule extends abstractModule
             } else {
                 $resultsObj = $results;
             }
-            //Need to redefine viewFile as 'local' i.e., inside service.foo/ so I can load files with the relative path correctly
-            //$viewFile = $extension.".template";
-            //chdir($conf['home']);
+
             Utils::processDocument($viewFile, $lodspk, $results);
         } catch (Exception $ex) {
             echo $ex->getMessage();
@@ -232,18 +225,17 @@ class ServiceModule extends abstractModule
         $count = 1;
         $prefixUri = $conf['basedir'];
         $functionAndParams = explode('/', str_replace($prefixUri . $lodspk['serviceName'], '', $uri, $count));
+
         if (sizeof($functionAndParams) > 1) {
             array_shift($functionAndParams);
             return $functionAndParams;
-        } else {
-            return array(null);
         }
+
+        return array(null);
     }
 
     protected function readScaffold($scaffold, $serviceArgs)
     {
-        global $conf;
-        require_once __DIR__ . '/../../vendor/semsol/arc2/ARC2.php';
         $parser = ARC2::getTurtleParser();
         $parser->parse($scaffold);
         $triples = $parser->getTriples();
@@ -253,19 +245,21 @@ class ServiceModule extends abstractModule
         );
         $scaffoldUri = $aux[0][0];
         $aux = Utils::filterTriples($triples, array($scaffoldUri, "http://lodspeakr.org/vocab/scaffold", null));
+
         foreach ($aux as $r) {
             $patterns = Utils::filterTriples($triples, array($r[2], "http://lodspeakr.org/vocab/uriPattern", null));
             $pattern = stripcslashes($patterns[0][2]);
+
             if (preg_match("|$pattern|", $serviceArgs) > 0) {
-//        echo "match ! \n ".$pattern."\n";
                 $patternDir = Utils::filterTriples(
                   $triples,
                   array($r[2], "http://lodspeakr.org/vocab/subComponent", null)
                 );
+
                 return $patternDir[0][2];
             }
         }
-//        exit(0);
+
         return "";
     }
 
diff --git a/classes/modules/sessionModule.php b/classes/modules/SessionModule.php
similarity index 96%
rename from classes/modules/sessionModule.php
rename to classes/modules/SessionModule.php
index f2552529d2cc1db7215ee47c107efe26d04e8f12..bf3f47ffafb15448c626a619fb8f03595b01aa85 100644
--- a/classes/modules/sessionModule.php
+++ b/classes/modules/SessionModule.php
@@ -4,9 +4,7 @@ namespace uib\ub\loadspeakr\modules;
 
 use uib\ub\loadspeakr\HTTPStatus;
 
-require_once('abstractModule.php');
-
-class SessionModule extends abstractModule
+class SessionModule implements ModuleInterface
 {
     //Session module
     private $sessionUri = "session";
diff --git a/classes/modules/sparqlFilterModule.php b/classes/modules/SparqlFilterModule.php
similarity index 97%
rename from classes/modules/sparqlFilterModule.php
rename to classes/modules/SparqlFilterModule.php
index 2adcb5e9c8a83a1e1bf25b2cd98fa6e8a8186f7f..6ac39fe6a89f4123948f84f666a9690c3fb458bd 100644
--- a/classes/modules/sparqlFilterModule.php
+++ b/classes/modules/SparqlFilterModule.php
@@ -2,6 +2,7 @@
 
 namespace uib\ub\loadspeakr\modules;
 
+use Haanga;
 use uib\ub\loadspeakr\Convert;
 use uib\ub\loadspeakr\HTTPStatus;
 use uib\ub\loadspeakr\Logging;
@@ -9,9 +10,7 @@ use uib\ub\loadspeakr\MetaDb;
 use uib\ub\loadspeakr\Queries;
 use uib\ub\loadspeakr\Utils;
 
-require_once('abstractModule.php');
-
-class sparqlFilterModule extends abstractModule
+class SparqlFilterModule implements ModuleInterface
 {
     public function match($uri)
     {
@@ -24,7 +23,6 @@ class sparqlFilterModule extends abstractModule
         global $results;
         global $firstResults;
 
-        require_once($conf['home'] . 'classes/MetaDb.php');
         $metaDb = new MetaDb($conf['metadata']['db']['location']);
 
         $pair = Queries::getMetadata($localUri, $acceptContentType, $metaDb);
@@ -46,7 +44,6 @@ class sparqlFilterModule extends abstractModule
         $uri = $res;
         $queries = $this->getQueries();
         $e = $endpoints['local'];
-        require_once __DIR__ . '/../../vendor/ubbdst/haanga/lib/Haanga.php';
         Haanga::configure(array(
           'cache_dir' => $conf['home'] . 'cache/',
           'autoescape' => false,
diff --git a/classes/modules/staticModule.php b/classes/modules/StaticModule.php
similarity index 98%
rename from classes/modules/staticModule.php
rename to classes/modules/StaticModule.php
index afced4760c5c355d73693f8d1a7919a6f8f2b1f5..b72072d7da2bdf52a3669be05d6747432e9f681e 100644
--- a/classes/modules/staticModule.php
+++ b/classes/modules/StaticModule.php
@@ -6,9 +6,7 @@ use uib\ub\loadspeakr\HTTPStatus;
 use uib\ub\loadspeakr\Logging;
 use uib\ub\loadspeakr\Utils;
 
-require_once('abstractModule.php');
-
-class StaticModule extends abstractModule
+class StaticModule implements ModuleInterface
 {
     public function match($uri)
     {
diff --git a/classes/modules/typeModule.php b/classes/modules/TypeModule.php
similarity index 98%
rename from classes/modules/typeModule.php
rename to classes/modules/TypeModule.php
index 5ea51363329ed664f658bef0112d565b31aa30f7..915b783b7047d423b8faa7ea8cf6ad5ca485aad9 100644
--- a/classes/modules/typeModule.php
+++ b/classes/modules/TypeModule.php
@@ -9,9 +9,7 @@ use uib\ub\loadspeakr\MetaDb;
 use uib\ub\loadspeakr\Queries;
 use uib\ub\loadspeakr\Utils;
 
-require_once('abstractModule.php');
-
-class TypeModule extends abstractModule
+class TypeModule implements ModuleInterface
 {
     public function match($uri)
     {
@@ -22,7 +20,6 @@ class TypeModule extends abstractModule
         global $endpoints;
         global $lodspk;
 
-        require_once($conf['home'] . 'classes/MetaDb.php');
         $metaDb = new MetaDb($conf['metadata']['db']['location']);
 
         $pair = Queries::getMetadata($localUri, $acceptContentType, $metaDb);
diff --git a/classes/modules/UnknownModule.php b/classes/modules/UnknownModule.php
new file mode 100644
index 0000000000000000000000000000000000000000..48f45017c58424ce72577bd06cfd7fce93f81504
--- /dev/null
+++ b/classes/modules/UnknownModule.php
@@ -0,0 +1,23 @@
+<?php declare(strict_types=1);
+
+namespace uib\ub\loadspeakr\modules;
+
+use uib\ub\loadspeakr\HTTPStatus;
+
+/**
+ * Null result Loadspkr module.
+ *
+ * Used when unknown module is requested.
+ */
+final class UnknownModule implements ModuleInterface
+{
+
+    public function match($uri): void
+    {
+        HTTPStatus::send404($uri);
+    }
+
+    public function execute($params): void
+    {
+    }
+}
diff --git a/classes/modules/uriModule.php b/classes/modules/UriModule.php
similarity index 98%
rename from classes/modules/uriModule.php
rename to classes/modules/UriModule.php
index e1f21c68e7e767a053627073728d9c7ff47baec9..112afd1964bed056f14a96cbb0339ed27c3f8d75 100644
--- a/classes/modules/uriModule.php
+++ b/classes/modules/UriModule.php
@@ -9,9 +9,7 @@ use uib\ub\loadspeakr\MetaDb;
 use uib\ub\loadspeakr\Queries;
 use uib\ub\loadspeakr\Utils;
 
-require_once('abstractModule.php');
-
-class UriModule extends abstractModule
+class UriModule implements ModuleInterface
 {
     public function match($uri)
     {
@@ -25,7 +23,7 @@ class UriModule extends abstractModule
         if (!empty($conf['disableComponents']) && $conf['disableComponents'] == true) {
             return false;
         }
-        require_once('classes/MetaDb.php');
+
         $metaDb = new MetaDb($conf['metadata']['db']['location']);
         #LocalURI as is for looking up existing metadata. Fix fails if first paramater is changed to stripped localUri.
         $pair = Queries::getMetadata($localUri, $acceptContentType, $metaDb);
diff --git a/classes/modules/abstractModule.php b/classes/modules/abstractModule.php
deleted file mode 100644
index 9a59faca9eccc8e6abd9adb5df549361bf9f1db9..0000000000000000000000000000000000000000
--- a/classes/modules/abstractModule.php
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php declare(strict_types=1);
-
-namespace uib\ub\loadspeakr\modules;
-
-abstract class AbstractModule
-{
-    abstract protected function match($uri);
-
-    abstract protected function execute($params);
-}
diff --git a/common.inc.php b/common.inc.php
index e96a79e2306e8a54771a1692580786bef8b95dfa..fb18ae8d37fcbbec64503da632951e64f82f6f7a 100644
--- a/common.inc.php
+++ b/common.inc.php
@@ -1,11 +1,11 @@
 <?php
 
 $conf['version'] = '20130612';
+$conf['home'] = LOADSPEAKR_ROOT . '/';
 $conf['output']['select'] = 'json';
 $conf['output']['ask'] = 'json';
 $conf['output']['describe'] = 'rdf';
-//$conf['endpointParams']['config']['show_inline'] = 0;
-//$conf['endpointParams']['config']['named_graph'] = '';
+$conf['endpointParams']['config'] = [];
 //ALternative endpoints
 $conf['endpoint']['dbpedia'] = 'http://dbpedia.org/sparql';
 $conf['endpoint']['data_gov'] = 'http://services.data.gov/sparql';
@@ -79,10 +79,12 @@ $conf['modules']['available'] = array('static','service', 'type');
 //$conf['modules']['available'] = array('session', 'static','uri', 'type', 'service');
 
 $conf['admin']['pass'] = 'admin';
+$conf['view']['standard']['baseUrl'] = '';
+$conf['basedir'] = '';
 
 global $lodspk;
-
 $lodspk['maxResults'] = 1000;
-include_once('settings.inc.php');
-$conf['view']['standard']['baseUrl'] = $conf['basedir'];
-?>
+
+if (file_exists(LOADSPEAKR_ROOT . '/settings.inc.php')) {
+    require_once LOADSPEAKR_ROOT . '/settings.inc.php';
+}
diff --git a/composer.json b/composer.json
index 960033977e93fa6b7ec76eaf91a0a1c0d8234b72..e662fd44ca15879fa0f51097d7048c7535fde67d 100644
--- a/composer.json
+++ b/composer.json
@@ -34,10 +34,11 @@
     }
   },
   "require-dev": {
-    "roave/security-advisories": "dev-latest",
     "phan/phan": "4.x",
     "phpstan/phpstan": "^0.12.83",
     "phpunit/phpunit": "^9",
+    "rector/rector": "^0.11.53",
+    "roave/security-advisories": "dev-latest",
     "squizlabs/php_codesniffer": "3.*"
   }
 }
diff --git a/composer.lock b/composer.lock
index 67609d55bf92ccfe9fec69a5c3f54a63372bae84..e14bc2738819b9ad2d96518c58f5348c77395d7a 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "6a721a617a138fb2f051106c7f959a79",
+    "content-hash": "3fa51561c5a390a56138089724f39b9d",
     "packages": [
         {
             "name": "psr/cache",
@@ -1959,16 +1959,16 @@
         },
         {
             "name": "phpstan/phpstan",
-            "version": "0.12.99",
+            "version": "0.12.98",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpstan/phpstan.git",
-                "reference": "b4d40f1d759942f523be267a1bab6884f46ca3f7"
+                "reference": "3bb7cc246c057405dd5e290c3ecc62ab51d57e00"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b4d40f1d759942f523be267a1bab6884f46ca3f7",
-                "reference": "b4d40f1d759942f523be267a1bab6884f46ca3f7",
+                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/3bb7cc246c057405dd5e290c3ecc62ab51d57e00",
+                "reference": "3bb7cc246c057405dd5e290c3ecc62ab51d57e00",
                 "shasum": ""
             },
             "require": {
@@ -1999,7 +1999,7 @@
             "description": "PHPStan - PHP Static Analysis Tool",
             "support": {
                 "issues": "https://github.com/phpstan/phpstan/issues",
-                "source": "https://github.com/phpstan/phpstan/tree/0.12.99"
+                "source": "https://github.com/phpstan/phpstan/tree/0.12.98"
             },
             "funding": [
                 {
@@ -2019,7 +2019,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-09-12T20:09:55+00:00"
+            "time": "2021-09-02T12:33:01+00:00"
         },
         {
             "name": "phpunit/php-code-coverage",
@@ -2442,6 +2442,65 @@
             ],
             "time": "2021-08-31T06:47:40+00:00"
         },
+        {
+            "name": "rector/rector",
+            "version": "0.11.53",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/rectorphp/rector.git",
+                "reference": "110c96451dee4dd58d3a1ffc05e0b700892d6601"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/rectorphp/rector/zipball/110c96451dee4dd58d3a1ffc05e0b700892d6601",
+                "reference": "110c96451dee4dd58d3a1ffc05e0b700892d6601",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.1|^8.0",
+                "phpstan/phpstan": "0.12.98"
+            },
+            "conflict": {
+                "phpstan/phpdoc-parser": "<=0.5.3",
+                "phpstan/phpstan": "<=0.12.82",
+                "rector/rector-cakephp": "*",
+                "rector/rector-doctrine": "*",
+                "rector/rector-nette": "*",
+                "rector/rector-phpunit": "*",
+                "rector/rector-prefixed": "*",
+                "rector/rector-symfony": "*"
+            },
+            "bin": [
+                "bin/rector"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "0.11-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Prefixed and PHP 7.1 downgraded version of rector/rector",
+            "support": {
+                "issues": "https://github.com/rectorphp/rector/issues",
+                "source": "https://github.com/rectorphp/rector/tree/0.11.53"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/tomasvotruba",
+                    "type": "github"
+                }
+            ],
+            "time": "2021-09-09T18:12:42+00:00"
+        },
         {
             "name": "roave/security-advisories",
             "version": "dev-latest",
diff --git a/index.php b/index.php
index 896e27a479376f65c793b84fc97eeb02481980d3..abc168558a8a16a695ffbdd925be7374dfe74c90 100644
--- a/index.php
+++ b/index.php
@@ -1,112 +1,89 @@
-<?php
+<?php declare(strict_types=1);
 
 use uib\ub\loadspeakr\Endpoint;
 use uib\ub\loadspeakr\Exporter;
 use uib\ub\loadspeakr\HTTPStatus;
 use uib\ub\loadspeakr\Importer;
+use uib\ub\loadspeakr\LoadModules;
 use uib\ub\loadspeakr\Logging;
 use uib\ub\loadspeakr\Utils;
 
+const LOADSPEAKR_ROOT = __DIR__;
+
 require_once __DIR__ . '/vendor/autoload.php';
+require_once __DIR__ . '/common.inc.php';
 
-//Import
-if (isset($_GET['q']) && $_GET['q'] == 'import') {
-    include_once('classes/Importer.php');
+if (isset($_GET['q']) && $_GET['q'] === 'import') {
     $imp = new Importer();
     $imp->run();
     exit(0);
 }
 
-//Test if LODSPeaKr is configured
+// Check that application is installed.
 if (!file_exists('settings.inc.php')) {
-    echo 'Need to configure lodspeakr first. Please run "install.sh". Alternatively, you can <a href="import">import an existing application</a>';
+    echo 'Need to configure lodspeakr first. Please run "install.sh". Alternatively, you can <a href="' . $_SERVER['HTTP_HOST'] . '/import">import an existing application</a>';
     exit(0);
 }
 
-include_once('common.inc.php');
-//Debug output
-
 $conf['logfile'] = null;
 if ($conf['debug']) {
-    include_once('classes/Logging.php');
-    if (isset($_GET['q']) && $_GET['q'] == 'logs') {
+    if (isset($_GET['q']) && $_GET['q'] === 'logs') {
         Logging::init();
         exit(0);
-    } else {
-        $conf['logfile'] = Logging::createLogFile($_GET['q']);
-        //error_reporting(E_ALL);
     }
-} else {
-    error_reporting(E_ERROR);
+
+    $conf['logfile'] = Logging::createLogFile($_GET['q']);
 }
 
-include_once('classes/HTTPStatus.php');
-include_once('classes/Utils.php');
-include_once('classes/Queries.php');
-include_once('classes/Endpoint.php');
-include_once('classes/Convert.php');
 $results = array();
 $firstResults = array();
-$endpoints = array();
 $endpoints['local'] = new Endpoint($conf['endpoint']['local'], $conf['endpointParams']['config']);
-
 $acceptContentType = Utils::getBestContentType($_SERVER['HTTP_ACCEPT'], $conf['http_accept']);
 $extension = Utils::getExtension($acceptContentType, $conf['http_accept']);
+$uri = $conf['basedir'] . $_GET['q'];
 
-
-//Check content type is supported by LODSPeaKr
-if ($acceptContentType == null) {
+// Check that content type is supported by LODSPeaKr.
+if ($acceptContentType === null) {
     HTTPStatus::send406($uri);
 }
 
-//Export
-if ($conf['export'] && $_GET['q'] == 'export') {
-    include_once('settings.inc.php');
-    include_once('classes/Exporter.php');
+if ($conf['export'] && $_GET['q'] === 'export') {
     $exp = new Exporter();
     header('Content-Type: text/plain');
     $exp->run();
     exit(0);
 }
 
-//Redirect to root URL if necessary
-$uri = $conf['basedir'] . $_GET['q'];
+// Redirect to root URL if necessary.
 $localUri = $uri;
-if ($uri == $conf['basedir']) {
+if ($uri === $conf['basedir']) {
     header('Location: ' . $conf['root']);
     exit(0);
 }
 
 
-//Configure external URIs if necessary
+// Configure external URIs if necessary.
 $localUri = $conf['basedir'] . $_GET['q'];
-
 $uri = Utils::getMirroredUri($localUri);
 
-
-//Load Loadspeakr modules.
-foreach ($conf['modules']['available'] as $i) {
-    $className = $i . 'Module';
-    $currentModule = $conf['modules']['directory'] . $className . '.php';
-
-    if (!is_file($currentModule)) {
-        HTTPStatus::send500('<br/>Can\'t load or error in module <pre>' . $currentModule . '</pre>');
-        exit(1);
-    }
-
-    require_once($currentModule);
-    $namespacedClassName = 'uib\ub\loadspeakr\modules\\' . ucfirst($className);
-    $module = new $namespacedClassName();
+/**
+ * Load Loadspeakr modules.
+ */
+foreach ($conf['modules']['available'] as $loadspkrModule) {
+    $loader = new LoadModules($conf);
+    $module = $loader->loadModule($loadspkrModule);
     $matching = $module->match($uri);
 
-    if ($matching != false) {
+    if ($matching) {
         $module->execute($matching);
-
-        if ($conf['logfile'] != null) {
+        if ($conf['logfile'] !== null) {
             fwrite($conf['logfile'], "]}");
             fclose($conf['logfile']);
         }
 
+        /**
+         * Only run first Loadspeakr modules that matches.
+         */
         exit(0);
     }
 }
diff --git a/tests/UtilsTest.php b/tests/UtilsTest.php
index 4e336debb43a70fcba4a5a4b5af732728184cc8d..0e84d476ff8f673ed698eeff7296bbe8d37afe83 100644
--- a/tests/UtilsTest.php
+++ b/tests/UtilsTest.php
@@ -115,7 +115,7 @@ final class UtilsTest extends TestCase
             'media-type' => '',
         ],
         'Plain text' => [
-          'expected' => 'html',
+          'expected' => 'nt',
           'media-type' => 'text/plain',
         ],
         'CSS request' => [
@@ -127,11 +127,11 @@ final class UtilsTest extends TestCase
           'media-type' => 'application/json',
         ],
         'Illegal JSON' => [
-          'expected' => 'json',
+          'expected' => 'html',
           'media-type' => 'application/jsons',
         ],
         'Image jpeg' => [
-          'expected' => 'json',
+          'expected' => 'html',
           'media-type' => 'image/jpeg',
         ],
       ];