[ 01 ]
Content Lock
Two people can't edit the same record at the same time, and everyone can see who has it.
Two editors open the same product. Both change something. The second one to save silently erases the first one's work, and nobody finds out until a customer sees the wrong price. When someone opens a record to edit, Content Lock locks it for everyone else and shows them who is editing it and since when.
It's one line of configuration and no PHP code: it hooks into EasyAdmin's CRUD events, so every edit page of the entities you choose is protected. The hard parts (stale locks, crashed browsers, privileged takeovers, and what happens to the person who was overridden) are handled for you.
easyadmin_pro:
content_lock:
enabled: true
# refresh the lock every 30 seconds
heartbeat_interval_seconds: 30
# abandoned locks expire after 15 minutes
lock_ttl_seconds: 900
Locks that take care of themselves
The lock is acquired when the edit page loads, refreshed by a heartbeat every 30 seconds and released the moment the user submits the form or leaves the page. If the browser crashes, the lock expires on its own after its TTL and the next editor takes it over. Meanwhile, the locked page polls in the background and redirects the waiting user to the form the instant the record is free, with a warning banner if the network drops in between.
Takeovers with rules, not surprises
Sometimes the lock owner went to lunch. A user can take over a lock, after an explicit confirmation, only if they hold every role the owner had when the lock was acquired, checked through Symfony's access decision manager so your custom voters apply. A lock with no recorded roles refuses every override.
The previous editor finds out on their next heartbeat: a banner names who took over, the save buttons are disabled, and any submit that still reaches the server is rejected.
Under the hood
- Zero code
content_lock.enabled: trueprotects every entity managed by EasyAdmin. Narrow it down withincluded_entitiesandexcluded_entities. The lock table is created with your regularmake:migration.- CSRF-protected, always
- Heartbeat, release, status and override are AJAX requests to the edit URL that must carry a per-entity CSRF token injected in the page. A missing or invalid token gets a
403. - Privacy per audience
- Show the owner's identifier or only "someone else" (
anonymous), globally or per dashboard, so external partners using your admin never learn the names of your staff. - Fails open
- If the lock store is unreachable, the error is logged and editing proceeds without a lock, never with a broken backend. The one exception is a missing table, which stops with the exact setup commands to run.
- Scope
- A lock covers the whole entity on EasyAdmin edit pages. APIs, console commands and custom controllers that write to the same entities are not aware of it and are not blocked by it.