Installation:
composer require cwd/grid-bundle
Ensure the bundle is enabled in config/bundles.php:
return [
// ...
Cwd\GridBundle\CwdGridBundle::class => ['all' => true],
];
First Use Case: Define a grid in a controller or service:
use Cwd\GridBundle\Grid\Grid;
use Cwd\GridBundle\Grid\Column\EnumType;
public function buildGrid(): Grid
{
return (new Grid())
->add(new EnumType('status', 'user.status', [
'label' => 'Status',
'class' => UserStatus::class,
]));
}
Enum Definition:
Create a PHP 8.1+ enum (e.g., UserStatus.php):
enum UserStatus: string {
case ACTIVE = 'active';
case INACTIVE = 'inactive';
case PENDING = 'pending';
}
Translations:
Add translations in config/packages/translation.yaml and define keys in translations/messages.en.yaml:
# messages.en.yaml
active: "Active"
inactive: "Inactive"
pending: "Pending"
Render the Grid: Use Twig to display the grid in a template:
{{ render(controller('App\Controller\YourController::buildGrid')) }}
Dynamic Enum Classes: Pass the enum class dynamically (e.g., via dependency injection or service container):
$enumClass = $this->container->getParameter('app.user_status_enum');
$grid->add(new EnumType('status', 'user.status', ['class' => $enumClass]));
Reusable Column Factories: Create a factory method to standardize enum column creation:
public function createEnumColumn(string $name, string $dataKey, string $enumClass, string $label): EnumType
{
return new EnumType($name, $dataKey, [
'label' => $label,
'class' => $enumClass,
'allOptionsLabel' => 'all_' . strtolower($label),
]);
}
Default Filter Values: Set a default filter value in the column options:
->add(new EnumType('status', 'user.status', [
'class' => UserStatus::class,
'defaultFilter' => UserStatus::PENDING->value,
]))
Custom Filter Logic:
Extend EnumType to override filter behavior (e.g., multi-select):
class MultiEnumType extends EnumType {
public function __construct(string $name, string $dataKey, array $options = [])
{
$options['multiple'] = true;
parent::__construct($name, $dataKey, $options);
}
}
Form Type Integration: Use the same enum class in Symfony forms for consistency:
$builder->add('status', EnumType::class, [
'class' => UserStatus::class,
'choice_label' => fn(UserStatus $status) => $this->translator->trans($status->value),
]);
API Responses: Normalize enum values in API responses using a transformer:
public function transform($object, string $format = null, array $context = [])
{
return [
'status' => $object->status->value,
'status_label' => $this->translator->trans($object->status->value),
];
}
Lazy-Loading Enums: Load enum classes dynamically to reduce memory usage:
$enumClass = $this->getEnumClassFromConfig($dataKey);
$grid->add(new EnumType('status', $dataKey, ['class' => $enumClass]));
Caching Translations: Cache translated enum labels to avoid repeated translation lookups:
$translator = $this->container->get('translator');
$cachedLabels = $translator->getCatalogue()->all('en', 'messages');
Enum Class Not Found:
Class [App\Domain\UserStatus] does not exist.composer dump-autoload).App\Domain\UserStatus) in the class option.Translation Keys Missing:
ACTIVE instead of Active).translator:dump to debug missing translations:
php bin/console translator:dump en messages
Filter Dropdown Empty:
var_dump((new \ReflectionClass($enumClass))->getCases());
Deprecated Symfony Features:
Symfony\Component\HttpFoundation\Request).composer require symfony/*:^6.3
Log Enum Data: Add debug logs to inspect enum data flow:
$grid->add(new EnumType('status', 'user.status', [
'class' => UserStatus::class,
'debug' => true, // Hypothetical option; log manually if needed
]));
Check Grid Events: Listen to grid events to debug column rendering:
$grid->on('column.build', function (ColumnEvent $event) {
if ($event->getColumn() instanceof EnumType) {
$this->logger->debug('Enum column built:', [
'name' => $event->getColumn()->getName(),
'options' => $event->getColumn()->getOptions(),
]);
}
});
Custom Enum Rendering:
Extend EnumType to render enums differently (e.g., badges or icons):
class BadgeEnumType extends EnumType {
public function renderCell($value, array $rowData)
{
$label = parent::renderCell($value, $rowData);
return sprintf('<span class="badge bg-%s">%s</span>', $this->getBadgeClass($value), $label);
}
private function getBadgeClass(string $value): string
{
return match ($value) {
'active' => 'success',
'inactive' => 'danger',
default => 'primary',
};
}
}
Dynamic Enum Loading: Implement a custom loader for enums fetched from a database or API:
class DynamicEnumType extends EnumType {
public function __construct(string $name, string $dataKey, array $options = [])
{
$options['class'] = $this->loadEnumClassFromDatabase($dataKey);
parent::__construct($name, $dataKey, $options);
}
private function loadEnumClassFromDatabase(string $dataKey): string
{
// Logic to fetch enum definition dynamically
return 'App\Domain\Dynamic\\' . ucfirst($dataKey) . 'Enum';
}
}
Integration with Doctrine: Use enums in Doctrine entities and sync grid columns:
// Entity
#[ORM\Column(enumType: UserStatus::class)]
private UserStatus $status;
// Grid
->add(new EnumType('status', 'user.status', [
'class' => UserStatus::class,
'doctrine_enum' => true, // Hypothetical option; validate manually
]))
All Options Label:
The allOptionsLabel must be a valid translation key. Defaults to 'all', but ensure it’s defined in translations:
# messages.en.yaml
all: "All"
all_states: "All States" # Custom label for enum columns
Translatable Option:
Setting translatable: false bypasses translation, but ensure the enum values are user-friendly:
->add(new EnumType('status', 'user.status', [
'class' => UserStatus::class,
'translatable' => false,
]))
Case Sensitivity:
Enum case values are case-sensitive in translations. Use strtolower() if needed:
// In a custom renderer
$transKey =
How can I help you explore Laravel packages today?