| name | symfony-framework |
| description | Comprehensive Symfony 6.4 development skill for creating web applications, APIs, and microservices. Provides workflows, best practices, and tools for efficient Symfony development including controllers, routing, database operations with Doctrine, forms, security, testing, and deployment. |
| license | MIT |
| version | 1.0.0 |
Symfony Framework Development Skill
This skill provides comprehensive guidance for developing applications with Symfony 6.4, the leading PHP framework for web applications and APIs.
Quick Start Workflow
1. Project Initialization
For a new Symfony project:
# Full web application
symfony new project_name --version="6.4.*" --webapp
# API/Microservice
symfony new project_name --version="6.4.*"
# If Symfony CLI not available, use Composer
composer create-project symfony/skeleton:"6.4.*" project_name
2. Development Server
symfony server:start
# Access at http://localhost:8000
Core Development Patterns
Controller Creation
Always extend AbstractController and use attributes for routing:
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class ProductController extends AbstractController
{
#[Route('/products', name: 'product_list')]
public function list(): Response
{
return $this->render('product/list.html.twig', [
'products' => $products,
]);
}
#[Route('/products/{id}', name: 'product_show')]
public function show(Product $product): Response
{
// Automatic entity parameter conversion
return $this->render('product/show.html.twig', [
'product' => $product,
]);
}
}
Service Configuration
Use autowiring by default in config/services.yaml:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
Database Operations with Doctrine
Entity Creation
php bin/console make:entity Product
Migration Workflow
# Generate migration
php bin/console make:migration
# Execute migration
php bin/console doctrine:migrations:migrate
Repository Pattern
// In controller
public function index(ProductRepository $repository): Response
{
$products = $repository->findBy(['active' => true]);
// Custom repository methods
$featured = $repository->findFeaturedProducts();
}
Form Handling
Build forms in dedicated classes:
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name')
->add('price')
->add('description')
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Product::class,
]);
}
}
Controller handling:
#[Route('/product/new', name: 'product_new')]
public function new(Request $request, EntityManagerInterface $em): Response
{
$product = new Product();
$form = $this->createForm(ProductType::class, $product);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($product);
$em->flush();
return $this->redirectToRoute('product_show', ['id' => $product->getId()]);
}
return $this->render('product/new.html.twig', [
'form' => $form,
]);
}
Security Implementation
User Authentication
# config/packages/security.yaml
security:
password_hashers:
App\Entity\User:
algorithm: auto
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
firewalls:
main:
form_login:
login_path: app_login
check_path: app_login
logout:
path: app_logout
Authorization with Voters
namespace App\Security\Voter;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
class ProductVoter extends Voter
{
public const EDIT = 'PRODUCT_EDIT';
public const VIEW = 'PRODUCT_VIEW';
protected function supports(string $attribute, mixed $subject): bool
{
return in_array($attribute, [self::EDIT, self::VIEW])
&& $subject instanceof Product;
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();
return match($attribute) {
self::VIEW => true,
self::EDIT => $user && $subject->getOwner() === $user,
default => false,
};
}
}
API Development
JSON Responses
#[Route('/api/products', name: 'api_products')]
public function apiList(ProductRepository $repository): JsonResponse
{
$products = $repository->findAll();
return $this->json($products, 200, [], [
'groups' => ['product:read']
]);
}
Request Validation
#[Route('/api/product', methods: ['POST'])]
public function create(
#[MapRequestPayload] ProductDto $dto,
ValidatorInterface $validator
): JsonResponse {
$errors = $validator->validate($dto);
if (count($errors) > 0) {
return $this->json($errors, 400);
}
// Process valid data
}
Essential Commands
Development
# Clear cache
php bin/console cache:clear
# Show routes
php bin/console debug:router
# Show services
php bin/console debug:container
# Show configuration
php bin/console debug:config framework
# Create controller
php bin/console make:controller
# Create CRUD
php bin/console make:crud Product
Database
# Create database
php bin/console doctrine:database:create
# Update schema (dev only)
php bin/console doctrine:schema:update --force
# Load fixtures
php bin/console doctrine:fixtures:load
Testing
# Run all tests
php bin/phpunit
# Specific test file
php bin/phpunit tests/Controller/ProductControllerTest.php
# With coverage
php bin/phpunit --coverage-html coverage/
Directory Structure
project/
├── assets/ # Frontend assets (JS, CSS)
├── bin/ # Executables (console, phpunit)
├── config/ # Configuration files
│ ├── packages/ # Package-specific config
│ ├── routes/ # Routing configuration
│ └── services.yaml # Service definitions
├── migrations/ # Database migrations
├── public/ # Web root
│ └── index.php # Front controller
├── src/ # Application code
│ ├── Controller/ # Controllers
│ ├── Entity/ # Doctrine entities
│ ├── Form/ # Form types
│ ├── Repository/ # Doctrine repositories
│ └── Service/ # Business logic
├── templates/ # Twig templates
├── tests/ # Test suites
├── translations/ # Translation files
├── var/ # Generated files (cache, logs)
└── vendor/ # Dependencies
Performance Optimization
Caching Strategy
# config/packages/cache.yaml
framework:
cache:
pools:
cache.product:
adapter: cache.adapter.redis
default_lifetime: 3600
Usage:
public function __construct(private CacheInterface $productCache) {}
public function getProduct(int $id): ?Product
{
return $this->productCache->get(
'product_' . $id,
function (ItemInterface $item) use ($id) {
$item->expiresAfter(3600);
return $this->repository->find($id);
}
);
}
Query Optimization
// Eager loading with Doctrine
$products = $repository->createQueryBuilder('p')
->leftJoin('p.category', 'c')
->addSelect('c')
->leftJoin('p.tags', 't')
->addSelect('t')
->getQuery()
->getResult();
Error Handling
// In controller
if (!$product) {
throw $this->createNotFoundException('Product not found');
}
// Custom exception
throw new BadRequestHttpException('Invalid product data');
// API error response
return $this->json([
'error' => 'Invalid request',
'details' => $errors
], Response::HTTP_BAD_REQUEST);
Deployment Checklist
Environment setup
APP_ENV=prod APP_DEBUG=0Optimize autoloader
composer install --no-dev --optimize-autoloaderClear and warm cache
php bin/console cache:clear --env=prod php bin/console cache:warmup --env=prodCompile assets
npm run buildRun migrations
php bin/console doctrine:migrations:migrate --env=prod
Testing Patterns
Functional Tests
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class ProductControllerTest extends WebTestCase
{
public function testListProducts(): void
{
$client = static::createClient();
$client->request('GET', '/products');
$this->assertResponseIsSuccessful();
$this->assertSelectorTextContains('h1', 'Products');
}
public function testCreateProduct(): void
{
$client = static::createClient();
$client->request('POST', '/api/products', [], [], [
'CONTENT_TYPE' => 'application/json'
], json_encode(['name' => 'Test Product']));
$this->assertResponseStatusCodeSame(201);
}
}
Common Patterns to Follow
- Always use dependency injection - Never instantiate services manually
- Prefer composition over inheritance - Use services and traits
- Keep controllers thin - Move business logic to services
- Use DTOs for API input/output - Decouple API from entities
- Implement repository pattern - Keep database queries in repositories
- Use voters for authorization - Centralize access control logic
- Cache expensive operations - Use Symfony's cache component
- Write tests first - TDD approach for critical features
Troubleshooting Guide
Common Issues
Issue: Services not autowiring
php bin/console debug:container ServiceName
# Check if service is properly registered
Issue: Route not found
php bin/console debug:router | grep pattern
# Verify route registration
Issue: Database connection errors
php bin/console doctrine:database:create
# Verify database credentials in .env
Issue: Template not found
- Check template path relative to
templates/ - Verify file extension is
.html.twig
When to Use Scripts
Refer to bundled scripts in scripts/ for:
- Complex entity generation
- Database migration helpers
- Deployment automation
- Performance profiling
Additional Resources
For detailed documentation on specific topics, load the appropriate reference file from references/:
references/doctrine-advanced.md- Complex ORM patternsreferences/security-detailed.md- Advanced security configurationsreferences/api-platform.md- API Platform integrationreferences/testing-complete.md- Comprehensive testing strategiesreferences/performance-tuning.md- Performance optimization techniques