Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like LoggableManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use LoggableManager, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
28 | class LoggableManager |
||
29 | { |
||
30 | /** |
||
31 | * @var AbstractUser[] |
||
32 | */ |
||
33 | protected static $userCache = []; |
||
34 | |||
35 | const ACTION_CREATE = 'create'; |
||
36 | const ACTION_UPDATE = 'update'; |
||
37 | const ACTION_REMOVE = 'remove'; |
||
38 | |||
39 | /** @var EntityManager */ |
||
40 | protected $em; |
||
41 | |||
42 | /** @var array */ |
||
43 | protected $configs = []; |
||
44 | |||
45 | /** @var string */ |
||
46 | protected $username; |
||
47 | |||
48 | /** @var Organization|null */ |
||
49 | protected $organization; |
||
50 | |||
51 | /** |
||
52 | * @deprecated 1.8.0:2.1.0 use AuditEntityMapper::getAuditEntryClass |
||
53 | * |
||
54 | * @var string |
||
55 | */ |
||
56 | protected $logEntityClass; |
||
57 | |||
58 | /** |
||
59 | * @deprecated 1.8.0:2.1.0 use AuditEntityMapper::getAuditEntryFieldClass |
||
60 | * |
||
61 | * @var string |
||
62 | */ |
||
63 | protected $logEntityFieldClass; |
||
64 | |||
65 | /** @var array */ |
||
66 | protected $pendingLogEntityInserts = []; |
||
67 | |||
68 | /** @var array */ |
||
69 | protected $pendingRelatedEntities = []; |
||
70 | |||
71 | /** @var array */ |
||
72 | protected $collectionLogData = []; |
||
73 | |||
74 | /** @var ConfigProvider */ |
||
75 | protected $auditConfigProvider; |
||
76 | |||
77 | /** @var ServiceLink */ |
||
78 | protected $securityContextLink; |
||
79 | |||
80 | /** @var AuditEntityMapper */ |
||
81 | protected $auditEntityMapper; |
||
82 | |||
83 | /** |
||
84 | * @param string $logEntityClass |
||
85 | * @param string $logEntityFieldClass |
||
86 | * @param ConfigProvider $auditConfigProvider |
||
87 | * @param ServiceLink $securityContextLink |
||
88 | * @param AuditEntityMapper $auditEntityMapper |
||
89 | */ |
||
90 | public function __construct( |
||
91 | $logEntityClass, |
||
92 | $logEntityFieldClass, |
||
93 | ConfigProvider $auditConfigProvider, |
||
94 | ServiceLink $securityContextLink, |
||
95 | AuditEntityMapper $auditEntityMapper |
||
96 | ) { |
||
97 | $this->auditConfigProvider = $auditConfigProvider; |
||
98 | $this->logEntityClass = $logEntityClass; |
||
|
|||
99 | $this->logEntityFieldClass = $logEntityFieldClass; |
||
100 | $this->securityContextLink = $securityContextLink; |
||
101 | $this->auditEntityMapper = $auditEntityMapper; |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * @param ClassMetadata $metadata |
||
106 | */ |
||
107 | public function addConfig(ClassMetadata $metadata) |
||
111 | |||
112 | /** |
||
113 | * @param string $name |
||
114 | * @return ClassMetadata |
||
115 | * @throws InvalidParameterException |
||
116 | */ |
||
117 | public function getConfig($name) |
||
118 | { |
||
119 | if (!isset($this->configs[$name])) { |
||
120 | throw new InvalidParameterException(sprintf('invalid config name %s', $name)); |
||
121 | } |
||
122 | |||
123 | return $this->configs[$name]; |
||
124 | } |
||
125 | |||
126 | /** |
||
127 | * @param string $username |
||
128 | * @throws \InvalidArgumentException |
||
129 | */ |
||
130 | public function setUsername($username) |
||
140 | |||
141 | /** |
||
142 | * @return null|Organization |
||
143 | */ |
||
144 | protected function getOrganization() |
||
145 | { |
||
146 | /** @var SecurityContextInterface $securityContext */ |
||
147 | $securityContext = $this->securityContextLink->getService(); |
||
148 | |||
149 | $token = $securityContext->getToken(); |
||
150 | if (!$token) { |
||
151 | return null; |
||
152 | } |
||
153 | |||
154 | if (!$token instanceof OrganizationContextTokenInterface) { |
||
155 | return null; |
||
156 | } |
||
157 | |||
158 | return $token->getOrganizationContext(); |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * @param EntityManager $em |
||
163 | */ |
||
164 | public function handleLoggable(EntityManager $em) |
||
165 | { |
||
166 | $this->em = $em; |
||
167 | $uow = $em->getUnitOfWork(); |
||
168 | |||
169 | $collections = array_merge($uow->getScheduledCollectionUpdates(), $uow->getScheduledCollectionDeletions()); |
||
170 | foreach ($collections as $collection) { |
||
171 | $this->calculateActualCollectionData($collection); |
||
172 | } |
||
173 | |||
174 | $entities = array_merge( |
||
175 | $uow->getScheduledEntityDeletions(), |
||
176 | $uow->getScheduledEntityInsertions(), |
||
177 | $uow->getScheduledEntityUpdates() |
||
178 | ); |
||
179 | |||
180 | $updatedEntities = []; |
||
181 | foreach ($entities as $entity) { |
||
182 | $entityMeta = $this->em->getClassMetadata(ClassUtils::getClass($entity)); |
||
183 | $updatedEntities = array_merge( |
||
184 | $updatedEntities, |
||
185 | $this->calculateManyToOneData($entityMeta, $entity) |
||
186 | ); |
||
187 | } |
||
188 | |||
189 | foreach ($uow->getScheduledEntityInsertions() as $entity) { |
||
190 | $this->createLogEntity(self::ACTION_CREATE, $entity); |
||
191 | } |
||
192 | foreach ($uow->getScheduledEntityUpdates() as $entity) { |
||
193 | $this->createLogEntity(self::ACTION_UPDATE, $entity); |
||
194 | } |
||
195 | foreach ($uow->getScheduledEntityDeletions() as $entity) { |
||
196 | $this->createLogEntity(self::ACTION_REMOVE, $entity); |
||
197 | } |
||
198 | |||
199 | foreach ($this->collectionLogData as $entityData) { |
||
200 | foreach ($entityData as $identifier => $values) { |
||
201 | if (!isset($updatedEntities[$identifier])) { |
||
202 | continue; |
||
203 | } |
||
204 | |||
205 | $this->createLogEntity(static::ACTION_UPDATE, $updatedEntities[$identifier]); |
||
206 | } |
||
207 | } |
||
208 | } |
||
209 | |||
210 | /** |
||
211 | * @param object $entity |
||
212 | * @param EntityManager $em |
||
213 | */ |
||
214 | public function handlePostPersist($entity, EntityManager $em) |
||
215 | { |
||
216 | $this->em = $em; |
||
217 | $uow = $em->getUnitOfWork(); |
||
218 | $oid = spl_object_hash($entity); |
||
219 | $logEntryMeta = null; |
||
220 | |||
221 | if ($this->pendingLogEntityInserts && array_key_exists($oid, $this->pendingLogEntityInserts)) { |
||
222 | $logEntry = $this->pendingLogEntityInserts[$oid]; |
||
223 | $logEntryMeta = $em->getClassMetadata(ClassUtils::getClass($logEntry)); |
||
224 | |||
225 | $id = $this->getIdentifier($entity); |
||
226 | $logEntryMeta->getReflectionProperty('objectId')->setValue($logEntry, $id); |
||
227 | |||
228 | $uow->scheduleExtraUpdate($logEntry, ['objectId' => [null, $id]]); |
||
229 | $uow->setOriginalEntityProperty(spl_object_hash($logEntry), 'objectId', $id); |
||
230 | |||
231 | unset($this->pendingLogEntityInserts[$oid]); |
||
232 | } |
||
233 | |||
234 | if ($this->pendingRelatedEntities && array_key_exists($oid, $this->pendingRelatedEntities)) { |
||
235 | $identifiers = $uow->getEntityIdentifier($entity); |
||
236 | |||
237 | foreach ($this->pendingRelatedEntities[$oid] as $props) { |
||
238 | /** @var AbstractAudit $logEntry */ |
||
239 | $logEntry = $props['log']; |
||
240 | $data = $logEntry->getData(); |
||
241 | if (empty($data[$props['field']]['new'])) { |
||
242 | $data[$props['field']]['new'] = implode(', ', $identifiers); |
||
243 | $oldField = $logEntry->getField($props['field']); |
||
244 | $logEntry->createField( |
||
245 | $oldField->getField(), |
||
246 | $oldField->getDataType(), |
||
247 | $data[$props['field']]['new'], |
||
248 | $oldField->getOldValue() |
||
249 | ); |
||
250 | |||
251 | if ($logEntryMeta) { |
||
252 | $uow->computeChangeSet($logEntryMeta, $logEntry); |
||
253 | } |
||
254 | $uow->setOriginalEntityProperty(spl_object_hash($logEntry), 'objectId', $data); |
||
255 | } |
||
256 | } |
||
257 | |||
258 | unset($this->pendingRelatedEntities[$oid]); |
||
259 | } |
||
260 | } |
||
261 | |||
262 | /** |
||
263 | * @param DoctrineClassMetadata $entityMeta |
||
264 | * @param object $entity |
||
265 | * |
||
266 | * @return array [entityIdentifier => entity, ...] |
||
267 | */ |
||
268 | protected function calculateManyToOneData(DoctrineClassMetadata $entityMeta, $entity) |
||
269 | { |
||
270 | $entities = []; |
||
271 | foreach ($entityMeta->associationMappings as $assoc) { |
||
272 | if ($assoc['type'] !== DoctrineClassMetadata::MANY_TO_ONE |
||
273 | || empty($assoc['inversedBy']) |
||
274 | ) { |
||
275 | continue; |
||
276 | } |
||
277 | |||
278 | $owner = $entityMeta->getReflectionProperty($assoc['fieldName'])->getValue($entity); |
||
279 | if (!$owner) { |
||
280 | continue; |
||
281 | } |
||
282 | |||
283 | $ownerMeta = $this->em->getClassMetadata($assoc['targetEntity']); |
||
284 | $collection = $ownerMeta->getReflectionProperty($assoc['inversedBy'])->getValue($owner); |
||
285 | if (!$collection instanceof PersistentCollection) { |
||
286 | continue; |
||
287 | } |
||
288 | |||
289 | $entityIdentifier = $this->getEntityIdentifierString($owner); |
||
290 | $this->calculateActualCollectionData($collection, $entityIdentifier); |
||
291 | |||
292 | $entities[$entityIdentifier] = $owner; |
||
293 | } |
||
294 | |||
295 | return $entities; |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * @param PersistentCollection $collection |
||
300 | * @param string $entityIdentifier |
||
301 | */ |
||
302 | protected function calculateActualCollectionData(PersistentCollection $collection, $entityIdentifier = null) |
||
303 | { |
||
304 | $ownerEntity = $collection->getOwner(); |
||
305 | $entityState = $this->em->getUnitOfWork()->getEntityState($ownerEntity, UnitOfWork::STATE_NEW); |
||
306 | if ($entityState === UnitOfWork::STATE_REMOVED) { |
||
307 | return; |
||
308 | } |
||
309 | |||
310 | $this->calculateCollectionData($collection, $entityIdentifier); |
||
311 | } |
||
312 | |||
313 | /** |
||
314 | * @param PersistentCollection $collection |
||
315 | * @param string $entityIdentifier |
||
316 | */ |
||
317 | protected function calculateCollectionData(PersistentCollection $collection, $entityIdentifier = null) |
||
318 | { |
||
319 | $ownerEntity = $collection->getOwner(); |
||
320 | $ownerEntityClassName = $this->getEntityClassName($ownerEntity); |
||
321 | |||
322 | if ($this->checkAuditable($ownerEntityClassName)) { |
||
323 | $meta = $this->getConfig($ownerEntityClassName); |
||
324 | $collectionMapping = $collection->getMapping(); |
||
325 | |||
326 | if (isset($meta->propertyMetadata[$collectionMapping['fieldName']])) { |
||
327 | $method = $meta->propertyMetadata[$collectionMapping['fieldName']]->method; |
||
328 | |||
329 | // calculate collection changes |
||
330 | $newCollection = $collection->toArray(); |
||
331 | $oldCollection = $collection->getSnapshot(); |
||
332 | |||
333 | $oldCollectionWithOldData = []; |
||
334 | foreach ($oldCollection as $entity) { |
||
335 | $oldCollectionWithOldData[] = $this->getOldEntity($entity); |
||
336 | } |
||
337 | |||
338 | $oldData = array_reduce( |
||
339 | $oldCollectionWithOldData, |
||
340 | function ($result, $item) use ($method) { |
||
341 | return $result . ($result ? ', ' : '') . $item->{$method}(); |
||
342 | } |
||
343 | ); |
||
344 | |||
345 | $newData = array_reduce( |
||
346 | $newCollection, |
||
347 | function ($result, $item) use ($method) { |
||
348 | return $result . ($result ? ', ' : '') . $item->{$method}(); |
||
349 | } |
||
350 | ); |
||
351 | |||
352 | if (!$entityIdentifier) { |
||
353 | $entityIdentifier = $this->getEntityIdentifierString($ownerEntity); |
||
354 | } |
||
355 | |||
356 | $fieldName = $collectionMapping['fieldName']; |
||
357 | $this->collectionLogData[$ownerEntityClassName][$entityIdentifier][$fieldName] = [ |
||
358 | 'old' => $oldData, |
||
359 | 'new' => $newData, |
||
360 | ]; |
||
361 | } |
||
362 | } |
||
363 | } |
||
364 | |||
365 | /** |
||
366 | * @param object $currentEntity |
||
367 | * |
||
368 | * @return object |
||
369 | */ |
||
370 | protected function getOldEntity($currentEntity) |
||
371 | { |
||
372 | $changeSet = $this->em->getUnitOfWork()->getEntityChangeSet($currentEntity); |
||
373 | |||
374 | if (!$changeSet) { |
||
375 | return $currentEntity; |
||
376 | } |
||
377 | |||
378 | $metadata = $this->em->getClassMetadata(ClassUtils::getClass($currentEntity)); |
||
379 | $oldEntity = clone $currentEntity; |
||
380 | foreach ($changeSet as $property => $values) { |
||
381 | $metadata->getReflectionProperty($property)->setValue($oldEntity, $values[0]); |
||
382 | } |
||
383 | |||
384 | return $oldEntity; |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * @param string $action |
||
389 | * @param object $entity |
||
390 | * @SuppressWarnings(PHPMD.NPathComplexity) |
||
391 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
||
392 | * @SuppressWarnings(PHPMD.ExcessiveMethodLength) |
||
393 | * |
||
394 | * @throws \ReflectionException |
||
395 | */ |
||
396 | protected function createLogEntity($action, $entity) |
||
397 | { |
||
398 | $entityClassName = $this->getEntityClassName($entity); |
||
399 | if (!$this->checkAuditable($entityClassName)) { |
||
400 | return; |
||
401 | } |
||
402 | |||
403 | $user = $this->getLoadedUser(); |
||
404 | $organization = $this->getOrganization(); |
||
405 | if (!$organization) { |
||
406 | return; |
||
407 | } |
||
408 | |||
409 | $uow = $this->em->getUnitOfWork(); |
||
410 | |||
411 | $meta = $this->getConfig($entityClassName); |
||
412 | $entityMeta = $this->em->getClassMetadata($entityClassName); |
||
413 | |||
414 | $logEntryMeta = $this->em->getClassMetadata($this->getLogEntityClass()); |
||
415 | /** @var AbstractAudit $logEntry */ |
||
416 | $logEntry = $logEntryMeta->newInstance(); |
||
417 | $logEntry->setAction($action); |
||
418 | $logEntry->setObjectClass($meta->name); |
||
419 | $logEntry->setLoggedAt(); |
||
420 | $logEntry->setUser($user); |
||
421 | $logEntry->setOrganization($organization); |
||
422 | $logEntry->setObjectName(method_exists($entity, '__toString') ? (string)$entity : $meta->name); |
||
423 | |||
424 | $entityId = $this->getIdentifier($entity); |
||
425 | |||
426 | if (!$entityId && $action === self::ACTION_CREATE) { |
||
427 | $this->pendingLogEntityInserts[spl_object_hash($entity)] = $logEntry; |
||
428 | } |
||
429 | |||
430 | $logEntry->setObjectId($entityId); |
||
431 | |||
432 | $newValues = []; |
||
433 | |||
434 | if ($action !== self::ACTION_REMOVE && count($meta->propertyMetadata)) { |
||
435 | foreach ($uow->getEntityChangeSet($entity) as $field => $changes) { |
||
436 | if (!isset($meta->propertyMetadata[$field])) { |
||
437 | continue; |
||
438 | } |
||
439 | |||
440 | $old = $changes[0]; |
||
441 | $new = $changes[1]; |
||
442 | |||
443 | if ($old == $new) { |
||
444 | continue; |
||
445 | } |
||
446 | |||
447 | $fieldMapping = null; |
||
448 | if ($entityMeta->hasField($field)) { |
||
449 | $fieldMapping = $entityMeta->getFieldMapping($field); |
||
450 | if ($fieldMapping['type'] === 'date') { |
||
451 | // leave only date |
||
452 | $utc = new \DateTimeZone('UTC'); |
||
453 | View Code Duplication | if ($old && $old instanceof \DateTime) { |
|
454 | $old->setTimezone($utc); |
||
455 | $old = new \DateTime($old->format('Y-m-d'), $utc); |
||
456 | } |
||
457 | View Code Duplication | if ($new && $new instanceof \DateTime) { |
|
458 | $new->setTimezone($utc); |
||
459 | $new = new \DateTime($new->format('Y-m-d'), $utc); |
||
460 | } |
||
461 | } |
||
462 | } |
||
463 | |||
464 | if ($old instanceof \DateTime && $new instanceof \DateTime |
||
465 | && $old->getTimestamp() == $new->getTimestamp() |
||
466 | ) { |
||
467 | continue; |
||
468 | } |
||
469 | |||
470 | if ($entityMeta->isSingleValuedAssociation($field) && $new) { |
||
471 | $oid = spl_object_hash($new); |
||
472 | $value = $this->getIdentifier($new); |
||
473 | |||
474 | if (!is_array($value) && !$value) { |
||
475 | $this->pendingRelatedEntities[$oid][] = [ |
||
476 | 'log' => $logEntry, |
||
477 | 'field' => $field |
||
478 | ]; |
||
479 | } |
||
480 | |||
481 | $method = $meta->propertyMetadata[$field]->method; |
||
482 | View Code Duplication | if ($old !== null) { |
|
483 | // check if an object has the required method to avoid a fatal error |
||
484 | if (!method_exists($old, $method)) { |
||
485 | throw new \ReflectionException( |
||
486 | sprintf('Try to call to undefined method %s::%s', get_class($old), $method) |
||
487 | ); |
||
488 | } |
||
489 | $old = $old->{$method}(); |
||
490 | } |
||
491 | View Code Duplication | if ($new !== null) { |
|
492 | // check if an object has the required method to avoid a fatal error |
||
493 | if (!method_exists($new, $method)) { |
||
494 | throw new \ReflectionException( |
||
495 | sprintf('Try to call to undefined method %s::%s', get_class($new), $method) |
||
496 | ); |
||
497 | } |
||
498 | $new = $new->{$method}(); |
||
499 | } |
||
500 | } |
||
501 | |||
502 | $newValues[$field] = [ |
||
503 | 'old' => $old, |
||
504 | 'new' => $new, |
||
505 | 'type' => $this->getFieldType($entityMeta, $field), |
||
506 | ]; |
||
507 | } |
||
508 | |||
509 | $entityIdentifier = $this->getEntityIdentifierString($entity); |
||
510 | if (!empty($this->collectionLogData[$entityClassName][$entityIdentifier])) { |
||
511 | $collectionData = $this->collectionLogData[$entityClassName][$entityIdentifier]; |
||
512 | foreach ($collectionData as $field => $changes) { |
||
513 | if (!isset($meta->propertyMetadata[$field])) { |
||
514 | continue; |
||
515 | } |
||
516 | |||
517 | if ($changes['old'] != $changes['new']) { |
||
518 | $newValues[$field] = $changes; |
||
519 | $newValues[$field]['type'] = $this->getFieldType($entityMeta, $field); |
||
520 | } |
||
521 | } |
||
522 | |||
523 | unset($this->collectionLogData[$entityClassName][$entityIdentifier]); |
||
524 | if (!$this->collectionLogData[$entityClassName]) { |
||
525 | unset($this->collectionLogData[$entityClassName]); |
||
526 | } |
||
527 | } |
||
528 | |||
529 | foreach ($newValues as $field => $newValue) { |
||
530 | $logEntry->createField($field, $newValue['type'], $newValue['new'], $newValue['old']); |
||
531 | } |
||
532 | } |
||
533 | |||
534 | if ($action === self::ACTION_UPDATE && 0 === count($newValues)) { |
||
535 | return; |
||
536 | } |
||
537 | |||
538 | $version = 1; |
||
539 | |||
540 | if ($action !== self::ACTION_CREATE) { |
||
541 | $version = $this->getNewVersion($logEntryMeta, $entity); |
||
542 | |||
543 | if (empty($version)) { |
||
544 | // was versioned later |
||
545 | $version = 1; |
||
546 | } |
||
547 | } |
||
548 | |||
549 | $logEntry->setVersion($version); |
||
550 | |||
551 | $this->em->persist($logEntry); |
||
552 | $uow->computeChangeSet($logEntryMeta, $logEntry); |
||
553 | |||
554 | $logEntryFieldMeta = $this->em->getClassMetadata( |
||
555 | $this->auditEntityMapper->getAuditEntryFieldClass($this->getLoadedUser()) |
||
556 | ); |
||
557 | foreach ($logEntry->getFields() as $field) { |
||
558 | $this->em->persist($field); |
||
559 | $uow->computeChangeSet($logEntryFieldMeta, $field); |
||
560 | } |
||
561 | } |
||
562 | |||
563 | /** |
||
564 | * @return AbstractUser|null |
||
565 | */ |
||
566 | protected function getLoadedUser() |
||
567 | { |
||
568 | if (!$this->username) { |
||
569 | return null; |
||
570 | } |
||
571 | |||
572 | $isInCache = array_key_exists($this->username, self::$userCache); |
||
573 | if (!$isInCache |
||
574 | || ($isInCache && !$this->em->getUnitOfWork()->isInIdentityMap(self::$userCache[$this->username])) |
||
575 | ) { |
||
576 | /** @var SecurityContextInterface $securityContext */ |
||
577 | $securityContext = $this->securityContextLink->getService(); |
||
578 | $token = $securityContext->getToken(); |
||
579 | if ($token) { |
||
580 | /** @var AbstractUser $user */ |
||
581 | $user = $token->getUser(); |
||
582 | self::$userCache[$this->username] = $this->em->getReference( |
||
583 | ClassUtils::getClass($user), |
||
584 | $user->getId() |
||
585 | ); |
||
586 | } |
||
587 | } |
||
588 | |||
589 | return self::$userCache[$this->username]; |
||
590 | } |
||
591 | |||
592 | /** |
||
593 | * Get the LogEntry class |
||
594 | * |
||
595 | * @return string |
||
596 | */ |
||
597 | protected function getLogEntityClass() |
||
601 | |||
602 | /** |
||
603 | * @param DoctrineClassMetadata $logEntityMeta |
||
604 | * @param object $entity |
||
605 | * @return mixed |
||
606 | */ |
||
607 | protected function getNewVersion($logEntityMeta, $entity) |
||
608 | { |
||
609 | $entityMeta = $this->em->getClassMetadata($this->getEntityClassName($entity)); |
||
610 | $entityId = $this->getIdentifier($entity); |
||
611 | |||
612 | $qb = $this->em->createQueryBuilder(); |
||
613 | $query = $qb |
||
614 | ->select($qb->expr()->max('log.version')) |
||
615 | ->from($logEntityMeta->name, 'log') |
||
616 | ->where( |
||
617 | $qb->expr()->andX( |
||
618 | $qb->expr()->eq('log.objectId', ':objectId'), |
||
619 | $qb->expr()->eq('log.objectClass', ':objectClass') |
||
620 | ) |
||
621 | ) |
||
622 | ->setParameter('objectId', $entityId) |
||
623 | ->setParameter('objectClass', $entityMeta->name) |
||
624 | ->getQuery(); |
||
625 | |||
626 | return $query->getSingleScalarResult() + 1; |
||
627 | } |
||
628 | |||
629 | /** |
||
630 | * @param object $entity |
||
631 | * @param DoctrineClassMetadata|null $entityMeta |
||
632 | * @return mixed |
||
633 | */ |
||
634 | protected function getIdentifier($entity, $entityMeta = null) |
||
635 | { |
||
636 | $entityMeta = $entityMeta ?: $this->em->getClassMetadata($this->getEntityClassName($entity)); |
||
637 | $identifierField = $entityMeta->getSingleIdentifierFieldName(); |
||
638 | |||
639 | return $entityMeta->getReflectionProperty($identifierField)->getValue($entity); |
||
640 | } |
||
641 | |||
642 | /** |
||
643 | * @param string $entityClassName |
||
644 | * @return bool |
||
645 | */ |
||
646 | protected function checkAuditable($entityClassName) |
||
647 | { |
||
648 | if ($this->auditConfigProvider->hasConfig($entityClassName) |
||
649 | && $this->auditConfigProvider->getConfig($entityClassName)->is('auditable') |
||
650 | ) { |
||
651 | $reflection = new \ReflectionClass($entityClassName); |
||
652 | $classMetadata = new ClassMetadata($reflection->getName()); |
||
653 | |||
654 | foreach ($reflection->getProperties() as $reflectionProperty) { |
||
655 | $fieldName = $reflectionProperty->getName(); |
||
656 | |||
657 | if ($this->auditConfigProvider->hasConfig($entityClassName, $fieldName) |
||
658 | && ($fieldConfig = $this->auditConfigProvider->getConfig($entityClassName, $fieldName)) |
||
659 | && $fieldConfig->is('auditable') |
||
660 | ) { |
||
661 | $propertyMetadata = new PropertyMetadata($entityClassName, $reflectionProperty->getName()); |
||
662 | $propertyMetadata->method = '__toString'; |
||
663 | |||
664 | $classMetadata->addPropertyMetadata($propertyMetadata); |
||
665 | } |
||
666 | } |
||
667 | |||
668 | if (count($classMetadata->propertyMetadata)) { |
||
669 | $this->addConfig($classMetadata); |
||
670 | |||
671 | return true; |
||
672 | } |
||
673 | } |
||
674 | |||
675 | return false; |
||
676 | } |
||
677 | |||
678 | /** |
||
679 | * @param object|string $entity |
||
680 | * @return string |
||
681 | */ |
||
682 | private function getEntityClassName($entity) |
||
683 | { |
||
684 | if (is_object($entity)) { |
||
685 | return ClassUtils::getClass($entity); |
||
686 | } |
||
687 | |||
688 | return $entity; |
||
689 | } |
||
690 | |||
691 | /** |
||
692 | * @param object $entity |
||
693 | * @return string |
||
694 | */ |
||
695 | protected function getEntityIdentifierString($entity) |
||
696 | { |
||
697 | $className = $this->getEntityClassName($entity); |
||
698 | $metadata = $this->em->getClassMetadata($className); |
||
699 | |||
700 | return serialize($metadata->getIdentifierValues($entity)); |
||
701 | } |
||
702 | |||
703 | /** |
||
704 | * @param DoctrineClassMetadata $entityMeta |
||
705 | * @param string $field |
||
706 | * |
||
707 | * @return string |
||
708 | */ |
||
709 | private function getFieldType(DoctrineClassMetadata $entityMeta, $field) |
||
729 | } |
||
730 |
This property has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.