Laminas:获取类中DB适配器的实例(Injection?)



我对Laminas相对陌生,有些事情对我来说仍然没有意义——在我看来,如何在Laminas中完成任务非常复杂。在我的情况下,现在我需要DB适配器的实例。

这个项目是这样的:

我有一个IndexController(和一个工厂(,它创建(在发布请求的情况下(邮件类的实例并且该Mail类应该在MailQueueTable中添加Data。但我不知道如何在MailQueueTable 中获取DB适配器

源代码如下:

IndexControllerFactory.php

<?php
declare(strict_types=1);
namespace TestControllerFactory;
use InteropContainerContainerInterface;
use LaminasServiceManagerFactoryFactoryInterface;
use TestControllerIndexController;

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

IndexController.php

<?php
declare(strict_types=1);
namespace TestController;
use LaminasConfigConfig;
use LaminasMvcControllerAbstractActionController;
use LaminasViewModelViewModel;
use MailModelMail;

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.php

<?php
namespace MailModel;
use LaminasViewModelViewModel;
use MailModelTableMailQueueTable;

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

MailQueueTable.php

<?php
declare(strict_types=1);
namespace MailModelTable;
use LaminasDbAdapterAdapter;
use MailModelMail;
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表代码是基于我读过的教程中的构造函数等。正如您所看到的,构造需要适配器。但我现在不知道如何获得适配器。

到目前为止,我所读到的内容是,我需要在索引控制器工厂中注入DB适配器,然后从索引控制器中的Action注入到新创建的邮件实例,然后从那里注入到MailQueue表?

我觉得这不是正确的解决方案-在使用Laminas之前,我可以只写

global $DB;

我的数据库可用。

一开始很复杂,但当你习惯了工厂(和DI(时,它会变得更容易:(

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

public function indexAction()
{
$request = $this->getRequest();

if ($request->isPost()) {
// !! wrong !!
$Mail = new Mail();
// !! wrong !!
$Mail->send();
}
}
}

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

IndexControllerFactory.php内部

public function __invoke(ContainerInterface $container, $requestName, array $options = null)
{
$applicationConfig = $container->get('ApplicationConfig');
$mail = $container->get(MailModelMail::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的实例(,您将遇到相同的问题。

因此,在构造对象和添加工厂时,应该提供这些依赖项MailModelMail:

class Mail {
private $mailQueueTable;
public function __construct(MailQueueTable $mailQueueTable)
{
$this->mailQueueTable = $mailQueueTable;
}
public function send()
{
$this->mailQueueTable->add();
}
}

其工厂MailModelMailFactory:

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

MailModelTableMailQueueTable实际上是正确的,因为构造函数已经需要Adapter的实例。您必须创建其工厂MailModelTableMailQueueTableFactory:

class MailQueueTableFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestName, 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' => [
MailModelMail::class => MailModelMailFactory::class,
MailModelTableMailQueueTable::class => MailModelTableMailQueueTableFactory::class
]
]

非常感谢您的精彩回答。

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

哇。Laminas真的需要大量的代码来实现这一点;简单的";实例

即使你的答案很好,它也会导致新的问题:

  1. 如果我在CCD_ 18中获得CCD_,我不能将变量传递给Mail类的构造函数(即电子邮件地址、电子邮件内容等,这些都是在IndexController中创建的(,因为Mail类的构造函数将是:
public function __construct(MailQueueTable $mailQueueTable)
{
$this->mailQueueTable = $mailQueueTable;
}

我认为正确吗?

  1. 我一直在关注蜡泥工作室的laminats youtube教程-DB教程在这里:https://www.youtube.com/watch?v=07h3OBIF9kc

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

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

我不必创建MailQueueTableFactory,也不必通过DB凭据等。不知何故,MailQueueTable似乎得到了适配器?!

最新更新