Download the PHP package danilovl/entity-traits-bundle without Composer
On this page you can find all versions of the php package danilovl/entity-traits-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download danilovl/entity-traits-bundle
More information about danilovl/entity-traits-bundle
Files in danilovl/entity-traits-bundle
Package entity-traits-bundle
Short Description Symfony bundle providing reusable Doctrine ORM entity traits, interfaces, listeners and validators to eliminate Entity boilerplate.
License MIT
Informations about the package entity-traits-bundle
EntityTraitsBundle
Symfony bundle providing 410 Doctrine ORM trait variants across 21 categories — plus interfaces, listeners, filters, validators and attributes — to eliminate the boilerplate that gets copy-pasted across every entity (id, createdAt, updatedAt, slug, active, deletedAt, …).
Requirements
- PHP 8.5+
- Symfony 8.0
- Doctrine ORM 3.0
Installation
If you are not using Symfony Flex, register the bundle in config/bundles.php:
Then create config/packages/danilovl_entity_traits.yaml:
Required vs Optional variants
Every trait and *AwareInterface ships in two variants, mirroring whether the underlying field is mandatory or optional at the database level:
| Variant | Folder | Doctrine | PHP type |
|---|---|---|---|
Required |
Trait/Required/<Group>/ |
nullable: false |
non-nullable (string, int, …) |
Optional |
Trait/Optional/<Group>/ |
nullable: true |
nullable (?string, ?int, …) |
Pick whichever matches your column constraint. You can mix freely within an entity:
The same split applies to interfaces under Contract/Required/<Group>/ and Contract/Optional/<Group>/. Listeners and filters in this bundle accept both variants — they instanceof-check both contract namespaces internally, so user entities are free to pick either side.
Quick start
That's an entity with 11 columns and 30+ helper methods (getCreatedAt(), setSlug(), publish(), isPublished(), incrementViewsCount(), …) without writing a single field by hand.
The bundle's listeners do the rest:
TimestampableListenerpopulatescreatedAt/updatedAtin the configured timezone.SluggableListenergenerates the slug fromtitle/namewhen empty.BlameableListenersetscreatedBy/updatedByfrom the current Security user (object or string identifier).SoftDeletableListenerconverts$em->remove($entity)intoUPDATE … SET deleted_at = NOW().RequestContextListenerpopulatesipAddress/userAgentfrom the current Request.LastLoginAtListenerupdateslastLoginAtonLoginSuccessEvent.RevisionListenerincrementsrevisionon everyonFlushupdate.TreePathListenerrebuilds materializedpath/depthfor entities marked with#[Tree].TagsNormalizationListenertrims, lowercases and dedupestagsarrays.AutoIdentifierListenerfills properties marked with#[AutoToken],#[AutoUuid],#[AutoUlid],#[AutoIdentifier].
Trait catalog
205 Optional + 205 Required = 410 trait variants across 21 categories. Every trait has a paired *AwareInterface under Contract/Required/<Group>/ and Contract/Optional/<Group>/.
| Group | Traits |
|---|---|
| Identity | IdTrait, UuidTrait, UlidTrait |
| Timestampable | CreatedAtTrait, UpdatedAtTrait, DeletedAtTrait, PublishedAtTrait, StartAtTrait, EndAtTrait, ExpiresAtTrait, ConfirmedAtTrait, ApprovedAtTrait, LastLoginAtTrait, ArchivedAtTrait, LockedAtTrait, ScheduledAtTrait, ProcessedAtTrait, CompletedAtTrait, FailedAtTrait, SentAtTrait, ReadAtTrait, AcceptedAtTrait, RejectedAtTrait, SuspendedAtTrait, RetiredAtTrait, TrialEndsAtTrait, SubscribedAtTrait, UnsubscribedAtTrait, NextBillingAtTrait, VerifiedAtTrait, BannedAtTrait, TimestampableTrait, FullTimestampableTrait, SoftDeletableTrait |
| Status / Flags | ActiveTrait, EnabledTrait, VisibleTrait, FeaturedTrait, PinnedTrait, VerifiedTrait, PublicTrait, WorkflowTrait, DraftTrait, SuspendedTrait, BannedTrait, ReadTrait, ProcessedTrait, ApprovedTrait, SpamTrait, LockedTrait |
| Content | NameTrait, TitleTrait, SubtitleTrait, DescriptionTrait, ContentTrait, ExcerptTrait, NotesTrait, CodeTrait, ReferenceTrait |
| People | FirstNameTrait, LastNameTrait, MiddleNameTrait, FullNameTrait, AcademicDegreeTrait, BirthdayTrait, GenderTrait, NationalityTrait, AvatarTrait, UsernameTrait, DisplayNameTrait, NicknameTrait, HeadlineTrait, PronounsTrait, BiographyTrait |
| Contact | EmailTrait, EmailConfirmableTrait, PhoneTrait, MobilePhoneTrait, WebsiteTrait, SocialLinksTrait, AddressTrait, SecondaryEmailTrait, StreetAddressTrait, EmergencyContactTrait |
| Geographic | LocationTrait, TimezoneTrait, LocaleTrait, CountryTrait, CurrencyTrait |
| Geolocation | RegionTrait, CityTrait, PostalCodeTrait, AddressLineTrait |
| Media | ImageTrait, ThumbnailTrait, FileTrait, VideoTrait, AudioTrait, AltTextTrait, CaptionTrait, DurationTrait, AttachmentsTrait, GalleryTrait |
| SEO | SlugTrait, MetaTrait, OgMetaTrait, CanonicalUrlTrait, RobotsTrait, TwitterCardTrait, SitemapTrait, HreflangTrait, SchemaOrgTrait, SlugAliasTrait |
| Business | PriceTrait, SkuTrait, BarcodeTrait, GtinTrait, IsbnTrait, StockTrait, WeightTrait, DimensionsTrait, TaxRateTrait, VatNumberTrait, DiscountTrait, CompareAtPriceTrait, CostPriceTrait, MinimumQuantityTrait, MaximumQuantityTrait, ReorderLevelTrait, UnitTrait, ManufacturerTrait, BrandTrait, ModelTrait, MpnTrait |
| Pricing | PriceRangeTrait, SubscriptionPriceTrait, TierPricingTrait |
| Sorting / Hierarchy | PriorityTrait, PositionTrait, LevelTrait, TreePathTrait, ParentTrait |
| Audit / Blameable | CreatedByTrait, UpdatedByTrait, DeletedByTrait, BlameableTrait, CreatedByStringTrait, UpdatedByStringTrait, OwnerTrait, AuthorTrait, IpAddressTrait, UserAgentTrait |
| Versioning | VersionTrait, RevisionTrait |
| Counters | ViewsCountTrait, LikesCountTrait, SharesCountTrait, CommentsCountTrait, DownloadsCountTrait, RatingTrait, FavoritesCountTrait, BookmarksCountTrait, FollowersCountTrait, FollowingCountTrait, SubscribersCountTrait, ClicksCountTrait, DislikesCountTrait, ErrorsCountTrait, PointsTrait, BalanceTrait |
| Misc | ColorTrait, IconTrait, TagsTrait, MetadataTrait, TokenTrait, HashTrait, SortKeyTrait, ChecksumTrait, LabelTrait, BadgeTrait, ExtrasTrait, SettingsTrait, FingerprintTrait, SecretTrait, EncryptedPayloadTrait, OriginalUrlTrait |
| Security | FailedLoginAttemptsTrait, LockedUntilTrait, TwoFactorEnabledTrait, ApiKeyTrait, PasswordChangedAtTrait, RememberTokenTrait |
| Tenancy | TenantTrait, OrganizationTrait, TeamTrait, WorkspaceTrait |
| Integration | ExternalIdTrait, ExternalSourceTrait, ExternalUrlTrait, ImportedAtTrait, SyncedAtTrait |
| Presets | BlogPostTrait, EcommerceProductTrait, UserAccountTrait, EventTrait |
Conventions
| Topic | Rule |
|---|---|
| Date type | Always \DateTimeImmutable. Doctrine column type is datetime_immutable / date_immutable. |
| Setter return | static (fluent), never void. |
| Property visibility | protected, so subclasses (e.g. STI / MappedSuperclass heirs) can adjust mapping. |
| Lifecycle logic | Lives in EventListener/, not inside traits. |
| Boolean methods | isX() / hasX(), never getX(). |
| Identity strategy | Pick one of IdTrait / UuidTrait / UlidTrait per entity. |
Required IdTrait |
Property is uninitialized typed (int $id;); use isNew() (which uses isset) before reading getId(). |
Attributes
| Attribute | Effect |
|---|---|
#[AutoSlug(from: 'title')] |
Class-level. Tells SluggableListener which field to slug from. |
#[AutoToken(property: 'apiKey', length: 32)] |
Generates a hex token (bin2hex(random_bytes())) on prePersist if empty. |
#[AutoUuid] / #[AutoUlid] |
Generates a UUID v7 / ULID for non-PK columns on prePersist. |
#[AutoIdentifier(property: 'externalId')] |
Generates a UUID v7 or ULID based on identity.default_strategy. Skipped for int. |
#[Tree] |
Marks a ParentTrait + TreePathTrait entity so TreePathListener rebuilds path / depth automatically. |
Validators
All validators are registered as services with the validator.constraint_validator tag — Symfony's validator pipeline picks them up automatically.
Doctrine SQL filters
soft_delete is registered automatically when soft_delete.filter_auto_enable: true (the default). The remaining filters must be registered manually.
| Filter | Auto-registered | Hides rows where… |
|---|---|---|
SoftDeleteFilter |
✅ by default | deleted_at IS NOT NULL |
PublishedFilter |
❌ manual | published_at IS NULL OR published_at > NOW() |
ActiveFilter |
❌ manual | active = false |
ArchivedFilter |
❌ manual | archived_at IS NOT NULL |
To disable auto-registration of SoftDeleteFilter:
To register the other filters manually:
Enums
Gender—Male,Female,NonBinary,Other,PreferNotToSayIdentityStrategy—Int,Uuid,UlidWorkflowState—Draft,Pending,InReview,Approved,Published,Rejected,Archived,CancelledRobotsDirective—Index,NoIndex,Follow,NoFollow,IndexFollow,NoIndexNoFollow,NoArchive,NoSnippet
Configuration as a service
Bundle config flows into a typed, autowireable EntityTraitsConfig value object:
| Field | Type | Config key |
|---|---|---|
blameableUserClass |
string |
blameable.user_class |
blameableUseUsernameString |
bool |
blameable.use_username_string |
sluggableFallbackField |
string |
sluggable.fallback_field |
userAgentMaxLength |
int |
request_context.user_agent_max_length |
lastLoginAtThrottleSeconds |
int |
last_login_at.throttle_seconds |
tagsNormalizationLowercase |
bool |
tags.lowercase |
identityDefaultStrategy |
string |
identity.default_strategy |
timestampableTimezone |
string |
timestampable.timezone |
Timestampable timezone
All auto-timestamps are converted to the configured timezone before being stored:
TimestampableListener calls $clock->now()->setTimezone(new DateTimeZone($config->timestampableTimezone)) — so the stored DateTimeImmutable carries the correct offset even when the app server is in UTC.
Slug source override
By default SluggableListener uses the name field. To slug from title (or any other field):
Auto-identifier with configured strategy
#[AutoIdentifier] generates a UUID or ULID depending on identity.default_strategy, making the choice central rather than per-entity:
On prePersist, AutoIdentifierListener generates Uuid::v7() (or new Ulid) and fills the property if it is empty. For int, no generation is performed — Doctrine handles auto-increment at the database level.
Soft delete
SoftDeleteFilter is auto-registered and enabled by default (see soft_delete.filter_auto_enable). All subsequent SELECTs hide the row automatically. To include deleted rows:
If the entity also implements DeletedByAwareInterface, the listener fills deletedBy from the current Security user during the same flush.
Blameable — object vs string
By default BlameableListener stores the full UserInterface object as a Doctrine relation. Use use_username_string: true to store the username string instead, which avoids a foreign key and is useful for audit logs, microservices, or any context where the user relation is not available:
BlameableListener detects the interface variant at runtime: when use_username_string = true it calls $entity->setCreatedBy($user->getUserIdentifier()) instead of $entity->setCreatedBy($user).
The standard object-based traits (CreatedByTrait, UpdatedByTrait) remain unchanged and work as before when the flag is false.
Tree (materialized path)
TreePathListener rebuilds path (e.g. /1/4/9) and depth on every save by walking the parent chain.
Testing
Functional tests use a minimal TestKernel (under tests/Functional/Kernel/TestKernel.php) that boots only FrameworkBundle + EntityTraitsBundle so wiring scenarios can be verified in isolation.
Security traits
Prevent brute-force and track authentication state:
Tenancy traits
Add multi-tenancy scoping with a single trait:
Integration traits
Track external system references without coupling your schema to foreign systems:
Pricing traits
Separate pricing concerns from the base product:
Extended counters
Geolocation traits
Fine-grained address decomposition, separate from the combined AddressTrait:
Extended SEO
License
The EntityTraitsBundle is open-sourced software licensed under the MIT license.
All versions of entity-traits-bundle with dependencies
ext-ctype Version *
ext-mbstring Version *
doctrine/dbal Version ^4.0
psr/clock Version ^1.0
symfony/clock Version ^8.0
symfony/config Version ^8.0
symfony/dependency-injection Version ^8.0
symfony/http-kernel Version ^8.0
symfony/security-bundle Version ^8.0
symfony/security-core Version ^8.0
symfony/string Version ^8.0
symfony/uid Version ^8.0
symfony/validator Version ^8.0