Installation
composer require cleentfaar/windmill-bundle
Add to config/bundles.php:
return [
// ...
Cleentfaar\WindmillBundle\CLWindmillBundle::class => ['all' => true],
];
Configuration Publish the default config:
php bin/console windmill:install
Update config/packages/cleentfaar_windmill.yaml with your Windmill API key.
First Use Case Create a controller to fetch a chess game:
use Cleentfaar\WindmillBundle\Service\WindmillService;
class ChessController extends AbstractController
{
public function showGame(WindmillService $windmill): Response
{
$game = $windmill->getGame('game_id_here');
return $this->render('chess/game.html.twig', ['game' => $game]);
}
}
Game Management
$windmill->getGame($id)$windmill->listGames($options)$windmill->makeMove($gameId, $move)$windmill->updateGame($gameId, $data)Player Integration
$windmill->registerPlayer($playerData)$windmill->getPlayerStats($playerId)Event Listeners Subscribe to game events via Symfony’s event dispatcher:
# config/services.yaml
services:
App\EventListener\ChessGameListener:
tags:
- { name: kernel.event_listener, event: windmill.game.created, method: onGameCreated }
API Rate Limiting: Cache responses aggressively (e.g., Symfony\Contracts\Cache\CacheInterface) to avoid hitting Windmill’s rate limits.
Twig Integration: Extend Twig with custom filters for chess notation:
{{ game.moves|chess_notation }}
Register in twig.config.php:
$twig->addFilter(new \Cleentfaar\WindmillBundle\Twig\ChessNotationFilter());
Command-Line Tools Use the bundle’s console commands for bulk operations:
php bin/console windmill:games:sync # Sync local games with Windmill
php bin/console windmill:players:export # Export player data
API Key Management
config/packages/cleentfaar_windmill.yaml is insecure. Use Symfony’s parameter_bag or environment variables:
windmill:
api_key: '%env(WINDMILL_API_KEY)%'
windmill:key:rotate command.Rate Limits
listGames() may trigger rate limits if called frequently.WindmillService to add caching:
$windmill->setCache($cache);
Data Serialization
json_decode($response, true) carefully to avoid type mismatches.$gameDto = new GameDto($windmill->getGame($id));
Event Dispatching
windmill.game.updated may fire unexpectedly if the API returns partial updates.isValidUpdate() check in your event listener:
public function onGameUpdated(GameEvent $event) {
if ($event->getGame()->isValid()) {
// Process update
}
}
Custom Move Validators
Extend the MoveValidatorInterface to enforce business rules:
class CustomMoveValidator implements MoveValidatorInterface
{
public function isValidMove(Game $game, string $move): bool
{
// Custom logic (e.g., check for checkmate)
}
}
Register in services.yaml:
services:
App\Validator\CustomMoveValidator:
tags:
- { name: cleentfaar_windmill.move_validator }
Webhook Handlers
Implement WebhookHandlerInterface for real-time updates:
class SlackWebhookHandler implements WebhookHandlerInterface
{
public function handle(GameEvent $event): void
{
$this->slack->send("Game updated: {$event->getGame()->getId()}");
}
}
Bind in config/packages/cleentfaar_windmill.yaml:
webhooks:
handlers:
- App\Handler\SlackWebhookHandler
Testing
WindmillService’s setClient() method to mock API calls in tests:
$windmill->setClient($mockClient);
$this->assertEquals('expected_move', $windmill->makeMove('game123', 'e4')->getMove());
How can I help you explore Laravel packages today?