ufo-tech / doctrine-eav-bundle
The DoctrineEAVBundle provides a seamless integration of the Entity-Attribute-Value (EAV) model with Doctrine ORM within the Symfony framework
Package info
github.com/UFO-Tech/doctrine-eav-bundle
Type:symfony-bundle
pkg:composer/ufo-tech/doctrine-eav-bundle
Requires
- php: >=8.3
- doctrine/doctrine-bundle: >=2.8
- doctrine/doctrine-migrations-bundle: >=3.2
- doctrine/orm: >=2.0
- scienta/doctrine-json-functions: ^6.1
- symfony/console: ^7
- symfony/framework-bundle: ^7
- symfony/http-kernel: ^7
- ufo-tech/doctrine-behaviors: ^1
- ufo-tech/doctrine-helper: *
Requires (Dev)
- phpunit/phpunit: ^12
- symfony/phpunit-bridge: ^7
- symfony/translation: ^7
- symfony/yaml: ^7
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-20 17:40:44 UTC
README
DoctrineEAVBundle integrates the Entity-Attribute-Value (EAV) model with Doctrine ORM in Symfony applications. It is meant for data whose set of attributes is not fixed in advance — product characteristics in e-commerce, configurable catalogs, and similar dynamic data.
Features
- Dynamic attributes: attach any number of parameters to an entity without changing the database schema.
- Typed values: string, number, boolean, option list and file values are stored in one table (Doctrine single-table inheritance); the type is chosen from the PHP value.
- Specifications (variants): an entity has a tree of specifications; a child specification inherits its parent's values and overrides only what differs.
- Localization: values and options can be stored per locale with fallback to the default locale; categories are translatable.
- Filtering and search: ready-made services for faceted filtering (available parameters, values and counts) and search over specification names and values, backed by SQL views.
- Categories: tree-structured, translatable categories with their own filter sets.
Requirements
- PHP 8.3+
- Symfony 7
- Doctrine ORM, DoctrineBundle, DoctrineMigrationsBundle
- MySQL — the SQL views use recursive CTEs, window functions and JSON functions (MySQL 8.0+). Other databases are not supported.
Installation
composer require ufo-tech/doctrine-eav-bundle
If the Symfony Flex recipe was not applied, register the bundle manually in config/bundles.php:
return [ // ... Ufo\EAV\UfoEAVBundle::class => ['all' => true], ];
The bundle configures Doctrine by itself: it registers the mapping of its entities, the enum DBAL type, and the DQL functions it needs (JSON_*, POWER, COUNT_SLASHES). No extra configuration is required.
Setup
1. Create your entities
EavEntity and EavCategory are mapped superclasses — extend them in your application:
use Doctrine\ORM\Mapping as ORM; use Ufo\EAV\Entity\EavEntity; #[ORM\Entity] #[ORM\Table(name: 'product')] class Product extends EavEntity { }
Relations from the bundle's tables are redirected to your table automatically during schema generation.
2. Generate and run migrations
php bin/console doctrine:migrations:diff php bin/console doctrine:migrations:migrate
The read side relies on three SQL views (eav_spec_details_view, eav_spec_details_json_view, eav_common_params_filter_view). On the first schema generation, if the views do not exist yet, the bundle generates a separate migration that creates them. It can also be generated manually:
php bin/console ufo:eav:create-view-migration
Usage
Writing values
use Ufo\EAV\Entity\Value; use Ufo\EAV\Services\EavFactoryService; $product = new Product('T-shirt', article: 'TS-001'); $spec = $product->getMainSpecification(); // $factory is EavFactoryService (autowired) $spec->setValue($factory->valueForParam($spec, 'color', 'red')); $spec->setValue($factory->valueForParam($spec, 'weight', 0.25)); // option values $size = $factory->getParam('size'); $spec->setValue(Value::create($size, [$factory->getOption($size, 'M')])); // a variant that inherits all values from the main specification $variant = $product->addSpecification('T-shirt XL', article: 'TS-001-XL'); $em->persist($product); $em->flush(); // localized value (after the base value is saved) $spec->setValue($factory->valueForParam($spec, 'color', 'червоний', locale: 'uk')); $em->flush();
Reading: $spec->getValue('color') or $spec->getValue('color', 'uk') (falls back to the default-locale value).
Filtering
use Ufo\EAV\Services\FilterDataFactory; use Ufo\EAV\Services\FilterService; // "param1=value1,value2;param2=value3" $filterData = $filterDataFactory->fromFilterRow('color=red,blue;size=M'); // or: $filterDataFactory->fromArray(['color' => ['red', 'blue']]); $specs = $filterService->applyFilterData($filterData)->getSpecs(page: 1, limit: 20); $filters = $filterService->getCommonFilters(); // available params, values and counts
Search
use Ufo\EAV\Services\SearchService; $results = $searchService->search('red', $filterData);
License
MIT — see LICENSE.