Skip to content

Commit 2507fb7

Browse files
committed
added lazy loading of product wallet.
1 parent e95ffa3 commit 2507fb7

File tree

8 files changed

+124
-0
lines changed

8 files changed

+124
-0
lines changed

config/config.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
use Bavix\Wallet\Services\CastService;
3939
use Bavix\Wallet\Services\ConsistencyService;
4040
use Bavix\Wallet\Services\DiscountService;
41+
use Bavix\Wallet\Services\EagerLoaderService;
4142
use Bavix\Wallet\Services\ExchangeService;
4243
use Bavix\Wallet\Services\PrepareService;
4344
use Bavix\Wallet\Services\PurchaseService;
@@ -100,6 +101,7 @@
100101
'cast' => CastService::class,
101102
'consistency' => ConsistencyService::class,
102103
'discount' => DiscountService::class,
104+
'eager_loader' => EagerLoaderService::class,
103105
'exchange' => ExchangeService::class,
104106
'prepare' => PrepareService::class,
105107
'purchase' => PurchaseService::class,

src/Internal/Repository/WalletRepository.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ public function getBySlug(string $holderType, int|string $holderId, string $slug
8383
]);
8484
}
8585

86+
/**
87+
* @param array<int|string> $holderIds
88+
*
89+
* @return Wallet[]
90+
*/
91+
public function findDefaultAll(string $holderType, array $holderIds): array
92+
{
93+
return $this->wallet->newQuery()
94+
->where('slug', config('wallet.wallet.default.slug', 'default'))
95+
->where('holder_type', $holderType)
96+
->whereIn('holder_id', $holderIds)
97+
->get()
98+
->all()
99+
;
100+
}
101+
86102
/**
87103
* @param array<string, int|string> $attributes
88104
*/

src/Internal/Repository/WalletRepositoryInterface.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ public function findByUuid(string $uuid): ?Wallet;
1717

1818
public function findBySlug(string $holderType, int|string $holderId, string $slug): ?Wallet;
1919

20+
/**
21+
* @param array<int|string> $holderIds
22+
*
23+
* @return Wallet[]
24+
*/
25+
public function findDefaultAll(string $holderType, array $holderIds): array;
26+
2027
/**
2128
* @throws ModelNotFoundException
2229
*/
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Bavix\Wallet\Services;
6+
7+
use Bavix\Wallet\Internal\Dto\BasketDtoInterface;
8+
use Bavix\Wallet\Internal\Repository\WalletRepositoryInterface;
9+
10+
final class EagerLoaderService implements EagerLoaderServiceInterface
11+
{
12+
public function __construct(
13+
private CastServiceInterface $castService,
14+
private WalletRepositoryInterface $walletRepository
15+
) {
16+
}
17+
18+
public function loadWalletsByBasket(BasketDtoInterface $basketDto): void
19+
{
20+
$products = [];
21+
/** @var array<array-key, array<array-key, int|string>> $productGroupIds */
22+
$productGroupIds = [];
23+
foreach ($basketDto->items() as $index => $item) {
24+
$model = $this->castService->getModel($item->getProduct());
25+
if (!$model->relationLoaded('wallet')) {
26+
$products[$index] = $item->getProduct();
27+
$productGroupIds[$model->getMorphClass()][$index] = $model->getKey();
28+
}
29+
}
30+
31+
foreach ($productGroupIds as $holderType => $holderIds) {
32+
$allWallets = $this->walletRepository->findDefaultAll($holderType, array_unique($holderIds));
33+
$wallets = [];
34+
foreach ($allWallets as $wallet) {
35+
$wallets[$wallet->holder_id] = $wallet;
36+
}
37+
38+
foreach ($holderIds as $index => $holderId) {
39+
$wallet = $wallets[$holderId] ?? null;
40+
if ($wallet !== null) {
41+
$model = $this->castService->getModel($products[$index]);
42+
$model->setRelation('wallet', $wallet);
43+
}
44+
}
45+
}
46+
}
47+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Bavix\Wallet\Services;
6+
7+
use Bavix\Wallet\Internal\Dto\BasketDtoInterface;
8+
9+
interface EagerLoaderServiceInterface
10+
{
11+
public function loadWalletsByBasket(BasketDtoInterface $basketDto): void;
12+
}

src/Traits/CartPay.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Bavix\Wallet\Services\BasketServiceInterface;
2424
use Bavix\Wallet\Services\CastServiceInterface;
2525
use Bavix\Wallet\Services\ConsistencyServiceInterface;
26+
use Bavix\Wallet\Services\EagerLoaderServiceInterface;
2627
use Bavix\Wallet\Services\PrepareServiceInterface;
2728
use Bavix\Wallet\Services\PurchaseServiceInterface;
2829
use Bavix\Wallet\Services\TransferServiceInterface;
@@ -55,6 +56,7 @@ public function payFreeCart(CartInterface $cart): array
5556
$basketDto = $cart->getBasketDto();
5657
$basketService = app(BasketServiceInterface::class);
5758
$availabilityAssembler = app(AvailabilityDtoAssemblerInterface::class);
59+
app(EagerLoaderServiceInterface::class)->loadWalletsByBasket($basketDto);
5860
if (!$basketService->availability($availabilityAssembler->create($this, $basketDto, false))) {
5961
throw new ProductEnded(
6062
app(TranslatorServiceInterface::class)->get('wallet::errors.product_stock'),
@@ -111,6 +113,7 @@ public function payCart(CartInterface $cart, bool $force = false): array
111113
$basketDto = $cart->getBasketDto();
112114
$basketService = app(BasketServiceInterface::class);
113115
$availabilityAssembler = app(AvailabilityDtoAssemblerInterface::class);
116+
app(EagerLoaderServiceInterface::class)->loadWalletsByBasket($basketDto);
114117
if (!$basketService->availability($availabilityAssembler->create($this, $basketDto, $force))) {
115118
throw new ProductEnded(
116119
app(TranslatorServiceInterface::class)->get('wallet::errors.product_stock'),
@@ -188,6 +191,7 @@ public function refundCart(CartInterface $cart, bool $force = false, bool $gifts
188191
{
189192
return app(AtomicServiceInterface::class)->block($this, function () use ($cart, $force, $gifts) {
190193
$basketDto = $cart->getBasketDto();
194+
app(EagerLoaderServiceInterface::class)->loadWalletsByBasket($basketDto);
191195
$transfers = app(PurchaseServiceInterface::class)->already($this, $basketDto, $gifts);
192196
if (count($transfers) !== $basketDto->total()) {
193197
throw new ModelNotFoundException(

src/WalletServiceProvider.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676
use Bavix\Wallet\Services\ConsistencyServiceInterface;
7777
use Bavix\Wallet\Services\DiscountService;
7878
use Bavix\Wallet\Services\DiscountServiceInterface;
79+
use Bavix\Wallet\Services\EagerLoaderService;
80+
use Bavix\Wallet\Services\EagerLoaderServiceInterface;
7981
use Bavix\Wallet\Services\ExchangeService;
8082
use Bavix\Wallet\Services\ExchangeServiceInterface;
8183
use Bavix\Wallet\Services\PrepareService;
@@ -198,6 +200,10 @@ private function services(array $configure, array $cache): void
198200
$configure['consistency'] ?? ConsistencyService::class
199201
);
200202
$this->app->singleton(DiscountServiceInterface::class, $configure['discount'] ?? DiscountService::class);
203+
$this->app->singleton(
204+
EagerLoaderServiceInterface::class,
205+
$configure['eager_loader'] ?? EagerLoaderService::class
206+
);
201207
$this->app->singleton(ExchangeServiceInterface::class, $configure['exchange'] ?? ExchangeService::class);
202208
$this->app->singleton(PrepareServiceInterface::class, $configure['prepare'] ?? PrepareService::class);
203209
$this->app->singleton(PurchaseServiceInterface::class, $configure['purchase'] ?? PurchaseService::class);

tests/Units/Domain/EagerLoadingTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44

55
namespace Bavix\Wallet\Test\Units\Domain;
66

7+
use Bavix\Wallet\Objects\Cart;
78
use Bavix\Wallet\Test\Infra\Factories\BuyerFactory;
9+
use Bavix\Wallet\Test\Infra\Factories\ItemFactory;
810
use Bavix\Wallet\Test\Infra\Factories\UserMultiFactory;
911
use Bavix\Wallet\Test\Infra\Models\Buyer;
12+
use Bavix\Wallet\Test\Infra\Models\Item;
1013
use Bavix\Wallet\Test\Infra\Models\UserMulti;
1114
use Bavix\Wallet\Test\Infra\TestCase;
1215
use Illuminate\Database\Eloquent\Collection;
@@ -85,4 +88,31 @@ public function testMultiWallets(): void
8588
self::assertTrue($user->getWallet('hello')->relationLoaded('holder'));
8689
self::assertTrue($user->is($user->getWallet('hello')->holder));
8790
}
91+
92+
public function testEagerLoaderPay(): void
93+
{
94+
/** @var Buyer $buyer */
95+
$buyer = BuyerFactory::new()->create();
96+
/** @var Item[] $products */
97+
$products = ItemFactory::times(50)->create([
98+
'quantity' => 10,
99+
'price' => 1,
100+
]);
101+
$productIds = [];
102+
foreach ($products as $product) {
103+
$productIds[] = $product->getKey();
104+
self::assertSame(0, $product->balanceInt);
105+
}
106+
107+
$products = Item::query()->whereKey($productIds)->get()->all();
108+
109+
$cart = app(Cart::class);
110+
foreach ($products as $product) {
111+
$cart = $cart->withItem($product, 10);
112+
}
113+
114+
$transfers = $buyer->forcePayCart($cart);
115+
self::assertSame((int) -$cart->getTotal($buyer), $buyer->balanceInt);
116+
self::assertCount(500, $transfers);
117+
}
88118
}

0 commit comments

Comments
 (0)