diff --git a/app/Config/ActivityPub.php b/app/Config/ActivityPub.php
index 976064542cc8ef4f2021c177542f1704ebb3b3da..50a9bddf001fb394d0a04bfc9a279fce103e060a 100644
--- a/app/Config/ActivityPub.php
+++ b/app/Config/ActivityPub.php
@@ -10,32 +10,21 @@ class ActivityPub extends ActivityPubBase
      * --------------------------------------------------------------------
      * ActivityPub Objects
      * --------------------------------------------------------------------
-     * @var string
      */
-    public $actorObject = PodcastActor::class;
-    /**
-     * @var string
-     */
-    public $noteObject = NoteObject::class;
+    public string $actorObject = PodcastActor::class;
+
+    public string $noteObject = NoteObject::class;
 
     /**
      * --------------------------------------------------------------------
      * Default avatar and cover images
      * --------------------------------------------------------------------
-     * @var string
      */
-    public $defaultAvatarImagePath = 'assets/images/castopod-avatar-default.jpg';
-    /**
-     * @var string
-     */
-    public $defaultAvatarImageMimetype = 'image/jpeg';
+    public string $defaultAvatarImagePath = 'assets/images/castopod-avatar-default.jpg';
 
-    /**
-     * @var string
-     */
-    public $defaultCoverImagePath = 'assets/images/castopod-cover-default.jpg';
-    /**
-     * @var string
-     */
-    public $defaultCoverImageMimetype = 'image/jpeg';
+    public string $defaultAvatarImageMimetype = 'image/jpeg';
+
+    public string $defaultCoverImagePath = 'assets/images/castopod-cover-default.jpg';
+
+    public string $defaultCoverImageMimetype = 'image/jpeg';
 }
diff --git a/app/Config/Analytics.php b/app/Config/Analytics.php
index 66fe694573386174ce48dc2073cd318bf8eb6342..cf79bf63d3a0d8e4445b1c08625a5e92736027c4 100644
--- a/app/Config/Analytics.php
+++ b/app/Config/Analytics.php
@@ -10,9 +10,8 @@ class Analytics extends AnalyticsBase
      * --------------------------------------------------------------------
      * Route filters options
      * --------------------------------------------------------------------
-     * @var array<string, string>
      */
-    public $routeFilters = [
+    public array $routeFilters = [
         'analytics-full-data' => 'permission:podcasts-view,podcast-view',
         'analytics-data' => 'permission:podcasts-view,podcast-view',
         'analytics-filtered-data' => 'permission:podcasts-view,podcast-view',
diff --git a/app/Config/App.php b/app/Config/App.php
index 610960079f1e8b362afb0ba9de74c1933cad3b82..29f171165257680632bc1e90d69eceed494bd737 100644
--- a/app/Config/App.php
+++ b/app/Config/App.php
@@ -22,9 +22,8 @@ class App extends BaseConfig
      * explicitly and never rely on auto-guessing, especially in production
      * environments.
      *
-     * @var string
      */
-    public $baseURL = 'http://localhost:8080/';
+    public string $baseURL = 'http://localhost:8080/';
 
     /**
      * --------------------------------------------------------------------------
@@ -36,9 +35,8 @@ class App extends BaseConfig
      *
      *    http://cdn.example.com/
      *
-     * @var string
      */
-    public $mediaBaseURL = 'http://127.0.0.2:8080/';
+    public string $mediaBaseURL = 'http://127.0.0.2:8080/';
 
     /**
      * --------------------------------------------------------------------------
@@ -49,9 +47,8 @@ class App extends BaseConfig
      * something else. If you are using mod_rewrite to remove the page set this
      * variable so that it is blank.
      *
-     * @var string
      */
-    public $indexPage = '';
+    public string $indexPage = '';
 
     /**
      * --------------------------------------------------------------------------
@@ -68,9 +65,8 @@ class App extends BaseConfig
      *
      * WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
      *
-     * @var string
      */
-    public $uriProtocol = 'REQUEST_URI';
+    public string $uriProtocol = 'REQUEST_URI';
 
     /**
      * --------------------------------------------------------------------------
@@ -82,9 +78,8 @@ class App extends BaseConfig
      * strings (like currency markers, numbers, etc), that your program
      * should run under for this request.
      *
-     * @var string
      */
-    public $defaultLocale = 'en';
+    public string $defaultLocale = 'en';
 
     /**
      * --------------------------------------------------------------------------
@@ -95,10 +90,8 @@ class App extends BaseConfig
      * language to use based on the value of the Accept-Language header.
      *
      * If false, no automatic detection will be performed.
-     *
-     * @var boolean
      */
-    public $negotiateLocale = true;
+    public bool $negotiateLocale = true;
 
     /**
      * --------------------------------------------------------------------------
@@ -111,7 +104,7 @@ class App extends BaseConfig
      *
      * @var string[]
      */
-    public $supportedLocales = ['en', 'fr'];
+    public array $supportedLocales = ['en', 'fr'];
 
     /**
      * --------------------------------------------------------------------------
@@ -121,9 +114,8 @@ class App extends BaseConfig
      * The default timezone that will be used in your application to display
      * dates with the date helper, and can be retrieved through app_timezone()
      *
-     * @var string
      */
-    public $appTimezone = 'UTC';
+    public string $appTimezone = 'UTC';
 
     /**
      * --------------------------------------------------------------------------
@@ -135,9 +127,8 @@ class App extends BaseConfig
      *
      * @see http://php.net/htmlspecialchars for a list of supported charsets.
      *
-     * @var string
      */
-    public $charset = 'UTF-8';
+    public string $charset = 'UTF-8';
 
     /**
      * --------------------------------------------------------------------------
@@ -149,9 +140,8 @@ class App extends BaseConfig
      * secure, the user will be redirected to a secure version of the page
      * and the HTTP Strict Transport Security header will be set.
      *
-     * @var boolean
      */
-    public $forceGlobalSecureRequests = true;
+    public bool $forceGlobalSecureRequests = true;
 
     /**
      * --------------------------------------------------------------------------
@@ -164,9 +154,8 @@ class App extends BaseConfig
      * - `CodeIgniter\Session\Handlers\MemcachedHandler`
      * - `CodeIgniter\Session\Handlers\RedisHandler`
      *
-     * @var string
      */
-    public $sessionDriver = FileHandler::class;
+    public string $sessionDriver = FileHandler::class;
 
     /**
      * --------------------------------------------------------------------------
@@ -175,9 +164,8 @@ class App extends BaseConfig
      *
      * The session cookie name, must contain only [0-9a-z_-] characters
      *
-     * @var string
      */
-    public $sessionCookieName = 'ci_session';
+    public string $sessionCookieName = 'ci_session';
 
     /**
      * --------------------------------------------------------------------------
@@ -187,9 +175,8 @@ class App extends BaseConfig
      * The number of SECONDS you want the session to last.
      * Setting to 0 (zero) means expire when the browser is closed.
      *
-     * @var integer
      */
-    public $sessionExpiration = 7200;
+    public int $sessionExpiration = 7200;
 
     /**
      * --------------------------------------------------------------------------
@@ -206,9 +193,8 @@ class App extends BaseConfig
      *
      * IMPORTANT: You are REQUIRED to set a valid save path!
      *
-     * @var string
      */
-    public $sessionSavePath = WRITEPATH . 'session';
+    public string $sessionSavePath = WRITEPATH . 'session';
 
     /**
      * --------------------------------------------------------------------------
@@ -220,9 +206,8 @@ class App extends BaseConfig
      * WARNING: If you're using the database driver, don't forget to update
      *          your session table's PRIMARY KEY when changing this setting.
      *
-     * @var boolean
      */
-    public $sessionMatchIP = false;
+    public bool $sessionMatchIP = false;
 
     /**
      * --------------------------------------------------------------------------
@@ -231,9 +216,8 @@ class App extends BaseConfig
      *
      * How many seconds between CI regenerating the session ID.
      *
-     * @var integer
      */
-    public $sessionTimeToUpdate = 300;
+    public int $sessionTimeToUpdate = 300;
 
     /**
      * --------------------------------------------------------------------------
@@ -244,9 +228,8 @@ class App extends BaseConfig
      * when auto-regenerating the session ID. When set to FALSE, the data
      * will be later deleted by the garbage collector.
      *
-     * @var boolean
      */
-    public $sessionRegenerateDestroy = false;
+    public bool $sessionRegenerateDestroy = false;
 
     /**
      * --------------------------------------------------------------------------
@@ -259,7 +242,7 @@ class App extends BaseConfig
      *
      * @deprecated use Config\Cookie::$prefix property instead.
      */
-    public $cookiePrefix = '';
+    public string $cookiePrefix = '';
 
     /**
      * --------------------------------------------------------------------------
@@ -272,7 +255,7 @@ class App extends BaseConfig
      *
      * @deprecated use Config\Cookie::$domain property instead.
      */
-    public $cookieDomain = '';
+    public string $cookieDomain = '';
 
     /**
      * --------------------------------------------------------------------------
@@ -285,7 +268,7 @@ class App extends BaseConfig
      *
      * @deprecated use Config\Cookie::$path property instead.
      */
-    public $cookiePath = '/';
+    public string $cookiePath = '/';
 
     /**
      * --------------------------------------------------------------------------
@@ -294,11 +277,11 @@ class App extends BaseConfig
      *
      * Cookie will only be set if a secure HTTPS connection exists.
      *
-     * @var boolean
+     * @var bool
      *
      * @deprecated use Config\Cookie::$secure property instead.
      */
-    public $cookieSecure = false;
+    public bool $cookieSecure = false;
 
     /**
      * --------------------------------------------------------------------------
@@ -311,7 +294,7 @@ class App extends BaseConfig
      *
      * @deprecated use Config\Cookie::$httponly property instead.
      */
-    public $cookieHTTPOnly = true;
+    public bool $cookieHTTPOnly = true;
 
     /**
      * --------------------------------------------------------------------------
@@ -337,7 +320,7 @@ class App extends BaseConfig
      *
      * @deprecated use Config\Cookie::$samesite property instead.
      */
-    public $cookieSameSite = 'Lax';
+    public string $cookieSameSite = 'Lax';
 
     /**
      * --------------------------------------------------------------------------
@@ -357,7 +340,7 @@ class App extends BaseConfig
      *
      * @var string|string[]
      */
-    public $proxyIPs = '';
+    public string|array $proxyIPs = '';
 
     /**
      * --------------------------------------------------------------------------
@@ -367,10 +350,8 @@ class App extends BaseConfig
      * The token name.
      *
      * @deprecated Use `Config\Security` $tokenName property instead of using this property.
-     *
-     * @var string
      */
-    public $CSRFTokenName = 'csrf_test_name';
+    public string $CSRFTokenName = 'csrf_test_name';
 
     /**
      * --------------------------------------------------------------------------
@@ -380,10 +361,8 @@ class App extends BaseConfig
      * The header name.
      *
      * @deprecated Use `Config\Security` $headerName property instead of using this property.
-     *
-     * @var string
      */
-    public $CSRFHeaderName = 'X-CSRF-TOKEN';
+    public string $CSRFHeaderName = 'X-CSRF-TOKEN';
 
     /**
      * --------------------------------------------------------------------------
@@ -393,10 +372,8 @@ class App extends BaseConfig
      * The cookie name.
      *
      * @deprecated Use `Config\Security` $cookieName property instead of using this property.
-     *
-     * @var string
      */
-    public $CSRFCookieName = 'csrf_cookie_name';
+    public string $CSRFCookieName = 'csrf_cookie_name';
 
     /**
      * --------------------------------------------------------------------------
@@ -406,10 +383,8 @@ class App extends BaseConfig
      * The number in seconds the token should expire.
      *
      * @deprecated Use `Config\Security` $expire property instead of using this property.
-     *
-     * @var integer
      */
-    public $CSRFExpire = 7200;
+    public int $CSRFExpire = 7200;
 
     /**
      * --------------------------------------------------------------------------
@@ -419,10 +394,8 @@ class App extends BaseConfig
      * Regenerate token on every submission?
      *
      * @deprecated Use `Config\Security` $regenerate property instead of using this property.
-     *
-     * @var boolean
      */
-    public $CSRFRegenerate = true;
+    public bool $CSRFRegenerate = true;
 
     /**
      * --------------------------------------------------------------------------
@@ -432,10 +405,8 @@ class App extends BaseConfig
      * Redirect to previous page with error on failure?
      *
      * @deprecated Use `Config\Security` $redirect property instead of using this property.
-     *
-     * @var boolean
      */
-    public $CSRFRedirect = true;
+    public bool $CSRFRedirect = true;
 
     /**
      * --------------------------------------------------------------------------
@@ -453,10 +424,8 @@ class App extends BaseConfig
      * @see https://portswigger.net/web-security/csrf/samesite-cookies
      *
      * @deprecated Use `Config\Security` $samesite property instead of using this property.
-     *
-     * @var string
      */
-    public $CSRFSameSite = 'Lax';
+    public string $CSRFSameSite = 'Lax';
 
     /**
      * --------------------------------------------------------------------------
@@ -473,48 +442,38 @@ class App extends BaseConfig
      *
      * @see http://www.html5rocks.com/en/tutorials/security/content-security-policy/
      * @see http://www.w3.org/TR/CSP/
-     *
-     * @var boolean
      */
-    public $CSPEnabled = false;
+    public bool $CSPEnabled = false;
 
     /**
      * --------------------------------------------------------------------------
      * Media root folder
      * --------------------------------------------------------------------------
      * Defines the root folder for media files storage
-     *
-     * @var string
      */
-    public $mediaRoot = 'media';
+    public string $mediaRoot = 'media';
 
     /**
      * --------------------------------------------------------------------------
      * Admin gateway
      * --------------------------------------------------------------------------
      * Defines a base route for all admin pages
-     *
-     * @var string
      */
-    public $adminGateway = 'cp-admin';
+    public string $adminGateway = 'cp-admin';
 
     /**
      * --------------------------------------------------------------------------
      * Auth gateway
      * --------------------------------------------------------------------------
      * Defines a base route for all authentication related pages
-     *
-     * @var string
      */
-    public $authGateway = 'cp-auth';
+    public string $authGateway = 'cp-auth';
 
     /**
      * --------------------------------------------------------------------------
      * Install gateway
      * --------------------------------------------------------------------------
      * Defines a base route for instance installation
-     *
-     * @var string
      */
-    public $installGateway = 'cp-install';
+    public string $installGateway = 'cp-install';
 }
diff --git a/app/Config/Cache.php b/app/Config/Cache.php
index c26c1cc46043ed676958cc21b41a29159b764bda..a59e6d1751667af4a226f65e0d9ee4e9308bf566 100644
--- a/app/Config/Cache.php
+++ b/app/Config/Cache.php
@@ -20,9 +20,8 @@ class Cache extends BaseConfig
      * The name of the preferred handler that should be used. If for some reason
      * it is not available, the $backupHandler will be used in its place.
      *
-     * @var string
      */
-    public $handler = 'file';
+    public string $handler = 'file';
 
     /**
      * --------------------------------------------------------------------------
@@ -33,9 +32,8 @@ class Cache extends BaseConfig
      * unreachable. Often, 'file' is used here since the filesystem is
      * always available, though that's not always practical for the app.
      *
-     * @var string
      */
-    public $backupHandler = 'dummy';
+    public string $backupHandler = 'dummy';
 
     /**
      * --------------------------------------------------------------------------
@@ -45,11 +43,9 @@ class Cache extends BaseConfig
      * The path to where cache files should be stored, if using a file-based
      * system.
      *
-     * @var string
-     *
      * @deprecated Use the driver-specific variant under $file
      */
-    public $storePath = WRITEPATH . 'cache/';
+    public string $storePath = WRITEPATH . 'cache/';
 
     /**
      * --------------------------------------------------------------------------
@@ -68,7 +64,7 @@ class Cache extends BaseConfig
      *
      * @var boolean|string[]
      */
-    public $cacheQueryString = false;
+    public bool|array $cacheQueryString = false;
 
     /**
      * --------------------------------------------------------------------------
@@ -78,9 +74,8 @@ class Cache extends BaseConfig
      * This string is added to all cache item names to help avoid collisions
      * if you run multiple applications with the same cache engine.
      *
-     * @var string
      */
-    public $prefix = '';
+    public string $prefix = '';
 
     /**
      * --------------------------------------------------------------------------
@@ -91,7 +86,7 @@ class Cache extends BaseConfig
      *
      * @var array<string, string|int|null>
      */
-    public $file = [
+    public array $file = [
         'storePath' => WRITEPATH . 'cache/',
         'mode' => 0640,
     ];
@@ -107,7 +102,7 @@ class Cache extends BaseConfig
      *
      * @var array<string, string|int|boolean>
      */
-    public $memcached = [
+    public array $memcached = [
         'host' => '127.0.0.1',
         'port' => 11211,
         'weight' => 1,
@@ -123,7 +118,7 @@ class Cache extends BaseConfig
      *
      * @var array<string, string|int|null>
      */
-    public $redis = [
+    public array $redis = [
         'host' => '127.0.0.1',
         'password' => null,
         'port' => 6379,
@@ -141,7 +136,7 @@ class Cache extends BaseConfig
      *
      * @var array<string, string>
      */
-    public $validHandlers = [
+    public array $validHandlers = [
         'dummy' => DummyHandler::class,
         'file' => FileHandler::class,
         'memcached' => MemcachedHandler::class,
diff --git a/app/Config/ContentSecurityPolicy.php b/app/Config/ContentSecurityPolicy.php
index 05ffa5d7c7adee603e02e5945079b4c9ed3ffe30..29c3e2d20147442292bdc4950340571ad4f08e58 100644
--- a/app/Config/ContentSecurityPolicy.php
+++ b/app/Config/ContentSecurityPolicy.php
@@ -22,9 +22,8 @@ class ContentSecurityPolicy extends BaseConfig
     /**
      * Default CSP report context
      *
-     * @var boolean
      */
-    public $reportOnly = false;
+    public bool $reportOnly = false;
 
     /**
      * Specifies a URL where a browser will send reports
@@ -32,16 +31,15 @@ class ContentSecurityPolicy extends BaseConfig
      *
      * @var string|null
      */
-    public $reportURI;
+    public ?string $reportURI = null;
 
     /**
      * Instructs user agents to rewrite URL schemes, changing
      * HTTP to HTTPS. This directive is for websites with
      * large numbers of old URLs that need to be rewritten.
      *
-     * @var boolean
      */
-    public $upgradeInsecureRequests = false;
+    public bool $upgradeInsecureRequests = false;
 
     //-------------------------------------------------------------------------
     // Sources allowed
@@ -53,28 +51,28 @@ class ContentSecurityPolicy extends BaseConfig
      *
      * @var string|string[]|null
      */
-    public $defaultSrc;
+    public string|array|null $defaultSrc;
 
     /**
      * Lists allowed scripts' URLs.
      *
      * @var string|string[]
      */
-    public $scriptSrc = 'self';
+    public string|array $scriptSrc = 'self';
 
     /**
      * Lists allowed stylesheets' URLs.
      *
      * @var string|string[]
      */
-    public $styleSrc = 'self';
+    public string|array $styleSrc = 'self';
 
     /**
      * Defines the origins from which images can be loaded.
      *
      * @var string|string[]
      */
-    public $imageSrc = 'self';
+    public string|array $imageSrc = 'self';
 
     /**
      * Restricts the URLs that can appear in a page's `<base>` element.
@@ -83,14 +81,14 @@ class ContentSecurityPolicy extends BaseConfig
      *
      * @var string|string[]|null
      */
-    public $baseURI;
+    public string|array|null $baseURI;
 
     /**
      * Lists the URLs for workers and embedded frame contents
      *
      * @var string|string[]
      */
-    public $childSrc = 'self';
+    public string|array $childSrc = 'self';
 
     /**
      * Limits the origins that you can connect to (via XHR,
@@ -98,21 +96,21 @@ class ContentSecurityPolicy extends BaseConfig
      *
      * @var string|string[]
      */
-    public $connectSrc = 'self';
+    public string|array $connectSrc = 'self';
 
     /**
      * Specifies the origins that can serve web fonts.
      *
      * @var string|string[]
      */
-    public $fontSrc;
+    public string|array $fontSrc;
 
     /**
      * Lists valid endpoints for submission from `<form>` tags.
      *
      * @var string|string[]
      */
-    public $formAction = 'self';
+    public string|array $formAction = 'self';
 
     /**
      * Specifies the sources that can embed the current page.
@@ -122,38 +120,38 @@ class ContentSecurityPolicy extends BaseConfig
      *
      * @var string|string[]|null
      */
-    public $frameAncestors;
+    public string|array|null $frameAncestors;
 
     /**
      * Restricts the origins allowed to deliver video and audio.
      *
      * @var string|string[]|null
      */
-    public $mediaSrc;
+    public string|array|null $mediaSrc;
 
     /**
      * Allows control over Flash and other plugins.
      *
      * @var string|string[]
      */
-    public $objectSrc = 'self';
+    public string|array $objectSrc = 'self';
 
     /**
      * @var string|string[]|null
      */
-    public $manifestSrc;
+    public string|array|null $manifestSrc;
 
     /**
      * Limits the kinds of plugins a page may invoke.
      *
      * @var string|string[]|null
      */
-    public $pluginTypes;
+    public string|array|null $pluginTypes;
 
     /**
      * List of actions allowed.
      *
      * @var string|string[]|null
      */
-    public $sandbox;
+    public string|array|null $sandbox;
 }
diff --git a/app/Config/Cookie.php b/app/Config/Cookie.php
index 68c403e5d4a3f13d60285e4582b7d4e06e7c38f3..dcd371ab65722b3a875c5c452632d79191bf5fbd 100644
--- a/app/Config/Cookie.php
+++ b/app/Config/Cookie.php
@@ -14,9 +14,8 @@ class Cookie extends BaseConfig
      *
      * Set a cookie name prefix if you need to avoid collisions.
      *
-     * @var string
      */
-    public $prefix = '';
+    public string $prefix = '';
 
     /**
      * --------------------------------------------------------------------------
@@ -27,9 +26,8 @@ class Cookie extends BaseConfig
      * cookie will not have the `Expires` attribute and will behave as a session
      * cookie.
      *
-     * @var DateTimeInterface|integer|string
      */
-    public $expires = 0;
+    public DateTimeInterface|int|string $expires = 0;
 
     /**
      * --------------------------------------------------------------------------
@@ -38,9 +36,8 @@ class Cookie extends BaseConfig
      *
      * Typically will be a forward slash.
      *
-     * @var string
      */
-    public $path = '/';
+    public string $path = '/';
 
     /**
      * --------------------------------------------------------------------------
@@ -49,9 +46,8 @@ class Cookie extends BaseConfig
      *
      * Set to `.your-domain.com` for site-wide cookies.
      *
-     * @var string
      */
-    public $domain = '';
+    public string $domain = '';
 
     /**
      * --------------------------------------------------------------------------
@@ -60,9 +56,8 @@ class Cookie extends BaseConfig
      *
      * Cookie will only be set if a secure HTTPS connection exists.
      *
-     * @var boolean
      */
-    public $secure = false;
+    public bool $secure = false;
 
     /**
      * --------------------------------------------------------------------------
@@ -71,9 +66,8 @@ class Cookie extends BaseConfig
      *
      * Cookie will only be accessible via HTTP(S) (no JavaScript).
      *
-     * @var boolean
      */
-    public $httponly = true;
+    public bool $httponly = true;
 
     /**
      * --------------------------------------------------------------------------
@@ -95,9 +89,8 @@ class Cookie extends BaseConfig
      * (empty string) means default SameSite attribute set by browsers (`Lax`)
      * will be set on cookies. If set to `None`, `$secure` must also be set.
      *
-     * @var string
      */
-    public $samesite = 'Lax';
+    public string $samesite = 'Lax';
 
     /**
      * --------------------------------------------------------------------------
@@ -110,10 +103,8 @@ class Cookie extends BaseConfig
      * If this is set to `true`, cookie names should be compliant of RFC 2616's
      * list of allowed characters.
      *
-     * @var boolean
-     *
      * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes
      * @see https://tools.ietf.org/html/rfc2616#section-2.2
      */
-    public $raw = false;
+    public bool $raw = false;
 }
diff --git a/app/Config/Database.php b/app/Config/Database.php
index a854688a5abb0912c02aef01bc1ff70d223a302e..b856344abfce41ceb0d91d7d92ca818d097784fa 100644
--- a/app/Config/Database.php
+++ b/app/Config/Database.php
@@ -50,6 +50,8 @@ class Database extends Config
      * This database connection is used when
      * running PHPUnit database tests.
      *
+     * @noRector StringClassNameToClassConstantRector
+     *
      * @var array<string, string|bool|int|array>
      */
     public array $tests = [
@@ -58,7 +60,6 @@ class Database extends Config
         'username' => '',
         'password' => '',
         'database' => ':memory:',
-        /** @noRector StringClassNameToClassConstantRector */
         'DBDriver' => 'SQLite3',
         'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS
         'pConnect' => false,
diff --git a/app/Config/DocTypes.php b/app/Config/DocTypes.php
index d29036f089bbd6fee20b0fd142cd835f8b3ca54f..81bdfb2607f29e0fad5c93f89954b0de44623e05 100644
--- a/app/Config/DocTypes.php
+++ b/app/Config/DocTypes.php
@@ -9,7 +9,7 @@ class DocTypes
      *
      * @var array<string, string>
      */
-    public $list = [
+    public array $list = [
         'xhtml11' =>
             '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
         'xhtml1-strict' =>
diff --git a/app/Config/Email.php b/app/Config/Email.php
index 61f9f140666af4e293b51f9dd704ec571b089a2b..f5f3b2d25d4fc12fdf6f2b3eeec87e17243aadef 100644
--- a/app/Config/Email.php
+++ b/app/Config/Email.php
@@ -6,165 +6,135 @@ use CodeIgniter\Config\BaseConfig;
 
 class Email extends BaseConfig
 {
-    /**
-     * @var string
-     */
-    public $fromEmail;
+    public string $fromEmail;
 
-    /**
-     * @var string
-     */
-    public $fromName;
+    public string $fromName;
 
-    /**
-     * @var string
-     */
-    public $recipients;
+    public string $recipients;
 
     /**
      * The "user agent"
      *
-     * @var string
      */
-    public $userAgent = 'CodeIgniter';
+    public string $userAgent = 'CodeIgniter';
 
     /**
      * The mail sending protocol: mail, sendmail, smtp
      *
-     * @var string
      */
-    public $protocol = 'mail';
+    public string $protocol = 'mail';
 
     /**
      * The server path to Sendmail.
      *
-     * @var string
      */
-    public $mailPath = '/usr/sbin/sendmail';
+    public string $mailPath = '/usr/sbin/sendmail';
 
     /**
      * SMTP Server Address
      *
-     * @var string
      */
-    public $SMTPHost;
+    public string $SMTPHost;
 
     /**
      * SMTP Username
      *
-     * @var string
      */
-    public $SMTPUser;
+    public string $SMTPUser;
 
     /**
      * SMTP Password
      *
-     * @var string
      */
-    public $SMTPPass;
+    public string $SMTPPass;
 
     /**
      * SMTP Port
      *
-     * @var integer
      */
-    public $SMTPPort = 25;
+    public int $SMTPPort = 25;
 
     /**
      * SMTP Timeout (in seconds)
      *
-     * @var integer
      */
-    public $SMTPTimeout = 5;
+    public int $SMTPTimeout = 5;
 
     /**
      * Enable persistent SMTP connections
      *
-     * @var boolean
      */
-    public $SMTPKeepAlive = false;
+    public bool $SMTPKeepAlive = false;
 
     /**
      * SMTP Encryption. Either tls or ssl
      *
-     * @var string
      */
-    public $SMTPCrypto = 'tls';
+    public string $SMTPCrypto = 'tls';
 
     /**
      * Enable word-wrap
      *
-     * @var boolean
      */
-    public $wordWrap = true;
+    public bool $wordWrap = true;
 
     /**
      * Character count to wrap at
      *
-     * @var integer
      */
-    public $wrapChars = 76;
+    public int $wrapChars = 76;
 
     /**
      * Type of mail, either 'text' or 'html'
      *
-     * @var string
      */
-    public $mailType = 'text';
+    public string $mailType = 'text';
 
     /**
      * Character set (utf-8, iso-8859-1, etc.)
      *
-     * @var string
      */
-    public $charset = 'UTF-8';
+    public string $charset = 'UTF-8';
 
     /**
      * Whether to validate the email address
      *
-     * @var boolean
      */
-    public $validate = false;
+    public bool $validate = false;
 
     /**
      * Email Priority. 1 = highest. 5 = lowest. 3 = normal
      *
-     * @var integer
      */
-    public $priority = 3;
+    public int $priority = 3;
 
     /**
      * Newline character. (Use “\r\n” to comply with RFC 822)
      *
-     * @var string
      */
-    public $CRLF = "\r\n";
+    public string $CRLF = "\r\n";
 
     /**
      * Newline character. (Use “\r\n” to comply with RFC 822)
      *
-     * @var string
      */
-    public $newline = "\r\n";
+    public string $newline = "\r\n";
 
     /**
      * Enable BCC Batch Mode.
      *
-     * @var boolean
      */
-    public $BCCBatchMode = false;
+    public bool $BCCBatchMode = false;
 
     /**
      * Number of emails in each BCC batch
      *
-     * @var integer
      */
-    public $BCCBatchSize = 200;
+    public int $BCCBatchSize = 200;
 
     /**
      * Enable notify message from server
      *
-     * @var boolean
      */
-    public $DSN = false;
+    public bool $DSN = false;
 }
diff --git a/app/Config/Encryption.php b/app/Config/Encryption.php
index 51f8d01a593f92393fad6d86d3777be2c40f2d35..5e806ff18aa6b36637bfb8f799a198405d56c1b2 100644
--- a/app/Config/Encryption.php
+++ b/app/Config/Encryption.php
@@ -21,9 +21,8 @@ class Encryption extends BaseConfig
      * You need to ensure it is long enough for the cipher and mode you plan to use.
      * See the user guide for more info.
      *
-     * @var string
      */
-    public $key = '';
+    public string $key = '';
 
     /**
      * --------------------------------------------------------------------------
@@ -36,9 +35,8 @@ class Encryption extends BaseConfig
      * - OpenSSL
      * - Sodium
      *
-     * @var string
      */
-    public $driver = 'OpenSSL';
+    public string $driver = 'OpenSSL';
 
     /**
      * --------------------------------------------------------------------------
@@ -50,9 +48,8 @@ class Encryption extends BaseConfig
      *
      * See the user guide for more information on padding.
      *
-     * @var integer
      */
-    public $blockSize = 16;
+    public int $blockSize = 16;
 
     /**
      * --------------------------------------------------------------------------
@@ -61,7 +58,6 @@ class Encryption extends BaseConfig
      *
      * HMAC digest to use, e.g. 'SHA512' or 'SHA256'. Default value is 'SHA512'.
      *
-     * @var string
      */
-    public $digest = 'SHA512';
+    public string $digest = 'SHA512';
 }
diff --git a/app/Config/Exceptions.php b/app/Config/Exceptions.php
index 47b85757628437c64c8628389575d1bb9e9caaee..5461e0cb32a717d14b200202dc2a88ca9bfb73e3 100644
--- a/app/Config/Exceptions.php
+++ b/app/Config/Exceptions.php
@@ -18,9 +18,8 @@ class Exceptions extends BaseConfig
      *
      * Default: true
      *
-     * @var boolean
      */
-    public $log = true;
+    public bool $log = true;
 
     /**
      * --------------------------------------------------------------------------
@@ -31,7 +30,7 @@ class Exceptions extends BaseConfig
      *
      * @var int[]
      */
-    public $ignoreCodes = [404];
+    public array $ignoreCodes = [404];
 
     /**
      * --------------------------------------------------------------------------
@@ -42,7 +41,6 @@ class Exceptions extends BaseConfig
      *
      * Default: APPPATH.'Views/errors'
      *
-     * @var string
      */
-    public $errorViewPath = APPPATH . 'Views/errors';
+    public string $errorViewPath = APPPATH . 'Views/errors';
 }
diff --git a/app/Config/Filters.php b/app/Config/Filters.php
index 573fc1ee23a805fdd5c478c195ecbf136e15235c..6a9ee2ddc1fd9d578884c2b30d09e73a27416ab3 100644
--- a/app/Config/Filters.php
+++ b/app/Config/Filters.php
@@ -19,7 +19,7 @@ class Filters extends BaseConfig
      *
      * @var array<string, string>
      */
-    public $aliases = [
+    public array $aliases = [
         'csrf' => CSRF::class,
         'toolbar' => DebugToolbar::class,
         'honeypot' => Honeypot::class,
@@ -35,7 +35,7 @@ class Filters extends BaseConfig
      *
      * @var array<string, string[]>
      */
-    public $globals = [
+    public array $globals = [
         'before' => [
             // 'honeypot',
             // 'csrf',
@@ -55,7 +55,7 @@ class Filters extends BaseConfig
      *
      * @var array<string, string[]>
      */
-    public $methods = [];
+    public array $methods = [];
 
     /**
      * List of filter aliases that should run on any
@@ -66,7 +66,7 @@ class Filters extends BaseConfig
      *
      * @var array<string, array<string, string[]>>
      */
-    public $filters = [];
+    public array $filters = [];
 
     public function __construct()
     {
diff --git a/app/Config/Format.php b/app/Config/Format.php
index b3ba469041166e857163d3c32a65009cba1c7d40..94d6d94802171614ac76507c4d57de25f92209f3 100644
--- a/app/Config/Format.php
+++ b/app/Config/Format.php
@@ -24,7 +24,7 @@ class Format extends BaseConfig
      *
      * @var string[]
      */
-    public $supportedResponseFormats = [
+    public array $supportedResponseFormats = [
         'application/json',
         'application/xml', // machine-readable XML
         'text/xml', // human-readable XML
@@ -41,7 +41,7 @@ class Format extends BaseConfig
      *
      * @var array<string, string>
      */
-    public $formatters = [
+    public array $formatters = [
         'application/json' => JSONFormatter::class,
         'application/xml' => XMLFormatter::class,
         'text/xml' => XMLFormatter::class,
@@ -57,7 +57,7 @@ class Format extends BaseConfig
      *
      * @var array<string, int>
      */
-    public $formatterOptions = [
+    public array $formatterOptions = [
         'application/json' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
         'application/xml' => 0,
         'text/xml' => 0,
diff --git a/app/Config/Generators.php b/app/Config/Generators.php
index 1f32e4bbb2d131048bea82eccd05688fc0518dd5..922a02ff6063dcbde900223cc34b3a7cdd4706cc 100644
--- a/app/Config/Generators.php
+++ b/app/Config/Generators.php
@@ -25,7 +25,7 @@ class Generators extends BaseConfig
      *
      * @var array<string, string>
      */
-    public $views = [
+    public array $views = [
         'make:command' =>
             'CodeIgniter\Commands\Generators\Views\command.tpl.php',
         'make:controller' =>
diff --git a/app/Config/Honeypot.php b/app/Config/Honeypot.php
index 84f2a8540053cfe4efe039e2d57c5d83d744d8a2..3e18afb5c0f14a42a76c7206ae81f25bc31156c6 100644
--- a/app/Config/Honeypot.php
+++ b/app/Config/Honeypot.php
@@ -9,35 +9,30 @@ class Honeypot extends BaseConfig
     /**
      * Makes Honeypot visible or not to human
      *
-     * @var boolean
      */
-    public $hidden = true;
+    public bool $hidden = true;
 
     /**
      * Honeypot Label Content
      *
-     * @var string
      */
-    public $label = 'Fill This Field';
+    public string $label = 'Fill This Field';
 
     /**
      * Honeypot Field Name
      *
-     * @var string
      */
-    public $name = 'honeypot';
+    public string $name = 'honeypot';
 
     /**
      * Honeypot HTML Template
      *
-     * @var string
      */
-    public $template = '<label>{label}</label><input type="text" name="{name}" value=""/>';
+    public string $template = '<label>{label}</label><input type="text" name="{name}" value=""/>';
 
     /**
      * Honeypot container
      *
-     * @var string
      */
-    public $container = '<div style="display:none">{template}</div>';
+    public string $container = '<div style="display:none">{template}</div>';
 }
diff --git a/app/Config/Images.php b/app/Config/Images.php
index e1067cb66da0013595f7381392e68a96af4aed43..dfe156941dfbbd7fa88e0aaec74297fbf2664169 100644
--- a/app/Config/Images.php
+++ b/app/Config/Images.php
@@ -11,24 +11,22 @@ class Images extends BaseConfig
     /**
      * Default handler used if no other handler is specified.
      *
-     * @var string
      */
-    public $defaultHandler = 'gd';
+    public string $defaultHandler = 'gd';
 
     /**
      * The path to the image library.
      * Required for ImageMagick, GraphicsMagick, or NetPBM.
      *
-     * @var string
      */
-    public $libraryPath = '/usr/local/bin/convert';
+    public string $libraryPath = '/usr/local/bin/convert';
 
     /**
      * The available handler classes.
      *
      * @var array<string, string>
      */
-    public $handlers = [
+    public array $handlers = [
         'gd' => GDHandler::class,
         'imagick' => ImageMagickHandler::class,
     ];
@@ -41,34 +39,19 @@ class Images extends BaseConfig
     | All uploaded images are of 1:1 ratio (width and height are the same).
 	*/
 
-    /**
-     * @var integer
-     */
-    public $thumbnailSize = 150;
-
-    /**
-     * @var integer
-     */
-    public $mediumSize = 320;
-
-    /**
-     * @var integer
-     */
-    public $largeSize = 1024;
+    public int $thumbnailSize = 150;
+    public int $mediumSize = 320;
+    public int $largeSize = 1024;
 
     /**
      * Size of images linked in the rss feed (should be between 1400 and 3000)
-     *
-     * @var integer
      */
-    public $feedSize = 1400;
+    public int $feedSize = 1400;
 
     /**
      * Size for ID3 tag cover art (should be between 300 and 800)
-     *
-     * @var integer
      */
-    public $id3Size = 500;
+    public int $id3Size = 500;
 
     /*
 	|--------------------------------------------------------------------------
@@ -77,28 +60,13 @@ class Images extends BaseConfig
     | The properties listed below set the name extensions for the resized images
 	*/
 
-    /**
-     * @var string
-     */
-    public $thumbnailSuffix = '_thumbnail';
+    public string $thumbnailSuffix = '_thumbnail';
 
-    /**
-     * @var string
-     */
-    public $mediumSuffix = '_medium';
+    public string $mediumSuffix = '_medium';
 
-    /**
-     * @var string
-     */
-    public $largeSuffix = '_large';
+    public string $largeSuffix = '_large';
 
-    /**
-     * @var string
-     */
-    public $feedSuffix = '_feed';
+    public string $feedSuffix = '_feed';
 
-    /**
-     * @var string
-     */
-    public $id3Suffix = '_id3';
+    public string $id3Suffix = '_id3';
 }
diff --git a/app/Config/Kint.php b/app/Config/Kint.php
index ce2ff28a8fcfcd0268514b5a90928d726af24fac..26a74ac5dd9b957d736697f50847f8d3ee1c7fbb 100644
--- a/app/Config/Kint.php
+++ b/app/Config/Kint.php
@@ -26,52 +26,35 @@ class Kint extends BaseConfig
     /**
      * @var string[]
      */
-    public $plugins = [];
+    public array $plugins = [];
 
-    /**
-     * @var int
-     */
-    public $maxDepth = 6;
+    public int $maxDepth = 6;
 
-    /**
-     * @var bool
-     */
-    public $displayCalledFrom = true;
+    public bool $displayCalledFrom = true;
 
-    /**
-     * @var bool
-     */
-    public $expanded = false;
+    public bool $expanded = false;
 
     /*
     |--------------------------------------------------------------------------
     | RichRenderer Settings
     |--------------------------------------------------------------------------
     */
-    /**
-     * @var string
-     */
-    public $richTheme = 'aante-light.css';
 
-    /**
-     * @var bool
-     */
-    public $richFolder = false;
+    public string $richTheme = 'aante-light.css';
 
-    /**
-     * @var int
-     */
-    public $richSort = Renderer::SORT_FULL;
+    public bool $richFolder = false;
+
+    public int $richSort = Renderer::SORT_FULL;
 
     /**
      * @var string[]
      */
-    public $richObjectPlugins = [];
+    public array $richObjectPlugins = [];
 
     /**
      * @var string[]
      */
-    public $richTabPlugins = [];
+    public array $richTabPlugins = [];
 
     /*
     |--------------------------------------------------------------------------
@@ -79,23 +62,11 @@ class Kint extends BaseConfig
     |--------------------------------------------------------------------------
     */
 
-    /**
-     * @var bool
-     */
-    public $cliColors = true;
+    public bool $cliColors = true;
 
-    /**
-     * @var bool
-     */
-    public $cliForceUTF8 = false;
+    public bool $cliForceUTF8 = false;
 
-    /**
-     * @var bool
-     */
-    public $cliDetectWidth = true;
+    public bool $cliDetectWidth = true;
 
-    /**
-     * @var int
-     */
-    public $cliMinWidth = 40;
+    public int $cliMinWidth = 40;
 }
diff --git a/app/Config/Logger.php b/app/Config/Logger.php
index cfee2757212248369e4b504ec3da2a9a13d54dc1..b0ae3c7d28df7bdbd83479ebbed133239f334cbe 100644
--- a/app/Config/Logger.php
+++ b/app/Config/Logger.php
@@ -36,7 +36,7 @@ class Logger extends BaseConfig
      * For a live site you'll usually enable Critical or higher (3) to be logged otherwise
      * your log files will fill up very fast.
      *
-     * @var integer|int[]
+     * @var int|int[]
      */
     public int|array $threshold = 4;
 
@@ -75,7 +75,7 @@ class Logger extends BaseConfig
      * Handlers are executed in the order defined in this array, starting with
      * the handler on top and continuing down.
      *
-     * @var array<string, string|int|array<string, string>>
+     * @var array<string, mixed>
      */
     public array $handlers = [
         /*
@@ -123,17 +123,5 @@ class Logger extends BaseConfig
              */
             'path' => '',
         ],
-
-        /**
-     * The ChromeLoggerHandler requires the use of the Chrome web browser
-     * and the ChromeLogger extension. Uncomment this block to use it.
-     */
-        //      'CodeIgniter\Log\Handlers\ChromeLoggerHandler' => [
-        //          /*
-        //           * The log levels that this handler will handle.
-        //           */
-        //          'handles' => ['critical', 'alert', 'emergency', 'debug',
-        //                        'error', 'info', 'notice', 'warning'],
-        //      ]
     ];
 }
diff --git a/app/Config/Migrations.php b/app/Config/Migrations.php
index 2913c4ca8560b1aa4c4deb1afbbc3ab8bc5cc49c..e62dabc519c96ea3614f211bcb2e6309b5841088 100644
--- a/app/Config/Migrations.php
+++ b/app/Config/Migrations.php
@@ -16,9 +16,8 @@ class Migrations extends BaseConfig
      * You should enable migrations whenever you intend to do a schema migration
      * and disable it back when you're done.
      *
-     * @var boolean
      */
-    public $enabled = true;
+    public bool $enabled = true;
 
     /**
      * --------------------------------------------------------------------------
@@ -31,9 +30,8 @@ class Migrations extends BaseConfig
      * table to the $config['migration_version'] if they are not the same it
      * will migrate up. This must be set.
      *
-     * @var string
      */
-    public $table = 'migrations';
+    public string $table = 'migrations';
 
     /**
      * --------------------------------------------------------------------------
@@ -49,7 +47,6 @@ class Migrations extends BaseConfig
      * - Y-m-d-His_
      * - Y_m_d_His_
      *
-     * @var string
      */
-    public $timestampFormat = 'Y-m-d-His_';
+    public string $timestampFormat = 'Y-m-d-His_';
 }
diff --git a/app/Config/Pager.php b/app/Config/Pager.php
index 8f38d983d371657a3c967bd0c15908cc18f0eccc..0f725d2108ecd2df99006474fc07a7d79d8f194e 100644
--- a/app/Config/Pager.php
+++ b/app/Config/Pager.php
@@ -20,7 +20,7 @@ class Pager extends BaseConfig
      *
      * @var array<string, string>
      */
-    public $templates = [
+    public array $templates = [
         'default_full' => 'App\Views\pager\default_full',
         'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
         'default_head' => 'CodeIgniter\Pager\Views\default_head',
@@ -33,7 +33,6 @@ class Pager extends BaseConfig
      *
      * The default number of results shown in a single page.
      *
-     * @var integer
      */
-    public $perPage = 20;
+    public int $perPage = 20;
 }
diff --git a/app/Config/Paths.php b/app/Config/Paths.php
index 38eb3057f819d602a608bdda2cfaf5d28bee79ed..7b8b85914fe1086aa373ccfd5ee9a91ee477c260 100644
--- a/app/Config/Paths.php
+++ b/app/Config/Paths.php
@@ -24,9 +24,8 @@ class Paths
      * This must contain the name of your "system" folder. Include
      * the path if the folder is not in the same directory as this file.
      *
-     * @var string
      */
-    public $systemDirectory =
+    public string $systemDirectory =
         __DIR__ . '/../../vendor/codeigniter4/codeigniter4/system';
     /**
      * ---------------------------------------------------------------
@@ -40,9 +39,8 @@ class Paths
      *
      * @see http://codeigniter.com/user_guide/general/managing_apps.html
      *
-     * @var string
      */
-    public $appDirectory = __DIR__ . '/..';
+    public string $appDirectory = __DIR__ . '/..';
 
     /**
      * ---------------------------------------------------------------
@@ -55,9 +53,8 @@ class Paths
      * for maximum security, keeping it out of the app and/or
      * system directories.
      *
-     * @var string
      */
-    public $writableDirectory = __DIR__ . '/../../writable';
+    public string $writableDirectory = __DIR__ . '/../../writable';
 
     /**
      * ---------------------------------------------------------------
@@ -66,9 +63,8 @@ class Paths
      *
      * This variable must contain the name of your "tests" directory.
      *
-     * @var string
      */
-    public $testsDirectory = __DIR__ . '/../../tests';
+    public string $testsDirectory = __DIR__ . '/../../tests';
 
     /**
      * ---------------------------------------------------------------
@@ -80,7 +76,6 @@ class Paths
      * default this is in `app/Views`. This value
      * is used when no value is provided to `Services::renderer()`.
      *
-     * @var string
      */
-    public $viewDirectory = __DIR__ . '/../Views';
+    public string $viewDirectory = __DIR__ . '/../Views';
 }
diff --git a/app/Config/Security.php b/app/Config/Security.php
index ba00bd08689f91f7532b525d705733019c137507..872fcf15389e93426d79c922c534538055460ed2 100644
--- a/app/Config/Security.php
+++ b/app/Config/Security.php
@@ -13,9 +13,8 @@ class Security extends BaseConfig
      *
      * Token name for Cross Site Request Forgery protection cookie.
      *
-     * @var string
      */
-    public $tokenName = 'csrf_test_name';
+    public string $tokenName = 'csrf_test_name';
 
     /**
      * --------------------------------------------------------------------------
@@ -24,9 +23,8 @@ class Security extends BaseConfig
      *
      * Token name for Cross Site Request Forgery protection cookie.
      *
-     * @var string
      */
-    public $headerName = 'X-CSRF-TOKEN';
+    public string $headerName = 'X-CSRF-TOKEN';
 
     /**
      * --------------------------------------------------------------------------
@@ -35,9 +33,8 @@ class Security extends BaseConfig
      *
      * Cookie name for Cross Site Request Forgery protection cookie.
      *
-     * @var string
      */
-    public $cookieName = 'csrf_cookie_name';
+    public string $cookieName = 'csrf_cookie_name';
 
     /**
      * --------------------------------------------------------------------------
@@ -48,9 +45,8 @@ class Security extends BaseConfig
      *
      * Defaults to two hours (in seconds).
      *
-     * @var integer
      */
-    public $expires = 7200;
+    public int $expires = 7200;
 
     /**
      * --------------------------------------------------------------------------
@@ -59,9 +55,8 @@ class Security extends BaseConfig
      *
      * Regenerate CSRF Token on every request.
      *
-     * @var boolean
      */
-    public $regenerate = true;
+    public bool $regenerate = true;
 
     /**
      * --------------------------------------------------------------------------
@@ -70,9 +65,8 @@ class Security extends BaseConfig
      *
      * Redirect to previous page with error on failure.
      *
-     * @var boolean
      */
-    public $redirect = true;
+    public bool $redirect = true;
 
     /**
      * --------------------------------------------------------------------------
@@ -88,5 +82,5 @@ class Security extends BaseConfig
      *
      * @var string 'Lax'|'None'|'Strict'
      */
-    public $samesite = 'Lax';
+    public string $samesite = 'Lax';
 }
diff --git a/app/Config/Toolbar.php b/app/Config/Toolbar.php
index 5d7596d92f367876d474c833986d388989d4f617..5be34fca2e9c5ea021da727edca7c8d6171181fe 100644
--- a/app/Config/Toolbar.php
+++ b/app/Config/Toolbar.php
@@ -33,7 +33,7 @@ class Toolbar extends BaseConfig
      *
      * @var string[]
      */
-    public $collectors = [
+    public array $collectors = [
         Timers::class,
         Database::class,
         Logs::class,
@@ -53,9 +53,8 @@ class Toolbar extends BaseConfig
      * helping to conserve file space used to store them. You can set it to
      * 0 (zero) to not have any history stored, or -1 for unlimited history.
      *
-     * @var integer
      */
-    public $maxHistory = 20;
+    public int $maxHistory = 20;
 
     /**
      * --------------------------------------------------------------------------
@@ -65,9 +64,8 @@ class Toolbar extends BaseConfig
      * The full path to the the views that are used by the toolbar.
      * This MUST have a trailing slash.
      *
-     * @var string
      */
-    public $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/';
+    public string $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/';
 
     /**
      * --------------------------------------------------------------------------
@@ -81,7 +79,6 @@ class Toolbar extends BaseConfig
      *
      * `$maxQueries` defines the maximum amount of queries that will be stored.
      *
-     * @var integer
      */
-    public $maxQueries = 100;
+    public int $maxQueries = 100;
 }
diff --git a/app/Config/UserAgents.php b/app/Config/UserAgents.php
index 18ad6c41faab091d642c71691cf72c3b6692653b..ef474693760ba88974f1929183e99780f3ca9819 100644
--- a/app/Config/UserAgents.php
+++ b/app/Config/UserAgents.php
@@ -22,7 +22,7 @@ class UserAgents extends BaseConfig
      *
      * @var array<string, string>
      */
-    public $platforms = [
+    public array $platforms = [
         'windows nt 10.0' => 'Windows 10',
         'windows nt 6.3' => 'Windows 8.1',
         'windows nt 6.2' => 'Windows 8',
@@ -77,7 +77,7 @@ class UserAgents extends BaseConfig
      *
      * @var array<string, string>
      */
-    public $browsers = [
+    public array $browsers = [
         'OPR' => 'Opera',
         'Flock' => 'Flock',
         'Edge' => 'Spartan',
@@ -118,7 +118,7 @@ class UserAgents extends BaseConfig
      *
      * @var array<string, string>
      */
-    public $mobiles = [
+    public array $mobiles = [
         // legacy array, old values commented out
         'mobileexplorer' => 'Mobile Explorer',
         // 'openwave'             => 'Open Wave',
@@ -227,7 +227,7 @@ class UserAgents extends BaseConfig
      *
      * @var array<string, string>
      */
-    public $robots = [
+    public array $robots = [
         'googlebot' => 'Googlebot',
         'msnbot' => 'MSNBot',
         'baiduspider' => 'Baiduspider',
diff --git a/app/Config/Validation.php b/app/Config/Validation.php
index 0db23ed2395c51ca704e24bddfc05a07b5467a6b..cd201f9783e729392016a99571316a4762087158 100644
--- a/app/Config/Validation.php
+++ b/app/Config/Validation.php
@@ -22,7 +22,7 @@ class Validation
      *
      * @var string[]
      */
-    public $ruleSets = [
+    public array $ruleSets = [
         Rules::class,
         FormatRules::class,
         FileRules::class,
@@ -38,7 +38,7 @@ class Validation
      *
      * @var array<string, string>
      */
-    public $templates = [
+    public array $templates = [
         'list' => 'CodeIgniter\Validation\Views\list',
         'single' => 'CodeIgniter\Validation\Views\single',
     ];
diff --git a/app/Controllers/Admin/ContributorController.php b/app/Controllers/Admin/ContributorController.php
index bcdc22145e401743756e8f666734fd09909002df..e1aabd783babcc774fa2e66229c0fa54b0853d91 100644
--- a/app/Controllers/Admin/ContributorController.php
+++ b/app/Controllers/Admin/ContributorController.php
@@ -19,15 +19,8 @@ use CodeIgniter\HTTP\RedirectResponse;
 
 class ContributorController extends BaseController
 {
-    /**
-     * @var Podcast
-     */
-    protected $podcast;
-
-    /**
-     * @var User|null
-     */
-    protected $user;
+    protected Podcast $podcast;
+    protected ?User $user;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Controllers/Admin/EpisodeController.php b/app/Controllers/Admin/EpisodeController.php
index 4eb61cf2ac00697a308c33861cc1c25ccabd7103..94d6d97df915be6df5837d64e046c56b101fe690 100644
--- a/app/Controllers/Admin/EpisodeController.php
+++ b/app/Controllers/Admin/EpisodeController.php
@@ -23,15 +23,8 @@ use CodeIgniter\I18n\Time;
 
 class EpisodeController extends BaseController
 {
-    /**
-     * @var Podcast
-     */
-    protected $podcast;
-
-    /**
-     * @var Episode|null
-     */
-    protected $episode;
+    protected Podcast $podcast;
+    protected ?Episode $episode;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Controllers/Admin/PageController.php b/app/Controllers/Admin/PageController.php
index 2308f3db8cce3cb723130ffa0b2839b56c35f927..e5364734960c25f318295f418c79239ce9c326a3 100644
--- a/app/Controllers/Admin/PageController.php
+++ b/app/Controllers/Admin/PageController.php
@@ -15,10 +15,7 @@ use App\Models\PageModel;
 
 class PageController extends BaseController
 {
-    /**
-     * @var Page|null
-     */
-    protected $page;
+    protected ?Page $page;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Controllers/Admin/PersonController.php b/app/Controllers/Admin/PersonController.php
index 6e07467def2a897445ea3de53946bb8b644acc49..7cbb03739a48d226029e74405474a92684080e00 100644
--- a/app/Controllers/Admin/PersonController.php
+++ b/app/Controllers/Admin/PersonController.php
@@ -16,10 +16,7 @@ use App\Models\PersonModel;
 
 class PersonController extends BaseController
 {
-    /**
-     * @var Person|null
-     */
-    protected $person;
+    protected ?Person $person;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Controllers/Admin/PodcastController.php b/app/Controllers/Admin/PodcastController.php
index cbeb6022d130cdbe41b91c4a5fb4aad7425cbe4d..c5d03fbd15b67c957e55f987f1999476d9202a24 100644
--- a/app/Controllers/Admin/PodcastController.php
+++ b/app/Controllers/Admin/PodcastController.php
@@ -25,7 +25,7 @@ class PodcastController extends BaseController
     /**
      * @var Podcast
      */
-    protected $podcast;
+    protected Podcast $podcast;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Controllers/Admin/PodcastImportController.php b/app/Controllers/Admin/PodcastImportController.php
index f94997b25a7ac1ee9092bb82871bf0db59ffa964..57380f3ef755040fb15d8c2c770455285a6977f0 100644
--- a/app/Controllers/Admin/PodcastImportController.php
+++ b/app/Controllers/Admin/PodcastImportController.php
@@ -32,7 +32,7 @@ class PodcastImportController extends BaseController
     /**
      * @var Podcast|null
      */
-    protected $podcast;
+    protected ?Podcast $podcast;
 
     public function _remap(string $method, string ...$params): mixed
     {
@@ -122,7 +122,7 @@ class PodcastImportController extends BaseController
 
         try {
             if (
-                isset($nsItunes->image) &&
+                property_exists($nsItunes, 'image') && $nsItunes->image !== null &&
                 $nsItunes->image->attributes()['href'] !== null
             ) {
                 $imageFile = download_file(
@@ -135,7 +135,7 @@ class PodcastImportController extends BaseController
             }
 
             $location = null;
-            if (isset($nsPodcast->location)) {
+            if (property_exists($nsPodcast, 'location') && $nsPodcast->location !== null) {
                 $location = new Location(
                     (string) $nsPodcast->location,
                     (string) $nsPodcast->location->attributes()['geo'],
@@ -160,7 +160,7 @@ class PodcastImportController extends BaseController
                 'language_code' => $this->request->getPost('language'),
                 'category_id' => $this->request->getPost('category'),
                 'parental_advisory' =>
-                isset($nsItunes->explicit)
+                property_exists($nsItunes, 'explicit') && $nsItunes->explicit !== null
                     ? (in_array((string) $nsItunes->explicit, ['yes', 'true'])
                         ? 'explicit'
                         : (in_array((string) $nsItunes->explicit, ['no', 'false'])
@@ -170,16 +170,12 @@ class PodcastImportController extends BaseController
                 'owner_name' => (string) $nsItunes->owner->name,
                 'owner_email' => (string) $nsItunes->owner->email,
                 'publisher' => (string) $nsItunes->author,
-                'type' => isset($nsItunes->type) ? (string) $nsItunes->type : 'episodic',
+                'type' => property_exists($nsItunes, 'type') && $nsItunes->type !== null ? (string) $nsItunes->type : 'episodic',
                 'copyright' => (string) $feed->channel[0]->copyright,
                 'is_blocked' =>
-                isset($nsItunes->block)
-                    ? (string) $nsItunes->block === 'yes'
-                    : false,
+                property_exists($nsItunes, 'block') && $nsItunes->block !== null && (string) $nsItunes->block === 'yes',
                 'is_completed' =>
-                isset($nsItunes->complete)
-                    ? (string) $nsItunes->complete === 'yes'
-                    : false,
+                property_exists($nsItunes, 'complete') && $nsItunes->complete !== null && (string) $nsItunes->complete === 'yes',
                 'location' => $location,
                 'created_by' => user_id(),
                 'updated_by' => user_id(),
@@ -337,7 +333,7 @@ class PodcastImportController extends BaseController
             };
 
             if (
-                isset($nsItunes->image) &&
+                property_exists($nsItunes, 'image') && $nsItunes->image !== null &&
                 $nsItunes->image->attributes()['href'] !== null
             ) {
                 $episodeImage = new Image(
@@ -350,7 +346,7 @@ class PodcastImportController extends BaseController
             }
 
             $location = null;
-            if (isset($nsPodcast->location)) {
+            if (property_exists($nsPodcast, 'location') && $nsPodcast->location !== null) {
                 $location = new Location(
                     (string) $nsPodcast->location,
                     (string) $nsPodcast->location->attributes()['geo'],
@@ -372,7 +368,7 @@ class PodcastImportController extends BaseController
                 'description_html' => $itemDescriptionHtml,
                 'image' => $episodeImage,
                 'parental_advisory' =>
-                isset($nsItunes->explicit)
+                property_exists($nsItunes, 'explicit') && $nsItunes->explicit !== null
                     ? (in_array((string) $nsItunes->explicit, ['yes', 'true'])
                         ? 'explicit'
                         : (in_array((string) $nsItunes->explicit, ['no', 'false'])
@@ -387,12 +383,10 @@ class PodcastImportController extends BaseController
                 $this->request->getPost('season_number') === null
                     ? $nsItunes->season
                     : $this->request->getPost('season_number'),
-                'type' => isset($nsItunes->episodeType)
+                'type' => property_exists($nsItunes, 'episodeType') && $nsItunes->episodeType !== null
                     ? (string) $nsItunes->episodeType
                     : 'full',
-                'is_blocked' => isset($nsItunes->block)
-                    ? (string) $nsItunes->block === 'yes'
-                    : false,
+                'is_blocked' => property_exists($nsItunes, 'block') && $nsItunes->block !== null && (string) $nsItunes->block === 'yes',
                 'location' => $location,
                 'created_by' => user_id(),
                 'updated_by' => user_id(),
diff --git a/app/Controllers/Admin/PodcastPersonController.php b/app/Controllers/Admin/PodcastPersonController.php
index 3b6a8147b6e72c3e30d2511e5048bfacb0cf6642..e2c12e5d8d585379c70b64edce8a6efd2317d877 100644
--- a/app/Controllers/Admin/PodcastPersonController.php
+++ b/app/Controllers/Admin/PodcastPersonController.php
@@ -19,7 +19,7 @@ class PodcastPersonController extends BaseController
     /**
      * @var Podcast
      */
-    protected $podcast;
+    protected Podcast $podcast;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Controllers/Admin/PodcastPlatformController.php b/app/Controllers/Admin/PodcastPlatformController.php
index c68d2a179dddb46be007aadcbabffdfd9c9b55f8..db00694f6e3d4d587140c0b348c2ddd8c33c68e2 100644
--- a/app/Controllers/Admin/PodcastPlatformController.php
+++ b/app/Controllers/Admin/PodcastPlatformController.php
@@ -20,7 +20,7 @@ class PodcastPlatformController extends BaseController
     /**
      * @var Podcast|null
      */
-    protected $podcast;
+    protected ?Podcast $podcast;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Controllers/Admin/UserController.php b/app/Controllers/Admin/UserController.php
index 04b105700c67f98c04d02c5f3d8a445065ba2d48..e537c3c23c957d514526d66785b8f236b8cd4f8e 100644
--- a/app/Controllers/Admin/UserController.php
+++ b/app/Controllers/Admin/UserController.php
@@ -17,10 +17,7 @@ use Config\Services;
 
 class UserController extends BaseController
 {
-    /**
-     * @var User|null
-     */
-    protected $user;
+    protected ?User $user;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Controllers/EpisodeController.php b/app/Controllers/EpisodeController.php
index ec531e16c08c8c59f78f6c7862cbf698802d192e..517048cd2893c456b6676aaec09b056f50fe0ab7 100644
--- a/app/Controllers/EpisodeController.php
+++ b/app/Controllers/EpisodeController.php
@@ -22,15 +22,9 @@ class EpisodeController extends BaseController
 {
     use AnalyticsTrait;
 
-    /**
-     * @var Podcast
-     */
-    protected $podcast;
-
-    /**
-     * @var Episode
-     */
-    protected $episode;
+    protected Podcast $podcast;
+
+    protected Episode $episode;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Controllers/NoteController.php b/app/Controllers/NoteController.php
index bcf8f09453ca8123cdb1bfbadf67abeeddb18774..e6f5106ed0b00a221feb416ae0f57e09e0057101 100644
--- a/app/Controllers/NoteController.php
+++ b/app/Controllers/NoteController.php
@@ -25,15 +25,8 @@ class NoteController extends ActivityPubNoteController
 {
     use AnalyticsTrait;
 
-    /**
-     * @var Podcast
-     */
-    protected $podcast;
-
-    /**
-     * @var Actor
-     */
-    protected $actor;
+    protected Podcast $podcast;
+    protected Actor $actor;
 
     /**
      * @var string[]
@@ -219,6 +212,7 @@ class NoteController extends ActivityPubNoteController
         }
 
         $action = $this->request->getPost('action');
+        /** @phpstan-ignore-next-line */
         switch ($action) {
             case 'favourite':
                 return $this->attemptFavourite();
diff --git a/app/Controllers/PageController.php b/app/Controllers/PageController.php
index 8f02363ab6046791a029cec20a84f97777e49b51..d10686fbb361206fc4d9e2778a18b5e7ac695fd7 100644
--- a/app/Controllers/PageController.php
+++ b/app/Controllers/PageController.php
@@ -16,10 +16,7 @@ use App\Models\PodcastModel;
 
 class PageController extends BaseController
 {
-    /**
-     * @var Page|null
-     */
-    protected $page;
+    protected ?Page $page;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Controllers/PodcastController.php b/app/Controllers/PodcastController.php
index f4ae6663eb944333361682bff31cfa4c3c0c1d81..2df70dc7761dcbac8a0d9b326b7b1c9019be14e1 100644
--- a/app/Controllers/PodcastController.php
+++ b/app/Controllers/PodcastController.php
@@ -22,7 +22,7 @@ class PodcastController extends BaseController
     /**
      * @var Podcast
      */
-    protected $podcast;
+    protected Podcast $podcast;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Database/Migrations/2020-12-25-140000_add_episodes_persons.php b/app/Database/Migrations/2020-12-25-140000_add_episodes_persons.php
index 9382b9ac8884d14cce5d28a249116cf7fbe41129..b23c70184d4265cd0f804efcec4cf41e59853ff5 100644
--- a/app/Database/Migrations/2020-12-25-140000_add_episodes_persons.php
+++ b/app/Database/Migrations/2020-12-25-140000_add_episodes_persons.php
@@ -44,7 +44,7 @@ class AddEpisodesPersons extends Migration
                 'constraint' => 32,
             ],
         ]);
-        $this->forge->addPrimaryKey('id', true);
+        $this->forge->addPrimaryKey('id');
         $this->forge->addUniqueKey([
             'podcast_id',
             'episode_id',
diff --git a/app/Database/Seeds/AuthSeeder.php b/app/Database/Seeds/AuthSeeder.php
index 24835c269bfdc4ea3bc4a23642d1675022ed6b3b..bd26b133d9dd45f6cfe6cc2c68ca89a3fe7b2dbc 100644
--- a/app/Database/Seeds/AuthSeeder.php
+++ b/app/Database/Seeds/AuthSeeder.php
@@ -18,7 +18,7 @@ class AuthSeeder extends Seeder
     /**
      * @var array<string, string>[]
      */
-    protected $groups = [
+    protected array $groups = [
         [
             'name' => 'superadmin',
             'description' =>
@@ -43,7 +43,7 @@ class AuthSeeder extends Seeder
      *
      * @var array<string, array<string, string|array>[]>
      */
-    protected $permissions = [
+    protected array $permissions = [
         'users' => [
             [
                 'name' => 'create',
diff --git a/app/Database/Seeds/FakePodcastsAnalyticsSeeder.php b/app/Database/Seeds/FakePodcastsAnalyticsSeeder.php
index 0a8e3d156024c23a393bf6e2a47c685637355f1d..7d84aa6cad38526eba9e7f4a946254a5d499276a 100644
--- a/app/Database/Seeds/FakePodcastsAnalyticsSeeder.php
+++ b/app/Database/Seeds/FakePodcastsAnalyticsSeeder.php
@@ -114,11 +114,11 @@ class FakePodcastsAnalyticsSeeder extends Seeder
                         try {
                             $city = $cityReader->city($fakeIp);
 
-                            $countryCode = empty($city->country->isoCode)
+                            $countryCode = $city->country->isoCode === null
                                 ? 'N/A'
                                 : $city->country->isoCode;
 
-                            $regionCode = empty($city->subdivisions[0]->isoCode)
+                            $regionCode = $city->subdivisions[0]->isoCode === null
                                 ? 'N/A'
                                 : $city->subdivisions[0]->isoCode;
                             $latitude = round($city->location->latitude, 3);
diff --git a/app/Database/Seeds/FakeWebsiteAnalyticsSeeder.php b/app/Database/Seeds/FakeWebsiteAnalyticsSeeder.php
index 21fbc8fad6196249066cc09c64f54a27cb2e221f..e33e509500deb5845ef1d528220a9906149bc9f8 100644
--- a/app/Database/Seeds/FakeWebsiteAnalyticsSeeder.php
+++ b/app/Database/Seeds/FakeWebsiteAnalyticsSeeder.php
@@ -21,7 +21,7 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
     /**
      * @var string[]
      */
-    protected $keywords = [
+    protected array $keywords = [
         'all the smoke podcast',
         'apple podcast',
         'bad friends podcast',
@@ -77,7 +77,7 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
     /**
      * @var string[]
      */
-    protected $domains = [
+    protected array $domains = [
         '360.cn ',
         'adobe.com ',
         'aliexpress.com ',
@@ -133,7 +133,7 @@ class FakeWebsiteAnalyticsSeeder extends Seeder
     /**
      * @var string[]
      */
-    protected $browsers = [
+    protected array $browsers = [
         'Android Browser',
         'Avast Secure Browser',
         'BlackBerry Browser',
diff --git a/app/Entities/Category.php b/app/Entities/Category.php
index afc4e265837529ce4552b66bc11394ef3c3dd880..b9c322090e6f17315bd41c5031dc08b2b1c57e97 100644
--- a/app/Entities/Category.php
+++ b/app/Entities/Category.php
@@ -36,7 +36,7 @@ class Category extends Entity
 
     public function getParent(): ?Category
     {
-        if (empty($this->parent_id)) {
+        if ($this->parent_id === null) {
             return null;
         }
 
diff --git a/app/Entities/Episode.php b/app/Entities/Episode.php
index a9d726561248fef4205eabd641f40b783feca859..a48e1e7106308617956c775dedf86799b285e6f5 100644
--- a/app/Entities/Episode.php
+++ b/app/Entities/Episode.php
@@ -95,19 +95,19 @@ class Episode extends Entity
     protected File $chapters_file;
 
     /**
-     * @var Person[]
+     * @var Person[]|null
      */
-    protected $persons = [];
+    protected ?array $persons = null;
 
     /**
-     * @var Soundbite[]
+     * @var Soundbite[]|null
      */
-    protected $soundbites = [];
+    protected ?array $soundbites = null;
 
     /**
-     * @var Note[]
+     * @var Note[]|null
      */
-    protected $notes = [];
+    protected ?array $notes = null;
 
     protected ?Location $location = null;
     protected string $custom_rss_string;
@@ -348,13 +348,13 @@ class Episode extends Entity
      */
     public function getPersons(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Episode must be created before getting persons.',
             );
         }
 
-        if (empty($this->persons)) {
+        if ($this->persons === null) {
             $this->persons = (new PersonModel())->getEpisodePersons(
                 $this->podcast_id,
                 $this->id,
@@ -371,13 +371,13 @@ class Episode extends Entity
      */
     public function getSoundbites(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Episode must be created before getting soundbites.',
             );
         }
 
-        if (empty($this->soundbites)) {
+        if ($this->soundbites === null) {
             $this->soundbites = (new SoundbiteModel())->getEpisodeSoundbites(
                 $this->getPodcast()->id,
                 $this->id,
@@ -392,13 +392,13 @@ class Episode extends Entity
      */
     public function getNotes(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Episode must be created before getting soundbites.',
             );
         }
 
-        if (empty($this->notes)) {
+        if ($this->notes === null) {
             $this->notes = (new NoteModel())->getEpisodeNotes($this->id);
         }
 
diff --git a/app/Entities/Location.php b/app/Entities/Location.php
index 40f256fa8c91c94bf1951768e5ed8a73ebbf855f..7726b15e692ca03b2f78727673f0dcfdd3d100c3 100644
--- a/app/Entities/Location.php
+++ b/app/Entities/Location.php
@@ -61,10 +61,8 @@ class Location extends Entity
 
     /**
      * Fetches places from Nominatim OpenStreetMap
-     *
-     * @return array<string, string>|null
      */
-    public function fetchOsmLocation(): self
+    public function fetchOsmLocation(): static
     {
         $client = Services::curlrequest();
 
@@ -93,11 +91,11 @@ class Location extends Entity
             return $this;
         }
 
-        if (isset($places[0]->lat, $places[0]->lon)) {
+        if (property_exists($places[0], 'lat') && $places[0]->lat !== null && (property_exists($places[0], 'lon') && $places[0]->lon !== null)) {
             $this->attributes['geo'] = "geo:{$places[0]->lat},{$places[0]->lon}";
         }
 
-        if (isset($places[0]->osm_type, $places[0]->osm_id)) {
+        if (property_exists($places[0], 'osm_type') && $places[0]->osm_type !== null && (property_exists($places[0], 'osm_id') && $places[0]->osm_id !== null)) {
             $this->attributes['osm'] = strtoupper(substr($places[0]->osm_type, 0, 1)) . $places[0]->osm_id;
         }
 
diff --git a/app/Entities/Person.php b/app/Entities/Person.php
index eb15dbdc6a312fd620d1de1bbf21bba7a23f0673..be338f1a5b178e64d57d8aec2b24282f009956f6 100644
--- a/app/Entities/Person.php
+++ b/app/Entities/Person.php
@@ -22,14 +22,16 @@ use RuntimeException;
  * @property string $image_mimetype
  * @property int $created_by
  * @property int $updated_by
- * @property string[]|null $roles
+ * @property object[]|null $roles
  */
 class Person extends Entity
 {
     protected Image $image;
+    protected ?int $podcast_id = null;
+    protected ?int $episode_id = null;
 
     /**
-     * @var string[]|null
+     * @var object[]|null
      */
     protected ?array $roles = null;
 
@@ -75,17 +77,17 @@ class Person extends Entity
     }
 
     /**
-     * @return stdClass[]
+     * @return object[]
      */
     public function getRoles(): array {
-        if ($this->podcast_id === null) {
+        if ($this->attributes['podcast_id'] === null) {
             throw new RuntimeException(
                 'Person must have a podcast_id before getting roles.',
             );
         }
 
         if ($this->roles === null) {
-            $this->roles = (new PersonModel())->getPersonRoles($this->id, $this->podcast_id, $this->episode_id);
+            $this->roles = (new PersonModel())->getPersonRoles($this->id, $this->attributes['podcast_id'], $this->episode_id);
         }
 
         return $this->roles;
diff --git a/app/Entities/Podcast.php b/app/Entities/Podcast.php
index 55ba035675d06def65987ed4847622dac9700ccf..f76156c595c7cc4403134bf79901316d3f33e3af 100644
--- a/app/Entities/Podcast.php
+++ b/app/Entities/Podcast.php
@@ -84,44 +84,44 @@ class Podcast extends Entity
     protected ?Category $category = null;
 
     /**
-     * @var Category[]
+     * @var Category[]|null
      */
-    protected $other_categories = [];
+    protected ?array $other_categories = null;
 
     /**
-     * @var string[]
+     * @var string[]|null
      */
-    protected $other_categories_ids = [];
+    protected ?array $other_categories_ids = null;
 
     /**
-     * @var Episode[]
+     * @var Episode[]|null
      */
-    protected $episodes = [];
+    protected ?array $episodes = null;
 
     /**
-     * @var Person[]
+     * @var Person[]|null
      */
-    protected $persons = [];
+    protected ?array $persons = null;
 
     /**
-     * @var User[]
+     * @var User[]|null
      */
-    protected $contributors = [];
+    protected ?array $contributors = null;
 
     /**
-     * @var Platform[]
+     * @var Platform[]|null
      */
-    protected $podcasting_platforms = [];
+    protected ?array $podcasting_platforms = null;
 
     /**
-     * @var Platform[]
+     * @var Platform[]|null
      */
-    protected $social_platforms = [];
+    protected ?array $social_platforms = null;
 
     /**
-     * @var Platform[]
+     * @var Platform[]|null
      */
-    protected $funding_platforms = [];
+    protected ?array $funding_platforms = null;
 
     protected ?Location $location = null;
     protected string $custom_rss_string;
@@ -216,13 +216,13 @@ class Podcast extends Entity
      */
     public function getEpisodes(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Podcast must be created before getting episodes.',
             );
         }
 
-        if (empty($this->episodes)) {
+        if ($this->episodes === null) {
             $this->episodes = (new EpisodeModel())->getPodcastEpisodes(
                 $this->id,
                 $this->type,
@@ -239,13 +239,13 @@ class Podcast extends Entity
      */
     public function getPersons(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Podcast must be created before getting persons.',
             );
         }
 
-        if (empty($this->persons)) {
+        if ($this->persons === null) {
             $this->persons = (new PersonModel())->getPodcastPersons($this->id);
         }
 
@@ -279,13 +279,13 @@ class Podcast extends Entity
      */
     public function getContributors(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Podcasts must be created before getting contributors.',
             );
         }
 
-        if (empty($this->contributors)) {
+        if ($this->contributors === null) {
             $this->contributors = (new UserModel())->getPodcastContributors(
                 $this->id,
             );
@@ -351,13 +351,13 @@ class Podcast extends Entity
      */
     public function getPodcastingPlatforms(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Podcast must be created before getting podcasting platform links.',
             );
         }
 
-        if (empty($this->podcasting_platforms)) {
+        if ($this->podcasting_platforms === null) {
             $this->podcasting_platforms = (new PlatformModel())->getPodcastPlatforms(
                 $this->id,
                 'podcasting',
@@ -374,13 +374,13 @@ class Podcast extends Entity
      */
     public function getSocialPlatforms(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Podcast must be created before getting social platform links.',
             );
         }
 
-        if (empty($this->social_platforms)) {
+        if ($this->social_platforms === null) {
             $this->social_platforms = (new PlatformModel())->getPodcastPlatforms(
                 $this->id,
                 'social',
@@ -397,13 +397,13 @@ class Podcast extends Entity
      */
     public function getFundingPlatforms(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Podcast must be created before getting funding platform links.',
             );
         }
 
-        if (empty($this->funding_platforms)) {
+        if ($this->funding_platforms === null) {
             $this->funding_platforms = (new PlatformModel())->getPodcastPlatforms(
                 $this->id,
                 'funding',
@@ -418,13 +418,13 @@ class Podcast extends Entity
      */
     public function getOtherCategories(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Podcast must be created before getting other categories.',
             );
         }
 
-        if (empty($this->other_categories)) {
+        if ($this->other_categories === null) {
             $this->other_categories = (new CategoryModel())->getPodcastCategories(
                 $this->id,
             );
@@ -434,11 +434,11 @@ class Podcast extends Entity
     }
 
     /**
-     * @return array<int>
+     * @return int[]
      */
     public function getOtherCategoriesIds(): array
     {
-        if (empty($this->other_categories_ids)) {
+        if ($this->other_categories_ids === null) {
             $this->other_categories_ids = array_column(
                 $this->getOtherCategories(),
                 'id',
@@ -497,7 +497,7 @@ class Podcast extends Entity
      */
     function getCustomRssString(): string
     {
-        if (empty($this->attributes['custom_rss'])) {
+        if ($this->attributes['custom_rss'] === null) {
             return '';
         }
 
@@ -521,7 +521,7 @@ class Podcast extends Entity
      */
     function setCustomRssString(string $customRssString): static
     {
-        if (empty($customRssString)) {
+        if ($customRssString === '') {
             return $this;
         }
 
diff --git a/app/Filters/PermissionFilter.php b/app/Filters/PermissionFilter.php
index 84495dc38cd5d59fb36be8ed45796fa30a70db7f..770f5fb2e5b9d90c7e3b294ecd607847d7cb666f 100644
--- a/app/Filters/PermissionFilter.php
+++ b/app/Filters/PermissionFilter.php
@@ -28,7 +28,7 @@ class PermissionFilter implements FilterInterface
     {
         helper('auth');
 
-        if (empty($params)) {
+        if ($params === null) {
             return;
         }
 
diff --git a/app/Helpers/components_helper.php b/app/Helpers/components_helper.php
index 172bfca118e7bd204ceb39e7505479d848085d77..d0dcdbc8294fa419dc264bf218c786c3b0159ec8 100644
--- a/app/Helpers/components_helper.php
+++ b/app/Helpers/components_helper.php
@@ -78,7 +78,7 @@ if (!function_exists('button')) {
             ' ' .
             $variantClass[$options['variant']];
 
-        if (!empty($customAttributes['class'])) {
+        if (array_key_exists('class', $customAttributes)) {
             $buttonClass .= ' ' . $customAttributes['class'];
             unset($customAttributes['class']);
         }
@@ -298,6 +298,7 @@ if (!function_exists('publication_button')) {
         int $episodeId,
         string $publicationStatus
     ): string {
+        /** @phpstan-ignore-next-line */
         switch ($publicationStatus) {
             case 'not_published':
                 $label = lang('Episode.publish');
@@ -406,7 +407,7 @@ if (!function_exists('location_link')) {
             [
                 'class' =>
                     'inline-flex items-baseline hover:underline' .
-                    (empty($class) ? '' : " {$class}"),
+                    ($class === '' ? '' : " {$class}"),
                 'target' => '_blank',
                 'rel' => 'noreferrer noopener',
             ],
diff --git a/app/Helpers/id3_helper.php b/app/Helpers/id3_helper.php
index d13239dda65580976c2a9b40006ffbc536af8288..1b789984cce9cb6e4f2eb33b2d77d101c433f24c 100644
--- a/app/Helpers/id3_helper.php
+++ b/app/Helpers/id3_helper.php
@@ -62,7 +62,7 @@ if (!function_exists('write_audio_file_tags')) {
         $TagData = [
             'title' => [$episode->title],
             'artist' => [
-                empty($episode->podcast->publisher)
+                $episode->podcast->publisher === null
                     ? $episode->podcast->owner_name
                     : $episode->podcast->publisher,
             ],
@@ -77,7 +77,7 @@ if (!function_exists('write_audio_file_tags')) {
             'track_number' => [(string) $episode->number],
             'copyright_message' => [$episode->podcast->copyright],
             'publisher' => [
-                empty($episode->podcast->publisher)
+                $episode->podcast->publisher === null
                     ? $episode->podcast->owner_name
                     : $episode->podcast->publisher,
             ],
@@ -103,7 +103,7 @@ if (!function_exists('write_audio_file_tags')) {
         // write tags
         if ($tagwriter->WriteTags()) {
             echo 'Successfully wrote tags<br>';
-            if (!empty($tagwriter->warnings)) {
+            if ($tagwriter->warnings !== []) {
                 echo 'There were some warnings:<br>' .
                     implode('<br><br>', $tagwriter->warnings);
             }
diff --git a/app/Helpers/misc_helper.php b/app/Helpers/misc_helper.php
index d90e8fa5f3577bdcade768f1279028f8210b46cb..e660118f5f561b899007e890ebfea9d5268721fe 100644
--- a/app/Helpers/misc_helper.php
+++ b/app/Helpers/misc_helper.php
@@ -10,16 +10,13 @@ if (!function_exists('get_browser_language')) {
     /**
      * Gets the browser default language using the request header key `HTTP_ACCEPT_LANGUAGE`
      *
-     * @return string|null ISO 639-1 language code or null
+     * @return string ISO 639-1 language code
      */
-    function get_browser_language(string $httpAcceptLanguage): ?string
+    function get_browser_language(string $httpAcceptLanguage): string
     {
         $langs = explode(',', $httpAcceptLanguage);
-        if (!empty($langs)) {
-            return substr($langs[0], 0, 2);
-        }
 
-        return null;
+        return substr($langs[0], 0, 2);
     }
 }
 
diff --git a/app/Helpers/rss_helper.php b/app/Helpers/rss_helper.php
index 8fed1cd0ad3b1bbb9eb92c5463e91c301ac51f2a..98485117f7261cc7bbbc89e69efe77778e7d8d44 100644
--- a/app/Helpers/rss_helper.php
+++ b/app/Helpers/rss_helper.php
@@ -181,53 +181,45 @@ if (!function_exists('get_rss_feed')) {
             }
         }
 
-        foreach ($podcast->persons as $podcastPerson) {
-            $podcastPersonElement = $channel->addChild(
-                'person',
-                htmlspecialchars($podcastPerson->full_name),
-                $podcastNamespace,
-            );
+        foreach ($podcast->persons as $person) {
+            foreach ($person->roles as $role) {
+                $personElement = $channel->addChild(
+                    'person',
+                    htmlspecialchars($person->full_name),
+                    $podcastNamespace,
+                );
+
+                $personElement->addAttribute('img', $person->image->large_url);
 
-            if (
-                $podcastPerson->role !== null &&
-                $podcastPerson->role !== null
-            ) {
-                $podcastPersonElement->addAttribute(
+                if ($person->information_url !== null) {
+                    $personElement->addAttribute(
+                        'href',
+                        $person->information_url,
+                    );
+                }
+
+                $personElement->addAttribute(
                     'role',
                     htmlspecialchars(
                         lang(
-                            "PersonsTaxonomy.persons.{$podcastPerson->group}.roles.{$podcastPerson->role}.label",
+                            "PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label",
                             [],
                             'en',
                         ),
                     ),
                 );
-            }
 
-            if ($podcastPerson->group !== null) {
-                $podcastPersonElement->addAttribute(
+                $personElement->addAttribute(
                     'group',
                     htmlspecialchars(
                         lang(
-                            "PersonsTaxonomy.persons.{$podcastPerson->group}.label",
+                            "PersonsTaxonomy.persons.{$role->group}.label",
                             [],
                             'en',
                         ),
                     ),
                 );
             }
-
-            $podcastPersonElement->addAttribute(
-                'img',
-                $podcastPerson->image->large_url,
-            );
-
-            if ($podcastPerson->information_url !== null) {
-                $podcastPersonElement->addAttribute(
-                    'href',
-                    $podcastPerson->information_url,
-                );
-            }
         }
 
         // set main category first, then other categories as apple
@@ -399,7 +391,7 @@ if (!function_exists('get_rss_feed')) {
             foreach ($episode->soundbites as $soundbite) {
                 $soundbiteElement = $item->addChild(
                     'soundbite',
-                    empty($soundbite->label) ? null : $soundbite->label,
+                    $soundbite->label,
                     $podcastNamespace,
                 );
                 $soundbiteElement->addAttribute(
@@ -412,55 +404,54 @@ if (!function_exists('get_rss_feed')) {
                 );
             }
 
-            foreach ($episode->persons as $episodePerson) {
-                $episodePersonElement = $item->addChild(
-                    'person',
-                    htmlspecialchars($episodePerson->full_name),
-                    $podcastNamespace,
-                );
-                if (
-                    !empty($episodePerson->role) &&
-                    !empty($episodePerson->group)
-                ) {
-                    $episodePersonElement->addAttribute(
+            foreach ($episode->persons as $person) {
+                foreach ($person->roles as $role) {
+                    $personElement = $item->addChild(
+                        'person',
+                        htmlspecialchars($person->full_name),
+                        $podcastNamespace,
+                    );
+
+                    $personElement->addAttribute(
                         'role',
                         htmlspecialchars(
                             lang(
-                                "PersonsTaxonomy.persons.{$episodePerson->group}.roles.{$episodePerson->role}.label",
+                                "PersonsTaxonomy.persons.{$role->group}.roles.{$role->role}.label",
                                 [],
                                 'en',
                             ),
                         ),
                     );
-                }
-                if (!empty($episodePerson->person_group)) {
-                    $episodePersonElement->addAttribute(
+
+                    $personElement->addAttribute(
                         'group',
                         htmlspecialchars(
                             lang(
-                                "PersonsTaxonomy.persons.{$episodePerson->group}.label",
+                                "PersonsTaxonomy.persons.{$role->group}.label",
                                 [],
                                 'en',
                             ),
                         ),
                     );
-                }
-                $episodePersonElement->addAttribute(
-                    'img',
-                    $episodePerson->image->large_url,
-                );
-                if (!empty($episodePerson->information_url)) {
-                    $episodePersonElement->addAttribute(
-                        'href',
-                        $episodePerson->information_url,
+
+                    $personElement->addAttribute(
+                        'img',
+                        $person->image->large_url,
                     );
+
+                    if ($person->information_url !== null) {
+                        $personElement->addAttribute(
+                            'href',
+                            $person->information_url,
+                        );
+                    }
                 }
             }
 
             $episode->is_blocked &&
                 $item->addChild('block', 'Yes', $itunesNamespace);
 
-            if (!empty($episode->custom_rss)) {
+            if ($episode->custom_rss !== null) {
                 array_to_rss(
                     [
                         'elements' => $episode->custom_rss,
@@ -557,9 +548,9 @@ if (!function_exists('array_to_rss')) {
                 $childXmlNode = $xmlNode->addChild(
                     $childArrayNode['name'],
                     $childArrayNode['content'] ?? null,
-                    empty($childArrayNode['namespace'])
-                        ? null
-                        : current($childArrayNode['namespace']),
+                    array_key_exists('namespace', $childArrayNode)
+                        ? current($childArrayNode['namespace'])
+                        : null,
                 );
                 if (array_key_exists('attributes', $childArrayNode)) {
                     foreach (
diff --git a/app/Helpers/url_helper.php b/app/Helpers/url_helper.php
index d58614bb5b7224ddf3efc1f54138858d247d6787..8574beda8a55f414018fe4f9d60b55585d80c573 100644
--- a/app/Helpers/url_helper.php
+++ b/app/Helpers/url_helper.php
@@ -16,7 +16,7 @@ if (!function_exists('host_url')) {
     {
         if (isset($_SERVER['HTTP_HOST'])) {
             $protocol =
-                (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
+                (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
                 $_SERVER['SERVER_PORT'] == 443
                     ? 'https://'
                     : 'http://';
diff --git a/app/Libraries/ActivityPub/Activities/AcceptActivity.php b/app/Libraries/ActivityPub/Activities/AcceptActivity.php
index 13c18021f214cf4835c23534c123967950dd1576..10d8b07f3cbb4c7290e39eb00642843e10bf1485 100644
--- a/app/Libraries/ActivityPub/Activities/AcceptActivity.php
+++ b/app/Libraries/ActivityPub/Activities/AcceptActivity.php
@@ -17,8 +17,5 @@ use ActivityPub\Core\Activity;
 
 class AcceptActivity extends Activity
 {
-    /**
-     * @var string
-     */
-    protected $type = 'Accept';
+    protected string $type = 'Accept';
 }
diff --git a/app/Libraries/ActivityPub/Activities/AnnounceActivity.php b/app/Libraries/ActivityPub/Activities/AnnounceActivity.php
index e96508982c8d69bdd427b81660e9065ebb8e998a..8371f709512eb3e2dced2e008db291aef6f99151 100644
--- a/app/Libraries/ActivityPub/Activities/AnnounceActivity.php
+++ b/app/Libraries/ActivityPub/Activities/AnnounceActivity.php
@@ -18,10 +18,7 @@ use ActivityPub\Entities\Note;
 
 class AnnounceActivity extends Activity
 {
-    /**
-     * @var string
-     */
-    protected $type = 'Announce';
+    protected string $type = 'Announce';
 
     public function __construct(Note $reblogNote)
     {
diff --git a/app/Libraries/ActivityPub/Activities/CreateActivity.php b/app/Libraries/ActivityPub/Activities/CreateActivity.php
index bb479e0424d2d6b417d20fadbee5ea91c397b2fb..29b6345113317187a25edcddfdf61b64ed5720f6 100644
--- a/app/Libraries/ActivityPub/Activities/CreateActivity.php
+++ b/app/Libraries/ActivityPub/Activities/CreateActivity.php
@@ -17,8 +17,5 @@ use ActivityPub\Core\Activity;
 
 class CreateActivity extends Activity
 {
-    /**
-     * @var string
-     */
-    protected $type = 'Create';
+    protected string $type = 'Create';
 }
diff --git a/app/Libraries/ActivityPub/Activities/DeleteActivity.php b/app/Libraries/ActivityPub/Activities/DeleteActivity.php
index 58483f6e216e219957423841ccd2267951c8fa13..0ae540176fccf050ff4b74cff2bbc15ea2b6c318 100644
--- a/app/Libraries/ActivityPub/Activities/DeleteActivity.php
+++ b/app/Libraries/ActivityPub/Activities/DeleteActivity.php
@@ -17,8 +17,5 @@ use ActivityPub\Core\Activity;
 
 class DeleteActivity extends Activity
 {
-    /**
-     * @var string
-     */
-    protected $type = 'Delete';
+    protected string $type = 'Delete';
 }
diff --git a/app/Libraries/ActivityPub/Activities/FollowActivity.php b/app/Libraries/ActivityPub/Activities/FollowActivity.php
index b78e091204323a7f81875380bdc94792fda02588..78fe915107ebf79542f3cde8a171f8d166eb377f 100644
--- a/app/Libraries/ActivityPub/Activities/FollowActivity.php
+++ b/app/Libraries/ActivityPub/Activities/FollowActivity.php
@@ -17,8 +17,5 @@ use ActivityPub\Core\Activity;
 
 class FollowActivity extends Activity
 {
-    /**
-     * @var string
-     */
-    protected $type = 'Follow';
+    protected string $type = 'Follow';
 }
diff --git a/app/Libraries/ActivityPub/Activities/LikeActivity.php b/app/Libraries/ActivityPub/Activities/LikeActivity.php
index df21cc42f4967ab8e5685c10aafe48f353f7ae49..e1789329db83f52d791e744a65e6f08696926b79 100644
--- a/app/Libraries/ActivityPub/Activities/LikeActivity.php
+++ b/app/Libraries/ActivityPub/Activities/LikeActivity.php
@@ -17,8 +17,5 @@ use ActivityPub\Core\Activity;
 
 class LikeActivity extends Activity
 {
-    /**
-     * @var string
-     */
-    protected $type = 'Like';
+    protected string $type = 'Like';
 }
diff --git a/app/Libraries/ActivityPub/Activities/UndoActivity.php b/app/Libraries/ActivityPub/Activities/UndoActivity.php
index aa21fd34a2ec9aaa33e2d4b06f358a11222ae7f9..ce239394c6574854022a65cdfcb010b82e68990c 100644
--- a/app/Libraries/ActivityPub/Activities/UndoActivity.php
+++ b/app/Libraries/ActivityPub/Activities/UndoActivity.php
@@ -17,8 +17,5 @@ use ActivityPub\Core\Activity;
 
 class UndoActivity extends Activity
 {
-    /**
-     * @var string
-     */
-    protected $type = 'Undo';
+    protected string $type = 'Undo';
 }
diff --git a/app/Libraries/ActivityPub/ActivityRequest.php b/app/Libraries/ActivityPub/ActivityRequest.php
index a79559763f58d8690ee5ff868c192ca74321fa9c..789684ca3cf40605fa1c420b8f894ce207d1ba83 100644
--- a/app/Libraries/ActivityPub/ActivityRequest.php
+++ b/app/Libraries/ActivityPub/ActivityRequest.php
@@ -18,25 +18,14 @@ use phpseclib\Crypt\RSA;
 
 class ActivityRequest
 {
-    /**
-     * @var CURLRequest
-     */
-    protected $request;
-
-    /**
-     * @var URI
-     */
-    protected $uri;
-
-    /**
-     * @var Activity|null
-     */
-    protected $activity;
+    protected CURLRequest $request;
+    protected URI $uri;
+    protected ?Activity $activity;
 
     /**
      * @var array<string, string[]>
      */
-    protected $options = [
+    protected array $options = [
         'headers' => [
             'Content-Type' => 'application/activity+json',
             'Accept' => 'application/activity+json', // TODO: outgoing and incoming requests
diff --git a/app/Libraries/ActivityPub/Config/ActivityPub.php b/app/Libraries/ActivityPub/Config/ActivityPub.php
index 47ae7d3e9b3faa364078bd2a91633d9916c5ffc3..45f63fb6af8461c7edc28e50ff1cec14a48845dd 100644
--- a/app/Libraries/ActivityPub/Config/ActivityPub.php
+++ b/app/Libraries/ActivityPub/Config/ActivityPub.php
@@ -18,43 +18,28 @@ class ActivityPub extends BaseConfig
      * --------------------------------------------------------------------
      * ActivityPub Objects
      * --------------------------------------------------------------------
-     * @var string
      */
-    public $actorObject = ActorObject::class;
+    public string $actorObject = ActorObject::class;
 
-    /**
-     * @var string
-     */
-    public $noteObject = NoteObject::class;
+    public string $noteObject = NoteObject::class;
 
     /**
      * --------------------------------------------------------------------
      * Default avatar and cover images
      * --------------------------------------------------------------------
-     * @var string
      */
-    public $defaultAvatarImagePath = 'assets/images/avatar-default.jpg';
+    public string $defaultAvatarImagePath = 'assets/images/avatar-default.jpg';
 
-    /**
-     * @var string
-     */
-    public $defaultAvatarImageMimetype = 'image/jpeg';
+    public string $defaultAvatarImageMimetype = 'image/jpeg';
 
-    /**
-     * @var string
-     */
-    public $defaultCoverImagePath = 'assets/images/cover-default.jpg';
+    public string $defaultCoverImagePath = 'assets/images/cover-default.jpg';
 
-    /**
-     * @var string
-     */
-    public $defaultCoverImageMimetype = 'image/jpeg';
+    public string $defaultCoverImageMimetype = 'image/jpeg';
 
     /**
      * --------------------------------------------------------------------
      * Cache options
      * --------------------------------------------------------------------
-     * @var string
      */
-    public $cachePrefix = 'ap_';
+    public string $cachePrefix = 'ap_';
 }
diff --git a/app/Libraries/ActivityPub/Controllers/ActorController.php b/app/Libraries/ActivityPub/Controllers/ActorController.php
index 671fa56a005d3cff417250e8a86eba064aa46a1a..a808d1a2a06ae38a29ffa9ee3c6257d2f0f8a762 100644
--- a/app/Libraries/ActivityPub/Controllers/ActorController.php
+++ b/app/Libraries/ActivityPub/Controllers/ActorController.php
@@ -26,15 +26,8 @@ class ActorController extends Controller
      */
     protected $helpers = ['activitypub'];
 
-    /**
-     * @var Actor
-     */
-    protected $actor;
-
-    /**
-     * @var ActivityPub
-     */
-    protected $config;
+    protected Actor $actor;
+    protected ActivityPub $config;
 
     public function __construct()
     {
@@ -87,6 +80,7 @@ class ActorController extends Controller
         );
 
         // switch/case on activity type
+        /** @phpstan-ignore-next-line */
         switch ($payload->type) {
             case 'Create':
                 if ($payload->object->type == 'Note') {
@@ -168,6 +162,7 @@ class ActorController extends Controller
                 return $this->response->setStatusCode(200)->setJSON([]);
             case 'Undo':
                 // switch/case on the type of activity to undo
+                /** @phpstan-ignore-next-line */
                 switch ($payload->object->type) {
                     case 'Follow':
                         // revert side-effect by removing follow from database
diff --git a/app/Libraries/ActivityPub/Controllers/NoteController.php b/app/Libraries/ActivityPub/Controllers/NoteController.php
index bea02669ef9e2c1c9d2d0c163f3ca4739a3730ea..52268929bbda6580c5914bfcd7703d556bc7a8d8 100644
--- a/app/Libraries/ActivityPub/Controllers/NoteController.php
+++ b/app/Libraries/ActivityPub/Controllers/NoteController.php
@@ -26,15 +26,8 @@ class NoteController extends Controller
      */
     protected $helpers = ['activitypub'];
 
-    /**
-     * @var Note
-     */
-    protected $note;
-
-    /**
-     * @var ActivityPub
-     */
-    protected $config;
+    protected Note $note;
+    protected ActivityPub $config;
 
     public function __construct()
     {
diff --git a/app/Libraries/ActivityPub/Core/Activity.php b/app/Libraries/ActivityPub/Core/Activity.php
index ece7239ca190d35f8e1397dc3d20ab6d6ab29c1c..bbe8345a03b04499bd28255b39b4bdcf93fda3e8 100644
--- a/app/Libraries/ActivityPub/Core/Activity.php
+++ b/app/Libraries/ActivityPub/Core/Activity.php
@@ -15,18 +15,7 @@ namespace ActivityPub\Core;
 
 class Activity extends ObjectType
 {
-    /**
-     * @var string
-     */
-    protected $type = 'Activity';
-
-    /**
-     * @var string
-     */
-    protected $actor;
-
-    /**
-     * @var string|ObjectType
-     */
-    protected $object;
+    protected string $type = 'Activity';
+    protected string $actor;
+    protected string|ObjectType $object;
 }
diff --git a/app/Libraries/ActivityPub/Core/ObjectType.php b/app/Libraries/ActivityPub/Core/ObjectType.php
index caf64e6d33bd668282d343f3ec2dc1c7b4c93d5e..82a476aee21665d6f97d5e27e09c56ebfef148af 100644
--- a/app/Libraries/ActivityPub/Core/ObjectType.php
+++ b/app/Libraries/ActivityPub/Core/ObjectType.php
@@ -18,35 +18,19 @@ class ObjectType extends AbstractObject
     /**
      * @var string|string[]
      */
-    protected $context = 'https://www.w3.org/ns/activitystreams';
-
-    /**
-     * @var string
-     */
-    protected $id;
-
-    /**
-     * @var string
-     */
-    protected $type = 'Object';
-
-    /**
-     * @var string
-     */
-    protected $content;
-
-    /**
-     * @var string
-     */
-    protected $published;
+    protected string|array $context = 'https://www.w3.org/ns/activitystreams';
+    protected string $id;
+    protected string $type = 'Object';
+    protected string $content;
+    protected string $published;
 
     /**
      * @var string[]
      */
-    protected $to = ['https://www.w3.org/ns/activitystreams#Public'];
+    protected array $to = ['https://www.w3.org/ns/activitystreams#Public'];
 
     /**
      * @var string[]
      */
-    protected $cc = [];
+    protected array $cc = [];
 }
diff --git a/app/Libraries/ActivityPub/Entities/Activity.php b/app/Libraries/ActivityPub/Entities/Activity.php
index 54cfc90fdb8ffe7758f66b1b35f08bb15015e732..a629b1f41958adc177efce67d1a3a51d2d837f84 100644
--- a/app/Libraries/ActivityPub/Entities/Activity.php
+++ b/app/Libraries/ActivityPub/Entities/Activity.php
@@ -27,20 +27,9 @@ use Michalsn\Uuid\UuidEntity;
  */
 class Activity extends UuidEntity
 {
-    /**
-     * @var Actor
-     */
-    protected $actor;
-
-    /**
-     * @var Actor|null
-     */
-    protected $target_actor;
-
-    /**
-     * @var Note|null
-     */
-    protected $note;
+    protected ?Actor $actor;
+    protected ?Actor $target_actor;
+    protected ?Note $note;
 
     /**
      * @var string[]
@@ -67,13 +56,13 @@ class Activity extends UuidEntity
 
     public function getActor(): Actor
     {
-        if (empty($this->actor_id)) {
+        if ($this->actor_id === null) {
             throw new RuntimeException(
                 'Activity must have an actor_id before getting the actor.',
             );
         }
 
-        if (empty($this->actor)) {
+        if ($this->actor === null) {
             $this->actor = model('ActorModel')->getActorById($this->actor_id);
         }
 
@@ -82,13 +71,13 @@ class Activity extends UuidEntity
 
     public function getTargetActor(): Actor
     {
-        if (empty($this->target_actor_id)) {
+        if ($this->target_actor_id === null) {
             throw new RuntimeException(
                 'Activity must have a target_actor_id before getting the target actor.',
             );
         }
 
-        if (empty($this->target_actor)) {
+        if ($this->target_actor === null) {
             $this->target_actor = model('ActorModel')->getActorById(
                 $this->target_actor_id,
             );
@@ -99,13 +88,13 @@ class Activity extends UuidEntity
 
     public function getNote(): Note
     {
-        if (empty($this->note_id)) {
+        if ($this->note_id === null) {
             throw new RuntimeException(
                 'Activity must have a note_id before getting note.',
             );
         }
 
-        if (empty($this->note)) {
+        if ($this->note === null) {
             $this->note = model('NoteModel')->getNoteById($this->note_id);
         }
 
diff --git a/app/Libraries/ActivityPub/Entities/Actor.php b/app/Libraries/ActivityPub/Entities/Actor.php
index 51215ceb4d705d4c85c56e72068e09f3d2cccee8..09fb61ffec68d057472f6cb65a7589e50be7b258 100644
--- a/app/Libraries/ActivityPub/Entities/Actor.php
+++ b/app/Libraries/ActivityPub/Entities/Actor.php
@@ -37,20 +37,13 @@ use CodeIgniter\Entity\Entity;
  */
 class Actor extends Entity
 {
-    /**
-     * @var string
-     */
-    protected $public_key_id;
+    protected string $public_key_id;
 
     /**
      * @var Actor[]
      */
-    protected $followers = [];
-
-    /**
-     * @var boolean
-     */
-    protected $is_local = false;
+    protected ?array $followers = null;
+    protected bool $is_local = false;
 
     /**
      * @var array<string, string>
@@ -100,13 +93,13 @@ class Actor extends Entity
      */
     public function getFollowers(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Actor must be created before getting followers.',
             );
         }
 
-        if (empty($this->followers)) {
+        if ($this->followers === null) {
             $this->followers = (array) model('ActorModel')->getFollowers(
                 $this->id,
             );
@@ -117,7 +110,7 @@ class Actor extends Entity
 
     public function getAvatarImageUrl(): string
     {
-        if (empty($this->attributes['avatar_image_url'])) {
+        if ($this->attributes['avatar_image_url'] === null) {
             return base_url(config('ActivityPub')->defaultAvatarImagePath);
         }
 
@@ -126,7 +119,7 @@ class Actor extends Entity
 
     public function getAvatarImageMimetype(): string
     {
-        if (empty($this->attributes['avatar_image_mimetype'])) {
+        if ($this->attributes['avatar_image_mimetype'] === null) {
             return config('ActivityPub')->defaultAvatarImageMimetype;
         }
 
@@ -135,7 +128,7 @@ class Actor extends Entity
 
     public function getCoverImageUrl(): string
     {
-        if (empty($this->attributes['cover_image_url'])) {
+        if ($this->attributes['cover_image_url'] === null) {
             return base_url(config('ActivityPub')->defaultCoverImagePath);
         }
 
@@ -144,7 +137,7 @@ class Actor extends Entity
 
     public function getCoverImageMimetype(): string
     {
-        if (empty($this->attributes['cover_image_mimetype'])) {
+        if ($this->attributes['cover_image_mimetype'] === null) {
             return config('ActivityPub')->defaultCoverImageMimetype;
         }
 
diff --git a/app/Libraries/ActivityPub/Entities/Note.php b/app/Libraries/ActivityPub/Entities/Note.php
index 484fc3dddb3571da9b9221e3f5e95779960c1f3a..a99a934da4c83dec29a79b00661656d67a304638 100644
--- a/app/Libraries/ActivityPub/Entities/Note.php
+++ b/app/Libraries/ActivityPub/Entities/Note.php
@@ -40,55 +40,25 @@ use Michalsn\Uuid\UuidEntity;
  */
 class Note extends UuidEntity
 {
-    /**
-     * @var Actor
-     */
-    protected $actor;
-
-    /**
-     * @var boolean
-     */
-    protected $is_reply = false;
-
-    /**
-     * @var Note
-     */
-    protected $reply_to_note;
-
-    /**
-     * @var boolean
-     */
-    protected $is_reblog = false;
+    protected ?Actor $actor = null;
+    protected bool $is_reply = false;
+    protected ?Note $reply_to_note = null;
+    protected bool $is_reblog = false;
+    protected ?Note $reblog_of_note = null;
+    protected ?PreviewCard $preview_card = null;
+    protected bool $has_preview_card = false;
 
     /**
-     * @var Note
+     * @var Note[]|null
      */
-    protected $reblog_of_note;
+    protected ?array $replies = null;
 
-    /**
-     * @var PreviewCard|null
-     */
-    protected $preview_card;
-
-    /**
-     * @var boolean
-     */
-    protected $has_preview_card = false;
-
-    /**
-     * @var Note[]
-     */
-    protected $replies = [];
-
-    /**
-     * @var boolean
-     */
-    protected $has_replies = false;
+    protected bool $has_replies = false;
 
     /**
-     * @var Note[]
+     * @var Note[]|null
      */
-    protected $reblogs = [];
+    protected ?array $reblogs = null;
 
     /**
      * @var string[]
@@ -121,13 +91,13 @@ class Note extends UuidEntity
      */
     public function getActor(): Actor
     {
-        if (empty($this->actor_id)) {
+        if ($this->actor_id === null) {
             throw new RuntimeException(
                 'Note must have an actor_id before getting actor.',
             );
         }
 
-        if (empty($this->actor)) {
+        if ($this->actor === null) {
             $this->actor = model('ActorModel')->getActorById($this->actor_id);
         }
 
@@ -136,13 +106,13 @@ class Note extends UuidEntity
 
     public function getPreviewCard(): ?PreviewCard
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Note must be created before getting preview_card.',
             );
         }
 
-        if (empty($this->preview_card)) {
+        if ($this->preview_card === null) {
             $this->preview_card = model('PreviewCardModel')->getNotePreviewCard(
                 $this->id,
             );
@@ -153,7 +123,7 @@ class Note extends UuidEntity
 
     public function getHasPreviewCard(): bool
     {
-        return !empty($this->getPreviewCard());
+        return $this->getPreviewCard() !== null;
     }
 
     public function getIsReply(): bool
@@ -168,13 +138,13 @@ class Note extends UuidEntity
      */
     public function getReplies(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Note must be created before getting replies.',
             );
         }
 
-        if (empty($this->replies)) {
+        if ($this->replies === null) {
             $this->replies = (array) model('NoteModel')->getNoteReplies(
                 $this->id,
             );
@@ -185,16 +155,16 @@ class Note extends UuidEntity
 
     public function getHasReplies(): bool
     {
-        return !empty($this->getReplies());
+        return $this->getReplies() !== null;
     }
 
     public function getReplyToNote(): Note
     {
-        if (empty($this->in_reply_to_id)) {
+        if ($this->in_reply_to_id === null) {
             throw new RuntimeException('Note is not a reply.');
         }
 
-        if (empty($this->reply_to_note)) {
+        if ($this->reply_to_note === null) {
             $this->reply_to_note = model('NoteModel')->getNoteById(
                 $this->in_reply_to_id,
             );
@@ -208,13 +178,13 @@ class Note extends UuidEntity
      */
     public function getReblogs(): array
     {
-        if (empty($this->id)) {
+        if ($this->id === null) {
             throw new RuntimeException(
                 'Note must be created before getting reblogs.',
             );
         }
 
-        if (empty($this->reblogs)) {
+        if ($this->reblogs === null) {
             $this->reblogs = (array) model('NoteModel')->getNoteReblogs(
                 $this->id,
             );
@@ -230,11 +200,11 @@ class Note extends UuidEntity
 
     public function getReblogOfNote(): Note
     {
-        if (empty($this->reblog_of_id)) {
+        if ($this->reblog_of_id === null) {
             throw new RuntimeException('Note is not a reblog.');
         }
 
-        if (empty($this->reblog_of_note)) {
+        if ($this->reblog_of_note === null) {
             $this->reblog_of_note = model('NoteModel')->getNoteById(
                 $this->reblog_of_id,
             );
diff --git a/app/Libraries/ActivityPub/Filters/ActivityPubFilter.php b/app/Libraries/ActivityPub/Filters/ActivityPubFilter.php
index 7355941722e59413d99cc9bfcbc6e0f93c841c86..6eb5c4bf945a64c68217721583d4d95db31c6cb0 100644
--- a/app/Libraries/ActivityPub/Filters/ActivityPubFilter.php
+++ b/app/Libraries/ActivityPub/Filters/ActivityPubFilter.php
@@ -28,7 +28,7 @@ class ActivityPubFilter implements FilterInterface
      */
     public function before(RequestInterface $request, $params = null)
     {
-        if (empty($params)) {
+        if ($params === null) {
             return;
         }
 
@@ -40,8 +40,7 @@ class ActivityPubFilter implements FilterInterface
                 'application/activity+json',
             ];
 
-            if (empty($negotiate->media($allowedContentTypes))) {
-                // return $this->response->setStatusCode(415)->setJSON([]);
+            if ($negotiate->media($allowedContentTypes) === '') {
                 throw PageNotFoundException::forPageNotFound();
             }
         }
diff --git a/app/Libraries/ActivityPub/Helpers/activitypub_helper.php b/app/Libraries/ActivityPub/Helpers/activitypub_helper.php
index abb73622c8620cf44be6e63d0eef3e97646efbcb..167d9925e136d13fb2dbce8a36bf8a7a2673a039 100644
--- a/app/Libraries/ActivityPub/Helpers/activitypub_helper.php
+++ b/app/Libraries/ActivityPub/Helpers/activitypub_helper.php
@@ -361,6 +361,7 @@ if (!function_exists('linkify')) {
 
         // Extract text links for each protocol
         foreach ($protocols as $protocol) {
+            /** @phpstan-ignore-next-line */
             switch ($protocol) {
                 case 'http':
                 case 'https':
diff --git a/app/Libraries/ActivityPub/Models/NoteModel.php b/app/Libraries/ActivityPub/Models/NoteModel.php
index 01c098848216fd6120b59ff6c1a3c2348a61585f..037f34c22671a66a5a128368892c299555e45099 100644
--- a/app/Libraries/ActivityPub/Models/NoteModel.php
+++ b/app/Libraries/ActivityPub/Models/NoteModel.php
@@ -238,7 +238,7 @@ class NoteModel extends UuidModel
             $messageUrls = extract_urls_from_message($note->message);
 
             if (
-                !empty($messageUrls) &&
+                $messageUrls !== [] &&
                 ($previewCard = get_or_create_preview_card_from_url(
                     new URI($messageUrls[0]),
                 )) &&
diff --git a/app/Libraries/ActivityPub/Objects/ActorObject.php b/app/Libraries/ActivityPub/Objects/ActorObject.php
index 20cc9cb83d1f5135342f6dbede4a2dd9158b4cd4..21677056f928affd1daf58ea9c819127c5ff14ea 100644
--- a/app/Libraries/ActivityPub/Objects/ActorObject.php
+++ b/app/Libraries/ActivityPub/Objects/ActorObject.php
@@ -16,65 +16,34 @@ class ActorObject extends ObjectType
     /**
      * @var string|string[]
      */
-    protected $context = [
+    protected string|array $context = [
         'https://www.w3.org/ns/activitystreams',
         'https://w3id.org/security/v1',
     ];
 
-    /**
-     * @var string
-     */
-    protected $type = 'Person';
-
-    /**
-     * @var string
-     */
-    protected $name;
-
-    /**
-     * @var string
-     */
-    protected $preferredUsername;
-
-    /**
-     * @var string
-     */
-    protected $summary;
-
-    /**
-     * @var string
-     */
-    protected $inbox;
-
-    /**
-     * @var string
-     */
-    protected $outbox;
-
-    /**
-     * @var string
-     */
-    protected $followers;
-
-    /**
-     * @var string
-     */
-    protected $url;
+    protected string $type = 'Person';
+    protected string $name;
+    protected string $preferredUsername;
+    protected string $summary;
+    protected string $inbox;
+    protected string $outbox;
+    protected string $followers;
+    protected string $url;
 
     /**
-     * @var array<string, string>|null
+     * @var array<string, string>
      */
-    protected $image;
+    protected array $image = [];
 
     /**
      * @var array<string, string>
      */
-    protected $icon = [];
+    protected array $icon = [];
 
     /**
      * @var array<string, string>
      */
-    protected $publicKey = [];
+    protected array $publicKey = [];
 
     public function __construct(Actor $actor)
     {
diff --git a/app/Libraries/ActivityPub/Objects/NoteObject.php b/app/Libraries/ActivityPub/Objects/NoteObject.php
index 2a43392770b04cdec9089bbefece889b8b615634..b6ebbed7f9f39a36f57de6a5e3c07c3ad6ef9295 100644
--- a/app/Libraries/ActivityPub/Objects/NoteObject.php
+++ b/app/Libraries/ActivityPub/Objects/NoteObject.php
@@ -18,25 +18,10 @@ use ActivityPub\Core\ObjectType;
 
 class NoteObject extends ObjectType
 {
-    /**
-     * @var string
-     */
-    protected $type = 'Note';
-
-    /**
-     * @var string
-     */
-    protected $attributedTo;
-
-    /**
-     * @var string
-     */
-    protected $inReplyTo;
-
-    /**
-     * @var string
-     */
-    protected $replies;
+    protected string $type = 'Note';
+    protected string $attributedTo;
+    protected string $inReplyTo;
+    protected string $replies;
 
     public function __construct(Note $note)
     {
diff --git a/app/Libraries/ActivityPub/Objects/OrderedCollectionObject.php b/app/Libraries/ActivityPub/Objects/OrderedCollectionObject.php
index e407965a7e74724145ce8b6c93f8084eb53d6261..024ab7c06ab16a451a46fe444beca413e221c381 100644
--- a/app/Libraries/ActivityPub/Objects/OrderedCollectionObject.php
+++ b/app/Libraries/ActivityPub/Objects/OrderedCollectionObject.php
@@ -16,30 +16,11 @@ use ActivityPub\Core\ObjectType;
 
 class OrderedCollectionObject extends ObjectType
 {
-    /**
-     * @var string
-     */
-    protected $type = 'OrderedCollection';
-
-    /**
-     * @var integer
-     */
-    protected $totalItems;
-
-    /**
-     * @var string|null
-     */
-    protected $first;
-
-    /**
-     * @var string|null
-     */
-    protected $current;
-
-    /**
-     * @var string|null
-     */
-    protected $last;
+    protected string $type = 'OrderedCollection';
+    protected int $totalItems;
+    protected ?string $first;
+    protected ?string $current;
+    protected ?string $last;
 
     /**
      * @param ObjectType[] $orderedItems
diff --git a/app/Libraries/ActivityPub/Objects/OrderedCollectionPage.php b/app/Libraries/ActivityPub/Objects/OrderedCollectionPage.php
index dfa237d012ac07319d1968ab9893fd751f8fa8f2..89d950758c5d5761a7573c9030cd062fafcd4ecf 100644
--- a/app/Libraries/ActivityPub/Objects/OrderedCollectionPage.php
+++ b/app/Libraries/ActivityPub/Objects/OrderedCollectionPage.php
@@ -14,25 +14,10 @@ namespace ActivityPub\Objects;
 use CodeIgniter\Pager\Pager;
 class OrderedCollectionPage extends OrderedCollectionObject
 {
-    /**
-     * @var string
-     */
-    protected $type = 'OrderedCollectionPage';
-
-    /**
-     * @var string
-     */
-    protected $partOf;
-
-    /**
-     * @var string|null
-     */
-    protected $prev;
-
-    /**
-     * @var string|null
-     */
-    protected $next;
+    protected string $type = 'OrderedCollectionPage';
+    protected string $partOf;
+    protected ?string $prev;
+    protected ?string $next;
 
     public function __construct(Pager $pager, ?array $orderedItems = null)
     {
diff --git a/app/Libraries/ActivityPub/Objects/TombstoneObject.php b/app/Libraries/ActivityPub/Objects/TombstoneObject.php
index a29bdd7a075bae197c3c3238de956297bb798b22..5f4a5ea6407e1630b772b705aca7815b6fe78ba7 100644
--- a/app/Libraries/ActivityPub/Objects/TombstoneObject.php
+++ b/app/Libraries/ActivityPub/Objects/TombstoneObject.php
@@ -12,8 +12,5 @@ use ActivityPub\Core\ObjectType;
 
 class TombstoneObject extends ObjectType
 {
-    /**
-     * @var string
-     */
-    protected $type = 'Tombstone';
+    protected string $type = 'Tombstone';
 }
diff --git a/app/Libraries/ActivityPub/WebFinger.php b/app/Libraries/ActivityPub/WebFinger.php
index 09113f92896652f1ce55000d29242a2214bc7310..108564e35f4d5470b46cacee06e97139b0e89163 100644
--- a/app/Libraries/ActivityPub/WebFinger.php
+++ b/app/Libraries/ActivityPub/WebFinger.php
@@ -17,35 +17,20 @@ class WebFinger
      */
     const RESOURCE_PATTERN = '/^acct:(?P<username>([\w_]+))@(?P<domain>([\w\-\.]+[\w]+)(:[\d]+)?)$/x';
 
-    /**
-     * @var string
-     */
-    protected $username;
-
-    /**
-     * @var string
-     */
-    protected $domain;
-
-    /**
-     * @var string
-     */
-    protected $host;
-
-    /**
-     * @var string
-     */
-    protected $port;
+    protected string $username;
+    protected string $domain;
+    protected string $host;
+    protected string $port;
 
     /**
      * @var string[]
      */
-    protected $aliases = [];
+    protected array $aliases = [];
 
     /**
      * @var array<array<string, string>>
      */
-    protected $links = [];
+    protected array $links = [];
 
     public function __construct(protected string $subject)
     {
diff --git a/app/Libraries/Analytics/AnalyticsTrait.php b/app/Libraries/Analytics/AnalyticsTrait.php
index 0e05b9ed1ad4cdf400f7d70eececf963615da09f..3b9ac2096ba704a30f3d07f00a8915ab893c28c4 100644
--- a/app/Libraries/Analytics/AnalyticsTrait.php
+++ b/app/Libraries/Analytics/AnalyticsTrait.php
@@ -29,11 +29,12 @@ trait AnalyticsTrait
             $db = Database::connect();
 
             $referer = $session->get('referer');
-            $domain = empty(parse_url($referer, PHP_URL_HOST))
-                ? '- Direct -'
-                : parse_url($referer, PHP_URL_HOST);
+            $domain =
+                parse_url($referer, PHP_URL_HOST) === null
+                    ? '- Direct -'
+                    : parse_url($referer, PHP_URL_HOST);
             parse_str(parse_url($referer, PHP_URL_QUERY), $queries);
-            $keywords = empty($queries['q']) ? null : $queries['q'];
+            $keywords = array_key_exists('q', $queries) ? null : $queries['q'];
 
             $procedureName = $db->prefixTable('analytics_website');
             $db->query("call {$procedureName}(?,?,?,?,?,?)", [
diff --git a/app/Libraries/Analytics/Config/Analytics.php b/app/Libraries/Analytics/Config/Analytics.php
index 7b00ebb4f3b2a61eeb0f13bf3e92b5ee111b8028..f4e29c52867664e39e525b8caba5efac323bb08c 100644
--- a/app/Libraries/Analytics/Config/Analytics.php
+++ b/app/Libraries/Analytics/Config/Analytics.php
@@ -9,10 +9,8 @@ class Analytics extends BaseConfig
     /**
      * Gateway to analytic routes.
      * By default, all analytics routes will be under `/analytics` path
-     *
-     * @var string
      */
-    public $gateway = 'analytics';
+    public string $gateway = 'analytics';
 
     /**
      * --------------------------------------------------------------------
@@ -20,7 +18,7 @@ class Analytics extends BaseConfig
      * --------------------------------------------------------------------
      * @var array<string, string>
      */
-    public $routeFilters = [
+    public array $routeFilters = [
         'analytics-full-data' => '',
         'analytics-data' => '',
         'analytics-filtered-data' => '',
diff --git a/app/Libraries/Analytics/Controllers/AnalyticsController.php b/app/Libraries/Analytics/Controllers/AnalyticsController.php
index 40c0478338f9ff0a9f21a59cfffdaf64b752aaa3..63a062906a50b10ac83ac49da44c90f1cfc8c4d8 100644
--- a/app/Libraries/Analytics/Controllers/AnalyticsController.php
+++ b/app/Libraries/Analytics/Controllers/AnalyticsController.php
@@ -11,31 +11,25 @@ namespace Analytics\Controllers;
 use CodeIgniter\HTTP\ResponseInterface;
 use CodeIgniter\Exceptions\PageNotFoundException;
 use CodeIgniter\Controller;
+use CodeIgniter\Model;
 
 class AnalyticsController extends Controller
 {
-    /**
-     * @var string
-     */
-    protected $className;
-
-    /**
-     * @var string
-     */
-    protected $methodName;
+    protected Model $analyticsModel;
+    protected string $methodName = '';
 
     public function _remap(string $method, string ...$params): mixed
     {
-        if (!isset($params[1])) {
+        if (count($params) < 2) {
             throw PageNotFoundException::forPageNotFound();
         }
 
-        $this->className = model('Analytics' . $params[1] . 'Model');
-        $this->methodName = 'getData' . (empty($params[2]) ? '' : $params[2]);
+        $this->analyticsModel = model('Analytics' . $params[1] . 'Model');
+        $this->methodName = 'getData' . (count($params) >= 3 ? $params[2] : '');
 
         return $this->$method(
             $params[0],
-            isset($params[3]) ? $params[3] : null,
+            count($params) >= 4 ? $params[3] : null,
         );
     }
 
@@ -43,17 +37,16 @@ class AnalyticsController extends Controller
         int $podcastId,
         ?int $episodeId = null
     ): ResponseInterface {
-        $analyticsModel = new $this->className();
         $methodName = $this->methodName;
 
         if ($episodeId === null) {
             return $this->response->setJSON(
-                $analyticsModel->$methodName($podcastId),
+                $this->analyticsModel->$methodName($podcastId),
             );
         }
 
         return $this->response->setJSON(
-            $analyticsModel->$methodName($podcastId, $episodeId),
+            $this->analyticsModel->$methodName($podcastId, $episodeId),
         );
     }
 }
diff --git a/app/Libraries/Analytics/Controllers/EpisodeAnalyticsController.php b/app/Libraries/Analytics/Controllers/EpisodeAnalyticsController.php
index 5c02415e5ef5ca7a127af8e3ffcc10ae8944e7ae..5efab3ccb9ad55cfabf7b42585659d317795e908 100644
--- a/app/Libraries/Analytics/Controllers/EpisodeAnalyticsController.php
+++ b/app/Libraries/Analytics/Controllers/EpisodeAnalyticsController.php
@@ -27,10 +27,8 @@ class EpisodeAnalyticsController extends Controller
      */
     protected $helpers = ['analytics'];
 
-    /**
-     * @var Analytics
-     */
-    protected $config;
+    protected Analytics $config;
+
     /**
      * Constructor.
      */
@@ -65,7 +63,7 @@ class EpisodeAnalyticsController extends Controller
         $serviceName = '';
         if (isset($_GET['_from'])) {
             $serviceName = $_GET['_from'];
-        } elseif (!empty($session->get('embeddable_player_domain'))) {
+        } elseif ($session->get('embeddable_player_domain') !== null) {
             $serviceName = $session->get('embeddable_player_domain');
         } elseif ($session->get('referer') !== '- Direct -') {
             $serviceName = parse_url($session->get('referer'), PHP_URL_HOST);
diff --git a/app/Libraries/Analytics/Controllers/EpisodeController.php b/app/Libraries/Analytics/Controllers/EpisodeController.php
index ec531e16c08c8c59f78f6c7862cbf698802d192e..fe03ec5aa03c68294b04ca5e0e0a5c2dc5766ae8 100644
--- a/app/Libraries/Analytics/Controllers/EpisodeController.php
+++ b/app/Libraries/Analytics/Controllers/EpisodeController.php
@@ -22,15 +22,8 @@ class EpisodeController extends BaseController
 {
     use AnalyticsTrait;
 
-    /**
-     * @var Podcast
-     */
-    protected $podcast;
-
-    /**
-     * @var Episode
-     */
-    protected $episode;
+    protected Podcast $podcast;
+    protected Episode $episode;
 
     public function _remap(string $method, string ...$params): mixed
     {
diff --git a/app/Libraries/Analytics/Helpers/analytics_helper.php b/app/Libraries/Analytics/Helpers/analytics_helper.php
index ed2cec5f8a89395ef122ca03d4ca1643928861a6..02e5382c75bc97e33b4c0f51493e39cda0c876e1 100644
--- a/app/Libraries/Analytics/Helpers/analytics_helper.php
+++ b/app/Libraries/Analytics/Helpers/analytics_helper.php
@@ -1,6 +1,5 @@
 <?php
 
-use CodeIgniter\I18n\Time;
 use Config\Services;
 use Podlibre\Ipcat\IpDb;
 use GeoIp2\Database\Reader;
@@ -122,10 +121,10 @@ if (!function_exists('set_user_session_location')) {
                 $city = $cityReader->city($_SERVER['REMOTE_ADDR']);
 
                 $location = [
-                    'countryCode' => empty($city->country->isoCode)
+                    'countryCode' => $city->country->isoCode === null
                         ? 'N/A'
                         : $city->country->isoCode,
-                    'regionCode' => empty($city->subdivisions[0]->isoCode)
+                    'regionCode' => $city->subdivisions[0]->isoCode === null
                         ? 'N/A'
                         : $city->subdivisions[0]->isoCode,
                     'latitude' => round($city->location->latitude, 3),
@@ -330,10 +329,10 @@ if (!function_exists('podcast_hit')) {
                     $ranges = explode(',', substr($httpRange, 6));
                     foreach ($ranges as $range) {
                         $parts = explode('-', $range);
-                        $downloadedBytes += empty($parts[1])
+                        $downloadedBytes += array_key_exists(1, $parts)
                             ? $fileSize
                             : (int) $parts[1] -
-                                (empty($parts[0]) ? 0 : (int) $parts[0]);
+                                (array_key_exists(0, $parts) ? 0 : (int) $parts[0]);
                     }
                 }
                 // We save the number of downloaded bytes for this user and this episode:
diff --git a/app/Libraries/Breadcrumb.php b/app/Libraries/Breadcrumb.php
index 68d76bf0723f66ced5c26484a5f95f54d037800c..42682bfe52de1efcc987b57f5a6bb215b053d657 100644
--- a/app/Libraries/Breadcrumb.php
+++ b/app/Libraries/Breadcrumb.php
@@ -22,7 +22,7 @@ class Breadcrumb
      *
      * @var array<array<string, string>>
      */
-    protected $links = [];
+    protected array $links = [];
 
     /**
      * Initializes the Breadcrumb object using the segments from
diff --git a/app/Libraries/PodcastActor.php b/app/Libraries/PodcastActor.php
index e926e8232d478fb3532eae06616f79482ed0a79c..b419ac89ea338d93fb7cccc3d70b0ad59550b094 100644
--- a/app/Libraries/PodcastActor.php
+++ b/app/Libraries/PodcastActor.php
@@ -14,10 +14,7 @@ use App\Models\PodcastModel;
 
 class PodcastActor extends ActorObject
 {
-    /**
-     * @var string
-     */
-    protected $rss;
+    protected string $rss;
 
     public function __construct(Actor $actor)
     {
diff --git a/app/Libraries/Router.php b/app/Libraries/Router.php
index dc41fa9b2ca113e72a58ff37ef062a4f368cfae7..0eb7e0f8045eb7db2ab1906fba80a1709f8a41e2 100644
--- a/app/Libraries/Router.php
+++ b/app/Libraries/Router.php
@@ -36,7 +36,7 @@ class Router extends CodeIgniterRouter
         );
 
         // Don't waste any time
-        if (empty($routes)) {
+        if ($routes === []) {
             return false;
         }
 
@@ -178,10 +178,7 @@ class Router extends CodeIgniterRouter
                         str_replace('/', '\\', $replacekey),
                         $val,
                     );
-                } elseif (
-                    str_contains($val, '$') &&
-                    str_contains($key, '(')
-                ) {
+                } elseif (str_contains($val, '$') && str_contains($key, '(')) {
                     $val = preg_replace('#^' . $key . '$#u', $val, $uri);
                 } elseif (str_contains($val, '/')) {
                     [$controller, $method] = explode('::', $val);
diff --git a/app/Models/CategoryModel.php b/app/Models/CategoryModel.php
index d827fcd5f0f8dbe8e0206163d1d06dbdd99e457e..acf9793c5cbd47c16da3592655815210450c76c5 100644
--- a/app/Models/CategoryModel.php
+++ b/app/Models/CategoryModel.php
@@ -83,11 +83,11 @@ class CategoryModel extends Model
     /**
      * Sets categories for a given podcast
      *
-     * @param int[] $categories
+     * @param int[] $categoriesIds
      * 
      * @return int|false Number of rows inserted or FALSE on failure
      */
-    public function setPodcastCategories(int $podcastId, array $categories): int|false
+    public function setPodcastCategories(int $podcastId, array $categoriesIds = []): int|false
     {
         cache()->delete("podcast#{$podcastId}_categories");
 
@@ -96,14 +96,14 @@ class CategoryModel extends Model
             ->table('podcasts_categories')
             ->delete(['podcast_id' => $podcastId]);
 
-        if (empty($categories)) {
+        if ($categoriesIds === []) {
             // no row has been inserted after deletion
             return 0;
         }
 
         // prepare data for `podcasts_categories` table
         $data = array_reduce(
-            $categories,
+            $categoriesIds,
             function (array $result, int $categoryId) use ($podcastId): array {
                 $result[] = [
                     'podcast_id' => $podcastId,
diff --git a/app/Models/PersonModel.php b/app/Models/PersonModel.php
index d7ce0be846558616b492b3cddfc8a8da07ac5073..3aaf42eb07e2ba453d2ac2450b9869273af925cf 100644
--- a/app/Models/PersonModel.php
+++ b/app/Models/PersonModel.php
@@ -100,7 +100,7 @@ class PersonModel extends Model
     }
 
     /**
-     * @return stdClass[]
+     * @return object[]
      */
     public function getPersonRoles(int $personId, int $podcastId, ?int $episodeId): array {
         if ($episodeId) {
@@ -276,7 +276,7 @@ class PersonModel extends Model
      * Add persons to podcast
      *
      * @param array<string> $persons
-     * @param array<string, string> $groupsRoles
+     * @param array<string, string> $roles
      *
      * @return bool|int Number of rows inserted or FALSE on failure
      */
@@ -342,7 +342,7 @@ class PersonModel extends Model
         array $personIds,
         array $groupsRoles
     ): bool|int {
-        if (!empty($personIds)) {
+        if ($personIds !== []) {
             (new EpisodeModel())->clearCache(['id' => $episodeId]);
 
             $data = [];
diff --git a/app/Models/PodcastModel.php b/app/Models/PodcastModel.php
index dddcc5e095cc9d37ee2ba3672b20fa7af44a9e72..0f7fc221fc7843042d778a5a1f4b3d084cb08af3 100644
--- a/app/Models/PodcastModel.php
+++ b/app/Models/PodcastModel.php
@@ -93,29 +93,29 @@ class PodcastModel extends Model
         'created_by' => 'required',
         'updated_by' => 'required',
     ];
-    /**
-     * @var mixed[]
-     */
-    protected $validationMessages = [];
 
     /**
      * @var string[]
      */
     protected $beforeInsert = ['createPodcastActor'];
+
     /**
      * @var string[]
      */
     protected $afterInsert = ['setActorAvatar'];
+
     /**
      * @var string[]
      */
     protected $afterUpdate = ['updatePodcastActor'];
 
-    // clear cache before update if by any chance, the podcast name changes, so will the podcast link
     /**
+     * clear cache before update if by any chance, the podcast name changes, so will the podcast link
+     * 
      * @var string[]
      */
     protected $beforeUpdate = ['clearCache'];
+
     /**
      * @var string[]
      */
@@ -336,7 +336,7 @@ class PodcastModel extends Model
         if (!($defaultQuery = cache($cacheName))) {
             $seasons = $this->getSeasons($podcastId);
 
-            if (!empty($seasons)) {
+            if ($seasons !== []) {
                 // get latest season
                 $defaultQuery = ['type' => 'season', 'data' => end($seasons)];
             } else {
@@ -348,6 +348,34 @@ class PodcastModel extends Model
         }
         return $defaultQuery;
     }
+    /**
+     * @param mixed[] $data
+     *
+     * @return mixed[]
+     */
+    public function clearCache(array $data): array
+    {
+        $podcast = (new PodcastModel())->getPodcastById(
+            is_array($data['id']) ? $data['id'][0] : $data['id'],
+        );
+
+        // delete cache all podcast pages
+        cache()->deleteMatching("page_podcast#{$podcast->id}*");
+
+        // delete all cache for podcast actor
+        cache()->deleteMatching(
+            config('ActivityPub')->cachePrefix . "actor#{$podcast->actor_id}*",
+        );
+
+        // delete model requests cache, includes feed / query / episode lists, etc.
+        cache()->deleteMatching("podcast#{$podcast->id}*");
+        cache()->delete("podcast-{$podcast->name}");
+
+        // clear cache for every credit page
+        cache()->deleteMatching('page_credits_*');
+
+        return $data;
+    }
 
     /**
      * Creates an actor linked to the podcast
@@ -440,33 +468,4 @@ class PodcastModel extends Model
 
         return $data;
     }
-
-    /**
-     * @param mixed[] $data
-     *
-     * @return mixed[]
-     */
-    public function clearCache(array $data): array
-    {
-        $podcast = (new PodcastModel())->getPodcastById(
-            is_array($data['id']) ? $data['id'][0] : $data['id'],
-        );
-
-        // delete cache all podcast pages
-        cache()->deleteMatching("page_podcast#{$podcast->id}*");
-
-        // delete all cache for podcast actor
-        cache()->deleteMatching(
-            config('ActivityPub')->cachePrefix . "actor#{$podcast->actor_id}*",
-        );
-
-        // delete model requests cache, includes feed / query / episode lists, etc.
-        cache()->deleteMatching("podcast#{$podcast->id}*");
-        cache()->delete("podcast-{$podcast->name}");
-
-        // clear cache for every credit page
-        cache()->deleteMatching('page_credits_*');
-
-        return $data;
-    }
 }
diff --git a/app/Views/admin/episode/soundbites.php b/app/Views/admin/episode/soundbites.php
index 462fa1a05e0cfba164dd6faa7e9ba02770c30257..dc1c23629c722b5154be6094de6f88a7b45865b4 100644
--- a/app/Views/admin/episode/soundbites.php
+++ b/app/Views/admin/episode/soundbites.php
@@ -148,7 +148,6 @@
                 'data-soundbite-id' => '0',
                 'data-type' => 'soundbite-field',
                 'data-field-type' => 'duration',
-                'min' => '0',
             ],
         ) ?></td>
         <td class="px-1 py-4 font-medium bg-white border border-light-blue-500"><?= form_input(
diff --git a/app/Views/admin/person/list.php b/app/Views/admin/person/list.php
index 193eb7e8757cbb9e0cdde3ce329a39ad5f599e7a..d093e48298395aa68fc8caaff8a00a1aa8594d85 100644
--- a/app/Views/admin/person/list.php
+++ b/app/Views/admin/person/list.php
@@ -20,7 +20,7 @@
 <?= $this->section('content') ?>
 
 <div class="flex flex-wrap">
-    <?php if (!empty($persons)): ?>
+    <?php if ($persons !== null): ?>
         <?php foreach ($persons as $person): ?>
             <article class="w-48 h-full mb-4 mr-4 overflow-hidden bg-white border rounded shadow">
             <img
diff --git a/app/Views/admin/podcast/list.php b/app/Views/admin/podcast/list.php
index 5a22b06e5c90b8e9c23ead14cc36656b80079c46..d6f7af28f3ccaf3ede519440225cff61c9ce28d1 100644
--- a/app/Views/admin/podcast/list.php
+++ b/app/Views/admin/podcast/list.php
@@ -25,7 +25,7 @@
 <?= $this->section('content') ?>
 
 <div class="grid gap-4 grid-cols-podcasts">
-    <?php if (!empty($podcasts)): ?>
+    <?php if ($podcasts !== null): ?>
         <?php foreach ($podcasts as $podcast): ?>
             <article class="h-full overflow-hidden bg-white border shadow rounded-xl">
             <img
diff --git a/app/Views/credits.php b/app/Views/credits.php
index 34344e76d433ea80d998e3b59bb05c4392c23bcf..2fa3c2aef858c4a34dc84c9be2087b83bc39a888 100644
--- a/app/Views/credits.php
+++ b/app/Views/credits.php
@@ -22,7 +22,7 @@
                     <span class="text-lg font-semibold text-gray-700 md:text-xl">
                         <?= $persons['full_name'] ?>
                     </span>
-                    <?php if (!empty($persons['information_url'])): ?>
+                    <?php if ($persons['information_url'] !== null): ?>
                         <a href="<?= $persons[
                             'information_url'
                         ] ?>" class="text-sm text-blue-800 hover:underline" target="_blank" rel="noreferrer noopener"><?= $persons[
diff --git a/app/Views/errors/html/error_404.php b/app/Views/errors/html/error_404.php
index bee5dc32bb90dfa555e8925bbe7eb788dfa01ea1..d3e674ed3360e8d7150642344a89ef88c78039ae 100644
--- a/app/Views/errors/html/error_404.php
+++ b/app/Views/errors/html/error_404.php
@@ -13,7 +13,7 @@
     <h1 class="text-3xl font-bold font-display md:text-4xl lg:text-5xl">404 - File Not Found</h1>
 
     <p class="mb-6 text-lg text-gray-600 md:text-xl lg:text-2xl">
-        <?php if (!empty($message) && $message !== '(null)'): ?>
+        <?php if (isset($message) && $message !== '(null)'): ?>
             <?= esc($message) ?>
         <?php else: ?>
             Sorry! Cannot seem to find the page you were looking for.
diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php
index d8ef20ebc03a0bb2a49a67838f2393fe0ac70505..815f79904576e43b13ed1ef5ad18ed0e8a88206e 100644
--- a/app/Views/errors/html/error_exception.php
+++ b/app/Views/errors/html/error_exception.php
@@ -102,7 +102,7 @@ $errorId = uniqid('error', true);
 									&nbsp;&nbsp;&mdash;&nbsp;&nbsp;<?= esc(
              $row['class'] . $row['type'] . $row['function'],
          ) ?>
-									<?php if (!empty($row['args'])): ?>
+									<?php if (array_key_exists('args', $row)): ?>
 										<?php $argsId = $errorId . 'args' . $index; ?>
 										( <a href="#" onclick="return toggle('<?= esc(
               $argsId,
@@ -266,13 +266,9 @@ $errorId = uniqid('error', true);
 
 				<?php $empty = true; ?>
 				<?php foreach (['_GET', '_POST', '_COOKIE'] as $var): ?>
-
-					if (empty($GLOBALS[$var])) {
-					continue;
-					}
-					if (!is_array($GLOBALS[$var])) {
-					continue;
-					} ?>
+					<?php if (empty($GLOBALS[$var]) || !is_array($GLOBALS[$var])) {
+         continue;
+     } ?>
 
 					<?php $empty = false; ?>
 
@@ -358,7 +354,7 @@ $errorId = uniqid('error', true);
 				</table>
 
 				<?php $headers = $response->getHeaders(); ?>
-				<?php if (!empty($headers)): ?>
+				<?php if ($headers !== []): ?>
 					<?php natsort($headers); ?>
 
 					<h3>Headers</h3>
diff --git a/app/Views/install/instance_config.php b/app/Views/install/instance_config.php
index f9d1bc95c4593eeb503e705466c98accd99dbc2a..4b99ff8d2ea9f421cf494e45ee1ece3bc493cf22 100644
--- a/app/Views/install/instance_config.php
+++ b/app/Views/install/instance_config.php
@@ -17,7 +17,7 @@
     'class' => 'form-input mb-4',
     'value' => old(
         'hostname',
-        empty(host_url()) ? config('App')->baseURL : host_url(),
+        host_url( === null) ? config('App')->baseURL : host_url(),
     ),
     'required' => 'required',
 ]) ?>
diff --git a/app/Views/podcast/episode_authenticated.php b/app/Views/podcast/episode_authenticated.php
index 524caead656da4308710559d4275acf44f520a01..6813299e9f87c211a42e098b09b0e3a861736ce5 100644
--- a/app/Views/podcast/episode_authenticated.php
+++ b/app/Views/podcast/episode_authenticated.php
@@ -111,35 +111,8 @@
                         ],
                     ) ?>
                 </div>
-                <?php if ($episode->location !== null): ?>
-                    <?= location_link($episode->location, 'text-sm mb-4') ?>
-                <?php endif; ?>
-                <?php if ($episodePersons): ?>
-                    <div class="flex w-full space-x-2 overflow-y-auto">
-                        <?php foreach ($episodePersons as $person): ?>
-                            <?php if ($person['information_url']): ?>
-                                <a href="<?= $person[
-                                    'information_url'
-                                ] ?>" target="_blank" rel="noreferrer noopener" class="flex-shrink-0">
-                                    <img src="<?= $person[
-                                        'thumbnail_url'
-                                    ] ?>" alt="<?= $person[
-    'full_name'
-] ?>" class="object-cover w-12 h-12 rounded-full" data-toggle="tooltip" data-placement="bottom" title="[<?= $person[
-    'full_name'
-] ?>] <?= $person['roles'] ?>" /></a>
-                            <?php else: ?>
-                                <img src="<?= $person[
-                                    'thumbnail_url'
-                                ] ?>" alt="<?= $person[
-    'full_name'
-] ?>" class="object-cover w-12 h-12 rounded-full" data-toggle="tooltip" data-placement="bottom" title="[<?= $person[
-    'full_name'
-] ?>] <?= $person['roles'] ?>" />
-                            <?php endif; ?>
-                        <?php endforeach; ?>
-                    </div>
-                <?php endif; ?>
+                <?= location_link($episode->location, 'text-sm mb-4') ?>
+                <?= person_list($episode->persons) ?>
             </div>
         </div>
         <audio controls preload="none" class="w-full mt-auto">
diff --git a/composer.json b/composer.json
index 8431bdfe5c19d303773533fdcf52fa4b100e6c62..8fef2e877cfcb71b8cb75085ef27d680af59832e 100644
--- a/composer.json
+++ b/composer.json
@@ -31,7 +31,8 @@
     "captainhook/plugin-composer": "^5.2",
     "phpstan/phpstan": "^0.12.85",
     "phpstan/extension-installer": "^1.1.0",
-    "rector/rector-phpstan-rules": "^0.2.6"
+    "rector/rector-phpstan-rules": "^0.2.6",
+    "symplify/phpstan-extensions": "^9.3"
   },
   "autoload": {
     "psr-4": {
diff --git a/composer.lock b/composer.lock
index 16611f06cfa4bb3a36d90889a36727adc3060aac..79fe9eeebc0bcf4398eccc187f43126f7eadbbcd 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": "d5423c58c26549da4a5a20bfa4e65909",
+    "content-hash": "2aefa52a0dcd46108a616d943b4aa739",
     "packages": [
         {
             "name": "brick/math",
@@ -68,12 +68,12 @@
             "source": {
                 "type": "git",
                 "url": "https://github.com/codeigniter4/CodeIgniter4.git",
-                "reference": "43e0e9611b7e527a4b927127fc6f26a1c6d123a5"
+                "reference": "10067ebb5a4a148888e989ce8481df23589bc004"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/codeigniter4/CodeIgniter4/zipball/43e0e9611b7e527a4b927127fc6f26a1c6d123a5",
-                "reference": "43e0e9611b7e527a4b927127fc6f26a1c6d123a5",
+                "url": "https://api.github.com/repos/codeigniter4/CodeIgniter4/zipball/10067ebb5a4a148888e989ce8481df23589bc004",
+                "reference": "10067ebb5a4a148888e989ce8481df23589bc004",
                 "shasum": ""
             },
             "require": {
@@ -84,26 +84,19 @@
                 "kint-php/kint": "^3.3",
                 "laminas/laminas-escaper": "^2.6",
                 "php": "^7.3 || ^8.0",
-                "psr/cache": "^1.0",
-                "psr/log": "^1.1",
-                "psr/simple-cache": "^1.0"
-            },
-            "provide": {
-                "psr/cache-implementation": "^1.0",
-                "psr/simple-cache-implementation": "^1.0"
+                "psr/log": "^1.1"
             },
             "require-dev": {
-                "cache/integration-tests": "^0.17.0",
                 "codeigniter4/codeigniter4-standard": "^1.0",
                 "fakerphp/faker": "^1.9",
                 "mikey179/vfsstream": "^1.6",
                 "nexusphp/tachycardia": "^1.0",
-                "nikic/php-parser": "4.10.4",
-                "phpstan/phpstan": "0.12.85",
+                "phpstan/phpstan": "0.12.86",
                 "phpunit/phpunit": "^9.1",
                 "predis/predis": "^1.1",
-                "rector/rector": "0.10.22",
-                "squizlabs/php_codesniffer": "^3.3"
+                "rector/rector": "0.11.2",
+                "squizlabs/php_codesniffer": "^3.3",
+                "symplify/package-builder": "^9.3"
             },
             "suggest": {
                 "ext-fileinfo": "Improves mime type detection for files"
@@ -152,7 +145,7 @@
                 "slack": "https://codeigniterchat.slack.com",
                 "issues": "https://github.com/codeigniter4/CodeIgniter4/issues"
             },
-            "time": "2021-05-13T17:30:38+00:00"
+            "time": "2021-05-18T02:06:22+00:00"
         },
         {
             "name": "composer/ca-bundle",
@@ -1196,12 +1189,12 @@
             "source": {
                 "type": "git",
                 "url": "https://github.com/lonnieezell/myth-auth.git",
-                "reference": "c7f79d1b938e371cfafdc7e3c59c810f2c672727"
+                "reference": "d3df41fb24b19c1362a163da4167b07efcff69e4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/lonnieezell/myth-auth/zipball/c7f79d1b938e371cfafdc7e3c59c810f2c672727",
-                "reference": "c7f79d1b938e371cfafdc7e3c59c810f2c672727",
+                "url": "https://api.github.com/repos/lonnieezell/myth-auth/zipball/d3df41fb24b19c1362a163da4167b07efcff69e4",
+                "reference": "d3df41fb24b19c1362a163da4167b07efcff69e4",
                 "shasum": ""
             },
             "require": {
@@ -1262,7 +1255,7 @@
                     "type": "patreon"
                 }
             ],
-            "time": "2021-05-13T18:19:37+00:00"
+            "time": "2021-05-15T03:29:54+00:00"
         },
         {
             "name": "opawg/user-agents-php",
@@ -1646,57 +1639,6 @@
             },
             "time": "2021-05-03T11:20:27+00:00"
         },
-        {
-            "name": "psr/simple-cache",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-fig/simple-cache.git",
-                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
-                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Psr\\SimpleCache\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
-                }
-            ],
-            "description": "Common interfaces for simple caching",
-            "keywords": [
-                "cache",
-                "caching",
-                "psr",
-                "psr-16",
-                "simple-cache"
-            ],
-            "support": {
-                "source": "https://github.com/php-fig/simple-cache/tree/master"
-            },
-            "time": "2017-10-23T01:57:42+00:00"
-        },
         {
             "name": "ramsey/collection",
             "version": "1.1.3",
@@ -2256,16 +2198,16 @@
     "packages-dev": [
         {
             "name": "captainhook/captainhook",
-            "version": "5.9.0",
+            "version": "5.10.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/captainhookphp/captainhook.git",
-                "reference": "76987f60c5c77d106ec6b589e4d658d7a2a7d6f5"
+                "reference": "2ee0cc1e356b95b3482be304bb31c68fe72d8ad6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/captainhookphp/captainhook/zipball/76987f60c5c77d106ec6b589e4d658d7a2a7d6f5",
-                "reference": "76987f60c5c77d106ec6b589e4d658d7a2a7d6f5",
+                "url": "https://api.github.com/repos/captainhookphp/captainhook/zipball/2ee0cc1e356b95b3482be304bb31c68fe72d8ad6",
+                "reference": "2ee0cc1e356b95b3482be304bb31c68fe72d8ad6",
                 "shasum": ""
             },
             "require": {
@@ -2327,7 +2269,7 @@
             ],
             "support": {
                 "issues": "https://github.com/captainhookphp/captainhook/issues",
-                "source": "https://github.com/captainhookphp/captainhook/tree/5.9.0"
+                "source": "https://github.com/captainhookphp/captainhook/tree/5.10.0"
             },
             "funding": [
                 {
@@ -2335,7 +2277,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-05-05T12:43:16+00:00"
+            "time": "2021-05-15T12:39:06+00:00"
         },
         {
             "name": "captainhook/plugin-composer",
@@ -4893,16 +4835,16 @@
         },
         {
             "name": "rector/rector-phpstan-rules",
-            "version": "0.2.8",
+            "version": "0.2.9",
             "source": {
                 "type": "git",
                 "url": "https://github.com/rectorphp/phpstan-rules.git",
-                "reference": "765d8bf702a3928a155be02d3b7413a16b46bf95"
+                "reference": "c53f5fad720fba2c13ab09d885f7be006523458f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/rectorphp/phpstan-rules/zipball/765d8bf702a3928a155be02d3b7413a16b46bf95",
-                "reference": "765d8bf702a3928a155be02d3b7413a16b46bf95",
+                "url": "https://api.github.com/repos/rectorphp/phpstan-rules/zipball/c53f5fad720fba2c13ab09d885f7be006523458f",
+                "reference": "c53f5fad720fba2c13ab09d885f7be006523458f",
                 "shasum": ""
             },
             "require": {
@@ -4914,8 +4856,8 @@
             "require-dev": {
                 "phpstan/extension-installer": "^1.1",
                 "phpunit/phpunit": "^9.5",
-                "symplify/easy-coding-standard": "^9.2.22",
-                "symplify/phpstan-extensions": "^9.2.22"
+                "symplify/easy-coding-standard": "^9.3",
+                "symplify/phpstan-extensions": "^9.3"
             },
             "type": "phpstan-extension",
             "extra": {
@@ -4937,9 +4879,9 @@
             "description": "PHPStan rules for Rector projects - with focus on static reflection, constant re-use and Rector design patterns",
             "support": {
                 "issues": "https://github.com/rectorphp/phpstan-rules/issues",
-                "source": "https://github.com/rectorphp/phpstan-rules/tree/0.2.8"
+                "source": "https://github.com/rectorphp/phpstan-rules/tree/0.2.9"
             },
-            "time": "2021-05-14T08:39:51+00:00"
+            "time": "2021-05-15T10:37:29+00:00"
         },
         {
             "name": "rector/rector-phpunit",
@@ -7755,16 +7697,16 @@
         },
         {
             "name": "symplify/astral",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/astral.git",
-                "reference": "4934e1f0fef054051441db7ecaa267bd80231e4f"
+                "reference": "8b704cb02702e8519a404aa775ef4d53c4c74037"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/astral/zipball/4934e1f0fef054051441db7ecaa267bd80231e4f",
-                "reference": "4934e1f0fef054051441db7ecaa267bd80231e4f",
+                "url": "https://api.github.com/repos/symplify/astral/zipball/8b704cb02702e8519a404aa775ef4d53c4c74037",
+                "reference": "8b704cb02702e8519a404aa775ef4d53c4c74037",
                 "shasum": ""
             },
             "require": {
@@ -7773,12 +7715,12 @@
                 "php": ">=7.3",
                 "symfony/dependency-injection": "^5.2",
                 "symfony/http-kernel": "^4.4|^5.2",
-                "symplify/autowire-array-parameter": "^9.3.11",
-                "symplify/package-builder": "^9.3.11"
+                "symplify/autowire-array-parameter": "^9.3.12",
+                "symplify/package-builder": "^9.3.12"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.5",
-                "symplify/easy-testing": "^9.3.11"
+                "symplify/easy-testing": "^9.3.12"
             },
             "type": "library",
             "extra": {
@@ -7797,7 +7739,7 @@
             ],
             "description": "Toolking for smart daily work with AST",
             "support": {
-                "source": "https://github.com/symplify/astral/tree/v9.3.11"
+                "source": "https://github.com/symplify/astral/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -7809,27 +7751,27 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-05-13T11:33:59+00:00"
+            "time": "2021-05-17T20:54:14+00:00"
         },
         {
             "name": "symplify/autowire-array-parameter",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/autowire-array-parameter.git",
-                "reference": "269fcb76ed64ca1e9dd0abe6c13273be8dfba64c"
+                "reference": "7fb6af895aacb9dbd48eaa24c0d9dc3294a82068"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/autowire-array-parameter/zipball/269fcb76ed64ca1e9dd0abe6c13273be8dfba64c",
-                "reference": "269fcb76ed64ca1e9dd0abe6c13273be8dfba64c",
+                "url": "https://api.github.com/repos/symplify/autowire-array-parameter/zipball/7fb6af895aacb9dbd48eaa24c0d9dc3294a82068",
+                "reference": "7fb6af895aacb9dbd48eaa24c0d9dc3294a82068",
                 "shasum": ""
             },
             "require": {
                 "nette/utils": "^3.2",
                 "php": ">=7.3",
                 "symfony/dependency-injection": "^5.2",
-                "symplify/package-builder": "^9.3.11"
+                "symplify/package-builder": "^9.3.12"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.5"
@@ -7851,7 +7793,7 @@
             ],
             "description": "Autowire array parameters for your Symfony applications",
             "support": {
-                "source": "https://github.com/symplify/autowire-array-parameter/tree/v9.3.11"
+                "source": "https://github.com/symplify/autowire-array-parameter/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -7863,20 +7805,20 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-05-13T11:33:56+00:00"
+            "time": "2021-05-17T20:54:14+00:00"
         },
         {
             "name": "symplify/composer-json-manipulator",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/composer-json-manipulator.git",
-                "reference": "87a675a761aa5df90f5d5cf2c7d49d1e7e7a91be"
+                "reference": "932727993137ac6be539cb637590b0b487111924"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/composer-json-manipulator/zipball/87a675a761aa5df90f5d5cf2c7d49d1e7e7a91be",
-                "reference": "87a675a761aa5df90f5d5cf2c7d49d1e7e7a91be",
+                "url": "https://api.github.com/repos/symplify/composer-json-manipulator/zipball/932727993137ac6be539cb637590b0b487111924",
+                "reference": "932727993137ac6be539cb637590b0b487111924",
                 "shasum": ""
             },
             "require": {
@@ -7886,8 +7828,8 @@
                 "symfony/dependency-injection": "^5.2",
                 "symfony/filesystem": "^4.4|^5.2",
                 "symfony/http-kernel": "^4.4|^5.2",
-                "symplify/package-builder": "^9.3.11",
-                "symplify/smart-file-system": "^9.3.11"
+                "symplify/package-builder": "^9.3.12",
+                "symplify/smart-file-system": "^9.3.12"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.5"
@@ -7909,7 +7851,7 @@
             ],
             "description": "Package to load, merge and save composer.json file(s)",
             "support": {
-                "source": "https://github.com/symplify/composer-json-manipulator/tree/v9.3.11"
+                "source": "https://github.com/symplify/composer-json-manipulator/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -7921,20 +7863,20 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-05-13T11:33:58+00:00"
+            "time": "2021-05-17T20:54:16+00:00"
         },
         {
             "name": "symplify/console-color-diff",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/console-color-diff.git",
-                "reference": "7b97c8e124eb790a24b2e3319e3795abeffef557"
+                "reference": "e6b1e2179b0dbd38f0f324c6a0c8f8ca2114b5f9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/console-color-diff/zipball/7b97c8e124eb790a24b2e3319e3795abeffef557",
-                "reference": "7b97c8e124eb790a24b2e3319e3795abeffef557",
+                "url": "https://api.github.com/repos/symplify/console-color-diff/zipball/e6b1e2179b0dbd38f0f324c6a0c8f8ca2114b5f9",
+                "reference": "e6b1e2179b0dbd38f0f324c6a0c8f8ca2114b5f9",
                 "shasum": ""
             },
             "require": {
@@ -7944,7 +7886,7 @@
                 "symfony/console": "^4.4|^5.2",
                 "symfony/dependency-injection": "^5.2",
                 "symfony/http-kernel": "^4.4|^5.2",
-                "symplify/package-builder": "^9.3.11"
+                "symplify/package-builder": "^9.3.12"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.5"
@@ -7966,7 +7908,7 @@
             ],
             "description": "Package to print diffs in console with colors",
             "support": {
-                "source": "https://github.com/symplify/console-color-diff/tree/v9.3.11"
+                "source": "https://github.com/symplify/console-color-diff/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -7978,32 +7920,32 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-05-13T11:34:04+00:00"
+            "time": "2021-05-17T20:54:14+00:00"
         },
         {
             "name": "symplify/console-package-builder",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/console-package-builder.git",
-                "reference": "4fd36633c3607f74a21eee5bd32c00f24130261f"
+                "reference": "f6c964c83de064b5c4fd6fc238bec75fbcd20221"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/console-package-builder/zipball/4fd36633c3607f74a21eee5bd32c00f24130261f",
-                "reference": "4fd36633c3607f74a21eee5bd32c00f24130261f",
+                "url": "https://api.github.com/repos/symplify/console-package-builder/zipball/f6c964c83de064b5c4fd6fc238bec75fbcd20221",
+                "reference": "f6c964c83de064b5c4fd6fc238bec75fbcd20221",
                 "shasum": ""
             },
             "require": {
                 "php": ">=7.3",
                 "symfony/console": "^4.4|^5.2",
                 "symfony/dependency-injection": "^5.2",
-                "symplify/symplify-kernel": "^9.3.11"
+                "symplify/symplify-kernel": "^9.3.12"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.5",
                 "symfony/http-kernel": "^4.4|^5.2",
-                "symplify/package-builder": "^9.3.11"
+                "symplify/package-builder": "^9.3.12"
             },
             "type": "library",
             "extra": {
@@ -8022,22 +7964,22 @@
             ],
             "description": "Package to speed up building command line applications",
             "support": {
-                "source": "https://github.com/symplify/console-package-builder/tree/v9.3.11"
+                "source": "https://github.com/symplify/console-package-builder/tree/v9.3.12"
             },
-            "time": "2021-05-13T11:33:59+00:00"
+            "time": "2021-05-17T20:54:15+00:00"
         },
         {
             "name": "symplify/easy-testing",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/easy-testing.git",
-                "reference": "5662ac6e55dca7d7ae7df0b47e84a165573359ed"
+                "reference": "f2a0e79a3893920b56dce110fb684c1760db8a74"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/easy-testing/zipball/5662ac6e55dca7d7ae7df0b47e84a165573359ed",
-                "reference": "5662ac6e55dca7d7ae7df0b47e84a165573359ed",
+                "url": "https://api.github.com/repos/symplify/easy-testing/zipball/f2a0e79a3893920b56dce110fb684c1760db8a74",
+                "reference": "f2a0e79a3893920b56dce110fb684c1760db8a74",
                 "shasum": ""
             },
             "require": {
@@ -8047,10 +7989,10 @@
                 "symfony/dependency-injection": "^5.2",
                 "symfony/finder": "^4.4|^5.2",
                 "symfony/http-kernel": "^4.4|^5.2",
-                "symplify/console-package-builder": "^9.3.11",
-                "symplify/package-builder": "^9.3.11",
-                "symplify/smart-file-system": "^9.3.11",
-                "symplify/symplify-kernel": "^9.3.11"
+                "symplify/console-package-builder": "^9.3.12",
+                "symplify/package-builder": "^9.3.12",
+                "symplify/smart-file-system": "^9.3.12",
+                "symplify/symplify-kernel": "^9.3.12"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.5"
@@ -8075,7 +8017,7 @@
             ],
             "description": "Testing made easy",
             "support": {
-                "source": "https://github.com/symplify/easy-testing/tree/v9.3.11"
+                "source": "https://github.com/symplify/easy-testing/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -8087,20 +8029,20 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-05-13T11:34:12+00:00"
+            "time": "2021-05-17T20:54:29+00:00"
         },
         {
             "name": "symplify/package-builder",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/package-builder.git",
-                "reference": "479752e9b19efbd0470aba8e92b9d6a01722430b"
+                "reference": "748eade6acc32798013e41203ab362f6ce77a024"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/package-builder/zipball/479752e9b19efbd0470aba8e92b9d6a01722430b",
-                "reference": "479752e9b19efbd0470aba8e92b9d6a01722430b",
+                "url": "https://api.github.com/repos/symplify/package-builder/zipball/748eade6acc32798013e41203ab362f6ce77a024",
+                "reference": "748eade6acc32798013e41203ab362f6ce77a024",
                 "shasum": ""
             },
             "require": {
@@ -8112,8 +8054,8 @@
                 "symfony/dependency-injection": "^5.2",
                 "symfony/finder": "^4.4|^5.2",
                 "symfony/http-kernel": "^4.4|^5.2",
-                "symplify/easy-testing": "^9.3.11",
-                "symplify/symplify-kernel": "^9.3.11"
+                "symplify/easy-testing": "^9.3.12",
+                "symplify/symplify-kernel": "^9.3.12"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.5"
@@ -8135,7 +8077,67 @@
             ],
             "description": "Dependency Injection, Console and Kernel toolkit for Symplify packages.",
             "support": {
-                "source": "https://github.com/symplify/package-builder/tree/v9.3.11"
+                "source": "https://github.com/symplify/package-builder/tree/v9.3.12"
+            },
+            "funding": [
+                {
+                    "url": "https://www.paypal.me/rectorphp",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/tomasvotruba",
+                    "type": "github"
+                }
+            ],
+            "time": "2021-05-17T20:54:52+00:00"
+        },
+        {
+            "name": "symplify/phpstan-extensions",
+            "version": "v9.3.12",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symplify/phpstan-extensions.git",
+                "reference": "21a5766407aba2013b65da53020dfc7fdc7fb495"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symplify/phpstan-extensions/zipball/21a5766407aba2013b65da53020dfc7fdc7fb495",
+                "reference": "21a5766407aba2013b65da53020dfc7fdc7fb495",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.3",
+                "phpstan/phpstan": "0.12.86",
+                "symplify/astral": "^9.3.12",
+                "symplify/package-builder": "^9.3.12",
+                "symplify/smart-file-system": "^9.3.12"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.5"
+            },
+            "type": "phpstan-extension",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "9.4-dev"
+                },
+                "phpstan": {
+                    "includes": [
+                        "config/config.neon"
+                    ]
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symplify\\PHPStanExtensions\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Pre-escaped error messages in 'symplify' error format, container aware test case and other useful extensions for PHPStan",
+            "support": {
+                "source": "https://github.com/symplify/phpstan-extensions/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -8147,20 +8149,20 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-05-13T11:34:38+00:00"
+            "time": "2021-05-17T20:54:58+00:00"
         },
         {
             "name": "symplify/phpstan-rules",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/phpstan-rules.git",
-                "reference": "e556dc413fc10804706d57b324e9aa14513c5f57"
+                "reference": "420dd5876ce7374e403f0a8b1d798ea22676e601"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/phpstan-rules/zipball/e556dc413fc10804706d57b324e9aa14513c5f57",
-                "reference": "e556dc413fc10804706d57b324e9aa14513c5f57",
+                "url": "https://api.github.com/repos/symplify/phpstan-rules/zipball/420dd5876ce7374e403f0a8b1d798ea22676e601",
+                "reference": "420dd5876ce7374e403f0a8b1d798ea22676e601",
                 "shasum": ""
             },
             "require": {
@@ -8169,11 +8171,11 @@
                 "php": ">=7.3",
                 "phpstan/phpdoc-parser": "^0.5",
                 "phpstan/phpstan": "0.12.86",
-                "symplify/astral": "^9.3.11",
-                "symplify/composer-json-manipulator": "^9.3.11",
-                "symplify/package-builder": "^9.3.11",
-                "symplify/rule-doc-generator-contracts": "^9.3.11",
-                "symplify/smart-file-system": "^9.3.11",
+                "symplify/astral": "^9.3.12",
+                "symplify/composer-json-manipulator": "^9.3.12",
+                "symplify/package-builder": "^9.3.12",
+                "symplify/rule-doc-generator-contracts": "^9.3.12",
+                "symplify/smart-file-system": "^9.3.12",
                 "webmozart/assert": "^1.9"
             },
             "require-dev": {
@@ -8181,9 +8183,9 @@
                 "nette/forms": "^3.1",
                 "phpunit/phpunit": "^9.5",
                 "symfony/framework-bundle": "^4.4|^5.2",
-                "symplify/easy-testing": "^9.3.11",
-                "symplify/phpstan-extensions": "^9.3.11",
-                "symplify/rule-doc-generator": "^9.3.11"
+                "symplify/easy-testing": "^9.3.12",
+                "symplify/phpstan-extensions": "^9.3.12",
+                "symplify/rule-doc-generator": "^9.3.12"
             },
             "type": "phpstan-extension",
             "extra": {
@@ -8211,7 +8213,7 @@
             ],
             "description": "Set of Symplify rules for PHPStan",
             "support": {
-                "source": "https://github.com/symplify/phpstan-rules/tree/v9.3.11"
+                "source": "https://github.com/symplify/phpstan-rules/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -8223,11 +8225,11 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-05-13T11:34:44+00:00"
+            "time": "2021-05-17T20:54:27+00:00"
         },
         {
             "name": "symplify/rule-doc-generator-contracts",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/rule-doc-generator-contracts.git",
@@ -8260,7 +8262,7 @@
             ],
             "description": "Contracts for production code of RuleDocGenerator",
             "support": {
-                "source": "https://github.com/symplify/rule-doc-generator-contracts/tree/v9.3.11"
+                "source": "https://github.com/symplify/rule-doc-generator-contracts/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -8276,16 +8278,16 @@
         },
         {
             "name": "symplify/set-config-resolver",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/set-config-resolver.git",
-                "reference": "cced883469d32b45f83471c17443faf18a3c2e75"
+                "reference": "d20fd0d7ad5ca57747299666e934d3868ecfe620"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/set-config-resolver/zipball/cced883469d32b45f83471c17443faf18a3c2e75",
-                "reference": "cced883469d32b45f83471c17443faf18a3c2e75",
+                "url": "https://api.github.com/repos/symplify/set-config-resolver/zipball/d20fd0d7ad5ca57747299666e934d3868ecfe620",
+                "reference": "d20fd0d7ad5ca57747299666e934d3868ecfe620",
                 "shasum": ""
             },
             "require": {
@@ -8296,8 +8298,8 @@
                 "symfony/dependency-injection": "^5.2",
                 "symfony/filesystem": "^4.4|^5.2",
                 "symfony/finder": "^4.4|^5.2",
-                "symplify/smart-file-system": "^9.3.11",
-                "symplify/symplify-kernel": "^9.3.11"
+                "symplify/smart-file-system": "^9.3.12",
+                "symplify/symplify-kernel": "^9.3.12"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.5"
@@ -8319,7 +8321,7 @@
             ],
             "description": "Resolve config and sets from configs and cli opptions for CLI applications",
             "support": {
-                "source": "https://github.com/symplify/set-config-resolver/tree/v9.3.11"
+                "source": "https://github.com/symplify/set-config-resolver/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -8331,20 +8333,21 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-05-13T11:34:45+00:00"
+            "abandoned": true,
+            "time": "2021-05-17T20:55:05+00:00"
         },
         {
             "name": "symplify/simple-php-doc-parser",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/simple-php-doc-parser.git",
-                "reference": "e70450dfaa94db70e34a4d2252891a43bc57f956"
+                "reference": "09478c31e9cd0cecedf6c82c13901d661318ab6a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/simple-php-doc-parser/zipball/e70450dfaa94db70e34a4d2252891a43bc57f956",
-                "reference": "e70450dfaa94db70e34a4d2252891a43bc57f956",
+                "url": "https://api.github.com/repos/symplify/simple-php-doc-parser/zipball/09478c31e9cd0cecedf6c82c13901d661318ab6a",
+                "reference": "09478c31e9cd0cecedf6c82c13901d661318ab6a",
                 "shasum": ""
             },
             "require": {
@@ -8353,11 +8356,11 @@
                 "symfony/config": "^4.4|^5.2",
                 "symfony/dependency-injection": "^5.2",
                 "symfony/http-kernel": "^4.4|^5.2",
-                "symplify/package-builder": "^9.3.11"
+                "symplify/package-builder": "^9.3.12"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.5",
-                "symplify/easy-testing": "^9.3.11"
+                "symplify/easy-testing": "^9.3.12"
             },
             "type": "library",
             "extra": {
@@ -8376,7 +8379,7 @@
             ],
             "description": "Service integration of phpstan/phpdoc-parser, with few extra goodies for practical simple use",
             "support": {
-                "source": "https://github.com/symplify/simple-php-doc-parser/tree/v9.3.11"
+                "source": "https://github.com/symplify/simple-php-doc-parser/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -8388,20 +8391,20 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-05-13T11:34:46+00:00"
+            "time": "2021-05-17T20:55:06+00:00"
         },
         {
             "name": "symplify/skipper",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/skipper.git",
-                "reference": "3b446ce9c78f0d455788d9bfd92915eac6da1054"
+                "reference": "6124002225f261d865ce9df2bf68bc8d58c6b0b3"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/skipper/zipball/3b446ce9c78f0d455788d9bfd92915eac6da1054",
-                "reference": "3b446ce9c78f0d455788d9bfd92915eac6da1054",
+                "url": "https://api.github.com/repos/symplify/skipper/zipball/6124002225f261d865ce9df2bf68bc8d58c6b0b3",
+                "reference": "6124002225f261d865ce9df2bf68bc8d58c6b0b3",
                 "shasum": ""
             },
             "require": {
@@ -8411,9 +8414,9 @@
                 "symfony/dependency-injection": "^5.2",
                 "symfony/filesystem": "^4.4|^5.2",
                 "symfony/finder": "^4.4|^5.2",
-                "symplify/package-builder": "^9.3.11",
-                "symplify/smart-file-system": "^9.3.11",
-                "symplify/symplify-kernel": "^9.3.11"
+                "symplify/package-builder": "^9.3.12",
+                "symplify/smart-file-system": "^9.3.12",
+                "symplify/symplify-kernel": "^9.3.12"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.5"
@@ -8435,7 +8438,7 @@
             ],
             "description": "Skip files by rule class, directory, file or fnmatch",
             "support": {
-                "source": "https://github.com/symplify/skipper/tree/v9.3.11"
+                "source": "https://github.com/symplify/skipper/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -8447,11 +8450,11 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-05-13T11:34:52+00:00"
+            "time": "2021-05-17T20:55:10+00:00"
         },
         {
             "name": "symplify/smart-file-system",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/smart-file-system.git",
@@ -8490,7 +8493,7 @@
             ],
             "description": "Sanitized FileInfo with safe getRealPath() and other handy methods",
             "support": {
-                "source": "https://github.com/symplify/smart-file-system/tree/v9.3.11"
+                "source": "https://github.com/symplify/smart-file-system/tree/v9.3.12"
             },
             "funding": [
                 {
@@ -8552,16 +8555,16 @@
         },
         {
             "name": "symplify/symplify-kernel",
-            "version": "v9.3.11",
+            "version": "v9.3.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symplify/symplify-kernel.git",
-                "reference": "d79a26c90ebd292d8b474dbee26b602379be3f66"
+                "reference": "213455059541e8a707b716c5759982876e4e1118"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symplify/symplify-kernel/zipball/d79a26c90ebd292d8b474dbee26b602379be3f66",
-                "reference": "d79a26c90ebd292d8b474dbee26b602379be3f66",
+                "url": "https://api.github.com/repos/symplify/symplify-kernel/zipball/213455059541e8a707b716c5759982876e4e1118",
+                "reference": "213455059541e8a707b716c5759982876e4e1118",
                 "shasum": ""
             },
             "require": {
@@ -8569,10 +8572,10 @@
                 "symfony/console": "^4.4|^5.2",
                 "symfony/dependency-injection": "^5.2",
                 "symfony/http-kernel": "^4.4|^5.2",
-                "symplify/autowire-array-parameter": "^9.3.11",
-                "symplify/composer-json-manipulator": "^9.3.11",
-                "symplify/package-builder": "^9.3.11",
-                "symplify/smart-file-system": "^9.3.11"
+                "symplify/autowire-array-parameter": "^9.3.12",
+                "symplify/composer-json-manipulator": "^9.3.12",
+                "symplify/package-builder": "^9.3.12",
+                "symplify/smart-file-system": "^9.3.12"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.5"
@@ -8594,9 +8597,9 @@
             ],
             "description": "Internal Kernel for Symplify packages",
             "support": {
-                "source": "https://github.com/symplify/symplify-kernel/tree/v9.3.11"
+                "source": "https://github.com/symplify/symplify-kernel/tree/v9.3.12"
             },
-            "time": "2021-05-13T11:35:17+00:00"
+            "time": "2021-05-17T20:54:52+00:00"
         },
         {
             "name": "theseer/tokenizer",
diff --git a/phpstan.neon b/phpstan.neon
index e90f864fe3b742391c36cb27adb7f3e528e4d2c7..b1b1936e940415115d8d77e9832553be091395d0 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -3,7 +3,7 @@ parameters:
     level: 6
     paths:
         - app
-        # - tests
+        - tests
     bootstrapFiles:
         - vendor/codeigniter4/codeigniter4/system/Test/bootstrap.php
     scanDirectories:
@@ -17,9 +17,8 @@ parameters:
         - app/Libraries/Analytics/Config/Routes.php
         - app/Views/*
     ignoreErrors:
+        - '#Access to property [\$a-zA-z]+ on an unknown class Myth\\Auth\\Controllers\\Auth.#'
         - '#This property type might be inlined to PHP. Do you have confidence it is correct\? Put it here#'
-        - '#Function \"preg_.*\(\)\" cannot be used/left in the code#'
-        - '#.* is forbidden to use#'
         - '#^Cognitive complexity for#'
         - '#^Class cognitive complexity is#'
         - '#Do not use chained method calls. Put each on separated lines.#'
@@ -28,12 +27,11 @@ parameters:
         - '#^Call to an undefined method CodeIgniter\\Database\\BaseBuilder#'
         - '#^Call to an undefined method CodeIgniter\\Database\\ConnectionInterface#'
         - '#Access to an undefined property CodeIgniter\\Database\\BaseBuilder::\$pager#'
+        - '#Function \"preg_.*\(\)\" cannot be used/left in the code#'
+        - '#Function "property_exists\(\)" cannot be used/left in the code#'
         -
             message: '#Function "function_exists\(\)" cannot be used/left in the code#'
             paths:
                 - app/Helpers
                 - app/Libraries/ActivityPub/Helpers
                 - app/Libraries/Analytics/Helpers
-        -
-            message: '#Function "property_exists\(\)" cannot be used/left in the code#'
-            path: app/Libraries/ActivityPub/Helpers
diff --git a/tests/_support/SessionTestCase.php b/tests/_support/SessionTestCase.php
index 6e781dec01951ac29a435c80bcc6b7cd1d8b2081..e645906a8e7c7f84d2e7d1e8311e954bfcfd12e5 100644
--- a/tests/_support/SessionTestCase.php
+++ b/tests/_support/SessionTestCase.php
@@ -28,7 +28,7 @@ class SessionTestCase extends CIUnitTestCase
      *
      * @var string
      */
-    protected function mockSession()
+    protected function mockSession(): void
     {
         $config = config('App');
         $this->session = new MockSession(
diff --git a/tests/unit/HealthTest.php b/tests/unit/HealthTest.php
index 28b64065e1cba545d1bcdd97dbae7a5794e5af5b..a2388ef0a58bcc364119b68c6698f4cd3396b2eb 100644
--- a/tests/unit/HealthTest.php
+++ b/tests/unit/HealthTest.php
@@ -14,14 +14,14 @@ class HealthTest extends CIUnitTestCase
         parent::setUp();
     }
 
-    public function testIsDefinedAppPath()
+    public function testIsDefinedAppPath(): void
     {
         $test = defined('APPPATH');
 
         $this->assertTrue($test);
     }
 
-    public function testBaseUrlHasBeenSet()
+    public function testBaseUrlHasBeenSet(): void
     {
         $validation = Services::validation();
         $env = false;