Reputation: 1448
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.
Upvotes: 3
Views: 2285
Reputation: 25431
You would probably define a Module like following:
<?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',
),
);
}
}
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 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']);
}
}
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('Marketo\Client\Client');
At this point, your Marketo\Client\Client
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:
'config'
) to instantiate the Marketo clientUpvotes: 2
Reputation: 7238
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 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.
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']);
}
}
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' => 'Marketo\Service\ClientServiceFactory'
);
}
Users can now get your client from the ServiceManager. All configuration is neatly setup.
$sm->get('marketo_client');
Upvotes: 2