Вызов функции-члена createQueryBuilder () для null при использовании репозитория - PullRequest
2 голосов
/ 30 марта 2019

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

Для этого я создал класс (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, 'somefakemaik@example.com', '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

Contructor класса auth

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

1 Ответ

1 голос
/ 31 марта 2019

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

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

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

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

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

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

услуга Auth.

Поскольку некоторая важная подготовка идет к созданию репозитория на стороне доктрины, и существуют некоторые синглтоноподобные зависимости (реестр, соединение, ...), которые где-то скрыты, перейдите по пути автоматического подключения / автоконфигурирование фреймворка и настройте 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, адрес электронной почты, пароль в качестве параметров для вашей аутентификации. Это имеет семантическое отличие: либо это Сервис, который аутентифицирует пользователей, в этом случае jwt, электронная почта и пароль определенно не должны быть частью конструктора, потому что тогда это будет аутентификация для ОДНОГО пользователя, для которого он создан ... что дает почти нет пользы. В противном случае он должен получить эти параметры при вызове authenticate - что, на мой взгляд, имеет больше смысла.

Если, однако, вы используете какой-то сложный протокол аутентификации, в котором вы общаетесь с внешним сервером, которому требуются некоторые дополнительные учетные данные в верхней части учетных данных пользователя (аутентификация пользователя в качестве службы или что-то еще), то мой аргумент недействителен, и вы должны изучить как определить учетные данные Auth в services.yaml.

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

исправление вашего контроллера

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

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

public function index(Request $request) {
    $auth = new Auth();
    $auth->authenticate(null, 'somefakemaik@example.com', '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)
}
...