Аутентификация по имени пользователя или электронной почте не удалась с DBAL Exception: Undefined offset: 1

Начиная с успешной проверки подлинности по электронной почте (в версии 4.2.4), попытка следовать Документы поставщика пользователей для добавления проверки подлинности по имени пользователя завершается с ошибкой.

DBAL Exception:... Undefined offset: 1

Любопытно, что если я запускаю оператор SQL, как показано в профилировщике отладки, View runnable query, запрос выполняется правильно и возвращает ненулевой результат. Так что, по крайней мере, репозиторий может вернуть имя пользователя.

Я попытался переписать оператор построителя запросов, используя entityManager; предоставление оператора setParameters() с двумя параметрами; все безрезультатно.

Редактировать № 2:

Тыкая в код Doctrine, указанный в трассировке (см. ниже), возникает исключение в строке

[$query, $params, $types] = SQLParserUtils::expandListParameters($query, $params, $types);

$query и $params (как показано с dd(...)) имеют смысл для меня. Однако переменная $types непрозрачна: это массив [0 => 102, 1 => 102]. Исключение возникает с утверждением SQLParserUtils....

конец Редактировать #2

Редактировать № 3:

Вот что происходит в Doctrine, но я понятия не имею о назначении кода. В Doctrine\DBAL\SQLParserUtils строки 129–133 содержатся в цикле foreach (), который запускается один раз для каждого элемента в $paramsPos массиве [0 => 496, 1 => 513], где значениями являются расположение заменяемых параметров в операторе SQL. Массив $params изначально содержит

array:2 [▼
  0 => array:1 [▼
    "username" => "gbrooks"
  ]
  1 => array:1 [▼
    "username" => "gbrooks"
  ]
]

После выполнения кода в 125 - 133 (как показано ниже)

$needle    += $paramOffset;
$needlePos += $queryOffset;
$count      = count($params[$needle]);

$params = array_merge(
    array_slice($params, 0, $needle),
    $params[$needle],
    array_slice($params, $needle + 1)
);

массив $params содержит

array:2 [▼
  "username" => "gbrooks"
  0 => array:1 [▼
    "username" => "gbrooks"
  ]
]

Обратите внимание, что ключа 1 больше не существует, поэтому, когда оператор count($params[$needle]) в строке 127 встречается при следующем проходе цикла (и $needle теперь равен 1, выдается DBAL Exception Undefined offset: 1.

конец Редактировать #3

Пользовательский репозиторий:

namespace App\Repository;

use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface;
use Doctrine\ORM\EntityRepository;

class UserRepository extends EntityRepository implements UserLoaderInterface
{
    public function loadUserByUsername($usernameOrEmail)
    {
        $user = $this->createQueryBuilder('u')
            ->where('u.username = :query OR u.email = :query')
            ->setParameter('query', $usernameOrEmail)
            ->getQuery()
            ->getOneOrNullResult();
    }
}

LoginFormAuthenticator содержит:

public function getUser($credentials, UserProviderInterface $userProvider)
{
    $token = new CsrfToken('authenticate', $credentials['csrf_token']);
    if (!$this->csrfTokenManager->isTokenValid($token)) {
        throw new InvalidCsrfTokenException();
    }

    $user = $this->entityManager->getRepository(User::class)->loadUserByUsername(['username' => $credentials['username']]);

    if (!$user) {
        // fail authentication with a custom error
        throw new CustomUserMessageAuthenticationException('Email could not be found.');
    }

    return $user;
}

След:

G:\Documents\workspace\mana\vendor\doctrine\dbal\lib\Doctrine\DBAL\DBALException.php:172 {▶}
  G:\Documents\workspace\mana\vendor\doctrine\dbal\lib\Doctrine\DBAL\DBALException.php:145 {▶}
  G:\Documents\workspace\mana\vendor\doctrine\dbal\lib\Doctrine\DBAL\Connection.php:911 {▶}
  G:\Documents\workspace\mana\vendor\doctrine\orm\lib\Doctrine\ORM\Query\Exec\SingleSelectExecutor.php:50 {▶}
  G:\Documents\workspace\mana\vendor\doctrine\orm\lib\Doctrine\ORM\Query.php:334 {▶}
  G:\Documents\workspace\mana\vendor\doctrine\orm\lib\Doctrine\ORM\AbstractQuery.php:967 {▶}
  G:\Documents\workspace\mana\vendor\doctrine\orm\lib\Doctrine\ORM\AbstractQuery.php:922 {▶}
  G:\Documents\workspace\mana\vendor\doctrine\orm\lib\Doctrine\ORM\AbstractQuery.php:765 {▶}
  G:\Documents\workspace\mana\src\Repository\UserRepository.php:24 {▶}
  G:\Documents\workspace\mana\src\Security\LoginFormAuthenticator.php:74 {▶}
  G:\Documents\workspace\mana\vendor\symfony\security-guard\Provider\GuardAuthenticationProvider.php:102 {▶}
  G:\Documents\workspace\mana\vendor\symfony\security-guard\Provider\GuardAuthenticationProvider.php:96 {▶}
  G:\Documents\workspace\mana\vendor\symfony\security-core\Authentication\AuthenticationProviderManager.php:76 {▶}
  G:\Documents\workspace\mana\vendor\symfony\security-guard\Firewall\GuardAuthenticationListener.php:130 {▶}
  G:\Documents\workspace\mana\vendor\symfony\security-guard\Firewall\GuardAuthenticationListener.php:82 {▶}
  G:\Documents\workspace\mana\vendor\symfony\security-bundle\Debug\WrappedListener.php:46 {▶}
  G:\Documents\workspace\mana\vendor\symfony\security-bundle\Debug\TraceableFirewallListener.php:35 {▶}
  G:\Documents\workspace\mana\vendor\symfony\security-http\Firewall.php:90 {▶}
  G:\Documents\workspace\mana\vendor\symfony\security-bundle\EventListener\FirewallListener.php:48 {▶}
  G:\Documents\workspace\mana\vendor\symfony\event-dispatcher\Debug\WrappedListener.php:115 {▶}
  G:\Documents\workspace\mana\vendor\symfony\event-dispatcher\EventDispatcher.php:212 {▶}
  G:\Documents\workspace\mana\vendor\symfony\event-dispatcher\EventDispatcher.php:44 {▶}
  G:\Documents\workspace\mana\vendor\symfony\event-dispatcher\Debug\TraceableEventDispatcher.php:145 {▶}
  G:\Documents\workspace\mana\vendor\symfony\http-kernel\HttpKernel.php:126 {▶}
  G:\Documents\workspace\mana\vendor\symfony\http-kernel\HttpKernel.php:67 {▶}
  G:\Documents\workspace\mana\vendor\symfony\http-kernel\Kernel.php:198 {▶}
  G:\Documents\workspace\mana/public\index.php:25 {▶}

Вы действительно должны добавить полную трассировку ошибки, которую вы получаете, а не только ее обрезанную версию (поскольку она укажет, какая строка/файл вызывает ее). Также для информации есть ярлык dump('test');die; в SF4: dd('test'); ;)

β.εηοιτ.βε 13.03.2019 22:32

Для улучшения вашего кода. В Symfony 4 рекомендуется внедрять то, что вам нужно, в репозиторий, а не в entityManager. Таким образом, вы можете ввести UserRepository с помощью конструктора и выполнить $this->userRepository->loadUserByUsername

AythaNzt 13.03.2019 22:36

Трассировка прилагается. Я недостаточно умен, чтобы разобраться в коде Doctrine. Спасибо за подсказку dd(). Кстати, я всегда стараюсь сначала следовать документам, а потом приводить в порядок.

geoB 13.03.2019 23:11

Какую версию доктрины вы используете?

Alexandru Cosoi 14.03.2019 14:35

Предполагая, что вас интересует доктрина/dbal: 2.9.2

geoB 14.03.2019 16:01

Я добавил правку №3, в которой подробно описывается код Doctrine\DBAL, вызывающий исключение. Как обойти этот код, для меня остается загадкой.

geoB 14.03.2019 22:37
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
6
127
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Обновите свой репозиторий до этого:

namespace App\Repository;

use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface;
use Doctrine\ORM\EntityRepository;

class UserRepository extends EntityRepository implements UserLoaderInterface
{
    public function loadUserByUsername($usernameOrEmail)
    {
        return $this->createQueryBuilder('u')
            ->where('u.username = :query')
            ->orWhere('u.email = :query')
            ->setParameter('query', $usernameOrEmail)
            ->getQuery()
            ->getOneOrNullResult();
    }
}

Неудивительно, что это не имеет значения.

geoB 14.03.2019 13:10
Ответ принят как подходящий

Вся проблема заключалась в том, что аргумент this->entityManager->getRepository(User::class)->loadUserByUsername(...) должен быть НЕ массивом, а скаляром.

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

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