Factory not getting constructed service manager class - zend-framework2

Here is my service configuration:
public function getServiceConfig()
{
return array(
'factories' => array(
'Squiddle\Designpackage' => function($sm){
$designPkg = new Designpackage($sm);
return $designPkg;
}
)
);
}
It's being used within a function that gets triggered on the dispatch event.
Here is it's usage:
$e->getApplication()->getServiceManager()->get('Squiddle\Designpackage');
My error is that the designpackage is being constructed with null instead of a service manager.
Not sure whats wrong here;

It could be a problem in the Designpackage constructor

Related

ZF2 use view helper in Validator class

UPDATED!
ZF2, l10n view helper. I can't understand how to use my view helper inside of a class.
I want to use it like: $this->t('STRING TO TRANSLATE');
example bellow
NB! i'm only localizing project, i'm not allowed to change code structure or smth like that.Also i'm absolute newb in ZF2.
my Class -
class Project extends InputFilter{
as i understood i have to implement ServiceLocatorAwareInterface interface, tried this:
use Zend\ServiceManager\ServiceLocatorInterface as ServiceLocator;
class Project extends InputFilter implements ServiceLocator
{
protected $services;
public function __construct(Connection $p4, $mode, ServiceLocator $services)
{
$this->services = $services;
//some code
$this->add(...);
$this->add(
array(
'name' => 'name',
'filters' => array('trim'),
'validators' => array(
array(
'name' => 'NotEmpty',
'options' => array(
'message' => "Name is required and can't be empty."
)
),
array(
'name' => '\Application\Validator\Callback',
'options' => array(
'callback' => function ($value) use ($p4, $toId, $mode, $reserved) {
$id = $toId($value);
if (!$id) {
return $this->t('STRING TO TRANSLATE');
}
// more code here
return true;
}
)
)
)
)
);
//some code
$this->add(...);
}
public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
$this->serviceLocator = $serviceLocator;
}
public function getServiceLocator() {
return $this->serviceLocator;
}
//how to get this method work ???
public function t($msg) {
$translate = $this->services->get('ViewHelperManager')->get('t');
return $translate($msg);
}
}
Usage in Controller:
use Projects\Filter\Project as ProjectFilter;
...
protected function doAddEdit($mode, $project = null)
{
$p4Admin = $this->getServiceLocator()->get('p4_admin');
$request = $this->getRequest();
// process add request.
if ($request->isPost()) {
// pull out the data
$data = $request->getPost();
// configure our filter with the p4 connection and add/edit mode
$filter = new ProjectFilter($p4Admin, $mode); //
$filter->setData($data);
// if the data is valid, setup the project and save it
$isValid = $filter->isValid();
if ($isValid) {
$values = $filter->getValues();
$project = new Project($p4Admin);
$project->set($values)
->save();
}
return new JsonModel(
array(
'isValid' => $isValid,
'messages' => $filter->getMessages(), // THESE array of messages i want to localize
'redirect' => '/projects/' . $filter->getValue('id')
)
);
}
// prepare view for form.
$view = new ViewModel;
$view->setVariables(
array(
'mode' => $mode,
'project' => $project ?: new Project
)
);
return $view;
}
What am i doing wrong ?
You're calling tr method inside a class constructor. tr method calls $this->getServiceLocator(). $this->getServiceLocator() will not return a service locator instance since it'll only be injected by service manager after it has created the object that implements ServiceLocatorAwareInterface.
So you'd have to pass a service locator instance to the constructor, or don't depend on it in your __construct method. Probably the easiest way to go is to move your code from the constructor to the init method. Init is supposed to get called automatically as long as you get your input filter through the InputFilterManager.
Also I don't think you need the translator view helper. You should be able to get it from the service manager like so: $serviceManager->get('translator')
There is no need to do this at all the validation message will be translated by the validator anyway. But your config is a bit wrong I think
$this->add(
array(
'name' => 'name',
'filters' => array('trim'),)
'validators' => array(
array(
'name' => 'NotEmpty',
'options' => array(
'messages' => array(
\Zend\Validator\NotEmpty::IS_EMPTY => 'YOUR_TRANSLATION_STRING_IS_EMPTY',
\Zend\Validator\NotEmpty::INVALID => 'YOUR_TRANSLATION_STRING_INVALID',
)
)
)
),
Have a read of https://zf2-docs.readthedocs.org/en/latest/modules/zend.validator.html#translating-messages
You will need to ensure you are managing your dependencies correctly for this to work so really depends how you are using the input filter.
If your not directly adding to a form or using InputFilterAwareInterface on your model you'll need to make sure your InputFilter is registered with InputFilterPluginManager and you retrieve it using InputFilterPluginManager rather than instantiating directly

ZF2 service manager use from a custom class

It looks like it has been touched several times already, but i still can't get it work. I set up an JSON-RPC server in a separate module, it works fine. Its functionality is in a new class Rpcapi. Now I want reuse DB related functions that already implemented in another module from that class. According to ZF2 docs my Rpcapi class has to be ServiceLocator-aware and it looks like I made it that way. Unfortunatelly still can't get it working. Please help keeping in mind that I'm new with ZF2 :)
Rpccontroller.php
namespace Rpc\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\Json\Server\Server;
use Zend\Json\Server\Smd;
use Rpc\Model\Rpcapi;
class RpcController extends AbstractActionController
{
public function indexAction()
{
header('Content-Type: application/json');
$jsonrpc = new Server();
$jsonrpc->setClass(new Rpcapi);
$jsonrpc->getRequest()->setVersion(Server::VERSION_2);
if ($this->getRequest()->getMethod() == "GET") {
$smd = $jsonrpc->getServiceMap()->setEnvelope(Smd::ENV_JSONRPC_2);
echo $smd;
} else {
$jsonrpc->handle();
}
}
}
module.config.php for Rpc module
'service_manager' => array(
'invokables' => array(
'rpcapi' => 'Search\Model\SiteTable',
),
),
Rpcapi.php
namespace Rpc\Model;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class Rpcapi implements ServiceLocatorAwareInterface
{
protected $services;
protected $siteTable;
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->services = $serviceLocator;
}
public function getServiceLocator()
{
return $this->services;
}
public function getSiteTable()
{
if (!$this->siteTable) {
$sm = $this->getServiceLocator();
$this->siteTable = $sm->get('rpcapi');
}
return $this->siteTable;
}
/**
* Returns list of all sites
*
*
* #return array
*/
public function getAllSites()
{
$results = $this->getSiteTable()->fetchAll();
$r = array ('1' => '1', '2' => 2); //Just to return something for now
return $r;
}
}
All I could get out is: Fatal error: Call to a member function get() on a non-object in /var/www/html/AmeriFluxZF2/module/Rpc/src/Rpc/Model/Rpcapi.php on line 28. Line 28 is:
$this->siteTable = $sm->get('rpcapi');
Any help is much appreciated!
Making the class service locator aware tells the ZF2 that the service locator should be injected into your class upon instantiation. However, you still need to use the service locator to instantiate this class, rather than creating an instance of it yourself, or this will never happen.
Your probably want to add a new entry to invokables for your Rpcapi class, and then grab this from the service locator instead of doing new Rpcapi in your controller.
PS: The naming of your classes is very confusing - you have an Rpcapi class, and an invokable called rpcapi, yet this invokable creates an instance of a completely different class?
If you want serviceLocator to be injected by the service manager in your Rpcapi, you must get it via the service manager itself :
'service_manager' => array(
'invokables' => array(
'rpcapi' => 'Search\Model\SiteTable',
'Rpc\Model\Rpcapi' => 'Rpc\Model\Rpcapi',
),
),
the action :
public function indexAction()
{
header('Content-Type: application/json');
$jsonrpc = new Server();
$jsonrpc->setClass($this->getServiceLocator()->get('Rpc\Model\Rpcapi'));
$jsonrpc->getRequest()->setVersion(Server::VERSION_2);
if ($this->getRequest()->getMethod() == "GET") {
$smd = $jsonrpc->getServiceMap()->setEnvelope(Smd::ENV_JSONRPC_2);
echo $smd;
} else {
$jsonrpc->handle();
}
}
And this is where you can see that your 'rcpai' name for SiteTable is not a good choice... ;)

getEventManager in ZF2 does not work

I have this code, where to get getEventManager but does not seem to work:
<?php
namespace Application\Service;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;
class ServiceUser implements EventManagerAwareInterface
{
protected $eventManager;
public function insert($data)
{
$this->getEventManager()->trigger('user.new', $this, array('user' => $data));
}
public function setEventManager(EventManagerInterface $eventManager)
{
$eventManager->addIdentifiers(array(__CLASS__, get_called_class(), 'Module\User'));
$this->eventManager = $eventManager;
return $this;
}
public function getEventManager()
{
return $this->eventManager;
}
}
the error that is generated:
Call to a member function trigger() on a non-object in
How do you construct your ServiceUser object? The *Aware interfaces only work when you construct them via the service locator.
So, you need to register the service in your configuration:
'service_manager' => array(
'invokables' => array(
'user-service' => 'My\Foo\Service\User',
),
),
And then request the service via the service locator (for example, in your controller):
$service = $this->getServiceLocator()->get('user-service');
This will give you a service where the event manager is injected into.

Is there any Zend2 library that provides filesystem abstraction layer?

I'm looking for something similar to: http://knplabs.com/blog/give-your-projects-a-gaufrette
Thanks.
Just use Gaufrette, I do it too (even in ZF2 projects)!
php composer.phar require knplabs/gaufrette:0.1.*
You can then use it anywhere in your application and eventually use it as a service by defining it in your YourNamespace\Module#getServiceConfig:
namespace YourNamespace;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Gaufrette\Filesystem;
use Gaufrette\Adapter\Local as LocalFs;
class Module implements ServiceProviderInterface, ConfigProviderInterface
{
public function getConfig()
{
return array(
'your_namespace' => array(
'filesystem' => array(
'base_path' => 'data/files',
),
),
);
}
public function getServiceConfig()
{
return array(
'factories' => array(
'YourNamespace\Filesystem' => function (ServiceLocatorInterface $sl) {
$config = $sl->get('Config');
$basePath = $config['your_namespace']['filesystem']['base_path'];
return new Filesystem(new LocalFs($basePath, true));
},
),
);
}
}
You can then use service YourNamespace\Filesystem across all your application.
I also use it in conjunction with Symfony\Filesystem to handle file moving/copying/checking operations. Not everything must come from Zend Framework 2 to be used in a ZF2 application.

Controller does not get called in initializers closure

I want to put the doctrine entity manager into many different classes in my ZF2 project. Thus. I have setup the following initializer in my Module.php:
'initializers' => array(
function ($instance, $services) {
if (is_object($instance)) { // just for debugging
var_dump(get_class($instance));
}
if (!$instance instanceof EntityManagerAwareInterface) {
return;
}
$entityManager = $services->get('doctrine.entitymanager.orm_default');
$instance->setEntityManager($entityManager);
},
),
)
Yet, it never gets called on my AuthController even though I am visiting a site of that controller (and get a null pointer exception, because the entity-manager was not set). Of course, the controller does implement the required interface:
class AuthController extends AbstractActionController implements EntityManagerAwareInterface
Is there anything else I have to configure so that my AuthController is checked against the initializer closure?
At the moment I have it under invokables in module.config.php.
'controllers' => array(
'invokables' => array(
'Auth\Controller\Auth' => 'Auth\Controller\AuthController',
),
),
When I remove it from there, the application cannot find the class anymore.
My debugging output lists other classes which are checked against the initializers, many managers and services. A small excerpt:
string(37) "Zend\\Mvc\\Controller\\ControllerManager"
string(33) "Zend\\Mvc\\Controller\\PluginManager"
string(29) "Zend\\View\\HelperPluginManager"
[...]
string(24) "Doctrine\\DBAL\\Connection"
string(26) "Doctrine\\ORM\\EntityManager"
string(41) "Zend\\Authentication\\AuthenticationService"
Try adding an initializer for the controller manager too, judging by your debug output, the one you posted appears to be for the service manager. You configure other managers the same way, the method to use for controller manager is getControllerConfig
public function getControllerConfig()
{
return array(
'initializers' => array(
// controller initializers here...
),
);
}

Resources