【问题标题】:Laminas: Get instance of DB Adapter in an Class (Injection?)Laminas:在类中获取数据库适配器的实例(注入?)
【发布时间】:2020-10-23 07:40:27
【问题描述】:

我对 Laminas 比较陌生,有些事情对我来说仍然没有意义 - 就我而言 - 在我看来,如何在 laminas 中完成事情非常复杂。就我而言,现在我需要数据库适配器的实例。

项目是这样的:

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

源码如下:

IndexControllerFactory.php

<?php

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

<?php

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

<?php

namespace Mail\Model;

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


class Mail {

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

}

MailQueueTable.php

<?php

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 表代码是基于我阅读的教程的构造函数等。如您所见,构造需要适配器。但我现在不知道如何获取适配器。

据我到目前为止所阅读的,我需要在索引控制器工厂中注入数据库适配器,然后从索引控制器中的操作到新创建的邮件实例,然后我必须将它注入到邮件队列表?

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

global $DB;

我的数据库可用。

【问题讨论】:

    标签: php zend-framework3 laminas


    【解决方案1】:

    一开始是相当复杂的,但是当你习惯了工厂(和 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(\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, $requestName, 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, $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' => [
            \Mail\Model\Mail::class => Mail\Model\MailFactory::class,
            \Mail\Model\Table\MailQueueTable::class => Mail\Model\Table\MailQueueTableFactory::class
        ]
    ]
    

    【讨论】:

      【解决方案2】:

      非常感谢您的精彩回答。

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

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

      即使你的回答很好,也会带来新的问题:

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

      我看对了吗?

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

      它将数据库凭据、数据库名称等保存在配置文件中。我怎样才能访问它们,而不是像你提到的那样将它们再次放在MailQueueTableFactory 中?从IndexControllerFactory 获取数据库适配器的实例将其传递给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,也不必传递数据库凭据等。不知何故,MailQueueTable 似乎获得了适配器...?!

      【讨论】:

        猜你喜欢
        • 2018-08-08
        • 1970-01-01
        • 2010-10-29
        • 2017-03-25
        • 1970-01-01
        • 2016-08-31
        • 1970-01-01
        • 2013-11-20
        • 2015-09-09
        相关资源
        最近更新 更多