From b1a8df112443acc7acbbd4eec15ef267e5c40e15 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= <jerome@tamarelle.net>
Date: Thu, 4 Jul 2024 21:28:43 +0200
Subject: [PATCH] Paginator total override

https://github.com/laravel/framework/pull/46410
---
 CHANGELOG.md                    |  1 +
 src/Relations/EmbedsMany.php    | 19 +++++++++++--------
 tests/EmbeddedRelationsTest.php |  6 ++++++
 3 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0a0a120f2..777a22304 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file.
 ## [4.6.0] - upcoming
 
 * Add `DocumentTrait` to use any 3rd party model with MongoDB @GromNaN in [#2580](https://github.com/mongodb/laravel-mongodb/pull/2580)
+* Add support for Closure for Embed pagination @GromNaN in [#3027](https://github.com/mongodb/laravel-mongodb/pull/3027)
 
 ## [4.5.0] - 2024-06-20
 
diff --git a/src/Relations/EmbedsMany.php b/src/Relations/EmbedsMany.php
index be7039506..72c77b598 100644
--- a/src/Relations/EmbedsMany.php
+++ b/src/Relations/EmbedsMany.php
@@ -4,6 +4,7 @@
 
 namespace MongoDB\Laravel\Relations;
 
+use Closure;
 use Illuminate\Database\Eloquent\Collection;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Pagination\LengthAwarePaginator;
@@ -18,6 +19,7 @@
 use function is_array;
 use function method_exists;
 use function throw_if;
+use function value;
 
 class EmbedsMany extends EmbedsOneOrMany
 {
@@ -288,21 +290,22 @@ protected function associateExisting($model)
     }
 
     /**
-     * @param  int|null $perPage
-     * @param  array    $columns
-     * @param  string   $pageName
-     * @param  int|null $page
+     * @param int|Closure      $perPage
+     * @param array|string     $columns
+     * @param string           $pageName
+     * @param int|null         $page
+     * @param Closure|int|null $total
      *
      * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
      */
-    public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
+    public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null, $total = null)
     {
         $page    = $page ?: Paginator::resolveCurrentPage($pageName);
-        $perPage = $perPage ?: $this->related->getPerPage();
-
         $results = $this->getEmbedded();
         $results = $this->toCollection($results);
-        $total   = $results->count();
+        $total   = value($total) ?? $results->count();
+        $perPage = $perPage ?: $this->related->getPerPage();
+        $perPage = $perPage instanceof Closure ? $perPage($total) : $perPage;
         $start   = ($page - 1) * $perPage;
 
         $sliced = $results->slice(
diff --git a/tests/EmbeddedRelationsTest.php b/tests/EmbeddedRelationsTest.php
index 2dd558679..00a84360c 100644
--- a/tests/EmbeddedRelationsTest.php
+++ b/tests/EmbeddedRelationsTest.php
@@ -925,6 +925,12 @@ public function testPaginateEmbedsMany()
         $results = $user->addresses()->paginate(2);
         $this->assertEquals(2, $results->count());
         $this->assertEquals(3, $results->total());
+
+        // With Closures
+        $results = $user->addresses()->paginate(fn () => 3, page: 1, total: fn () => 5);
+        $this->assertEquals(3, $results->count());
+        $this->assertEquals(5, $results->total());
+        $this->assertEquals(3, $results->perPage());
     }
 
     public function testGetQueueableRelationsEmbedsMany()