원클릭으로
symfony-conventions
Symfony best practices for services, Doctrine, Twig, forms, and dependency injection
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Symfony best practices for services, Doctrine, Twig, forms, and dependency injection
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
RESTful API design patterns, HTTP standards, versioning, error handling, and documentation
Joomla 4/5 component development with MVC, services, plugins, and language handling
Joomla 3.x legacy patterns with JFactory, non-namespaced MVC, JDatabase, and plugin structure
Laravel best practices for Eloquent, controllers, validation, services, and testing
Performance optimization for PHP, JavaScript, databases, and caching strategies
PHP coding standards including strict typing, OOP patterns, error handling, and documentation
| name | symfony-conventions |
| description | Symfony best practices for services, Doctrine, Twig, forms, and dependency injection |
| license | MIT |
| compatibility | opencode |
| metadata | {"framework":"symfony","version":"6.0+"} |
src/
├── Controller/
├── Entity/
├── Repository/
├── Service/
├── EventSubscriber/
├── Form/
├── Security/
└── Twig/
Keep controllers thin, use autowiring:
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Service\UserService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
#[Route('/api/users')]
final class UserController extends AbstractController
{
public function __construct(
private readonly UserService $user_service
) {}
#[Route('', methods: ['POST'])]
public function create(Request $request): JsonResponse
{
$data = json_decode($request->getContent(), true);
$user = $this->user_service->create($data);
return $this->json($user, 201);
}
}
<?php
declare(strict_types=1);
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: 'users')]
class User
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank]
#[Assert\Length(max: 255)]
private string $name;
#[ORM\Column(length: 255, unique: true)]
#[Assert\NotBlank]
#[Assert\Email]
private string $email;
#[ORM\OneToMany(mappedBy: 'author', targetEntity: Post::class)]
private Collection $posts;
public function __construct()
{
$this->posts = new ArrayCollection();
}
// Getters and setters...
}
<?php
declare(strict_types=1);
namespace App\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<User>
*/
final class UserRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, User::class);
}
/**
* @return User[]
*/
public function findActiveUsers(): array
{
return $this->createQueryBuilder('u')
->andWhere('u.is_active = :active')
->setParameter('active', true)
->orderBy('u.created_at', 'DESC')
->getQuery()
->getResult();
}
}
<?php
declare(strict_types=1);
namespace App\Service;
use App\Entity\User;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
final class UserService
{
public function __construct(
private readonly EntityManagerInterface $entity_manager,
private readonly UserRepository $user_repository,
private readonly UserPasswordHasherInterface $password_hasher
) {}
public function create(array $data): User
{
$user = new User();
$user->setName($data['name']);
$user->setEmail($data['email']);
$user->setPassword($this->password_hasher->hashPassword($user, $data['password']));
$this->entity_manager->persist($user);
$this->entity_manager->flush();
return $user;
}
}
<?php
declare(strict_types=1);
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
final class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name', TextType::class)
->add('email', EmailType::class)
->add('password', PasswordType::class);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => User::class,
'csrf_protection' => true,
]);
}
}
{# Auto-escaping is ON by default #}
<h1>{{ user.name }}</h1>
{# Only use raw when content is trusted/sanitized #}
{{ trusted_html|raw }}
{# Translation #}
{{ 'user.welcome'|trans({'%name%': user.name}) }}
{# Routing #}
<a href="{{ path('user_show', {id: user.id}) }}">View</a>
{# CSRF in forms #}
{{ form_start(form) }}
{{ form_widget(form) }}
<button type="submit">Submit</button>
{{ form_end(form) }}
<?php
declare(strict_types=1);
namespace App\EventSubscriber;
use App\Event\UserCreatedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
final class UserEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
UserCreatedEvent::class => 'onUserCreated',
];
}
public function onUserCreated(UserCreatedEvent $event): void
{
// Send welcome email, etc.
}
}
// Message
final readonly class SendEmailMessage
{
public function __construct(
public string $recipient,
public string $subject,
public string $content
) {}
}
// Handler
#[AsMessageHandler]
final class SendEmailHandler
{
public function __invoke(SendEmailMessage $message): void
{
// Send email
}
}
// Dispatch
$this->message_bus->dispatch(new SendEmailMessage($email, $subject, $content));
->select() in DQL for partial objectsfetch="EXTRA_LAZY" for large collections