Задать вопрос
Ответы пользователя по тегу Symfony
  • Почему сущность не видит связанную созданную сущность,а пытается создать новую?

    @HellWalk Автор вопроса
    Какой-то отдельной опции, которая бы указала доктрине "не создавай новую сущность по этим данным, найди её в базе по id" нет, по этому, чтобы исправить эту ошибку необходимо написать свой нормалайзер, который будет вручную получать сущность из базы по id и привязывать её к родительской сущности:

    use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
    use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
    
    class EntityNormalizer implements DenormalizerInterface, NormalizerInterface
    {
        public function __construct(
            private readonly ObjectNormalizer $normalizer,
            private readonly EntityManagerInterface $em,
        ) {
        }
    
        public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): mixed
        {
            $entity = $this->normalizer->denormalize($data, $type, $format, $context);
            
            if ($file = $entity->getFile()) {
                $entity->setFile(
                    $this-em->getRepository(UploadFile::class)->findOneBy(['id' => $file->getId()])
                );
            }
    
            return $entity;
        }
    
        // ...
    }
    Ответ написан
    Комментировать
  • Почему симфони не может создать сервис для when@test?

    @HellWalk Автор вопроса
    Способа подменить класс классом в симфони нет, нужно переделывать привязку на интерфейс:

    App\Service\S3Client\S3Client:
            arguments:
                $version: 'latest'
                $region: 'us-east-1'
                $host: '%env(MINIO_HOSTNAME)%'
                $port: '%env(MINIO_INTERNAL_PORT)%'
                $accessKey: '%env(MINIO_ACCESS_KEY)%'
                $secretKey: '%env(MINIO_SECRET_KEY)%'
    
        App\Service\S3Client\S3ClientInterface:
            class: App\Service\S3Client\S3Client
            arguments:
                $version: 'latest'
                $region: 'us-east-1'
                $host: '%env(MINIO_HOSTNAME)%'
                $port: '%env(MINIO_INTERNAL_PORT)%'
                $accessKey: '%env(MINIO_ACCESS_KEY)%'
                $secretKey: '%env(MINIO_SECRET_KEY)%'
    
    when@test:
        services:
            App\Service\S3Client\S3ClientInterface:
                class: App\Service\S3Client\TestS3Client
    Ответ написан
    Комментировать
  • Как можно пропустить коннекты к внешним API в clear:cache?

    @HellWalk Автор вопроса
    Легкого варианта средствами симфони нет.

    Наиболее простой найденный вариант - развернуть внутри сети инстанс keycloak и указать к нему ссылку в gitlab-ci.yaml:

    variables:
      KEYCLOAK_SERVER_URL: http://11.11.11.11:11
    Ответ написан
    Комментировать
  • Как подменить используемый EntityManager?

    @HellWalk Автор вопроса
    Не смотря на наличие документации на которую сослался Денис Дерепко, она мало помогает в задаче подменить именно EntityManager, и именно когда к нему идет обращение в зависимостях через EntityManagerInterface.

    По этому отдельным ответом пишу решение:

    config/services.yaml:
    App\Proxy\EntityManagerProxy:
        decorates: 'doctrine.orm.entity_manager'


    Proxy-обертка (здесь оставив за скобками почему в документации декоратор, а в моем случае proxy) с нужным функционалом - чтобы EntityManager переподключался в базе в случае потери соединения с базой (а доктрина закрывает соединение в случае любой SQL-ошибки):

    class EntityManagerProxy implements EntityManagerInterface
    {
        private ObjectManager $entityManager;
        private ManagerRegistry $doctrine;
    
        public function __construct(ObjectManager $entityManager, ManagerRegistry $doctrine)
        {
            $this->entityManager = $entityManager;
            $this->doctrine = $doctrine;
        }
    
        /**
         * @param $object
         * @return void
         * @throws Exception
         */
        public function persist($object): void
        {
            $this->correctionConnect();
            $this->entityManager->persist($object);
        }
    
        /**
         * @return void
         * @throws Exception
         */
        public function flush(): void
        {
            $this->correctionConnect();
            $this->entityManager->flush();
        }
    
    
        private function correctionConnect(): void
        {
            // Для ошибок когда падает сама база или соединение с ней, например:
            // SQLSTATE[57P01]: Admin shutdown: 7 FATAL:  terminating connection due to administrator command
            // SQLSTATE[08006] [7] could not translate host name "postgres" to address: Temporary failure in name resolution
            // (например, когда на время падает контейнер с postgres)
            if ($this->entityManager->getConnection()->ping() === false) {
                $this->entityManager->getConnection()->close();
                $this->entityManager->getConnection()->connect();
            }
    
            // Для ошибки "The EntityManager is closed" (например, при ошибки SQL-запроса)
            if (!$this->entityManager->isOpen()) {
                $this->doctrine->resetManager();
                $this->entityManager = $this->doctrine->getManager();
            }
        }
        
        // Все другие методы для EntityManagerInterface перебрасываются напрямую на базовый EntityManager
    Ответ написан
    Комментировать
  • Как понять, что кэш сохранился в Redis?

    @HellWalk Автор вопроса
    Все, разобрался. Ожидаемо Symfony добавляет свой хеш к ключам.

    Посмотреть с каким ключом сохранилось значение можно через вывод всех ключей:

    127.0.0.1:6379> keys *
    1) "gTPBdlcdoq:270378f0-b29c-4bf6-b7d1-7a64d6e212ff"
    Ответ написан
    Комментировать
  • Как в Doctrine, в DBAL указать PDO::ATTR_PERSISTENT => true?

    @HellWalk Автор вопроса
    Проблема с лимитом подключений к базе в тестах решилась добавлением $this->entityManager->getConnection()->close(); в tearDown()

    /**
    * @throws ConnectionException
    */
    public function tearDown(): void
    {
        parent::tearDown();
        // ...
        $this->entityManager->getConnection()->close();
    }


    Забавно, что в официальной документации (с.м. последний пример):
    https://symfony.com/doc/current/testing/database.html

    Указано:
    protected function tearDown(): void
    {
        parent::tearDown();
    
        // doing this is recommended to avoid memory leaks
        $this->entityManager->close();
        $this->entityManager = null;
    }


    Что, по факту, не помогало решить проблему с лимитом подключений.
    Ответ написан
    2 комментария
  • Возможно ли подружить Symfony + gRPC + Codeception?

    @HellWalk Автор вопроса
    В общем, все оказалось просто (когда знаешь что делать)

    Необходимо в config/services.yaml в существующую строку:
    exclude: '../src/{DependencyInjection,Entity,Tests,Kernel.php}'

    добавить папку, в которой находятся gRPC-классы, в моем случае это папка src/Grpc и строчка в конфиге выглядит так:
    exclude: '../src/{DependencyInjection,Entity,Tests,Grpc,Kernel.php}'


    Спасибо за наводку по решению BoShurik
    Ответ написан
    Комментировать
  • Как обнулить или объединить миграции и оставить одну?

    @HellWalk
    Если миграции делались через
    php bin/console make:migration
    А под сохранением данных вы подразумеваете структуру таблиц, а не их содержимое, то все просто:

    1. удаляете все миграции
    2. удаляете все таблицы из базы (включая migrations)
    3. выполняете еще раз команду "php bin/console make:migration"

    P.S. На всякий случай, сделайте бекап базы и git-коммит, чтобы в случае чего откатить все назад.

    P.P.S. Можно и данные в базе сохранить - сделать нулевым пунктом бекап базы, изменить его так, чтобы в нем остались только команды на добавление данных, и накатить дамп четвертым пунктом.
    Ответ написан
    6 комментариев
  • Существует ли аналог RBAC Yii2 в Symfony?

    @HellWalk Автор вопроса
    Итак, поразбирался-покопался сам - для симфони есть Sonata - несколько больших бандлов для создания админки. В том числе там есть функционал схожий с RBAC.

    Но само решение спорное:
    1. Sonata слабо развивается, и выглядит брошенной
    2. Чем сложнее становится логика в проекте - тем меньше помогают (и начинают мешать) решения из коробки
    3. Сами разработчики Симфони рекомендуют использовать Voters

    Вот такие дела.

    P.S. Официальная документация по Sonata устарела, и по ней её не поставить. Мне помогло это руководство с хабра.
    Ответ написан
    Комментировать