薄片:在类中获取数据库适配器实例注入?

问题描述

我对拉米纳斯(Laminas)相对较新,有些事情对我来说仍然没有意义-就我而言,如何在薄片中完成事情看起来非常复杂。就我而言,我现在需要数据库适配器的实例。

该项目是这样的:

我有一个IndexController(和一个Factory)可以创建(在发布请求的情况下) 邮件类的实例 并且该Mail类应该在MailQueueTable中添加数据。 但是我不知道如何在MailQueueTable中获得数据库适配器

代码如下:

IndexControllerFactory.@R_502_6278@

<?@R_502_6278@

declare(strict_types=1);

namespace Test\Controller\Factory;

use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Test\Controller\IndexController;


class IndexControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container,$requestName,array $options = null)
    {
        return new IndexController(
            $container->get('ApplicationConfig')
        );
    }
}

IndexController.@R_502_6278@

<?@R_502_6278@

declare(strict_types=1);

namespace Test\Controller;

use Laminas\Config\Config;
use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\viewmodel;
use Mail\Model\Mail;


class IndexController extends AbstractActionController
{
    private $config;

    public function __construct(array $config)
    {
        $this->config = $config;
    }


    public function indexAction()
    {
        $request = $this->getRequest();
     
        if ($request->isPost()) {     
                $Mail = new Mail();
                $Mail->send();
            }
        }
    }
}

Mail.@R_502_6278@

<?@R_502_6278@

namespace Mail\Model;

use Laminas\View\Model\viewmodel;
use Mail\Model\Table\MailQueueTable;


class Mail {

    public function send()
    {
        $MailQueueTable = new MailQueueTable();
        $MailQueueTable->add();
    }

}

MailQueueTable.@R_502_6278@

<?@R_502_6278@

declare(strict_types=1);

namespace Mail\Model\Table;

use Laminas\Db\Adapter\Adapter;
use Mail\Model\Mail;

class MailQueueTable extends AbstractTableGateway
{
    protected $adapter;
    protected $table = 'mail_queue';


    public function __construct(Adapter $adapter)
    {
        // Here starts the problem...
        // As far as I understand,I have to inject
        // the DB Adapter in the Construct of the
        // AbstractTableGateway Class...
        // But no idea how to get it here...

        $this->adapter = $adapter;
        $this->initialize();
    }


    public function add()
    {
        // sql Insert Statement would be here
    }
}

基于我已阅读的教程,MailQueue表代码在构造函数等方面。如您所见,该构造需要适配器。但是我现在不知道如何获得适配器。

到目前为止,我需要在索引控制器工厂中注入数据库适配器,然后从索引控制器中的操作注入到新创建的邮件实例中,然后从那里将其注入到MailQueue中。表?

我不认为这是正确的解决方案-在使用Laminas之前,我只能写

global $DB;

我有可用的数据库

解决方法

一开始它很复杂,但是当您习惯了工厂(和DI)后,它将变得更加容易:)

问题出在您的控制器内部:

public function indexAction()
{
    $request = $this->getRequest();
    
    if ($request->isPost()) {
            // !! wrong !!
            $Mail = new Mail();
            // !! wrong !!

            $Mail->send();
        }
    }
}

您正在创建Mail的实例,但是邮件几乎没有必须解决的依赖关系,但是您的控制器却无法做到。要解决此问题,您应该从DI(Mail)中获取ContainerInterface实例。

IndexControllerFactory.php

public function __invoke(ContainerInterface $container,$requestName,array $options = null)
{
    $applicationConfig = $container->get('ApplicationConfig');
    $mail = $container->get(\Mail\Model\Mail::class);
    return new IndexController($applicationConfig,$mail);
}

这样,IndexController的依赖项将由其工厂解决。现在,您必须调整控制器以接受构造函数中的新实例:

class IndexController extends AbstractActionController
{
    private $config;

    private $mail;

    public function __construct(array $config,Mail $mail)
    {
        $this->config = $config;
        $this->mail = $mail;
    }


    public function indexAction()
    {
        $request = $this->getRequest();
     
        if ($request->isPost()) {     
                $this->mail->send();
            }
        }
    }
}

但是,对于Mail(因为它需要一个MailQueuqTable的实例)和MailQueueTable(因为它需要一个Adapter的实例,您将遇到相同的问题)。

因此,在构造对象和添加工厂时,应提供这些依赖关系。 Mail\Model\Mail

class Mail {
    private $mailQueueTable;

    public function __construct(MailQueueTable $mailQueueTable)
    {
        $this->mailQueueTable = $mailQueueTable;
    }

    public function send()
    {
        $this->mailQueueTable->add();
    }
}

其工厂Mail\Model\MailFactory

class MailFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container,array $options = null)
    {
        return new Mail(
            $container->get(\Mail\Model\Table\MailQueueTable::class)
        );
    }
}

Mail\Model\Table\MailQueueTable实际上是正确的,因为构造函数已经需要Adapter的实例。您必须创建其工厂Mail\Model\Table\MailQueueTableFactory

class MailQueueTableFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container,array $options = null)
    {
        // Create the DB adapter
        $dbConfig = [
            'driver' => 'PDO','pdodriver' => '...','dbname' => '...','host' => '...','username' => '...','password' => '...'
        ];
        $adapter = new Adapter($dbConfig);
        return new MailQueueTable($adapter);
    }
}

最后,您必须告诉DI在哪里找到这些工厂,因此在模块配置文件中:

'service_manager' => [
    'factories' => [
        \Mail\Model\Mail::class => Mail\Model\MailFactory::class,\Mail\Model\Table\MailQueueTable::class => Mail\Model\Table\MailQueueTableFactory::class
    ]
]
,

非常感谢您的出色回答。

这意味着,对于我的控制器中“我可能可能需要” /“我可能会创建一个实例”的每个类,我必须声明它在ControllerFactory中?

哇。对于这个“简单”的示例,Laminas确实需要大量代码。

即使您的回答很好,也会导致新的问题:

  1. 如果我在Mail中获得了IndexControllerFactory.php实例,则会导致问题, 我无法将变量传递给Mail类的构造函数(即,在IndexController中创建的电子邮件地址,电子邮件内容等),因为Mail类的构造函数为:
    public function __construct(MailQueueTable $mailQueueTable)
    {
        $this->mailQueueTable = $mailQueueTable;
    }

我看到正确吗?

  1. 我正在关注Waxmud工作室的laminas youtube教程-数据库教程在这里: https://www.youtube.com/watch?v=07h3OBIF9kc

它将数据库凭证,数据库名称等保存在配置文件中。我如何才能访问它们,而不是像您提到的那样再次将它们放入MailQueueTableFactory中?从IndexControllerFactory获取数据库适配器实例将其传递到IndexController,然后从那里传递给Mail

  1. 我还没有弄清楚的是,如果我在MailQueueTable中注入IndexControllerFactory,即:
class IndexControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container,array $options = null)
    {
        return new IndexController(
            $container->get(MailQueue::class)
        );
    }
}

不必不必创建MailQueueTableFactory,也不必传递DB凭据等。以某种方式,MailQueueTable似乎可以得到适配器。 ??!