问题描述
我对拉米纳斯(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确实需要大量代码。
即使您的回答很好,也会导致新的问题:
- 如果我在
Mail
中获得了IndexControllerFactory.php
实例,则会导致问题, 我无法将变量传递给Mail
类的构造函数(即,在IndexController中创建的电子邮件地址,电子邮件内容等),因为Mail
类的构造函数为:
public function __construct(MailQueueTable $mailQueueTable)
{
$this->mailQueueTable = $mailQueueTable;
}
我看到正确吗?
- 我正在关注Waxmud工作室的laminas youtube教程-数据库教程在这里: https://www.youtube.com/watch?v=07h3OBIF9kc
它将数据库凭证,数据库名称等保存在配置文件中。我如何才能访问它们,而不是像您提到的那样再次将它们放入MailQueueTableFactory
中?从IndexControllerFactory
获取数据库适配器实例将其传递到IndexController
,然后从那里传递给Mail
?
- 我还没有弄清楚的是,如果我在
MailQueueTable
中注入IndexControllerFactory
,即:
class IndexControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container,array $options = null)
{
return new IndexController(
$container->get(MailQueue::class)
);
}
}
我不必不必创建MailQueueTableFactory
,也不必传递DB凭据等。以某种方式,MailQueueTable
似乎可以得到适配器。 ??!