Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Behaviors Bundle Laravel Package

ruwork/doctrine-behaviors-bundle

Symfony bundle for integrating Doctrine behavioral extensions, simplifying configuration of behaviors such as timestampable, blameable, sluggable, tree, and soft-deletable entities in your projects.

View on GitHub
Deep Wiki
Context7

Getting Started

This bundle is archived (last release 2018-06-13) and has zero dependents, so treat the README and src/ as the only source of truth. Before wiring anything in, clone the repo and read three things in this order: DependencyInjection/Configuration.php (what is configurable), the EventListener/ or Doctrine/ folder (the subscribers that actually mutate entities), and src/ for the traits you are expected to put on entities. The package follows the standard "traits + Doctrine event subscribers" pattern used by behavior bundles: you add a trait to an entity, a listener fills in the field on prePersist/preUpdate.

Minimal setup on the Symfony 3.4/4.x + Doctrine ORM 2.x stack it targets:

  1. Install with a pinned version; if it is abandoned on Packagist, add the GitHub URL as a vcs repository in composer.json and require dev-master (or the 2018 tag) explicitly.
  2. Register the bundle: new Ruwork\DoctrineBehaviorsBundle\RuworkDoctrineBehaviorsBundle() in AppKernel.php, or the equivalent line in config/bundles.php on Symfony 4.
  3. Import the bundle's service definitions if they are not autoloaded (older bundles often require an explicit services: import or rely on Extension::load).
  4. Run bin/console debug:event-dispatcher doctrine.eventSubscriber (or doctrine.event_listener) to confirm the subscribers registered.

First use case to validate the whole chain: add the timestampable trait to one throwaway entity, map the two columns (created_at, updated_at) yourself if the bundle does not do it via loadClassMetadata, run doctrine:schema:update --dump-sql, persist, and check the values are populated. If that works end to end, the rest of the behaviors (blameable, soft-deletable, etc.) follow the same wiring.

Implementation Patterns

Trait-per-entity, one behavior at a time. Apply a single trait to a single entity first, verify the columns and listener fire, then add the next behavior. Do not stack four behaviors on a fresh entity and debug them together — the failure modes (missing mapping, listener not registered, wrong field name) look identical from the outside.

Blameable needs a user resolver. This is the main integration point. The bundle will either call a global callable, read from a configured service, or expect you to set the user on the subscriber. In a Symfony app, wire it to Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage and resolve getToken()->getUser(); handle the CLI/anonymous case explicitly (return null or a system user) or console commands will fail on prePersist.

Use a MappedSuperclass or shared base entity if you apply the same traits across many entities. Traits alone give you properties but not necessarily mapping, depending on whether the bundle adds fields in loadClassMetadata. A mapped superclass is the safer route: define the fields once with real mapping, put the trait on it, and inherit.

Soft delete is a query concern, not a persist concern. The listener only sets a deleted-at value. Every read path — repositories, query builders, counts, associations — must filter on it. The durable pattern is a base repository that applies the filter and exposes withTrashed()/onlyTrashed() style overrides, rather than sprinkling andWhere('e.deletedAt IS NULL') through controllers.

Keep the behavior surface small and wrap it. Because the package is archived, write a thin application-level abstraction: your own TimestampableListener-shaped service or a BehaviorManager you control, delegating to the bundle today and replaceable tomorrow. The traits are cheap to own; the listener registration is the part you want behind an interface.

Testing. Use a kernel test case with SQLite in-memory and call doctrine:schema:create in setUp so the trait mapping is actually exercised. For blameable, mock or stub the token storage with a real UserInterface implementation; for timestamps, freeze time with a clock abstraction so assertions are deterministic.

Gotchas and Tips

  • Archived means no PHP 8 / Symfony 5+ / Doctrine ORM 3 support. The 2018 code almost certainly uses APIs that were removed or deprecated (e.g. ContainerAware, old event class signatures, annotation reader assumptions). Pin PHP 7.x, Symfony 3.4/4.x and Doctrine ORM 2.x, or budget time to fork and modernize. The "opportunity" here is exactly that: a small, MIT-licensed codebase you can adopt and maintain yourself.
  • Traits do not always carry mapping. Check whether the bundle adds columns via loadClassMetadata or expects you to map them. If it is the latter, forgetting the @Column gives you a trait property that is silently ignored — the listener writes to a non-persisted field and nothing errors.
  • Listener ordering and update loops. Timestampable subscribers that touch updatedAt on preUpdate combined with other listeners can cause extra UPDATE statements or, worse, re-entrancy if a listener flushes. Never call flush() inside a behavior listener; let the unit of work finish. Verify with the SQL logger.
  • Unit of Work and proxies. Fields set in prePersist are fine, but if you read the timestamp immediately after persist() before flush(), you may see null depending on when the listener runs. Always assert after flush().
  • Config quirks. Older bundles often register listeners unconditionally or only when a config key is present. If nothing fires, check Configuration.php for required nodes and confirm the service is tagged (doctrine.event_subscriber) rather than merely defined.
  • Debugging checklist: debug:container for the subscriber service, debug:event-dispatcher for the tag, doctrine:schema:validate for mapping drift, and a temporary dump() in the listener to prove it runs. In that order — it isolates registration from configuration from mapping.
  • Extension points are limited but sufficient: the user resolver for blameable, overriding the subscriber service in your app config, and subclassing traits. If you need more, fork — at this size the fork is a few hundred lines and removes the abandoned-dependency warning from Composer.
  • Migration target. If you decide to replace it, gedmo/doctrine-extensions and knplabs/doctrine-behaviors cover the same ground with active maintenance; Symfony's own symfony/uid and Carbon-style clock injection cover the timestamping piece if you only use one behavior.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo