ZF2 config from module with no controllers

I'm currently in the process of building a module to serve as a re-usable library throughout multiple projects, however due to it being a library there isn't a need for a controller. What I'm trying to do for instance is create a zf2 module for Marketo soap API for instance. User adds their keys and wsdl location in /ROOT/config/autoload/local.php. The configuration would include something like 'marketo'=>array(),

Now the problem that I'm having is I want to give myself and others using the module the ability to do something like...

$marketo = new MarketoClientClient();

and inside the MarketoClientClient() class have the constructor read the array key of $config['marketo'];

I could however put all of this in an ini file, but I would prefer to keep it similar to how everything else in zf2 is configuration wise.

So to summarize I would like to get an array key of the merged zend configuration to use inside the class something like...

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

============ Fully working solution as of ZF 2.1.1 per the answers below =============

Module structure looks as follows (Using a new example so I could start fresh) + indicates directory name - indicates filename

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

module.config.php

return array(
    'service_manager' => array(
        'factories' => array(
            'CybersourceClientClient' => 'CybersourceServiceFactoryClientServiceFactory',
        )
    ),
    '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' => '',
    ),
);

Client.php

namespace CybersourceClient;

class Client {

    private $config;

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

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

}

ClientServiceFactory.php

namespace CybersourceServiceFactory;

use CybersourceClientClient;
use ZendServiceManagerFactoryInterface;
use ZendServiceManagerServiceLocatorInterface;

class ClientServiceFactory implements FactoryInterface {

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

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

}

Module.php

namespace Cybersource;
use ZendModuleManagerFeatureConfigProviderInterface;

class Module implements ConfigProviderInterface {

    public function getAutoloaderConfig() {
        return array(
            'ZendLoaderClassMapAutoloader' => 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(
    'CybersourceModule'                              => __DIR__ . '/Module.php',
    'CybersourceClientClient'                       => __DIR__ . '/src/Cybersource/Client/Client.php',
    'CybersourceServiceFactoryClientServiceFactory' => __DIR__ . '/src/ServiceFactory/ClientServiceFactory.php',
);

Once the module has been activated in the application.config.php I could then use it in my IndexController on my Application Module by using:

<?php


namespace ApplicationController;

use ZendMvcControllerAbstractActionController;
use ZendViewModelViewModel;
class IndexController extends AbstractActionController {

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

}

The above controller output would dump the output of the configuration as I added a function called getConfig() to the Client class for display / testing purposes.

Thanks again for all the help.


You would probably define a Module like following:

<?php

namespace Marketo;

use ZendModuleManagerFeatureConfigProviderInterface;

class Module implements ConfigProviderInterface
{
    public function getConfig()
    {
        return array(
            'service_manager' => array(
                'factories' => array(
                    'MarketoClientClient' => 'MarketoServiceFactoryClientServiceFactory',
                ),
            ),
            'marketo' => array(
                'key'  => 'DEFAULT',
                'pass' => 'DEFAULT',
            ),
        );
    }
}

Note: I preferred to use getConfig over getServiceConfig since it is more flexible (overrideable) and the method call is cached when you setup your application to do so.

Then the MarketoServiceFactoryClientServiceFactory :

<?php

namespace MarketoServiceFactory;

use MarketoClientClient;
use ZendServiceManagerFactoryInterface;
use ZendServiceManagerServiceLocatorInterface;

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

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

After that, you will be able to pull the Marketo client from the service locator by calling following (for example in controllers):

$marketoClient = $this->getServiceLocator()->get('MarketoClientClient');

At this point, your MarketoClientClient is anyway built with key and pass both set to DEFAULT .

Let's go on and override this by creating a config/autoload/marketo.local.php file (in your application root, not in the module!):

<?php

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

This is VERY important since you should never redistribute your key and pass , so put this file into .gitignore or svn:ignore !

So basically what we did here is:

  • Setup service manager configuration to use a service factory to instantiate our Marketo client
  • Setup the service factory to use merged configuration (service name: 'config' ) to instantiate the Marketo client
  • Add local configuration for the actual application instance
  • Retrieve the Marketo service via service locator.

  • You should define a ServiceFactory to create your Client . The ServiceFactory can get the merged module configuration and set it on your Client. You have clean seperation now and your class is even reusable without ZendConfig at all. If you have a lot of configuration options you could create a seperate configuration class extending ZendStdLibAbstractOptions and pass this to your client.

    namespace MarketoService;
    
    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 MarketoClientClient($configuration['key'], $configuration['pass']);
        }
    }
    

    Now register your client factory in the service locator. Do this in the module.config.php or Module.php

    public function getServiceConfig()
    {
        return array('factories' => array(
            'marketo_client' => 'MarketoServiceClientServiceFactory'
        );
    }
    

    Users can now get your client from the ServiceManager. All configuration is neatly setup.

    $sm->get('marketo_client');
    
    链接地址: http://www.djcxy.com/p/67780.html

    上一篇: ZfcTwig不加载配置并在启动时失败

    下一篇: 不带控制器的模块配置ZF2