robiningelbrecht/symfony-skeleton

A Symfony skeleton I use to bootstrap new projects


README

CI PHP Symfony PHPStan Enabled License

Bootstrap new project

> composer create-project robiningelbrecht/symfony-skeleton [app-name] --no-install --ignore-platform-reqs

Open .env and set following ENV VARIABLES:

DOCKER_CONTAINER_BASE_NAME=skeleton
DOCKER_MYSQL_PORT=3306
DOCKER_NGINX_PORT=8081
# Install dependencies
> make composer arg="install"
# Setup project (configure containers and functionality)
> make console arg="app:setup"
# Build docker containers
> make build-containers

Makefile

There are some predefined commands in the Makefile:

# Run test suite
> make phpunit
# Run cs fixer
> make csfix
# Run PHPstan
> make phpstan
# Create and run migrations
> make migrate-diff
> make migrate-run
# Run a console command
> make console arg="your:fancy:command"

Events

Recording Events

In your entity use RecordsEvents; and record events when needed:

class User
{
    use RecordsEvents;
    
    public static function create(
        UserId $id,
    ): self {
        // ...
        $user->recordThat(new UserWasCreated(
            userId: $user->getUserId(),
        ));

        return $user;
    }
}

Publishing Events

In your repository, inject the EventBus and publish the recorded events:

final readonly class UserRepository implements CommandHandler
{
    public function __construct(
        private EventBus $eventBus,
    ) {
    }
    
    public function save(User $user): void
    {
        // ...
        $this->eventBus->publishEvents($user->getRecordedEvents());
    }    

Registering Event Listeners

Create a manager / event listener and add the AsEventListener attribute:

final readonly class UserEmailManager
{
    #[AsEventListener]
    public function reactToUserWasCreated(UserWasCreated $event): void
    {
        // ...
    }
}

More info: https://symfony.com/doc/current/event_dispatcher.html#defining-event-listeners-with-php-attributes

Rate Limiter

Create a Rate Limiter

Define a new rate limiter in config/packages/rate_limiter.yaml:

framework:
  rate_limiter:
    anonymous:
      policy: 'sliding_window'
      limit: 100
      interval: '60 minutes'

Apply a limiter to a route

Then apply it to the necessary routes:

    #[RateLimiter('anonymous')]
    #[Route(path: '/your/important/route', methods: ['GET', 'POST'])]
    public function handle(Request $request): Response
    {
      // ...
    }

more info: https://symfony.com/doc/current/rate_limiter.html