Вызов функции-члена createQueryBuilder() для нулевого значения при использовании репозитория

Я пытаюсь внедрить пользовательскую систему аутентификации для своего приложения.

Для этого я создал класс (lib) с именем Auth, который расширяет мой UserRepository, поэтому я могу использовать модель непосредственно в своем классе аутентификации.

<?php

namespace App\Lib;
use App\Repository\UserRepository;

class Auth extends UserRepository {

Внутри моей функции аутентификации, которая находится в Auth, я вызываю функцию findByCredentials, которая должна вернуть мне некоторые пользовательские данные из базы данных.

$user = $this->findByCredentials($email, $password);

Я вызываю это внутри своего контроллера, чтобы заставить его работать

public function index(Request $request) {
    $auth = new Auth();
    $auth->authenticate(null, '[email protected]', '1234');
    return $this->tpl();
}

Это мой UserRepository, который был сгенерирован автоматически, и я добавил только эту функцию.

<?php

namespace App\Repository;

use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;

class UserRepository extends ServiceEntityRepository
{
    public function __construct(RegistryInterface $registry)
    {
        parent::__construct($registry, User::class);
    }

    public function findByCredentials($email, $password)
    {
        return $this->createQueryBuilder('user')
            ->andWhere('user.email = :email')
            ->andWhere('user.password = :password')
            ->setParameters([
                'email' => $email,
                'password' => $password
              ])
            ->getQuery()
            ->getResult();
}

Но тогда я получаю ошибку, упомянутую в заголовке.

Я использовал cli/console для генерации всего и убедился, что моя таблица существует в базе данных. Я использую MySQL v5.7 на Linux-машине.

Я также настроил config/packages/doctrine.yaml

Конструктор класса авторизации

public function __construct($jwt = null, $email = null, $password = null) {
    $this->jwt = $jwt;
    $this->email = $email;
    $this->password = $password;
}

Я подозреваю, что у вас есть __construct в вашем Auth классе? пожалуйста, покажите это. Но я подозреваю, что вы нарушаете используемую инъекцию зависимостей. Почему бы вам просто не добавить функции в Auth к вашему UserRepository? В вашем контроллере вам, вероятно, следует добавить UserRepository в список параметров функции, чтобы он правильно вводился. (Пожалуйста, также покажите заголовок функции/маршрута вашего контроллера)

Jakumi 31.03.2019 04:22

@Jakumi Я обновил вопрос, как вы просили. Вы имеете в виду, что конструктор класса Auth должен иметь эту зависимость?

n0body7331 31.03.2019 10:34

Проблема в том, что вы создаете экземпляр Auth самостоятельно, а не через методы DependencyInjection. Если вы внимательно посмотрите, то заметите, что new Auth() не получает никаких аргументов, необходимых __construct() в вашем классе UserRepository. Следуйте рекомендациям и немного реорганизуйте свой код, и все будет хорошо.

Artamiel 31.03.2019 11:33

@Artamiel Привет, спасибо за ответ. Не могли бы вы предоставить мне некоторые ресурсы, где я могу прочитать больше об этом материале. Я попытался внедрить RegistryInterface и вызвать parent::__construct() внутри моего конструктора класса Auth, но он говорит: «Невозможно создать экземпляр интерфейса». Единственное, чего я действительно пытаюсь добиться, - это иметь небольшую библиотеку, которая имеет некоторую логику и может выполнять некоторые простые запросы sql и в то же время не быть контроллером.

n0body7331 31.03.2019 12:15
Стоит ли изучать 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 и хотите разрабатывать...
2
4
828
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вы, по-видимому, удаляете преимущества внедрения зависимостей.

внедрение зависимостей, по сути, заключается в том, что вы не создаете службу внутри своего класса, а вместо этого предоставляете ее в качестве параметра либо в конструкторе, либо в вызовах функций. (В фреймворке symfony вам обычно не нужно создавать его в другом месте, но symfony позаботится о том, чтобы предоставить его вам, если только вы явно не хотите вызывать функцию/конструктор... вот почему вы обычно не т.)

Одним из примеров может быть контроллер, где Request $request (подсказка типа) предоставляется фреймворком. Технически у вас может быть почти любой класс с подсказкой типа, если фреймворк (точнее, контейнер) знает этот класс и как сгенерировать его/экземпляр. То, что контейнер генерирует для вас зависимости, подключается к автопроводке или автоконфигурации, и это очень-очень удобно. (Документы для Symfony: https://symfony.com/doc/current/service_container.html)

В вашем конкретном примере: я бы посоветовал не расширять UserRepository и предложить две лучшие альтернативы:

переместите его внутрь своего UserRepository

если вы хотите расширить UserRepository, и этот UserRepository уже специфичен и несколько уникален для вашего проекта, почему бы не поместить «расширение» прямо в UserRepository? Я действительно не могу придумать очень веской причины, чтобы не делать этого. Однако ...

сервис Auth.

Поскольку в создание репозитория на стороне доктрины входит некоторая серьезная подготовка, и в нем задействованы некоторые одноэлементные зависимости (реестр, соединение, ...) и где-то закопанные, пойдите по пути автоматического подключения/автоматической настройки framework и сделайте UserRepository параметром вашего Auth сервиса:

class Auth {
    /** @var UserRepository */
    private $userRepository;

    public function __construct(UserRepository $userRepository) {
        $this->userRepository = $userRepository;
    }

    public function authenticate(...) {
        /* some logic that can use $this->userRepository */
    }
}

Важное замечание: у вас есть jwt, электронная почта, пароль в качестве параметров вашего Auth. Это имеет семантическое различие: либо это Сервис, который аутентифицирует пользователей, и в этом случае jwt, электронная почта и пароль точно не должны быть частью конструктора, потому что тогда это будет аутентификация для ОДНОГО пользователя, для которого он создан ... что почти не приносит пользы. В противном случае он должен получить эти параметры при вызове аутентификации, что, на мой взгляд, имеет больше смысла.

Однако, ЕСЛИ вы используете какой-то сложный протокол аутентификации, когда вы взаимодействуете с внешним сервером, которому требуются некоторые дополнительные учетные данные ПОВЕРХ учетных данных пользователя (авторизация пользователя как служба или что-то еще), тогда мой аргумент недействителен, и вы должны научиться определять Учетные данные аутентификации в services.yaml.

Но я подозреваю, что это не так. Вероятно, стоит на мгновение подумать о состоянии. В общем, узнайте, что на самом деле необходимо для построения сервиса, и эти вещи добавьте в конструктор. Когда служба должна что-то СДЕЛАТЬ, это относится к параметрам методов службы.

ремонт вашего контроллера

Создавать Auth самостоятельно довольно неудобно, потому что вам пришлось бы переделывать многие функции, которые уже предоставляет внедрение зависимостей symfony + автосвязывание + автонастройка. Чистый способ - ввести то, что вам нужно.

Я повторю ваш индексный маршрут здесь и добавлю комментарий ниже

public function index(Request $request) {
    $auth = new Auth();
    $auth->authenticate(null, '[email protected]', '1234');
    return $this->tpl();
}

хотя это и не является строго обязательным, обычно функции маршрута контроллера называют [something]Action, поэтому indexAction. Во-вторых, вы, видимо, не используете Request, поэтому вам следует удалить его. В-третьих, добавьте либо UserRepository, либо Auth в заголовок вашего метода (в зависимости от того, какой вариант вы выбрали):

// this goes into your controller

// or: public function indexAction(UserRepository $userRepository) { 
public function indexAction(Auth $auth) {
    $auth->authenticate(/** ... your parameters ... */);
    return $this->tpl(); // <-- what's this? ;o)
}

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