aschaeffer/sonata-editable-list-bundle
Install the Bundle
composer require aschaeffer/sonata-editable-list-bundle
Enable the bundle in config/bundles.php (Symfony Flex) or AppKernel.php (legacy):
Aschaeffer\SonataEditableListBundle\AschaefferSonataEditableListBundle::class => ['all' => true],
Configure Entity Classes
Update config/packages/aschaeffer_sonata_editable_list.yaml:
aschaeffer_sonata_editable_list:
class:
list: App\Entity\SonataEditableList
item: App\Entity\SonataEditableItem
Create Base Entities
Use the provided SonataEditableList and SonataEditableItem entities (from the recipe branch) or create your own extending them.
Initialize Lists
Run the command to create a list (e.g., user_gender):
php bin/console sonata:editable_list:create user_gender
Define items via Sonata Admin or manually in the database.
Annotate the Entity
Add @Listable to a property (e.g., User entity):
use Aschaeffer\SonataEditableListBundle\Model\Listable;
class User {
/**
* @Listable(code="user_gender")
* @ORM\ManyToOne(targetEntity="SonataEditableItem")
*/
protected $gender;
}
Configure Sonata Admin
Extend configureFormFieldsProperties and configureDatagridFilters in your UserAdmin:
use Aschaeffer\SonataEditableListBundle\Form\Type\ItemSelectorType;
protected function configureFormFieldsProperties(FormMapper $formMapper) {
$formMapper->add('gender', ItemSelectorType::class, [
'model_manager' => $this->getModelManager(),
'class' => SonataEditableItem::class,
'expanded' => true,
]);
}
Test in Admin Panel
Navigate to the Sonata Admin for User. The gender field should now appear as a selectable item from the predefined list.
Define Lists
Use the CLI or Sonata Admin to create lists (e.g., user_gender, user_interests).
Example CLI command:
php bin/console sonata:editable_list:create user_gender --items="Male,Female,Other"
Integrate with Entities
@Listable with @ORM\ManyToOne (e.g., gender).@Listable with @ORM\ManyToMany (e.g., interests).getListableCode() in entities for dynamic list codes.Admin Integration
ItemSelectorType for dropdowns/checkboxes.
$formMapper->add('interests', ItemSelectorType::class, [
'multiple' => true, // For many-to-many
'expanded' => true, // Checkboxes instead of dropdown
]);
DatagridMapper for filtering:
$datagridMapper->add('gender', null, [], ItemSelectorType::class, [
'field_name' => 'gender',
'class_name' => User::class,
]);
Dynamic Lists Fetch lists dynamically in templates or services:
{% set genderList = app.service('aschaeffer_sonata_editable_list.list.manager').findByCode('user_gender') %}
Sonata Admin CRUD
Extend SonataEditableListAdmin and SonataEditableItemAdmin for custom list/item management.
Validation Validate listable fields in entity constraints:
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @UniqueEntity(fields={"gender"}, message="Gender already selected")
*/
class User {}
Translations
Store item labels in translation files (e.g., messages.en.yaml):
user_gender:
Male: "Mr."
Female: "Ms."
Other: "Other"
Fetch translations in ItemSelectorType via translator.
APIs Serialize listable fields in APIs using serializers:
use JMS\Serializer\Annotation\SerializedName;
class User {
/**
* @SerializedName("gender_label")
*/
public function getGenderLabel() {
return $this->gender->getLabel();
}
}
Circular Dependencies
persist in @ORM\ManyToOne for SonataEditableItem can cause "detached entity" errors.cascade={"persist"} to listable fields:
@ORM\ManyToOne(targetEntity="SonataEditableItem", cascade={"persist"})
List Code Mismatches
@Listable(code="...") or CLI commands break list associations.SonataEditableListManager or use a constant:
class User {
const LIST_GENDER = 'user_gender';
/**
* @Listable(code=self::LIST_GENDER)
*/
protected $gender;
}
Form Type Misconfiguration
ItemSelectorType fails if model_manager or class is misconfigured.Doctrine\ORM\EntityManagerInterface:
$formMapper->add('gender', ItemSelectorType::class, [
'model_manager' => $this->getModelManager(), // Critical!
'class' => SonataEditableItem::class,
]);
Permission Issues
security.yaml:
access_control:
- { path: ^/admin/editable_list, roles: ROLE_ADMIN }
Check List Existence Verify lists exist in the database:
php bin/console doctrine:query:sql "SELECT * FROM sonata_editable_list"
Log Form Errors
Enable Symfony debug mode and check var/log/dev.log for ItemSelectorType errors.
Validate Entity Mapping Use Doctrine’s schema validation:
php bin/console doctrine:schema:validate
Custom Item Selector
Extend ItemSelectorType for custom UI (e.g., autocomplete):
class CustomItemSelectorType extends ItemSelectorType {
public function getParent() {
return AutocompleteType::class; // Symfony UX Autocomplete
}
}
Event Listeners Hook into list/item lifecycle:
// src/EventListener/EditableListListener.php
class EditableListListener {
public function onPrePersist(SonataEditableItem $item) {
$item->setCreatedAt(new \DateTime());
}
}
Register in services.yaml:
services:
App\EventListener\EditableListListener:
tags:
- { name: doctrine.event_listener, event: prePersist }
Custom List Providers
Override SonataEditableListManager to fetch lists from external sources (e.g., API):
class ApiEditableListManager extends SonataEditableListManager {
public function findByCode($code) {
$data = $this->fetchFromApi($code);
return $this->createListFromData($data);
}
}
Caching
php bin/console cache:clear
Translation Fallback
config/packages/framework.yaml:
framework:
default_locale: en
translator:
fallbacks:
- en
Database Schema
php bin/console make:migration
php bin/console doctrine
How can I help you explore Laravel packages today?