Skip to main content
The ChampionSkinController handles HTTP requests for the skin catalog with advanced filtering and pagination.

Overview

Located at source/app/Http/Controllers/ChampionSkinController.php, this controller:
  • Displays paginated skin catalog (16 skins per page)
  • Implements search by skin name
  • Filters by rarity tier
  • Supports HTMX for dynamic updates
  • Shows individual skin details with chromas
  • Uses 48-hour caching on detail pages

Class Definition

namespace App\Http\Controllers;

use App\Http\Requests\StoreChampionSkinRequest;
use App\Http\Requests\UpdateChampionSkinRequest;
use App\Models\ChampionSkin;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Spatie\QueryBuilder\AllowedFilter;
use Spatie\QueryBuilder\QueryBuilder;

class ChampionSkinController extends Controller
{
    // Controller methods
}

Routes

Defined in source/routes/web.php:47-48:
Route::get('skins', static fn (Request $request) => (new ChampionSkinController)->index($request))
    ->name('skins.index');
    
Route::get('skin/{championSkin}', static fn (ChampionSkin $championSkin) => (new ChampionSkinController)->show($championSkin))
    ->name('skins.show');

Methods

index()

Displays a filterable, paginated listing of skins.
public function index(Request $request)
{
    $skins = QueryBuilder::for(ChampionSkin::class)
        ->allowedFilters(AllowedFilter::partial('name', 'skin_name'), 'rarity')
        ->paginate(16)
        ->appends(request()->query());

    $rarityColor = [
        'Common' => 'text-stone-300',
        'Epic' => 'text-blue-400',
        'Legendary' => 'text-red-500',
        'Rare' => 'text-pink-300',
        'Mythic' => 'text-purple-500',
        'Ultimate' => 'text-yellow-400',
        'Transcendent' => 'text-violet-400',
        'Exalted' => 'text-violet-300',
    ];

    return view('skins.index', ['skins' => $skins, 'rarityColor' => $rarityColor])
        ->fragmentIf($request->hasHeader('HX-Request'), 'skin-list');
}

Parameters

request
Illuminate\Http\Request
required
HTTP request object containing query parameters and headers

Query Parameters

filter[name]
string
Partial match search on skin_name columnExample: ?filter[name]=star matches “Star Guardian Ahri”
filter[rarity]
string
Exact match on rarity columnValid values: Common, Rare, Epic, Legendary, Mythic, Ultimate, Transcendent, ExaltedExample: ?filter[rarity]=Legendary
page
integer
default:"1"
Page number for pagination (16 skins per page)Example: ?page=2

Return Value

view
Illuminate\View\View
Rendered skins.index Blade template (or skin-list fragment for HTMX requests)

View Data

skins
LengthAwarePaginator<ChampionSkin>
Paginated collection of skins (16 per page) with query string preservation
rarityColor
array
Mapping of rarity tiers to TailwindCSS color classes

Rarity Color Mapping

[
    'Common' => 'text-stone-300',
    'Epic' => 'text-blue-400',
    'Legendary' => 'text-red-500',
    'Rare' => 'text-pink-300',
    'Mythic' => 'text-purple-500',
    'Ultimate' => 'text-yellow-400',
    'Transcendent' => 'text-violet-400',
    'Exalted' => 'text-violet-300',
]

HTMX Support

->fragmentIf($request->hasHeader('HX-Request'), 'skin-list')
When the request contains the HX-Request header (indicating an HTMX request), only the skin-list Blade fragment is rendered instead of the full page.
Benefits:
  • Faster partial page updates
  • Reduced bandwidth usage
  • Smoother user experience for filtering/pagination

Usage Examples

GET /skins

show()

Displays a specific skin’s detail page with chromas.
public function show(ChampionSkin $championSkin)
{
    $skin = Cache::remember(
        'championSkinShowCache'.$championSkin->slug,
        60 * 60 * 48,  // 48 hours
        static fn () => $championSkin->load('champion', 'chromas')
    );

    return view('skins.show', ['skin' => $skin]);
}

Parameters

championSkin
ChampionSkin
required
ChampionSkin model instance (automatically resolved via route model binding)

Return Value

view
Illuminate\View\View
Rendered skins.show Blade template

View Data

skin
ChampionSkin
Skin model with eager-loaded relationships:
  • champion - Parent champion
  • chromas - All chroma variants for this skin

Cache Strategy

Each skin page is cached for 48 hours with a unique cache key based on the skin’s slug.
Cache key format: championSkinShowCache{slug} Examples:
  • championSkinShowCasestar-guardian-ahri
  • championSkinShowCaseproject-vayne
  • championSkinShowCasespirit-blossom-yasuo

Eager Loading

$championSkin->load('champion', 'chromas')
Type: BelongsToThe parent champion for this skin
public function champion(): BelongsTo
{
    return $this->belongsTo(Champion::class, 'champion_id', 'champion_id');
}
Type: HasManyAll chroma color variants for this skin
public function chromas(): HasMany
{
    return $this->hasMany(SkinChroma::class, 'skin_id', 'skin_id');
}

Usage Example

GET /skin/star-guardian-ahri
GET /skin/project-vayne
GET /skin/elementalist-lux

Spatie Query Builder

This controller uses Spatie Query Builder for filtering:
QueryBuilder::for(ChampionSkin::class)
    ->allowedFilters(
        AllowedFilter::partial('name', 'skin_name'), 
        'rarity'
    )
    ->paginate(16)
    ->appends(request()->query());

Allowed Filters

Column: skin_nameType: Partial match (LIKE query)Example: ?filter[name]=dragon matches:
  • “Dragon Trainer Tristana”
  • “Dragonslayer Vayne”
  • “Dragon Fist Lee Sin”
Column: rarityType: Exact matchExample: ?filter[rarity]=Mythic matches only Mythic rarity skins

Query String Preservation

->appends(request()->query())
This ensures pagination links preserve filter parameters. Clicking “Next Page” maintains your search/filter state.

Pagination

perPage
integer
default:"16"
Number of skins displayed per page
Pagination URLs:
/skins?page=1
/skins?page=2&filter[rarity]=Legendary
/skins?page=3&filter[name]=star

CRUD Methods (Unused)

The controller includes standard CRUD method stubs but they’re not implemented:
public function create() { }
public function store(StoreChampionSkinRequest $request) { }
public function edit(ChampionSkin $championSkin) { }
public function update(UpdateChampionSkinRequest $request, ChampionSkin $championSkin) { }
public function destroy(ChampionSkin $championSkin) { }
Skin data is managed through Artisan commands and data imports, not through web CRUD interfaces.

Performance Considerations

Indexed Queries

Ensure skin_name and rarity columns are indexed for fast filtering

48-Hour Cache

Individual skin pages cached for 2 days

Pagination

Limits query size to 16 rows per request

Fragment Rendering

HTMX requests return only the updated fragment

Skin Model

View the ChampionSkin model API reference

Skin Feature

Learn about the skin catalog feature

Champion Model

View the parent Champion model

Architecture

Understand the MVC architecture

Build docs developers (and LLMs) love