ZF2 & Doctrine2 getServiceConfig factories connection function - php

I have factories for Doctrine in Module.php method getServiceConfig() :
public function getServiceConfig()
{
return array(
'factories' => array(
'doctrine.entitymanager.orm_cst' => new \DoctrineORMModule\Service\EntityManagerFactory('orm_cst'),
'doctrine.connection.orm_cst' => function ($sm) {
$config = $sm->get('config');
return new \DoctrineORMModule\Service\DBALConnectionFactory('doctrine.entitymanager.' . $config['connection']);
},
'doctrine.configuration.orm_cst' => new \DoctrineORMModule\Service\ConfigurationFactory('orm_cst'),
'doctrine.driver.orm_cst' => new \DoctrineModule\Service\DriverFactory('orm_cst'),
'doctrine.eventmanager.orm_cst' => new \DoctrineModule\Service\EventManagerFactory('orm_cst'),
),
);
}
I'm trying to get connection value from config and I'm getting the following error:
Catchable fatal error: Object of class DoctrineORMModule\Service\DBALConnectionFactory could not be converted to string in W:\domains\zf\vendor\doctrine\orm\lib\Doctrine\ORM\EntityManager.php on line 939
It's ok if I'm not using function as array value:
'doctrine.connection.orm_cst' => new \DoctrineORMModule\Service\DBALConnectionFactory('orm_cst'),
What am I doing wrong? Please help.

The doctrine.connection should return a configured \Doctrine\DBAL\Connection.
At the moment, you are incorrectly returning the actual ZF2 factory instance (\DoctrineORMModule\Service\DBALConnectionFactory) rather than using it to create the connection.
If you wish to keep the closure, you can just manually call the createService() method and it should work.
'doctrine.connection.orm_cst' => function ($sm) {
$config = $sm->get('config');
$key = 'doctrine.entitymanager.' . $config['connection'];
$factory = new DBALConnectionFactory($key);
// Manually call the createService method and the factory will then
// return the Connection instance
return $factory->createService($sm);
},
The other (preferred) option would be to extend the default Doctrine factory and define the configuration key within the factory itself, this way you have everything needed to create the connection in one place (which is really the idea behind using a factory).
If you are not using the above closure, it is also worth noting that by creating your service factories with new you are recreating every service factory on every request - This will have an unnecessary negative performance impact. The solution again would be to extend and/or wrap the Doctrine factories in your own custom factory and just use a string to reference them. The service manager will then be able to lazy load them.
'doctrine.connection.orm_cst' => 'MyModule\Factory\CstConnectionFactory',

Related

Mocking in Laravel with GitHub API Wrapper?

I'm new to Mockery. I'm trying to figure it out with the GitHub API by using a Laravel Package as a wrapper. How can I mock GitHub::repo()->show('symfony', 'demo'); without hiting the actual API? Is there something weird with Facades? I'm getting an error here:
In EvalLoader.php(34) : eval()'d code line 993:
Cannot redeclare Mockery_0_GrahamCampbell_GitHub_Facades_GitHub::shouldReceive()
Code:
use Mockery;
use Tests\TestCase;
use GrahamCampbell\GitHub\Facades\GitHub;
public function testExample()
{
$this->mockGitHubWith([
'id' => 1,
'name' => 'demo',
'full_name' => 'symfony/demo',
]);
$repo = GitHub::repo()->show('symfony', 'demo');
dd($repo);
}
protected function mockGitHubWith($expectations)
{
$github = Mockery::mock(GitHub::class, $expectations);
$github->shouldReceive('api')->andReturn($github);
app()->instance(GitHub::class, $github);
}
also tried:
use GrahamCampbell\GitHub\Facades\GitHub;
public function testExample()
{
Github::shouldReceive('api')->once()->andReturn(['id' => 1]);
$repo = Github::repo()->show('symfony', 'demo');
dd($repo);
}
Returns: Mockery\Exception\BadMethodCallException: Method Mockery_0::repo() does not exist on this mock object
Just to confirm, if I remove the GitHub::shouldReceive... line, it's successful but actually hits the GitHub API.
With the last example you are almost there. Remember you are trying to mock a two step call, first a static method and a call to an instance, therefor the mock should emulate that.
Create the repository that the repo() call will return. Using standard mockery functionality.
use Github\Api\Repo;
$repoMock = Mockery::mock(Repo::class);
$repoMock->shouldReceive('show')->with('symfony', 'demo')->once()->andReturn(['id' => 1]);
Now you can set the return type of the repo call through Laravels approach to mock facades.
Github::shouldReceive('repo')->once()->andReturn($repoMock);
When you call your code repo will return the repo mock, that expects a show call with the parameters symfony and demo.
$repo = Github::repo()->show('symfony', 'demo');

ZF2 Unit test of login in wierd code

I am new to ZF2 and I want to test the login method in a legacy application. Or introduce Unit tests in old code :).
The code that I have is not done according to the manual; it seems super strange if I compare it to the manual examples or even best practices.
I the login method like this:
http://pastebin.com/ZzvuBcGe
in this case the legacy is that Helper, Carts, Users, Userslogs and Usertests are models .... all of them extend DB.
In the module.config.php I have this code:
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
'AuthService' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$dbTableAuthAdapter = new DbTableAuthAdapter(
$dbAdapter,
'tbl_user',
'USER_LOGIN',
'USER_PASSWORD',
'MD5(?)'
);
$authService = new AuthenticationService();
$authService->setAdapter($dbTableAuthAdapter);
$authService->setStorage(new StorageSession('session'));
return $authService;
},
'Helper' => function ($sm) {
return new Helper($sm);
},
'Users' => function ($sm) {
return new Users($sm);
},
'Carts' => function ($sm) {
return new Carts($sm);
}
...
I know that the DbTableAuthAdapter is deprecated but I have to understand how to modify this in order to change it in the best way possible. I have the feeling if I change this all the User, Carts etc models will crash.
My Unit test is like this for the moment:
<?php namespace ApplicationTest\Controller;
use Application\Controller\LoginController;
use Zend\Stdlib\ArrayUtils;
use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;
class LoginControllerTest extends AbstractHttpControllerTestCase
{
protected $traceError = true;
public function setUp()
{
parent::setUp();
// The module configuration should still be applicable for tests.
// You can override configuration here with test case specific values,
// such as sample view templates, path stacks, module_listener_options,
// etc.
$configOverrides = [];
$this->setApplicationConfig(ArrayUtils::merge(
// Grabbing the full application configuration:
include __DIR__ . '/../../../../../config/application.config.php',
$configOverrides
));
}
public function loginCredentialsProvider()
{
return [
['userDev', '12345'],
];
}
/**
* #covers LoginController::loginAction()
* #dataProvider loginCredentialsProvider
* #param $username
* #param $password
*/
public function testLogin($username, $password)
{
// prepare request
//$this->getRequest()
//->setMethod('POST')
//->setPost(new Parameters(array(
//'user_login' => $username,
//'user_password' => $password
//)));
$helperMock = $this->getMockBuilder('Application\Model\Helper')
->disableOriginalConstructor()
->getMock();
$serviceManager = $this->getApplicationServiceLocator();
$serviceManager->setAllowOverride(true);
$serviceManager->setService('Application\Model\Helper', $helperMock);
// send request
$this->dispatch('/login', 'POST', $this->loginCredentialsProvider());
$this->assertEquals('userDev12345', $username . $password);
// $this->markTestIncomplete('login incomplete');
}
/**
* #depends testLogin
*/
public function testLogout()
{
$this->markTestIncomplete('logout incomplete');
}
}
I tried different ways to test but no succes and of course that I get errors:
Zend\ServiceManager\Exception\ServiceNotCreatedException: An exception was raised while creating "Helper"; no instance returned
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:930
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:1057
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:633
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:593
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:525
/project/module/Application/src/Application/Controller/LoginController.php:38
/project/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractActionController.php:83
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:468
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:207
/project/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractController.php:116
/project/vendor/zendframework/zendframework/library/Zend/Mvc/DispatchListener.php:113
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:468
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:207
/project/vendor/zendframework/zendframework/library/Zend/Mvc/Application.php:313
/project/vendor/zendframework/zendframework/library/Zend/Test/PHPUnit/Controller/AbstractControllerTestCase.php:282
/project/module/Application/test/ApplicationTest/Controller/LoginControllerTest.php:69
/project/vendor/phpunit/phpunit/phpunit:47
Caused by
Zend\ServiceManager\Exception\ServiceNotCreatedException: An exception was raised while creating "Zend\Db\Adapter\Adapter"; no instance returned
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:930
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:1055
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:633
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:593
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:525
/project/module/Application/src/Application/Model/DB.php:17
/project/module/Application/config/module.config.php:1324
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:923
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:1057
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:633
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:593
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:525
/project/module/Application/src/Application/Controller/LoginController.php:38
/project/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractActionController.php:83
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:468
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:207
/project/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractController.php:116
/project/vendor/zendframework/zendframework/library/Zend/Mvc/DispatchListener.php:113
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:468
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:207
/project/vendor/zendframework/zendframework/library/Zend/Mvc/Application.php:313
/project/vendor/zendframework/zendframework/library/Zend/Test/PHPUnit/Controller/AbstractControllerTestCase.php:282
/project/module/Application/test/ApplicationTest/Controller/LoginControllerTest.php:69
/project/vendor/phpunit/phpunit/phpunit:47
Caused by
PHPUnit_Framework_Error_Notice: Undefined index: db
/project/vendor/zendframework/zendframework/library/Zend/Db/Adapter/AdapterServiceFactory.php:26
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:923
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:1055
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:633
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:593
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:525
/project/module/Application/src/Application/Model/DB.php:17
/project/module/Application/config/module.config.php:1324
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:923
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:1057
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:633
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:593
/project/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:525
/project/module/Application/src/Application/Controller/LoginController.php:38
/project/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractActionController.php:83
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:468
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:207
/project/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractController.php:116
/project/vendor/zendframework/zendframework/library/Zend/Mvc/DispatchListener.php:113
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:468
/project/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:207
/project/vendor/zendframework/zendframework/library/Zend/Mvc/Application.php:313
/project/vendor/zendframework/zendframework/library/Zend/Test/PHPUnit/Controller/AbstractControllerTestCase.php:282
/project/module/Application/test/ApplicationTest/Controller/LoginControllerTest.php:69
/project/vendor/phpunit/phpunit/phpunit:47
The issues that I have are first how to get the test to pass with this code? I know that normally you do the test and after that the code but I need a starting point to understand the mess that I have in the application. Second, what is the easy or the best way to modify the "models" to not be a dependency for each method and then pass the test? How to modify the deprecated DbTableAuthAdapter in order not to brake all things?
Like i said I am new to ZF2 and Phpunit and I am stuck over this messy code and I have the best practices in my mind but I don't know how to put them in action in this code. Thank you for all the info that I will receive for this.
LATER EDIT
the solution is to add this line in the test, foreach model:
// access via application object..
$bla = $this->getApplication()->getServiceManager()->get('Tests');
the solution is to add this line in the test, foreach model:
$bla = $this->getApplication()->getServiceManager()->get('Tests');
Thank you i336_ :)

How to make availableIncludes work in thephpleague/fractal

I'm having trouble implementing Fractal includes. I am trying to include posts with a particular user.
All goes well when I add 'posts' to $defaultIncludes at the top of my UserItemTransformer. Posts are included as expected.
However, posts are NOT included in my json output when I change $defaultIncludes to $availableIncludes, even after calling $fractal->parseIncludes('posts');
The problem seems to lie the fact that the method that includes the posts is only called when I use $defaultIncludes. it is never called when I use $availableIncludes.
I'm probably missing something obvious here. Can you help me find out what it is?
This works:
// [...] Class UserItemTransformer
protected $defaultIncludes = [
'posts'
];
This does not work:
// [...] Class UserItemTransformer
protected $availableIncludes = [
'posts'
];
// [...] Class PostsController
// $fractal is injected in the method (Laravel 5 style)
$fractal->parseIncludes('posts');
Got it!
When I called parseIncludes('posts'), this was on a new Fractal instance, injected into the controller method. Of course I should have called parseIncludes() on the Fractal instance that that did the actual parsing (and that I injected somewhere else, into an Api class).
public function postsWithUser($user_id, Manager $fractal, UserRepositoryInterface $userRepository)
{
$api = new \App\Services\Api();
$user = $userRepository->findById($user_id);
if ( ! $user) {
return $api->errorNotFound();
}
$params = [
'offset' => $api->getOffset(),
'limit' => $api->getLimit()
];
$user->posts = $this->postRepository->findWithUser($user_id, $params);
// It used to be this, using $fractal, that I injected as method parameter
// I can now also remove the injected Manager $fractal from this method
// $fractal->parseIncludes('posts');
// I created a new getFractal() method on my Api class, that gives me the proper Fractal instance
$api->getFractal()->parseIncludes('posts');
return $api->respondWithItem($user, new UserItemTransformer());
}
I'll just go sit in a corner and be really quit for a while, now.

Possible to create a factory to instantiate custom Form validators?

(using Zend Framework 2.2.4)
My validator factory, doesn't seem to "exist" at validation time. If I attempt to instantiate the validator from the controller in which the form is housed, it conversely works fine:
This works...
$mycustomvalidator = $this->getServiceLocator()
->get('ValidatorManager')
->get('LDP_PinAvailable');
Here's how things are set up otherwise in the code, I can't seem to find the problem, and was hopeful to avoid opening up ZF2 source to understand. By way of documentation, it seems right.
Module Config
public function getValidatorConfig()
{
return array(
'abstract_factories' => array(
'\LDP\Form\Validator\ValidatorAbstractFactory',
),
);
}
Factory Class
namespace LDP\Form\Validator;
use Zend\ServiceManager\AbstractFactoryInterface,
Zend\ServiceManager\ServiceLocatorInterface;
class ValidatorAbstractFactory implements AbstractFactoryInterface
{
public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
return stristr($requestedName, 'LDP_PinAvailable') !== false;
}
public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName)
{
// baked in for sake of conversation
$validator = new \LDP\Form\Validator\PinAvailable();
if( $validator instanceof DatabaseFormValidatorInterface )
$validator->setDatabase( $locator->get('mysql_slave') );
return $validator;
}
}
Custom Validator
namespace LDP\Form\Validator;
class PinAvailable extends \Zend\Validator\AbstractValidator implements DatabaseFormValidatorInterface
{
/**
* #var \Zend\Db\Sql\Sql
*/
private $database;
public function setDatabase( \Zend\Db\Sql\Sql $db )
{
$this->database = $db;
}
public function isValid( $value )
{
$DBA = $this->database->getAdapter();
// do the mixed database stuff here
return true;
}
}
Lastly, the form field validator config part of the array:
'pin' => array(
'required' => true,
'filters' => array(
array('name' => 'alnum'),
array('name' => 'stringtrim'),
),
'validators' => array(
array( 'name' => 'LDP_PinAvailable' )
),
),
),
Piecing it all together, the form loads, and when submitted, it does with the stack trace below:
2013-10-28T17:09:35-04:00 ERR (3): Exception:
1: Zend\Validator\ValidatorPluginManager::get was unable to fetch or create an instance for LDP_PinAvailable
Trace:
#0 /Users/Saeven/Documents/workspace/Application/vendor/zendframework/zendframework/library/Zend/ServiceManager/AbstractPluginManager.php(103): Zend\ServiceManager\ServiceManager->get('LDP_PinAvailabl...', true)
#1 /Users/Saeven/Documents/workspace/Application/vendor/zendframework/zendframework/library/Zend/Validator/ValidatorChain.php(82): Zend\ServiceManager\AbstractPluginManager->get('LDP_PinAvailabl...', Array)
The ValidatorPluginManager extends the Zend\ServiceManager\AbstractPluginManager. The AbstractPluginManager has a feature called "autoAddInvokableClass", which is enabled by default.
Basically, what this means, is that if the service name requested can't be resolved by the ValidatorPluginManager, it will then check if the name is a valid class name. If so, it will simply add it as an invokable class right there, on-demand, which of course means that it will never fall back to your abstract factory.
To circumvent this behavior, the easiest method is to simply make your abstract factory respond to service names that do not actually resolve to the actual class names.
See: AbstractPluginManager.php#L98-L100
Digging some more, I've found the problem. It distilled to these lines in Zend\Validator\ValidatorChain circa line 80:
public function plugin($name, array $options = null)
{
$plugins = $this->getPluginManager();
return $plugins->get($name, $options);
}
There was no plugin manager available in context.
It took about three seconds of Googling to find that I had to do this when I prepared the form in the controller:
$validators = $this->getServiceLocator()->get('ValidatorManager');
$chain = new ValidatorChain();
$chain->setPluginManager( $validators );
$form->getFormFactory()->getInputFilterFactory()->setDefaultValidatorChain( $chain );
Hopefully this helps someone else. You are able to use regular old classnames when setting it up this way, no need to warp the classnames.
In ZF3/Laminas, if a validator is registered as an invokable, you can call the validator in the getInputFilterSpecification() of your form, and no problem. If a validator is instantiated using a factory, you get into trouble. If I understand correctly, even if your form is registered like this
'form_elements' => [
'factories' => [
SomeForm::class => SomeFormFactory::class,
]
]
and your validator:
'validators' => [
'factories' => [
SomeValidator::class => SomeValidatorFactory::class,
]
]
you won't be instantiating the validator via factory. The reason is that the form factory (the one you get like $form->getFormFactory()) has an input filter factory and in there sits default validator chain. And this validator chain has no ValidatorManager attached. And without the ValidatorManager, the default chain cannot map the validator name to the validator factory.
To solve all this headache, in your controller factory do this:
$form->('FormElementManager')->get(SomeForm::class);
$form->getFormFactory()->getInputFilterFactory()
->getDefaultValidatorChain()->setPluginManager($container->get('ValidatorManager'));
and your troubles are over.

Access to module config in Zend Framework 2

How I can get access to my module config from the controller?
I am really surprised at how obscure this is, because I had exactly the same problem and could not find a definitive answer. One would think the ZF2 documentation would say something about this. Anyhow, using trial and error, I came across this extremely simple answer:
Inside controller functions:
$config = $this->getServiceLocator()->get('Config');
Inside Module class functions (the Module.php file):
$config = $e->getApplication()->getServiceManager()->get('Config');
whereas $e is an instance of Zend\Mvc\MvcEvent
In general, the config is accessible from anywhere you have access to the global service manager since the config array is registered as a service named Config. (Note the uppercase C.)
This returns an array of the union of application.config.php (global and local) and your module.config.php. You can then access the array elements as you need to.
Even though the OP is quite old now, I hope this saves someone the hour or more it took me to get to this answer.
What exactly do you want to do in your controller with the module configuration? Is it something that can't be done by having the DI container inject a fully configured object into your controller instead?
For example, Rob Allen's Getting Started with Zend Framework 2 gives this example of injecting a configured Zend\Db\Table instance into a controller:
return array(
'di' => array(
'instance' => array(
'alias' => array(
'album' => 'Album\Controller\AlbumController',
),
'Album\Controller\AlbumController' => array(
'parameters' => array(
'albumTable' => 'Album\Model\AlbumTable',
),
),
'Album\Model\AlbumTable' => array(
'parameters' => array(
'config' => 'Zend\Db\Adapter\Mysqli',
)),
'Zend\Db\Adapter\Mysqli' => array(
'parameters' => array(
'config' => array(
'host' => 'localhost',
'username' => 'rob',
'password' => '123456',
'dbname' => 'zf2tutorial',
),
),
),
...
If you need to do additional initialization after the application has been fully bootstrapped, you could attach an init method to the bootstrap event, in your Module class. A blog post by Matthew Weier O'Phinney gives this example:
use Zend\EventManager\StaticEventManager,
Zend\Module\Manager as ModuleManager
class Module
{
public function init(ModuleManager $manager)
{
$events = StaticEventManager::getInstance();
$events->attach('bootstrap', 'bootstrap', array($this, 'doMoarInit'));
}
public function doMoarInit($e)
{
$application = $e->getParam('application');
$modules = $e->getParam('modules');
$locator = $application->getLocator();
$router = $application->getRouter();
$config = $modules->getMergedConfig();
// do something with the above!
}
}
Would either of these approaches do the trick?
for Beta5, you can add function like this in Module.php
public function init(ModuleManager $moduleManager)
{
$sharedEvents = $moduleManager->getEventManager()->getSharedManager();
$sharedEvents->attach(__NAMESPACE__, 'dispatch', function($e) {
$config = $e->getApplication()->getConfiguration();
$controller = $e->getTarget();
$controller->config = $config;
});
}
in controller, you can get config :
print_r($this->config);
To read module-only config your module should just implement LocatorRegisteredInterface
Before:
namespace Application;
class Module
{
// ...
}
After:
namespace Application;
use Zend\ModuleManager\Feature\LocatorRegisteredInterface;
class Module implements LocatorRegisteredInterface
{
// ...
}
That implementation says LocatorRegistrationListener to save module intance in service locator as namespace\Module
Then anywhere you can get access to your module:
class IndexController extends AbstractActionController
{
public function indexAction()
{
/** #var \Application\Module $module */
$module = $this->getServiceLocator()->get('Application\Module');
$moduleOnlyConfig = $module->getConfig();
// ...
}
}
There is a pull request ready now which pulls the module class (so the modules/foo/Module.php Foo\Module class) from the DI container. This gives several advantages, but you are also able to grab that module instance another time if you have access to the Zend\Di\Locator.
If your action controller extends the Zend\Mvc\Controller\ActionController, then your controller is LocatorAware. Meaning, upon instantiation your controller is injected with the locator knowing about modules. So, you can pull the module class from the DIC in your controller. Now, when your module consumes a config file and stores this inside the module class instance, you can create a getter to access that config data from any class with a locator. You probably have already an accessor with your module Foo\Module::getConfig()
While ZF2 is heavily under development and perhaps this code will change later on, this feature is currently covered by this test, with this the most relevant part:
$sharedInstance = $locator->instanceManager()->getSharedInstance('ListenerTestModule\Module');
$this->assertInstanceOf('ListenerTestModule\Module', $sharedInstance);
So with $sharedInstance your module class, you can access the config from there. I expect a shorthand for this feature soon, but this can only be done after PR #786 has been merged in ZF2 master.
You need to implements ServiceLocatorAwareInterface from your model. And then you can set setServiceLocator() and getServiceLocator() which give you direct access to the service manager. Take a look at this code sample https://gist.github.com/ppeiris/7308289
I created the module with controller plugin and view helper for reading a config in controllers and views. GitHub link __ Composer link
Install it via composer
composer require tasmaniski/zf2-config-helper
Register new module "ConfigHelper" in your config/application.config.php file
'modules' => array(
'...',
'ConfigHelper'
),
Use it in controller and view files
echo $this->configHelp('key_from_config'); // read specific key from config
$config = $this->configHelp(); // return config object Zend\Config\Config
echo $config->key_from_config;
you can also access any config value anywhere by this hack/tricks
$configReader = new ConfigReader();
$configData = $configReader->fromFile('./config.ini');
$config = new Config($configData, true);

Categories