*/ class LogRepository extends Repository { /** @var Functions */ private $wp; public function __construct( EntityManager $entityManager, Functions $wp ) { parent::__construct($entityManager); $this->wp = $wp; } public function saveLog(LogEntity $log): void { // Save log entity using DBAL to avoid calling "flush()" on the entity manager. // Calling "flush()" can have unintended side effects, such as saving unwanted // changes or trying to save entities that were detached from the entity manager. $this->entityManager->getConnection()->insert( $this->entityManager->getClassMetadata(LogEntity::class)->getTableName(), [ 'name' => $log->getName(), 'level' => $log->getLevel(), 'message' => $log->getMessage(), 'raw_message' => $log->getRawMessage(), 'context' => json_encode($log->getContext()), 'created_at' => ( $log->getCreatedAt() ?? Carbon::createFromTimestamp($this->wp->currentTime('timestamp')) )->format('Y-m-d H:i:s'), ], ); // sync the changes with the entity manager if ($this->entityManager->isOpen()) { $lastInsertId = (int)$this->entityManager->getConnection()->lastInsertId(); $log->setId($lastInsertId); $this->entityManager->getUnitOfWork()->registerManaged($log, ['id' => $log->getId()], []); $this->entityManager->refresh($log); } } /** * @param \DateTimeInterface|null $dateFrom * @param \DateTimeInterface|null $dateTo * @param string|null $search * @param string $offset * @param string $limit * @return LogEntity[] */ public function getLogs( \DateTimeInterface $dateFrom = null, \DateTimeInterface $dateTo = null, string $search = null, string $offset = null, string $limit = null ): array { $query = $this->doctrineRepository->createQueryBuilder('l') ->select('l'); if ($dateFrom instanceof \DateTimeInterface) { $query ->andWhere('l.createdAt >= :dateFrom') ->setParameter('dateFrom', $dateFrom->format('Y-m-d 00:00:00')); } if ($dateTo instanceof \DateTimeInterface) { $query ->andWhere('l.createdAt <= :dateTo') ->setParameter('dateTo', $dateTo->format('Y-m-d 23:59:59')); } if ($search) { $search = Helpers::escapeSearch($search); $query ->andWhere('l.name LIKE :search or l.message LIKE :search') ->setParameter('search', "%$search%"); } $query->orderBy('l.createdAt', 'desc'); if ($offset !== null) { $query->setFirstResult((int)$offset); } if ($limit === null) { $query->setMaxResults(500); } else { $query->setMaxResults((int)$limit); } return $query->getQuery()->getResult(); } public function purgeOldLogs(int $daysToKeepLogs, int $limit = 1000) { $logsTable = $this->entityManager->getClassMetadata(LogEntity::class)->getTableName(); $this->entityManager->getConnection()->executeStatement(" DELETE FROM $logsTable WHERE `created_at` < :date ORDER BY `id` ASC LIMIT :limit ", [ 'date' => Carbon::now()->subDays($daysToKeepLogs)->toDateTimeString(), 'limit' => $limit, ], [ 'date' => Connection::PARAM_STR, 'limit' => Connection::PARAM_INT, ]); } public function getRawMessagesForNewsletter(NewsletterEntity $newsletter, string $topic): array { return $this->entityManager->createQueryBuilder() ->select('DISTINCT logs.rawMessage message') ->from(LogEntity::class, 'logs') ->where('logs.name = :topic') ->andWhere('logs.context LIKE :context') ->orderBy('logs.createdAt') ->setParameter('context', json_encode(['newsletter_id' => $newsletter->getId()])) ->setParameter('topic', $topic) ->getQuery() ->getSingleColumnResult(); } public function persist($entity): void { throw new InvalidStateException('Use saveLog() instead to avoid unintended side effects'); } public function flush(): void { throw new InvalidStateException('Use saveLog() instead to avoid unintended side effects'); } protected function getEntityClassName() { return LogEntity::class; } }