Installation
composer require baks-dev/article-category
php bin/console baks:assets:install
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
config/packages/baks_article_category.yaml exists (auto-generated by baks:assets:install).First Use Case: Create a Category
use Baks\ArticleCategory\Entity\Category;
use Baks\ArticleCategory\Repository\CategoryRepository;
$category = new Category();
$category->setName('Technology');
$category->setSlug('technology');
$category->setDescription('Latest tech trends');
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->flush();
Key Classes to Explore
Baks\ArticleCategory\Entity\Category (Core entity)Baks\ArticleCategory\Repository\CategoryRepository (Default repository)Baks\ArticleCategory\Form\CategoryType (Symfony form type)Baks\ArticleCategory\Event\CategoryEvents (Event system)Hierarchical Categories
Use setParent() to create nested categories:
$parent = $categoryRepository->findOneBy(['slug' => 'technology']);
$child = new Category();
$child->setName('AI');
$child->setParent($parent);
Slug Generation
Auto-slugging via setSlug() (falls back to setName() if slug is empty):
$category->setName('Machine Learning'); // Auto-generates 'machine-learning'
Symfony Form Builder
use Baks\ArticleCategory\Form\CategoryType;
$form = $this->createForm(CategoryType::class, $category);
parent field.Validation Built-in constraints:
UniqueEntity (slug uniqueness per parent)NotBlank (name/description)// config/services.yaml
Baks\ArticleCategory\EventListener\CategoryListener:
tags:
- { name: kernel.event_listener, event: baks.article_category.pre_persist, method: onPrePersist }
pre_persist, post_persist, pre_remove, post_remove.RESTful Endpoints Example with Symfony UX:
use Baks\ArticleCategory\Controller\CategoryController;
// Auto-generated CRUD routes (if using `baks:assets:install` with API config)
$this->addRoute('GET', '/api/categories', CategoryController::class, 'list');
Serialization
Uses Symfony’s Serializer (configure via config/packages/baks_article_category.yaml):
baks_article_category:
serializer:
enabled: true
groups: [category_list, category_detail]
Custom Repositories
Extend CategoryRepository for complex queries:
namespace App\Repository;
use Baks\ArticleCategory\Repository\CategoryRepository as BaseRepository;
class CustomCategoryRepository extends BaseRepository {
public function findByParentSlug(string $slug): array {
return $this->createQueryBuilder('c')
->where('c.parent.slug = :slug')
->setParameter('slug', $slug)
->getQuery()
->getResult();
}
}
QueryBuilder Helpers
$qb = $categoryRepository->createQueryBuilder('c');
$qb->addSelect('COUNT(a.id) AS articleCount')
->leftJoin('c.articles', 'a')
->groupBy('c.id');
Migration Conflicts
category table, reset migrations:
php bin/console doctrine:migrations:diff --complete
id, name, slug, description, parent_id, and created_at/updated_at fields.Circular References in Serialization
baks_article_category:
serializer:
circular_reference_handler: ~
Event Listener Priority
@Priority annotations to control order:
use Symfony\Component\DependencyInjection\Attribute\Priority;
#[Priority(10)] // Higher priority = earlier execution
public function onPrePersist(CategoryEvent $event): void {}
Translation Issues
baks_article_category.translation for labels. Override in your translation files:
# config/packages/translation.yaml
baks_article_category:
translation_domain: 'messages'
Enable SQL Logging
# config/packages/dev/doctrine.yaml
doctrine:
dbal:
logging: true
article_category queries:
grep -i "article_category" app/log/dev.log
Dump Entity State
use Symfony\Component\VarDumper\VarDumper;
VarDumper::dump($category->getParent()->getChildren());
Custom Fields Add fields via Doctrine extensions or entity inheritance:
// app/src/Entity/ExtendedCategory.php
use Baks\ArticleCategory\Entity\Category;
class ExtendedCategory extends Category {
#[ORM\Column]
private ?string $customField = null;
}
Override Forms
Extend CategoryType:
use Baks\ArticleCategory\Form\CategoryType as BaseType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class ExtendedCategoryType extends BaseType {
public function buildForm(FormBuilderInterface $builder, array $options) {
parent::buildForm($builder, $options);
$builder->add('customField', TextType::class);
}
}
Modify Serialization Groups
Add custom groups in config/packages/baks_article_category.yaml:
baks_article_category:
serializer:
groups:
- 'default'
- 'custom_group'
Hook into Lifecycle Callbacks
Use @ORM\PrePersist/@ORM\PostUpdate in a custom listener:
use Doctrine\ORM\Event\LifecycleEventArgs;
public function prePersist(LifecycleEventArgs $args): void {
$category = $args->getObject();
if ($category instanceof Category && empty($category->getSlug())) {
$category->setSlug(StringUtil::slugify($category->getName()));
}
}
N+1 Queries in Hierarchy Fetch children eagerly:
$category = $categoryRepository->findOneBy(['slug' => 'technology'], ['children' => 'ASC']);
$qb = $categoryRepository->createQueryBuilder('c')
->leftJoin('c.children', 'child')
->addSelect('child')
->where('c.slug = :slug')
->setParameter('slug', 'technology');
Indexing for Large Datasets Add indexes manually if slug lookups are slow:
CREATE INDEX idx_category_slug_parent ON article_category (slug, parent_id);
How can I help you explore Laravel packages today?