Một buổi chiều, một chiếc máy tính: Dẹp bỏ 90% việc lặp lại khi code Symfony
Khi làm các dự án Symfony, những công việc lặt vặt ở tầng dưới (low-level) thực sự rất đau đầu. Xử lý upload file, viết giao diện CRUD, đồng bộ timestamp cơ sở dữ liệu... Nếu dự án nào cũng hì hục viết lại từ đầu (from scratch), bạn không chỉ dễ phải OT (làm thêm giờ) mà code còn dễ sinh Bug.

Mình đã tổng hợp lại 9 Symfony bundle giúp giải quyết triệt để những nỗi đau không thể tránh khỏi trong quá trình phát triển.
1. FOSElasticaBundle: Tìm kiếm Full-Text nhanh như gió
Khi dữ liệu trong database lên tới vài trăm nghìn dòng, việc dùng LIKE %...% để tìm kiếm sẽ trở nên cực kỳ chậm chạp. FOSElastica giúp tích hợp Elasticsearch vào Symfony một cách mượt mà.
Bạn có thể tìm kiếm nội dung trong index trực tiếp thông qua service Finder:
$results = $container->get('fos_elastica.finder.app.article')->find('từ khóa tìm kiếm');
Điểm yên tâm nhất là: khi bạn lưu một Entity bằng Doctrine, nó sẽ tự động đồng bộ dữ liệu sang Elasticsearch. Quên đi việc phải viết code đồng bộ thủ công.
2. StofDoctrineExtensionsBundle: Đừng cập nhật Timestamp bằng tay nữa
Trước đây, mỗi khi tạo bảng, mình đều phải viết hàm setCreatedAt trong Entity. Lỡ quên một cái là mất dấu vết dữ liệu (data tracking). Tính năng hay dùng nhất của bundle này là tự động xử lý thời gian và tạo đường dẫn ảo (Slug).
Chỉ cần thêm Annotation (chú thích) vào trường dữ liệu, phần còn lại cứ để nó lo:
use Gedmo\Mapping\Annotation as Gedmo;
class Post
{
// Tự động điền khi tạo mới
#[Gedmo\Timestampable(on: 'create')]
#[ORM\Column]
private \DateTime $createdAt;
// Tự động cập nhật khi có thay đổi
#[Gedmo\Timestampable(on: 'update')]
#[ORM\Column]
private \DateTime $updatedAt;
// Tự động tạo slug URL duy nhất từ tiêu đề, không cần regex thủ công
#[Gedmo\Slug(fields: ['title'])]
#[ORM\Column(length: 150)]
private $slug;
}
3. LiipImagineBundle: Cân mọi loại kích thước ảnh thumbnail
Nếu để người dùng upload ảnh 5MB và hiển thị nguyên xi ở trang danh sách, trang web sẽ load chậm như rùa bò. Tư duy của LiipImagine là: lưu một bản gốc, còn thumbnail sẽ được tạo và cache theo nhu cầu (on demand).
Gọi trực tiếp filter đã định nghĩa ngay trong template:
{# Tự động tạo và hiển thị ảnh thumbnail crop 120x120 #}
<img src="{{ asset(product.image) | imagine_filter('thumbnail_120') }}" />
4. EasyAdminBundle: Dựng trang Admin trong nửa ngày
Nếu dự án cần trang quản trị, chẳng việc gì phải viết HTML template từ đầu. EasyAdmin gần như là lựa chọn mặc định của Symfony developer; nó cấu hình trọn bộ CRUD chỉ thông qua các class PHP đơn giản.
class ProductCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Product::class;
}
public function configureFields(string $pageName): iterable
{
yield TextField::new('name');
yield MoneyField::new('price')->setCurrency('VND');
}
}
5. VichUploaderBundle: Upload file không còn là mớ hỗn độn
Viết code upload file thủ công rất mệt: phải check đuôi file, đổi tên để tránh trùng lặp, rồi lưu đường dẫn vào database. VichUploader chuẩn hóa quy trình này.
Chỉ cần định nghĩa mapping trong file config và bind một đối tượng File vào Entity:
#[Vich\Uploadable]
class UserProfile
{
#[Vich\UploadableField(mapping: 'avatars', fileNameProperty: 'imageName')]
private ?File $imageFile = null;
#[ORM\Column]
private ?string $imageName = null;
public function setImageFile(?File $imageFile = null): void
{
$this->imageFile = $imageFile;
if ($imageFile) {
$this->updatedAt = new \DateTimeImmutable();
}
}
}
6. KnpPaginatorBundle: Logic phân trang "một lần và mãi mãi"
Phần phiền phức nhất của phân trang là tính toán offset và tổng số trang. Thói quen của mình là ném thẳng đối tượng Query cho KnpPaginator, nó sẽ tự xử lý logic.
// Trong Controller
$pagination = $paginator->paginate(
$queryBuilder,
$request->query->getInt('page', 1),
12 // Số item mỗi trang
);
return $this->render('list.html.twig', ['pagination' => $pagination]);
Trong Twig, chỉ một dòng code là render ra thanh phân trang: {{ knp_pagination_render(pagination) }}.
7. SchebTwoFactorBundle: Bảo mật 2 lớp (2FA) nhanh gọn
Nhiều dự án hiện nay yêu cầu xác thực 2 bước (2FA). Tự viết logic sinh mã và bind với Google Authenticator rất cực. Bundle này đã lo hết quy trình bảo mật.
Chỉ cần bật nó trong security.yaml:
security:
firewalls:
main:
two_factor:
auth_form_path: 2fa_login
check_path: 2fa_login_check
Nó tự động xử lý logic check mã; chúng ta chỉ cần quan tâm đến giao diện UI.
8. JMSTranslationBundle: Đa ngôn ngữ không lo sót key
Khi làm dự án Multi-language, sợ nhất là sót key dịch ở trang nào đó. Bundle này quét toàn bộ dự án và trích xuất tất cả nội dung cần dịch.
# Chạy lệnh này để tự động cập nhật file translation.yaml
php bin/console translation:extract vi --config=app
Nó tìm tất cả thẻ trans và các hàm gọi dịch, bạn chỉ cần điền vào chỗ trống trong file mà không lo bỏ sót.
9. MakerBundle: Trợ lý sinh code hiệu quả
Đây là cái quen thuộc nhất, nhưng nhiều người chỉ dùng nó để tạo Entity. Thực tế nó làm được nhiều hơn thế, ví dụ như tạo Voter (kiểm soát quyền) hay tạo Custom Command.
# Tạo nhanh trình kiểm tra quyền hạn
php bin/console make:voter PostVoter
# Tạo nhanh quy trình CRUD trọn gói (Controller, Form, Template)
php bin/console make:crud Product
Tập thói quen dùng dòng lệnh để sinh code sẽ giúp bạn tránh được rất nhiều lỗi ngớ ngẩn do gõ tay (typo).
Nền tảng: Quản lý môi trường của bạn
Khi phát triển Symfony ở local, không thể không nhắc đến việc cấu hình môi trường PHP. Đôi khi dự án cũ yêu cầu PHP 5.6, dự án mới lại cần PHP 8.3, mỗi dự án lại cần các extension khác nhau. Việc chuyển đổi giữa một đống phiên bản trên máy tính thực sự là cực hình.
Gần đây mình đang dùng ServBay. Nó cho phép bạn cài đặt PHP chỉ với một cú click, hỗ trợ từ PHP 5.3 cổ đại đến PHP 8.6-dev mới nhất, và hỗ trợ chạy song song nhiều phiên bản PHP cùng lúc.

Trước đây, thay đổi môi trường có thể mất cả buổi chiều vật lộn với Docker hoặc máy ảo. ServBay là giải pháp cài đặt một chạm, tích hợp sẵn các thành phần dev phổ biến như PHP, MariaDB, PostgreSQL, Redis và Elasticsearch. Tiện nhất là chạy nhiều bản PHP trên cùng một giao diện, không cần phải đập đi xây lại môi trường chỉ để chạy một dự án cũ (legacy).
Nếu bạn cũng đã chán ngấy việc gõ brew install hay sửa loạn xạ các file config ở local, hãy thử dùng ServBay kết hợp với các Bundle kể trên. Bạn sẽ dành được nhiều năng lượng hơn cho logic nghiệp vụ, và nhịp độ phát triển sẽ mượt mà hơn rất nhiều.
Lời kết
Đừng lãng phí thời gian vào những việc vặt vãnh như viết code upload hay phân trang thủ công nữa. Hoặc là học cách tận dụng những "bánh xe" có sẵn, hoặc là để nhiệt huyết nghề nghiệp cạn kiệt trong những công việc tay chân vô nghĩa.
Bạn sẽ nhận ra rằng, code chất lượng cao thực ra có thể làm rất nhanh.
All rights reserved