3

我目前正在构建一个模块以在多个项目中用作可重用库,但是由于它是一个库,因此不需要控制器。例如,我正在尝试为 Marketo soap API 创建一个 zf2 模块。用户在 /ROOT/config/autoload/local.php 中添加他们的密钥和 wsdl 位置。配置将包括类似'marketo'=>array(),

现在我遇到的问题是我想让自己和使用该模块的其他人能够执行类似...

$marketo = new \Marketo\Client\Client();

并在 \Marketo\Client\Client() 类中让构造函数读取 $config['marketo']; 的数组键;

然而,我可以将所有这些都放在一个 ini 文件中,但我更愿意让它与 zf2 中的其他所有内容在配置方面保持相似。

所以总结一下,我想获得一个合并的zend配置的数组键,以便在类中使用,比如......

class Marketo{
    private $key;
    private $pass;
    public function __construct(){
        $c = \Zend\Config\Config('marketo);
        $this->key = $c['key'];
        $this->pass = $c['pass'];
    }
}

============ 根据以下答案,自 ZF 2.1.1 起完全有效的解决方案 =============

模块结构如下所示(使用新示例,以便我可以重新开始)+ 表示目录名称 - 表示文件名

modules
  - Application /* Standard setup with an IndexController */
  - Cybersource /* The new module to be added */
      + config
         - module.config.php
      + src
         + Cybersource
            + Client
               - Client.php
            + ServiceFactory
               - ClientServiceFactory.php
      - Module.php
      - autoload_classmap.php

模块.config.php

return array(
    'service_manager' => array(
        'factories' => array(
            'Cybersource\Client\Client' => 'Cybersource\ServiceFactory\ClientServiceFactory',
        )
    ),
    'cybersource' => array(
        'Endpoint' => 'https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor', // test environment
        'WSDL' => 'https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.80.wsdl',
        'TXKey' => '',
        'MerchID' => '',
    ),
);

客户端.php

namespace Cybersource\Client;

class Client {

    private $config;

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

    public function getConfig() {
        return $this->config;
    }

}

客户端服务工厂.php

namespace Cybersource\ServiceFactory;

use Cybersource\Client\Client;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class ClientServiceFactory implements FactoryInterface {

    public function createService(ServiceLocatorInterface $serviceLocator) {
        $config = $serviceLocator->get('Config');

        return new Client($config['cybersource']);
    }

}

模块.php

namespace Cybersource;
use Zend\ModuleManager\Feature\ConfigProviderInterface;

class Module implements ConfigProviderInterface {

    public function getAutoloaderConfig() {
        return array(
            'Zend\Loader\ClassMapAutoloader' => array(
                __DIR__ . '/autoload_classmap.php',
            )
        );
    }

    public function getConfig() {
        return include __DIR__ . '/config/module.config.php';
    }

}

autoload_classmap.php

<?php
// Generated by ZF2's ./bin/classmap_generator.php
return array(
    'Cybersource\Module'                              => __DIR__ . '/Module.php',
    'Cybersource\Client\Client'                       => __DIR__ . '/src/Cybersource/Client/Client.php',
    'Cybersource\ServiceFactory\ClientServiceFactory' => __DIR__ . '/src/ServiceFactory/ClientServiceFactory.php',
);

在 application.config.php 中激活模块后,我可以在我的应用程序模块上的 IndexController 中使用它,方法是:

<?php


namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class IndexController extends AbstractActionController {

    public function indexAction() {
        $c = $this->getServiceLocator()->get('Cybersource\Client\Client');
        $conf = $c->getConfig();
        var_dump($conf);
        return new ViewModel();
    }

}

上面的控制器输出将转储配置的输出,因为我向 Client 类添加了一个名为 getConfig() 的函数以用于显示/测试目的。

再次感谢所有帮助。

4

2 回答 2

2

您应该定义一个ServiceFactory来创建您的Client. ServiceFactory 可以获取合并的模块配置并将其设置在您的客户端上。现在你已经完全分离了,你的类甚至可以在没有 Zend\Config 的情况下重用。如果您有很多配置选项,您可以创建一个单独的配置类扩展\Zend\StdLib\AbstractOptions并将其传递给您的客户端。

namespace Marketo\Service;

class ClientServiceFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        //Get the merged config of all modules
        $configuration = $serviceLocator->get('Config');
        $configuration = $configuration['marketo'];

        $client = new \Marketo\Client\Client($configuration['key'], $configuration['pass']);
    }
}

现在在服务定位器中注册您的客户工厂。module.config.php在或中执行此操作Module.php

public function getServiceConfig()
{
    return array('factories' => array(
        'marketo_client' => 'Marketo\Service\ClientServiceFactory'
    );
}

用户现在可以从 ServiceManager 获取您的客户端。所有配置都整齐地设置。

$sm->get('marketo_client');
于 2013-02-20T20:15:02.767 回答
2

您可能会定义一个模块,如下所示:

<?php

namespace Marketo;

use Zend\ModuleManager\Feature\ConfigProviderInterface;

class Module implements ConfigProviderInterface
{
    public function getConfig()
    {
        return array(
            'service_manager' => array(
                'factories' => array(
                    'Marketo\Client\Client' => 'Marketo\ServiceFactory\ClientServiceFactory',
                ),
            ),
            'marketo' => array(
                'key'  => 'DEFAULT',
                'pass' => 'DEFAULT',
            ),
        );
    }
}

注意:我更喜欢使用getConfigover,getServiceConfig因为它更灵活(可覆盖),并且在设置应用程序时方法调用会被缓存。

然后Marketo\ServiceFactory\ClientServiceFactory

<?php

namespace Marketo\ServiceFactory;

use Marketo\Client\Client;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class ClientServiceFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $config = $serviceLocator->get('Config');

        return new Client($config['marketo']['key'], $value['marketo']['pass']);
    }
}

之后,您将能够通过调用以下命令(例如在控制器中)从服务定位器中拉出 Marketo 客户端:

$marketoClient = $this->getServiceLocator()->get('Marketo\Client\Client');

在这一点上,Marketo\Client\Client无论如何,你的构建keypass设置为DEFAULT.

让我们继续并通过创建一个config/autoload/marketo.local.php文件来覆盖它(在您的应用程序根目录中,而不是在模块中!):

<?php

return array(
    'marketo' => array(
        'key'  => 'MarketoAdmin',
        'pass' => 'Pa$$w0rd',
    ),
);

这是非常重要的,因为你永远不应该重新分发你的keyand pass,所以把这个文件放到.gitignoreor svn:ignore

所以基本上我们在这里所做的是:

  1. 设置服务管理器配置以使用服务工厂来实例化我们的 Marketo 客户端
  2. 设置服务工厂以使用合并配置(服务名称'config':)来实例化 Marketo 客户端
  3. 为实际应用实例添加本地配置
  4. 通过服务定位器检索 Marketo 服务。
于 2013-02-20T20:28:15.840 回答