Пользователь службы Symfony Twig из хранилища токенов иногда имеет значение null

У меня есть служба, которую я определил как глобальную переменную веточки, которая использует автоматическое подключение TokenStorageInterface, чтобы получить текущего пользователя, вошедшего в систему.

Иногда токен равен нулю и выдает исключение при попытке доступа к нулевому объекту. Call to a member function getUser() on null

Это код barebone, который ломается.

BonusService.php

namespace AppBundle\Service;

use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class BonusService {

    private $user;
    private $manager;

    __construct(TokenStorageInterface, $tokenStorage, ObjectManager $manager) {
        $this->user = $tokenStorage->getToken()->getUser();    // Sometimes fails here
        $this->manager = $manager;
    }

    public function hasBonuses() {
        return count($this->manager->getRepository(Bonus::class)->findBy(array('contact' => $user)) > 0;
    }
}

services.yml

services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: true

    AppBundle\Service\BonusService:

config.yml

twig:
    ...
    globals:
        bonus_service: '@AppBundle\Service\BonusService'

index.html.twig

...
{% if bonus_service.hasBonuses %}Have Bonuses{% endif %}
...

Я искал причины, по которым хранилище токенов может быть нулевым, когда веточка делает это. В основном возникла одна проблема - убедиться, что мой маршрут находится за брандмауэром, который в данном случае и требует аутентифицированного пользователя.

Также следует отметить, что у меня есть аналогичная служба с идентичным конструктором, который используется в контроллере. Когда BonusService не решает использовать нулевой токен и страница загружается, у другой службы нет проблем с захватом токена. Когда я удаляю вызов службы в twig, страница загружается в 100% случаев, даже с другой службой и идентичным конструктором.

Любая помощь приветствуется!

Когда пользователь не вошел в систему, он даст вам null

Eakethet 18.06.2018 10:02

@Eakethet в этом случае пользователь вошел в систему. (Обычно у меня токен окружен предложением is_null(), но для краткости я не включил его во фрагмент)

SteppingHat 18.06.2018 10:06

Вы должны сохранить ссылку на хранилище токенов, а не вводить пользователя в конструктор. Токен может по-прежнему иметь значение null, но приложение находится в двух разных состояниях - когда конструктор вызывается, контейнер все еще загружается.

vstm 18.06.2018 10:07

Или вы можете избежать сохранения пользователя в службе и сделать что-то вроде Bonus_service.hasBonuses, {user: app.user}

Eakethet 18.06.2018 10:10

пожалуйста, никогда и никогда не меняйте код (кроме затенения переменных / паролей и т. д.), который вы публикуете здесь. Удаление is_null меняет все.

DonCallisto 18.06.2018 10:10

Спасибо @vstm! Мне удалось заставить его работать, назначив tokenStorage свойству класса и создав метод getUser() для выборки пользователя при необходимости. Не могли бы вы сделать свой комментарий ответом, чтобы я мог его принять?

SteppingHat 18.06.2018 10:11

@Eakethet Я думал об этом, однако могут быть случаи, когда я хотел бы повторно использовать эту службу в других ситуациях, которые могут выходить за пределы ветки. Я бы предпочел, чтобы это было автоматически подключено к службе, чем придумывать другие беспорядочные способы поиска пользователя в других контекстах.

SteppingHat 18.06.2018 10:13

@SteppingHat например. вы хотите знать, если у кого-то еще есть бонусы, а не у пользователя, который на самом деле вошел в систему, поэтому для меня это выглядит более многоразовым, когда вы передаете User в качестве параметра, но я не знаю вашего бизнес-случая

Eakethet 18.06.2018 10:15

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

SteppingHat 18.06.2018 10:26
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
1
9
835
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

При создании сервисов ваш конструктор должен избегать выполнения чего-то большего, кроме сохранения внедренных сервисов в качестве ссылки.

class BonusService {

    private $tokenStorage;
    private $manager;

    public function __construct(TokenStorageInterface $tokenStorage, ObjectManager $manager) {
        $this->tokenStorage = $tokenStorage;
        $this->manager = $manager;
    }

    public function hasBonuses() {
        if (!$this-tokenStorage->getToken() instanceof User) {
             return false;
        }
        return count($this->manager->getRepository(Bonus::class)->findBy(array(
            'contact' => $this-tokenStorage->getToken()->getUser())
        ) > 0;
    }
}

Вам все равно нужно проверить, установлен ли токен и является ли он экземпляром User (или, как бы то ни было, вызывается ваш User).

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

Другие вопросы по теме