diff --git a/app/Activity/Models/Comment.php b/app/Activity/Models/Comment.php
index 7d1c54646..d0385d396 100644
--- a/app/Activity/Models/Comment.php
+++ b/app/Activity/Models/Comment.php
@@ -26,7 +26,6 @@ class Comment extends Model implements Loggable
     use HasCreatorAndUpdater;
 
     protected $fillable = ['parent_id'];
-    protected $appends = ['created', 'updated'];
 
     /**
      * Get the entity that this comment belongs to.
@@ -54,22 +53,6 @@ class Comment extends Model implements Loggable
         return $this->updated_at->timestamp > $this->created_at->timestamp;
     }
 
-    /**
-     * Get created date as a relative diff.
-     */
-    public function getCreatedAttribute(): string
-    {
-        return $this->created_at->diffForHumans();
-    }
-
-    /**
-     * Get updated date as a relative diff.
-     */
-    public function getUpdatedAttribute(): string
-    {
-        return $this->updated_at->diffForHumans();
-    }
-
     public function logDescriptor(): string
     {
         return "Comment #{$this->local_id} (ID: {$this->id}) for {$this->entity_type} (ID: {$this->entity_id})";
diff --git a/composer.json b/composer.json
index 58b89fcce..2c3c04732 100644
--- a/composer.json
+++ b/composer.json
@@ -45,7 +45,7 @@
         "itsgoingd/clockwork": "^5.1",
         "mockery/mockery": "^1.5",
         "nunomaduro/collision": "^8.1",
-        "larastan/larastan": "^2.7",
+        "larastan/larastan": "^v3.0",
         "phpunit/phpunit": "^10.0",
         "squizlabs/php_codesniffer": "^3.7",
         "ssddanbrown/asserthtml": "^3.0"
diff --git a/composer.lock b/composer.lock
index 1d512f851..c7c4018a1 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": "518176ac5bb608061e0f74b06fdae582",
+    "content-hash": "36bd84db9a3fd3e801fbd8375b91e0e5",
     "packages": [
         {
             "name": "aws/aws-crt-php",
@@ -8115,40 +8115,40 @@
         },
         {
             "name": "larastan/larastan",
-            "version": "v2.9.12",
+            "version": "v3.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/larastan/larastan.git",
-                "reference": "19012b39fbe4dede43dbe0c126d9681827a5e908"
+                "reference": "b2e24e1605cff1d1097ccb6fb8af3bbd1dfe1c6f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/larastan/larastan/zipball/19012b39fbe4dede43dbe0c126d9681827a5e908",
-                "reference": "19012b39fbe4dede43dbe0c126d9681827a5e908",
+                "url": "https://api.github.com/repos/larastan/larastan/zipball/b2e24e1605cff1d1097ccb6fb8af3bbd1dfe1c6f",
+                "reference": "b2e24e1605cff1d1097ccb6fb8af3bbd1dfe1c6f",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
-                "illuminate/console": "^9.52.16 || ^10.28.0 || ^11.16",
-                "illuminate/container": "^9.52.16 || ^10.28.0 || ^11.16",
-                "illuminate/contracts": "^9.52.16 || ^10.28.0 || ^11.16",
-                "illuminate/database": "^9.52.16 || ^10.28.0 || ^11.16",
-                "illuminate/http": "^9.52.16 || ^10.28.0 || ^11.16",
-                "illuminate/pipeline": "^9.52.16 || ^10.28.0 || ^11.16",
-                "illuminate/support": "^9.52.16 || ^10.28.0 || ^11.16",
-                "php": "^8.0.2",
+                "illuminate/console": "^11.15.0",
+                "illuminate/container": "^11.15.0",
+                "illuminate/contracts": "^11.15.0",
+                "illuminate/database": "^11.15.0",
+                "illuminate/http": "^11.15.0",
+                "illuminate/pipeline": "^11.15.0",
+                "illuminate/support": "^11.15.0",
+                "php": "^8.2",
                 "phpmyadmin/sql-parser": "^5.9.0",
-                "phpstan/phpstan": "^1.12.11"
+                "phpstan/phpstan": "^2.0.2"
             },
             "require-dev": {
                 "doctrine/coding-standard": "^12.0",
-                "laravel/framework": "^9.52.16 || ^10.28.0 || ^11.16",
-                "mockery/mockery": "^1.5.1",
-                "nikic/php-parser": "^4.19.1",
-                "orchestra/canvas": "^7.11.1 || ^8.11.0 || ^9.0.2",
-                "orchestra/testbench-core": "^7.33.0 || ^8.13.0 || ^9.0.9",
-                "phpstan/phpstan-deprecation-rules": "^1.2",
-                "phpunit/phpunit": "^9.6.13 || ^10.5.16"
+                "laravel/framework": "^11.15.0",
+                "mockery/mockery": "^1.6",
+                "nikic/php-parser": "^5.3",
+                "orchestra/canvas": "^v9.1.3",
+                "orchestra/testbench-core": "^9.5.2",
+                "phpstan/phpstan-deprecation-rules": "^2.0.0",
+                "phpunit/phpunit": "^10.5.16"
             },
             "suggest": {
                 "orchestra/testbench": "Using Larastan for analysing a package needs Testbench"
@@ -8183,7 +8183,7 @@
                     "email": "enunomaduro@gmail.com"
                 }
             ],
-            "description": "Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel",
+            "description": "Larastan - Discover bugs in your code without running it. A phpstan/phpstan wrapper for Laravel",
             "keywords": [
                 "PHPStan",
                 "code analyse",
@@ -8196,7 +8196,7 @@
             ],
             "support": {
                 "issues": "https://github.com/larastan/larastan/issues",
-                "source": "https://github.com/larastan/larastan/tree/v2.9.12"
+                "source": "https://github.com/larastan/larastan/tree/v3.0.2"
             },
             "funding": [
                 {
@@ -8204,7 +8204,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2024-11-26T23:09:02+00:00"
+            "time": "2024-11-26T23:15:21+00:00"
         },
         {
             "name": "mockery/mockery",
@@ -8653,20 +8653,20 @@
         },
         {
             "name": "phpstan/phpstan",
-            "version": "1.12.15",
+            "version": "2.1.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpstan/phpstan.git",
-                "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1"
+                "reference": "cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c91d4e8bc056f46cf653656e6f71004b254574d1",
-                "reference": "c91d4e8bc056f46cf653656e6f71004b254574d1",
+                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7",
+                "reference": "cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7",
                 "shasum": ""
             },
             "require": {
-                "php": "^7.2|^8.0"
+                "php": "^7.4|^8.0"
             },
             "conflict": {
                 "phpstan/phpstan-shim": "*"
@@ -8707,7 +8707,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2025-01-05T16:40:22+00:00"
+            "time": "2025-01-05T16:43:48+00:00"
         },
         {
             "name": "phpunit/php-code-coverage",
diff --git a/database/migrations/2015_08_31_175240_add_search_indexes.php b/database/migrations/2015_08_31_175240_add_search_indexes.php
index 4d58d9409..13141698a 100644
--- a/database/migrations/2015_08_31_175240_add_search_indexes.php
+++ b/database/migrations/2015_08_31_175240_add_search_indexes.php
@@ -26,25 +26,19 @@ return new class extends Migration
      */
     public function down(): void
     {
-        $sm = Schema::getConnection()->getDoctrineSchemaManager();
-        $prefix = DB::getTablePrefix();
-        $pages = $sm->introspectTable($prefix . 'pages');
-        $books = $sm->introspectTable($prefix . 'books');
-        $chapters = $sm->introspectTable($prefix . 'chapters');
-
-        if ($pages->hasIndex('search')) {
+        if (Schema::hasIndex('pages', 'search')) {
             Schema::table('pages', function (Blueprint $table) {
                 $table->dropIndex('search');
             });
         }
 
-        if ($books->hasIndex('search')) {
+        if (Schema::hasIndex('books', 'search')) {
             Schema::table('books', function (Blueprint $table) {
                 $table->dropIndex('search');
             });
         }
 
-        if ($chapters->hasIndex('search')) {
+        if (Schema::hasIndex('chapters', 'search')) {
             Schema::table('chapters', function (Blueprint $table) {
                 $table->dropIndex('search');
             });
diff --git a/database/migrations/2015_12_05_145049_fulltext_weighting.php b/database/migrations/2015_12_05_145049_fulltext_weighting.php
index b20c04520..3d0d21e70 100644
--- a/database/migrations/2015_12_05_145049_fulltext_weighting.php
+++ b/database/migrations/2015_12_05_145049_fulltext_weighting.php
@@ -26,25 +26,19 @@ return new class extends Migration
      */
     public function down(): void
     {
-        $sm = Schema::getConnection()->getDoctrineSchemaManager();
-        $prefix = DB::getTablePrefix();
-        $pages = $sm->introspectTable($prefix . 'pages');
-        $books = $sm->introspectTable($prefix . 'books');
-        $chapters = $sm->introspectTable($prefix . 'chapters');
-
-        if ($pages->hasIndex('name_search')) {
+        if (Schema::hasIndex('pages', 'name_search')) {
             Schema::table('pages', function (Blueprint $table) {
                 $table->dropIndex('name_search');
             });
         }
 
-        if ($books->hasIndex('name_search')) {
+        if (Schema::hasIndex('books', 'name_search')) {
             Schema::table('books', function (Blueprint $table) {
                 $table->dropIndex('name_search');
             });
         }
 
-        if ($chapters->hasIndex('name_search')) {
+        if (Schema::hasIndex('chapters', 'name_search')) {
             Schema::table('chapters', function (Blueprint $table) {
                 $table->dropIndex('name_search');
             });
diff --git a/database/migrations/2017_03_19_091553_create_search_index_table.php b/database/migrations/2017_03_19_091553_create_search_index_table.php
index 56281741e..7f96aca6b 100644
--- a/database/migrations/2017_03_19_091553_create_search_index_table.php
+++ b/database/migrations/2017_03_19_091553_create_search_index_table.php
@@ -25,27 +25,21 @@ return new class extends Migration
             $table->index('score');
         });
 
-        $sm = Schema::getConnection()->getDoctrineSchemaManager();
-        $prefix = DB::getTablePrefix();
-        $pages = $sm->introspectTable($prefix . 'pages');
-        $books = $sm->introspectTable($prefix . 'books');
-        $chapters = $sm->introspectTable($prefix . 'chapters');
-
-        if ($pages->hasIndex('search')) {
+        if (Schema::hasIndex('pages', 'search')) {
             Schema::table('pages', function (Blueprint $table) {
                 $table->dropIndex('search');
                 $table->dropIndex('name_search');
             });
         }
 
-        if ($books->hasIndex('search')) {
+        if (Schema::hasIndex('books', 'search')) {
             Schema::table('books', function (Blueprint $table) {
                 $table->dropIndex('search');
                 $table->dropIndex('name_search');
             });
         }
 
-        if ($chapters->hasIndex('search')) {
+        if (Schema::hasIndex('chapters', 'search')) {
             Schema::table('chapters', function (Blueprint $table) {
                 $table->dropIndex('search');
                 $table->dropIndex('name_search');
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
index aa2ad3d9e..0f2021383 100644
--- a/phpstan.neon.dist
+++ b/phpstan.neon.dist
@@ -21,6 +21,4 @@ parameters:
 
     excludePaths:
         - ./Config/**/*.php
-        - ./dev/**/*.php
-
-    checkMissingIterableValueType: false
\ No newline at end of file
+        - ./dev/**/*.php
\ No newline at end of file
diff --git a/tests/Entity/PageTest.php b/tests/Entity/PageTest.php
index b96d455eb..deeead099 100644
--- a/tests/Entity/PageTest.php
+++ b/tests/Entity/PageTest.php
@@ -300,7 +300,7 @@ class PageTest extends TestCase
         ]);
 
         $resp = $this->asAdmin()->get('/pages/recently-updated');
-        $this->withHtml($resp)->assertElementContains('.entity-list .page:nth-child(1)', 'Updated 1 second ago by ' . $user->name);
+        $this->withHtml($resp)->assertElementContains('.entity-list .page:nth-child(1)', 'Updated 0 seconds ago by ' . $user->name);
     }
 
     public function test_recently_updated_pages_view_shows_parent_chain()