p-chess/chess-bundle
A Symfony bundle for chess applications, providing integration with the p-chess library for board state, legal move validation, FEN/PGN handling, and game management. Add chess logic to your Symfony services and controllers without building the rules engine from scratch.
composer require p-chess/chess gives you the rules engine (boards, pieces, moves, FEN/PGN). p-chess/chess-bundle is a Symfony bundle: it ships a Bundle class, DI extension, and Twig extensions/templates. Laravel has no use for any of that, and package discovery will not find it — do not expect a service provider to register itself.vendor/p-chess/chess/src. The engine namespace is PChess\Chess (Chess, Board, Piece, Move). Read the class you will call most — the Chess facade — before the bundle's Twig layer. The bundle is worth reading only as a reference implementation: its templates show how the maintainers render a board, which is a good starting point for a Blade component.ChessService in app/Services resolved from the container, so controllers, jobs, and tests share one entry point rather than instantiating the engine in five places:// app/Providers/AppServiceProvider.php
$this->app->singleton(ChessService::class, fn () => new ChessService());
// app/Services/ChessService.php
namespace App\Services;
use PChess\Chess\Chess;
class ChessService
{
public function fromFen(string $fen): Chess
{
return Chess::create()->load($fen);
}
public function legalMoves(string $fen): array
{
return $this->fromFen($fen)->moves(); // verify return shape in vendor source
}
}
POST /games/{game}/moves endpoint that takes a game's stored FEN plus a SAN/UCI move, loads the position, rejects illegal moves, applies the move, and persists the resulting FEN. That single round trip exercises the whole engine surface you will actually use day to day and is the fastest way to learn the API.<x-chess-board :fen="..." /> component once FEN round-tripping is trustworthy.fen string column on your games table, not as serialized piece rows. Every load is Chess::create()->load($game->fen), every save is ->fen(). This keeps your schema stable if you swap engines and makes debug snapshots trivial to paste into any chess tool.moves table (game_id, ply, san, uci, fen_after, created_at) gives you replay, undo, and an audit trail for free. Undo becomes "load fen_after from ply N-1" rather than an engine feature you have to trust.LegalChessMove rule that loads the game's FEN and checks the submitted move against legal moves keeps the controller thin and makes the rule unit-testable without HTTP. This is the single biggest ergonomics win in a Laravel codebase.GET /games/{game}/moves returning { from, to, san, promotion } per candidate lets you build click-to-move boards and highlight overlays in Alpine or Livewire without shipping the rules engine to the browser. Cache this response per FEN (see below).{{-- resources/views/components/chess-board.blade.php --}}
<div class="chess-board" data-fen="{{ $fen }}" role="img" aria-label="Chess position">
@foreach ($this->squares() as $square)
<div class="chess-square {{ $square['class'] }}">
@if ($square['piece'])
<x-chess-piece :piece="$square['piece']" />
@endif
</div>
@endforeach
</div>
--square-size (or aspect-ratio: 1 and percentages) and make piece SVGs width: 100%; height: 100%. This is exactly what v1.5.0 addresses upstream — if you copy the bundle's approach, copy the CSS-variable pattern rather than fixed pixel dimensions.Cache::remember("chess:moves:".md5($fen), $ttl, fn () => $this->legalMoves($fen)) is a one-line win and safe because the output is a pure function of the FEN.tests/Fixtures/positions/ directory of FEN → expected legal-move sets, plus a handful of PGN games with known results. Assert against that corpus after every engine bump. This is the highest-value test suite for this dependency, well above anything you would write about rendering."p-chess/chess": "^1.5" in composer.json. Record the bundle's version and PR link in a comment or ADR for reference, but keep it out of require.symfony/twig-bundle and a config/bundles.php shim to render a chessboard is a losing trade. Consume the engine directly.vendor/ before trusting a tutorial. Small packages like this have thin docs; the source is the contract. moves(), load(), fen(), move() are the shape, but check return types and exception behaviour in the installed version rather than assuming from the README.width/height rules in your app CSS, flex/grid constraints, or an SVG without a proper viewBox/preserveAspectRatio will all defeat square-based scaling. When pieces look wrong at non-default board sizes: inspect computed square size vs. piece size first, then the SVG attributes, then your own overrides.php artisan view:clear && php artisan cache:clear and rebuild front-end assets. Stale compiled Blade views and stale public/build hashes are the usual culprits for "I changed it but nothing happened."vendor/p-chess/chess. If you need custom rules (variant chess, custom starting positions), extend or wrap the engine classes in app/, or fork-and-vendor with a documented upstream diff. Vendor edits vanish on the next composer update and are invisible in code review.composer.json PHP constraint before upgrading. The changelog does not state PHP/Symfony floors. If your runtime is on an older PHP minor, a routine composer update can fail or, worse, resolve to an older engine tag without telling you. Commit the lock file.variant column is needed later.data-fen attributes and debug panels. Blade's {{ }} protects you; {!! !!} does not.How can I help you explore Laravel packages today?