|
17 | 17 | use Doctrine\Persistence\Mapping\ClassMetadata;
|
18 | 18 | use Doctrine\Persistence\ObjectManager;
|
19 | 19 | use Gedmo\Exception\InvalidArgumentException;
|
| 20 | +use Gedmo\Exception\UnexpectedValueException; |
20 | 21 | use Gedmo\Loggable\Mapping\Event\LoggableAdapter;
|
21 | 22 | use Gedmo\Mapping\MappedEventSubscriber;
|
| 23 | +use Gedmo\Tool\ActorProviderInterface; |
22 | 24 | use Gedmo\Tool\Wrapper\AbstractWrapper;
|
23 | 25 |
|
24 | 26 | /**
|
@@ -55,6 +57,8 @@ class LoggableListener extends MappedEventSubscriber
|
55 | 57 | */
|
56 | 58 | public const ACTION_REMOVE = LogEntryInterface::ACTION_REMOVE;
|
57 | 59 |
|
| 60 | + protected ?ActorProviderInterface $actorProvider = null; |
| 61 | + |
58 | 62 | /**
|
59 | 63 | * Username for identification
|
60 | 64 | *
|
@@ -85,9 +89,19 @@ class LoggableListener extends MappedEventSubscriber
|
85 | 89 | */
|
86 | 90 | protected $pendingRelatedObjects = [];
|
87 | 91 |
|
| 92 | + /** |
| 93 | + * Set an actor provider for the user value. |
| 94 | + */ |
| 95 | + public function setActorProvider(ActorProviderInterface $actorProvider): void |
| 96 | + { |
| 97 | + $this->actorProvider = $actorProvider; |
| 98 | + } |
| 99 | + |
88 | 100 | /**
|
89 | 101 | * Set username for identification
|
90 | 102 | *
|
| 103 | + * If an actor provider is also provided, it will take precedence over this value. |
| 104 | + * |
91 | 105 | * @param mixed $username
|
92 | 106 | *
|
93 | 107 | * @throws InvalidArgumentException Invalid username
|
@@ -229,6 +243,41 @@ protected function getLogEntryClass(LoggableAdapter $ea, $class)
|
229 | 243 | return self::$configurations[$this->name][$class]['logEntryClass'] ?? $ea->getDefaultLogEntryClass();
|
230 | 244 | }
|
231 | 245 |
|
| 246 | + /** |
| 247 | + * Retrieve the username to use for the log entry. |
| 248 | + * |
| 249 | + * This method will try to fetch a username from the actor provider first, falling back to the {@see $this->username} |
| 250 | + * property if the provider is not set or does not provide a value. |
| 251 | + * |
| 252 | + * @throws UnexpectedValueException if the actor provider provides an unsupported username value |
| 253 | + */ |
| 254 | + protected function getUsername(): ?string |
| 255 | + { |
| 256 | + if ($this->actorProvider instanceof ActorProviderInterface) { |
| 257 | + $actor = $this->actorProvider->getActor(); |
| 258 | + |
| 259 | + if (is_string($actor) || null === $actor) { |
| 260 | + return $actor; |
| 261 | + } |
| 262 | + |
| 263 | + if (method_exists($actor, 'getUserIdentifier')) { |
| 264 | + return (string) $actor->getUserIdentifier(); |
| 265 | + } |
| 266 | + |
| 267 | + if (method_exists($actor, 'getUsername')) { |
| 268 | + return (string) $actor->getUsername(); |
| 269 | + } |
| 270 | + |
| 271 | + if (method_exists($actor, '__toString')) { |
| 272 | + return $actor->__toString(); |
| 273 | + } |
| 274 | + |
| 275 | + throw new UnexpectedValueException(\sprintf('The loggable extension requires the actor provider to return a string or an object implementing the "getUserIdentifier()", "getUsername()", or "__toString()" methods. "%s" cannot be used as an actor.', get_class($actor))); |
| 276 | + } |
| 277 | + |
| 278 | + return $this->username; |
| 279 | + } |
| 280 | + |
232 | 281 | /**
|
233 | 282 | * Handle any custom LogEntry functionality that needs to be performed
|
234 | 283 | * before persisting it
|
@@ -328,7 +377,7 @@ protected function createLogEntry($action, $object, LoggableAdapter $ea)
|
328 | 377 | $logEntry = $logEntryMeta->newInstance();
|
329 | 378 |
|
330 | 379 | $logEntry->setAction($action);
|
331 |
| - $logEntry->setUsername($this->username); |
| 380 | + $logEntry->setUsername($this->getUsername()); |
332 | 381 | $logEntry->setObjectClass($meta->getName());
|
333 | 382 | $logEntry->setLoggedAt();
|
334 | 383 |
|
|
0 commit comments