Examples & Use Cases
Real-world examples and practical implementations using the Trading Card API PHP SDK.
Card Price Tracker
Track price changes for specific cards over time.
<?php
namespace App\Services;
use CardTechie\TradingCardApiSdk\Facades\TradingCardApiSdk;
use CardTechie\TradingCardApiSdk\Exceptions\{CardNotFoundException, TradingCardApiException};
use Illuminate\Support\Facades\{Cache, Log};
class CardPriceTracker
{
public function trackCard(string $cardId): array
{
try {
// Get card with price data
$cardData = TradingCardApiSdk::card()->get($cardId, [
'include' => 'prices,set,player'
]);
$currentPrice = $this->getCurrentPrice($cardData['prices'] ?? []);
return [
'success' => true,
'card' => $cardData,
'current_price' => $currentPrice,
'price_trend' => $this->calculatePriceTrend($cardId, $currentPrice)
];
} catch (CardNotFoundException $e) {
Log::warning("Card not found for tracking", ['card_id' => $cardId]);
return ['success' => false, 'error' => 'Card not found'];
} catch (TradingCardApiException $e) {
Log::error("API error while tracking card", [
'card_id' => $cardId,
'error' => $e->getMessage()
]);
return ['success' => false, 'error' => 'API error'];
}
}
private function getCurrentPrice(array $prices): ?float
{
if (empty($prices)) {
return null;
}
// Sort by date and get most recent
usort($prices, fn($a, $b) =>
strtotime($b['date']) <=> strtotime($a['date'])
);
return (float) $prices[0]['price'];
}
private function calculatePriceTrend(string $cardId, ?float $currentPrice): array
{
$previousPrice = Cache::get("price_history_{$cardId}");
if (!$previousPrice || !$currentPrice) {
return ['trend' => 'insufficient_data'];
}
$change = $currentPrice - $previousPrice;
$percentageChange = ($change / $previousPrice) * 100;
// Store current price for next comparison
Cache::put("price_history_{$cardId}", $currentPrice, now()->addDay());
return [
'previous_price' => $previousPrice,
'current_price' => $currentPrice,
'change' => round($change, 2),
'percentage_change' => round($percentageChange, 2),
'trend' => $change > 0 ? 'increasing' : 'decreasing'
];
}
}
// Usage
$tracker = new CardPriceTracker();
$result = $tracker->trackCard('card-123');
if ($result['success']) {
echo "Card: " . $result['card']['name'] . "\n";
echo "Current Price: $" . $result['current_price'] . "\n";
echo "Trend: " . $result['price_trend']['trend'] . "\n";
}
Collection Manager
Manage card collections with valuation and completion tracking.
<?php
namespace App\Services;
use CardTechie\TradingCardApiSdk\Facades\TradingCardApiSdk;
use CardTechie\TradingCardApiSdk\Exceptions\TradingCardApiException;
use App\Models\{Collection, CollectionCard};
class CollectionManager
{
public function addCardToCollection(Collection $collection, string $cardId, array $metadata = []): array
{
try {
// Get card data from API
$cardData = TradingCardApiSdk::card()->get($cardId, [
'include' => 'set,player,prices'
]);
// Check if card already exists in collection
$existingCard = $collection->cards()
->where('api_card_id', $cardId)
->first();
if ($existingCard) {
// Update quantity if card already exists
$existingCard->increment('quantity', $metadata['quantity'] ?? 1);
return [
'success' => true,
'action' => 'updated',
'card' => $existingCard
];
}
// Add new card to collection
$collectionCard = $collection->cards()->create([
'api_card_id' => $cardId,
'name' => $cardData['name'],
'set_name' => $cardData['set']['name'] ?? null,
'player_name' => $cardData['player']['name'] ?? null,
'quantity' => $metadata['quantity'] ?? 1,
'condition' => $metadata['condition'] ?? 'near_mint',
'purchase_price' => $metadata['purchase_price'] ?? null,
'current_price' => $this->getCurrentPrice($cardData['prices'] ?? []),
'notes' => $metadata['notes'] ?? null
]);
return [
'success' => true,
'action' => 'added',
'card' => $collectionCard
];
} catch (TradingCardApiException $e) {
return [
'success' => false,
'error' => $e->getMessage()
];
}
}
public function calculateCollectionValue(Collection $collection): array
{
$cards = $collection->cards()->get();
$totalValue = 0;
$totalPurchasePrice = 0;
foreach ($cards as $card) {
$cardValue = ($card->current_price ?? 0) * $card->quantity;
$totalValue += $cardValue;
if ($card->purchase_price) {
$totalPurchasePrice += $card->purchase_price * $card->quantity;
}
}
$profitLoss = $totalPurchasePrice > 0 ? $totalValue - $totalPurchasePrice : 0;
return [
'total_cards' => $cards->sum('quantity'),
'unique_cards' => $cards->count(),
'total_value' => round($totalValue, 2),
'total_purchase_price' => round($totalPurchasePrice, 2),
'profit_loss' => round($profitLoss, 2)
];
}
private function getCurrentPrice(array $prices): ?float
{
if (empty($prices)) {
return null;
}
usort($prices, fn($a, $b) =>
strtotime($b['date']) <=> strtotime($a['date'])
);
return (float) $prices[0]['price'];
}
}
// Usage
$manager = new CollectionManager();
// Add card to collection
$result = $manager->addCardToCollection($collection, 'card-123', [
'quantity' => 2,
'condition' => 'near_mint',
'purchase_price' => 15.99,
'notes' => 'Bought at local card shop'
]);
// Calculate collection value
$value = $manager->calculateCollectionValue($collection);
echo "Collection worth: $" . number_format($value['total_value'], 2);
Laravel Controllers
Integrate SDK into Laravel controllers for web applications.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use CardTechie\TradingCardApiSdk\Facades\TradingCardApiSdk;
use CardTechie\TradingCardApiSdk\Exceptions\{
CardNotFoundException,
ValidationException,
TradingCardApiException
};
class CardController extends Controller
{
public function index(Request $request)
{
try {
$cards = TradingCardApiSdk::card()->getList([
'page' => $request->get('page', 1),
'limit' => 25,
'name' => $request->get('search'),
'genre' => $request->get('genre'),
'year' => $request->get('year')
]);
return view('cards.index', [
'cards' => $cards['data'] ?? [],
'pagination' => $cards['meta'] ?? [],
'filters' => $request->only(['search', 'genre', 'year'])
]);
} catch (TradingCardApiException $e) {
return back()->withError('Unable to load cards. Please try again.');
}
}
public function show($id)
{
try {
$card = TradingCardApiSdk::card()->get($id, [
'include' => 'set,player,team,prices'
]);
return view('cards.show', compact('card'));
} catch (CardNotFoundException $e) {
abort(404, 'Card not found');
} catch (TradingCardApiException $e) {
return back()->withError('Unable to load card details.');
}
}
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'set_id' => 'required|string',
'player_id' => 'nullable|string',
'condition' => 'required|string|in:mint,near_mint,excellent,good,fair,poor'
]);
try {
$card = TradingCardApiSdk::card()->create($request->all());
return redirect()->route('cards.show', $card['id'])
->with('success', 'Card created successfully!');
} catch (ValidationException $e) {
return back()
->withErrors($e->getValidationErrors())
->withInput();
} catch (TradingCardApiException $e) {
return back()
->withError('Failed to create card. Please try again.')
->withInput();
}
}
}
Artisan Commands
Create CLI commands for batch operations and maintenance tasks.
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use CardTechie\TradingCardApiSdk\Facades\TradingCardApiSdk;
use CardTechie\TradingCardApiSdk\Exceptions\TradingCardApiException;
class SyncCardsCommand extends Command
{
protected $signature = 'cards:sync {--limit=100 : Number of cards to sync} {--genre= : Filter by genre}';
protected $description = 'Sync cards from Trading Card API';
public function handle()
{
$this->info('Starting card synchronization...');
$limit = (int) $this->option('limit');
$genre = $this->option('genre');
$filters = ['limit' => $limit];
if ($genre) {
$filters['genre'] = $genre;
}
try {
$response = TradingCardApiSdk::card()->getList($filters);
$cards = $response['data'] ?? [];
$this->output->progressStart(count($cards));
foreach ($cards as $cardData) {
// Process each card (store in database, update cache, etc.)
$this->processCard($cardData);
$this->output->progressAdvance();
// Small delay to respect rate limits
usleep(50000); // 50ms
}
$this->output->progressFinish();
$this->info('Card synchronization completed!');
$this->line("Processed " . count($cards) . " cards");
} catch (TradingCardApiException $e) {
$this->error('Synchronization failed: ' . $e->getMessage());
return Command::FAILURE;
}
return Command::SUCCESS;
}
private function processCard(array $cardData): void
{
// Implementation depends on your needs
// This could update a local database, cache, search index, etc.
$this->line("Processing: {$cardData['name']}");
}
}
Queue Jobs
Handle API operations asynchronously using Laravel's queue system.
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use CardTechie\TradingCardApiSdk\Facades\TradingCardApiSdk;
use CardTechie\TradingCardApiSdk\Exceptions\TradingCardApiException;
use App\Models\User;
use App\Notifications\PriceAlertNotification;
class ProcessPriceAlertJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(
private string $cardId,
private User $user,
private float $targetPrice
) {}
public function handle()
{
try {
$card = TradingCardApiSdk::card()->get($this->cardId, [
'include' => 'prices'
]);
$currentPrice = $this->getCurrentPrice($card['prices'] ?? []);
if ($currentPrice && $currentPrice <= $this->targetPrice) {
// Price target reached, send notification
$this->user->notify(new PriceAlertNotification([
'card' => $card,
'current_price' => $currentPrice,
'target_price' => $this->targetPrice
]));
}
} catch (TradingCardApiException $e) {
// Log error and potentially retry
\Log::error('Price alert job failed', [
'card_id' => $this->cardId,
'user_id' => $this->user->id,
'error' => $e->getMessage()
]);
// Retry the job if it's a temporary error
if ($e instanceof RateLimitException) {
$this->release($e->getRetryAfter());
}
}
}
private function getCurrentPrice(array $prices): ?float
{
if (empty($prices)) {
return null;
}
usort($prices, fn($a, $b) =>
strtotime($b['date']) <=> strtotime($a['date'])
);
return (float) $prices[0]['price'];
}
}
// Dispatch the job
ProcessPriceAlertJob::dispatch($cardId, $user, $targetPrice);
API Resource Integration
Create Laravel API resources for consistent response formatting.
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class CardResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->resource['id'],
'name' => $this->resource['name'],
'description' => $this->resource['description'] ?? null,
'condition' => $this->resource['condition'] ?? 'unknown',
'rarity' => $this->resource['rarity'] ?? 'common',
'set' => $this->when(
isset($this->resource['set']),
fn() => new SetResource($this->resource['set'])
),
'player' => $this->when(
isset($this->resource['player']),
fn() => new PlayerResource($this->resource['player'])
),
'prices' => $this->when(
isset($this->resource['prices']),
fn() => PriceResource::collection($this->resource['prices'])
),
'links' => [
'self' => route('api.cards.show', $this->resource['id']),
'web' => route('cards.show', $this->resource['id'])
]
];
}
}
// API Controller usage
class ApiCardController extends Controller
{
public function show($id)
{
try {
$card = TradingCardApiSdk::card()->get($id, [
'include' => 'set,player,prices'
]);
return new CardResource($card);
} catch (CardNotFoundException $e) {
return response()->json(['error' => 'Card not found'], 404);
} catch (TradingCardApiException $e) {
return response()->json(['error' => 'API error'], 500);
}
}
}
Testing with the SDK
Write tests for your SDK integrations.
<?php
namespace Tests\Feature;
use Tests\TestCase;
use CardTechie\TradingCardApiSdk\Facades\TradingCardApiSdk;
use CardTechie\TradingCardApiSdk\Exceptions\CardNotFoundException;
class CardControllerTest extends TestCase
{
public function test_can_view_card_details()
{
// Mock the SDK response
TradingCardApiSdk::shouldReceive('card->get')
->with('card-123', ['include' => 'set,player,team,prices'])
->andReturn([
'id' => 'card-123',
'name' => 'Test Card',
'description' => 'A test card',
'set' => ['name' => 'Test Set'],
'player' => ['name' => 'Test Player']
]);
$response = $this->get('/cards/card-123');
$response->assertStatus(200);
$response->assertViewIs('cards.show');
$response->assertViewHas('card');
}
public function test_returns_404_for_missing_card()
{
// Mock the SDK to throw an exception
TradingCardApiSdk::shouldReceive('card->get')
->with('invalid-id', ['include' => 'set,player,team,prices'])
->andThrow(new CardNotFoundException('Card not found'));
$response = $this->get('/cards/invalid-id');
$response->assertStatus(404);
}
}
Best Practices
1. Error Handling
Always handle exceptions appropriately:
try {
$card = TradingCardApiSdk::card()->get($id);
} catch (CardNotFoundException $e) {
// Handle not found specifically
} catch (ValidationException $e) {
// Handle validation errors
} catch (TradingCardApiException $e) {
// Handle general API errors
}
2. Rate Limiting
Respect API rate limits:
foreach ($cardIds as $cardId) {
try {
$card = TradingCardApiSdk::card()->get($cardId);
// Process card
} catch (RateLimitException $e) {
sleep($e->getRetryAfter());
// Retry the request
}
// Add small delay between requests
usleep(100000); // 100ms
}
3. Caching
Cache API responses when appropriate:
$cacheKey = "card_{$cardId}";
$card = Cache::remember($cacheKey, 3600, function() use ($cardId) {
return TradingCardApiSdk::card()->get($cardId);
});
4. Logging
Log API interactions for debugging:
try {
$card = TradingCardApiSdk::card()->get($cardId);
Log::info('Card fetched successfully', ['card_id' => $cardId]);
} catch (TradingCardApiException $e) {
Log::error('Card fetch failed', [
'card_id' => $cardId,
'error' => $e->getMessage(),
'request_id' => $e->getRequestId()
]);
}
These examples demonstrate practical, real-world usage patterns for the Trading Card API PHP SDK in Laravel applications. Each example includes proper error handling, follows Laravel conventions, and demonstrates best practices for API integration.