Skip to content

Commit

Permalink
refactor: extract lookup of models into repositories (#342)
Browse files Browse the repository at this point in the history
  • Loading branch information
faustbrian committed Oct 31, 2020
1 parent ec26cd4 commit 5c3a57a
Show file tree
Hide file tree
Showing 16 changed files with 363 additions and 10 deletions.
12 changes: 12 additions & 0 deletions app/Contracts/BlockRepository.php
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace App\Contracts;

use App\Models\Block;

interface BlockRepository
{
public function findByHeight(int $height): Block;
}
15 changes: 15 additions & 0 deletions app/Contracts/RoundRepository.php
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace App\Contracts;

use App\Models\Round;
use Illuminate\Support\Collection;

interface RoundRepository
{
public function allByRound(int $round): Collection;

public function currentRound(): Round;
}
16 changes: 16 additions & 0 deletions app/Contracts/TransactionRepository.php
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace App\Contracts;

use Illuminate\Support\Collection;

interface TransactionRepository
{
public function allByWallet(string $address, string $publicKey): Collection;

public function allBySender(string $publicKey): Collection;

public function allByRecipient(string $address): Collection;
}
16 changes: 16 additions & 0 deletions app/Contracts/WalletRepository.php
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace App\Contracts;

use App\Models\Wallet;

interface WalletRepository
{
public function findByAddress(string $address): Wallet;

public function findByPublicKey(string $publicKey): Wallet;

public function findByUsername(string $username): Wallet;
}
43 changes: 38 additions & 5 deletions app/Providers/EloquentServiceProvider.php
Expand Up @@ -4,19 +4,33 @@

namespace App\Providers;

use App\Contracts\BlockRepository as BlockRepositoryContract;
use App\Contracts\RoundRepository as RoundRepositoryContract;
use App\Contracts\TransactionRepository as TransactionRepositoryContract;
use App\Contracts\WalletRepository as WalletRepositoryContract;
use App\Repositories\BlockRepository;
use App\Repositories\BlockRepositoryWithCache;
use App\Repositories\RoundRepository;
use App\Repositories\RoundRepositoryWithCache;
use App\Repositories\TransactionRepository;
use App\Repositories\TransactionRepositoryWithCache;
use App\Repositories\WalletRepository;
use App\Repositories\WalletRepositoryWithCache;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\ServiceProvider;
use LogicException;

final class EloquentServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
$this->registerScopes();

$this->registerRepositories();
}

private function registerScopes(): void
{
Builder::macro('withScope', function ($scope, ...$parameters): Builder {
/** @var Builder $query */
Expand All @@ -35,4 +49,23 @@ public function register()
return $query;
});
}

private function registerRepositories(): void
{
$this->app->bind(BlockRepositoryContract::class, function (): BlockRepositoryWithCache {
return new BlockRepositoryWithCache(new BlockRepository());
});

$this->app->bind(RoundRepositoryContract::class, function (): RoundRepositoryWithCache {
return new RoundRepositoryWithCache(new RoundRepository());
});

$this->app->bind(TransactionRepositoryContract::class, function (): TransactionRepositoryWithCache {
return new TransactionRepositoryWithCache(new TransactionRepository());
});

$this->app->bind(WalletRepositoryContract::class, function (): WalletRepositoryWithCache {
return new WalletRepositoryWithCache(new WalletRepository());
});
}
}
16 changes: 16 additions & 0 deletions app/Repositories/BlockRepository.php
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace App\Repositories;

use App\Contracts\BlockRepository as Contract;
use App\Models\Block;

final class BlockRepository implements Contract
{
public function findByHeight(int $height): Block
{
return Block::where('height', $height)->firstOrFail();
}
}
25 changes: 25 additions & 0 deletions app/Repositories/BlockRepositoryWithCache.php
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace App\Repositories;

use App\Contracts\BlockRepository;
use App\Models\Block;

final class BlockRepositoryWithCache implements BlockRepository
{
use Concerns\ManagesCache;

private BlockRepository $blocks;

public function __construct(BlockRepository $blocks)
{
$this->blocks = $blocks;
}

public function findByHeight(int $height): Block
{
return $this->remember(fn () => $this->blocks->findByHeight($height));
}
}
29 changes: 29 additions & 0 deletions app/Repositories/Concerns/ManagesCache.php
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace App\Repositories\Concerns;

use Closure;
use Illuminate\Support\Facades\Cache;

trait ManagesCache
{
/**
* @return mixed
*/
private function remember(Closure $callback, int $seconds = 60)
{
return Cache::remember($this->cacheKey(), $seconds, $callback);
}

private function cacheKey(): string
{
return sprintf(
'%s/%s-%s',
class_basename($this),
debug_backtrace()[2]['function'],
serialize(debug_backtrace()[2]['args'])
);
}
}
26 changes: 26 additions & 0 deletions app/Repositories/RoundRepository.php
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace App\Repositories;

use App\Contracts\RoundRepository as Contract;
use App\Models\Round;
use Illuminate\Support\Collection;

final class RoundRepository implements Contract
{
public function allByRound(int $round): Collection
{
return Round::query()
->where('round', $round)
->orderBy('balance', 'desc')
->orderBy('public_key', 'asc')
->get();
}

public function currentRound(): Round
{
return Round::orderBy('round', 'desc')->firstOrFail();
}
}
31 changes: 31 additions & 0 deletions app/Repositories/RoundRepositoryWithCache.php
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace App\Repositories;

use App\Contracts\RoundRepository;
use App\Models\Round;
use Illuminate\Support\Collection;

final class RoundRepositoryWithCache implements RoundRepository
{
use Concerns\ManagesCache;

private RoundRepository $rounds;

public function __construct(RoundRepository $rounds)
{
$this->rounds = $rounds;
}

public function allByRound(int $round): Collection
{
return $this->remember(fn () => $this->rounds->allByRound($round));
}

public function currentRound(): Round
{
return $this->remember(fn () => $this->rounds->currentRound());
}
}
35 changes: 35 additions & 0 deletions app/Repositories/TransactionRepository.php
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace App\Repositories;

use App\Contracts\TransactionRepository as Contract;
use App\Models\Transaction;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;

final class TransactionRepository implements Contract
{
public function allByWallet(string $address, string $publicKey): Collection
{
return Transaction::query()
->where(fn ($query): Builder => $query->where('sender_public_key', $publicKey))
->orWhere(fn ($query): Builder => $query->where('recipient_id', $address))
->orWhere(fn ($query): Builder => $query->whereJsonContains('asset->payments', [['recipientId' => $address]]))
->get();
}

public function allBySender(string $publicKey): Collection
{
return Transaction::where('sender_public_key', $publicKey)->get();
}

public function allByRecipient(string $address): Collection
{
return Transaction::query()
->orWhere(fn ($query): Builder => $query->where('recipient_id', $address))
->orWhere(fn ($query): Builder => $query->whereJsonContains('asset->payments', [['recipientId' => $address]]))
->get();
}
}
35 changes: 35 additions & 0 deletions app/Repositories/TransactionRepositoryWithCache.php
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace App\Repositories;

use App\Contracts\TransactionRepository;
use Illuminate\Support\Collection;

final class TransactionRepositoryWithCache implements TransactionRepository
{
use Concerns\ManagesCache;

private TransactionRepository $transactions;

public function __construct(TransactionRepository $transactions)
{
$this->transactions = $transactions;
}

public function allByWallet(string $address, string $publicKey): Collection
{
return $this->remember(fn () => $this->transactions->allByWallet($address, $publicKey));
}

public function allBySender(string $publicKey): Collection
{
return $this->remember(fn () => $this->transactions->allBySender($publicKey));
}

public function allByRecipient(string $address): Collection
{
return $this->remember(fn () => $this->transactions->allByRecipient($address));
}
}
26 changes: 26 additions & 0 deletions app/Repositories/WalletRepository.php
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace App\Repositories;

use App\Contracts\WalletRepository as Contract;
use App\Models\Wallet;

final class WalletRepository implements Contract
{
public function findByAddress(string $address): Wallet
{
return Wallet::where('address', $address)->firstOrFail();
}

public function findByPublicKey(string $publicKey): Wallet
{
return Wallet::where('public_key', $publicKey)->firstOrFail();
}

public function findByUsername(string $username): Wallet
{
return Wallet::where('attributes->delegate->username', $username)->firstOrFail();
}
}
35 changes: 35 additions & 0 deletions app/Repositories/WalletRepositoryWithCache.php
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace App\Repositories;

use App\Contracts\WalletRepository;
use App\Models\Wallet;

final class WalletRepositoryWithCache implements WalletRepository
{
use Concerns\ManagesCache;

private WalletRepository $wallets;

public function __construct(WalletRepository $wallets)
{
$this->wallets = $wallets;
}

public function findByAddress(string $address): Wallet
{
return $this->remember(fn () => $this->wallets->findByAddress($address));
}

public function findByPublicKey(string $publicKey): Wallet
{
return $this->remember(fn () => $this->wallets->findByPublicKey($publicKey));
}

public function findByUsername(string $username): Wallet
{
return $this->remember(fn () => $this->wallets->findByUsername($username));
}
}

0 comments on commit 5c3a57a

Please sign in to comment.