Маршрут лиги, контейнер и PDO

TL; DR;

Как сделать соединение PDO доступным для класса CardOnFile\Controller, чтобы он мог выполнять запросы к базе данных? (Я думаю, мне нужно использовать контейнер, но не знаю, как это сделать).

Задний план

Я хочу избежать множественных подключений к базе данных каждый раз, когда я создаю экземпляр объекта, которому требуется доступ к базе данных. Итак, я считать Мне нужно создать ОДНУ копию соединения с базой данных (PDO), а затем внедрить ее в классы, где она понадобится, используя League \ Route и League \ Container.

Я не хочу вставлять контейнер в классы, потому что это местоположение службы. Но я совершенно не уверен, как поместить объект PDO в класс, которому он понадобится, чтобы он мог работать.

Как сделать так, чтобы отображаемый вызываемый объект имел доступ к базе данных?

Код:

/* Connect to a MySQL database using driver invocation */
$dsn = 'mysql:dbname=foo;host=localhost';
$user = 'bar';
$password = 'supersecret';

try {
    $pdo = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
    die(__FILE__ . ":" . __LINE__);
}

$container = new League\Container\Container;

$container->share('response', Zend\Diactoros\Response::class);
$container->share('request', function () {
    return Zend\Diactoros\ServerRequestFactory::fromGlobals(
        $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES
    );
});

$container->share('emitter', Zend\Diactoros\Response\SapiEmitter::class);

//DI PDO instance and connection.
$container->share('PDO', $pdo);

$route = new League\Route\RouteCollection($container);

$route->map('GET', '/cards/', 'CardOnFile\Controller::requestEmail' );
$route->map('GET', '/cards/emails/confirm', 'CardOnFile\Controller::getUserController' );
$route->map('GET', '/cards/emails/', 'CardOnFile\Controller::getCardController' );

$response = $route->dispatch($container->get('request'), $container->get('response'));

$container->get('emitter')->emit($response);

FWIW: Шаблоны проектирования: как создать объект / соединение с базой данных только при необходимости?. Думаю, мой типичный подход - синглтон (с фабрикой / реестром?). Я думаю о том, как Doctrine используется в ZF и Symfony.

ficuscr 23.07.2018 22:38

Это полезно, и я согласен с этим, но я не вижу, как я могу проникнуть в область действия $route->map(), чтобы предоставить экземпляр базы данных ИЛИ передать переменную $pdo самому классу.

DrDamnit 23.07.2018 23:03

Отредактировано, чтобы переформулировать вопрос, чтобы прояснить то, что мне нужно.

DrDamnit 23.07.2018 23:12

Получая соединение в Controller, я, вероятно, просто получил бы соединение по умолчанию из статического фабричного класса. Не уверен, что в вашем приложении есть концепция «помощника контроллера», как в некоторых фреймворках. $db = $this->_helper->dbManager() ... А фреймворк пользуетесь? У вас есть какой-то подход к базе данных / модели?

ficuscr 23.07.2018 23:13

Я не использую фреймворк. Подход, который вы здесь перечисляете, действителен, но я старался не использовать глобальное пространство имен. Не уверен, что смогу провести модульное тестирование таким образом.

DrDamnit 24.07.2018 00:00

Я чувствую, что ответ может быть спрятан здесь, но я не могу его найти. stackoverflow.com/questions/44387343/…

DrDamnit 24.07.2018 00:10

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

ficuscr 24.07.2018 00:12

Позвольте нам продолжить обсуждение в чате.

ficuscr 24.07.2018 00:13
Стоит ли изучать 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
8
411
1

Ответы 1

Я понял.

документы не делает это настолько очевидным, насколько возможно, но объект-контейнер требует, чтобы у вас был определенный интерфейс И чтобы вы использовали методы ->add()->withArgument().

Итак, сложив все вместе, мы получаем следующее:

Создайте экземпляры ваших исходных объектов

В приведенном ниже коде используется закрытие для добавления объекта PDO с правильным подключением к базе данных в контейнер. Это наиболее эффективный способ добавления объектов в ваш контейнер, поскольку они не создаются до тех пор, пока не будут использованы.

//DI PDO instance and connection.
$container->add('pdo', function() {
    /* Connect to a MySQL database using driver invocation */
    $dsn = 'mysql:dbname=foo;host=localhost';
    $user = 'bar';
    $password = 'supersecret';

    try {
        $pdo = new PDO($dsn, $user, $password);
    } catch (PDOException $e) {
        echo 'Connection failed: ' . $e->getMessage();
        die(__FILE__ . ":" . __LINE__);
    }

    return $pdo;
});

Добавьте свой класс в контейнер и укажите конструктор *

$container
    ->add('controller', 'CardOnFile\Controller')
    ->withArgument($container->get('pdo'));

На этом этапе объект-контейнер будет пытаться использовать подсказки типа, чтобы выяснить, следует ли добавлять что-то в конструктор, поэтому убедитесь, что ваш класс имеет подсказку типа в своем конструкторе. В этом случае мы используем класс PDO, но мы также находимся в пространстве имен CardOnFile, поэтому нам нужно добавить оператор use, а также подсказку типа:

<?php

namespace CardOnFile;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
**use \PDO;**

class Controller implements CardControllerInterface
{
    public $content = '';
    protected $pdo = null;

    public function __construct(**PDO** $pdo) {
        $this->pdo = $pdo;
    }

    // ...
}

Создайте интерфейс, чтобы Контейнер мог найти / распознать, что объект PDO должен быть вставлен в созданный объект.

<?php

namespace CardOnFile;

interface CardControllerInterface
{

}

Ага. Пусто. Он просто используется, чтобы помочь системе контейнеров.

Теперь вы успешно внедрили объект зависимости PDO в свое приложение и его классы.

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