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 \Marketo\Client\Client();
and inside the \Marketo\Client\Client() 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 = \Zend\Config\Config('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(
'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' => '',
),
);
Client.php
namespace Cybersource\Client;
class Client {
private $config;
public function __construct($config) {
$this->config = $config;
}
public function getConfig() {
return $this->config;
}
}
ClientServiceFactory.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']);
}
}
Module.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',
);
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 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();
}
}
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 should define a
ServiceFactory
to create yourClient
. 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 Zend\Config at all. If you have a lot of configuration options you could create a seperate configuration class extending\Zend\StdLib\AbstractOptions
and pass this to your client.Now register your client factory in the service locator. Do this in the
module.config.php
orModule.php
Users can now get your client from the ServiceManager. All configuration is neatly setup.
You would probably define a Module like following:
Note: I preferred to use
getConfig
overgetServiceConfig
since it is more flexible (overrideable) and the method call is cached when you setup your application to do so.Then the
Marketo\ServiceFactory\ClientServiceFactory
:After that, you will be able to pull the Marketo client from the service locator by calling following (for example in controllers):
At this point, your
Marketo\Client\Client
is anyway built withkey
andpass
both set toDEFAULT
.Let's go on and override this by creating a
config/autoload/marketo.local.php
file (in your application root, not in the module!):This is VERY important since you should never redistribute your
key
andpass
, so put this file into.gitignore
orsvn:ignore
!So basically what we did here is:
'config'
) to instantiate the Marketo client