Обновляйте каждый запрос doctrine перед его отправкой в базу данных

#php #mysql #doctrine-orm #doctrine

#php #mysql #doctrine-orm #doctrine

Вопрос:

Мы используем огромную платформу, которая имеет единую базу данных для нескольких интерфейсов. Теперь мы собираемся попытаться определить наши медленные запросы и получить лучшее представление о том, с какой страницы поступает наш трафик.

У меня была идея вводить имя страницы в качестве комментария в каждый sql-запрос, чтобы иметь возможность видеть его при просмотре базы данных с помощью SHOW FULL PROCESSLIST

введите описание изображения здесь

В конце это должно выглядеть так: /*PAGE NAME*/ SHOW FULL PROCESSLIST

Если я сделаю это в sequel pro, кажется, что комментарий попадает в список, а затем:

введите описание изображения здесь

Как я могу обновлять каждый запрос doctrine, используя слушателя / подписчика для ввода пользовательского комментария?

Комментарии:

1. Прослушиватель / подписчик / фильтры Doctrine не будут поддерживать это. Все, что я могу предложить, это расширить объект Doctrine connection, а затем, возможно, найти место, прежде чем сгенерированный sql будет отправлен на сервер базы данных. Но я не думаю, что ваш подход является хорошим. На серверах баз данных есть много инструментов, профилирующих инструменты для такого рода вещей.

Ответ №1:

Doctrine DBAL позволяет вам определить свой собственный класс подключения.

 doctrine:
    dbal:
        wrapper_class: AppDBALMyConnectionWrapper
  

Вы можете реализовать дочерний класс DoctrineDBALConnection и переопределить executeQuery() его в соответствии с вашими потребностями.

 class MyConnectionWrapper extends Connection
{
  public function executeQuery($sql, array $params = [], $types = [], ?QueryCacheProfile $qcp = null)
  {
    $sql = '/*PAGE NAME*/ '.$sql;
    return parent::executeQuery($sql, $params, $types, $qcp);
  }
}
  

Ответ №2:

Пожалуйста, ознакомьтесь с этой документацией Symfony: прослушиватели и подписчики событий Doctrine, чтобы понять следующий код

Вот как я это делал для каждого обновления, чтобы обновить время обновления:

     <?php

namespace AppEventListener;

use AppEntityAbstractEntity;
use AppEntityUser;
use DoctrineCommonEventSubscriber;
use DoctrineORMEvents;
use DoctrinePersistenceEventLifecycleEventArgs;
use Exception;
use Stringable;
use SymfonyComponentSecurityCoreAuthenticationTokenStorageTokenStorageInterface;
use SymfonyComponentSecurityCoreUserUserInterface;
use function is_object;

class DatabaseActivitySubscriber implements EventSubscriber
{
    /**
     * @var TokenStorageInterface
     */
    private TokenStorageInterface $tokenStorage;
    /**
     * @var null|User
     */
    private ?User $user;

    public function __construct(TokenStorageInterface $tokenStorage)
    {
        $this->tokenStorage = $tokenStorage;
        $this->user = null;
    }

    /**
     * @return array|string[]
     */
    public function getSubscribedEvents()
    {
        return [
            Events::prePersist,
            Events::preUpdate,
        ];
    }

    /**
     * Initiate the name of the user creating the object with "LastName FirstName (id)"
     *
     * @param LifecycleEventArgs $args
     * @throws Exception
     */
    public function prePersist(LifecycleEventArgs $args)
    {
        $object = $args->getObject();
        if ($object instanceof AbstractEntity amp;amp; $this->getUser() instanceof User) {
            $object->setCreateUser($this->getUser()->getLastName() . ' ' . $this->getuser()->getLastName() . ' (' . $this->getuser()->getId() . ')');
            $object->setCreateDate();
        }
    }

    /**
     * @return string|Stringable|UserInterface|null|User
     */
    private function getUser()
    {
        if ($this->user instanceof User){
            return $this->user;
        }
        $token = $this->tokenStorage->getToken();
        if (null === $token) {
            return null;
        }

        if (!is_object($user = $token->getUser())) {
            return null;
        }
        $this->user = $user;
        return $this->user;
    }

    /**
     * @param LifecycleEventArgs $args
     * @throws Exception
     */
    public function preUpdate(LifecycleEventArgs $args)
    {
        $object = $args->getObject();
        if ($object instanceof AbstractEntity amp;amp; $this->getUser() instanceof User) {
            $object->setUpdateUser($this->getuser()->getLastName() . ' ' . $this->getuser()->getLastName() . ' (' . $this->getuser()->getId() . ')');
            $object->setUpdateDate();
        }
    }
}
  

И добавьте в service.yaml:

     AppEventListenerDatabaseActivitySubscriber:
        tags:
            - { name: 'doctrine.event_subscriber' }
  

Комментарии:

1. Спасибо за ваш ответ. Но я не вижу, чтобы вы вводили / изменяли какой-либо sql-запрос в своем коде? 🙂

2. Все мои сущности расширяют абстрактность. Поэтому, когда я обновляю один из них, я устанавливаю UpdateUser и UpdateDate в функции preupdate. Это изменение автоматически преобразуется в dql / sql

3. Jep, но вопрос заключается в том, как расширять каждый запрос перед его отправкой, а не в получении обновлений при изменении объектов 🙂