DomingoSL
DomingoSL

Reputation: 15484

Creating a service in ZF2

Im having some issues to understand the best way to reuse a code across different controllers in ZF2.

One solution is to extend from a controller where I have my desire function:

class someController extends whereMyFunctionIs {
  //DO SOME THINGS THAT MAY OR MAY NOT NEED foo function
}

And so the controller is:

class whereMyFunctionIs {
  public function foo() {
    return "bar";
  }
  //and a some other functions...
}

This work but is not very smart since I will have to extend all my controllers from whereMyFunctionIs and it can have many functions some of my controller may not need. I will like to have single functions I can use and load only when I really need them. Reading the ZF2 documentation I see a solution could be creating services. But I can not have them to work properly. This is what I got:

IndexController (just where Im testing things):

public function indexAction() {
  $auth = $this->getServiceLocator()->get('Application\Service\Authentication');
}

Module.php (In my module main app)

public function getServiceConfig()
{
    return array(
        'factories' => array(
            'Application\Model\UserTable' =>  function($sm) {
                    $tableGateway = $sm->get('UserTableGateway');
                    $table = new UserTable($tableGateway);
                    return $table;
                },
            'UserTableGateway' => function ($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    $resultSetPrototype = new ResultSet();
                    $resultSetPrototype->setArrayObjectPrototype(new User());
                    return new TableGateway('user', $dbAdapter, null, $resultSetPrototype);
                },
            'Application\Service\Authentication' => 'Application\Service\AuthenticationFactory',
        ),
    );
}

The in Application\src\Service I have two files: Authentication.php and AuthenticationFactory.php, where:

Authentication.php

class Authentication {

    public function isUser($email, $password) {
        return $email;
    }

}

AuthenticationFactory.php

<?php

namespace Application\Service\Authentication;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class AuthenticationFactory implements FactoryInterface
{

    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $authentication = new Authentication(
            $serviceLocator->get('Application\Model\Asset\AbstractAsset')
        );
        return $authentication;
    }

}

Executing IndexController i got:

An error occurred during execution; please try again later.

Informazioni aggiuntive:

Zend\ServiceManager\Exception\ServiceNotCreatedException

File:
C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:1059
Messaggio:
While attempting to create applicationserviceauthentication(alias: Application\Service\Authentication) an invalid factory was registered for this instance type.
Stack trace:
#0 C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php(633): Zend\ServiceManager\ServiceManager->createFromFactory('applicationserv...', 'Application\\Ser...')
#1 C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php(593): Zend\ServiceManager\ServiceManager->doCreate('Application\\Ser...', 'applicationserv...')
#2 C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php(525): Zend\ServiceManager\ServiceManager->create(Array)
#3 C:\WT-NMP\WWW\marketplace\module\Application\src\Application\Controller\IndexController.php(16): Zend\ServiceManager\ServiceManager->get('Application\\Ser...')
#4 C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\Mvc\Controller\AbstractActionController.php(83): Application\Controller\IndexController->indexAction()
#5 [internal function]: Zend\Mvc\Controller\AbstractActionController->onDispatch(Object(Zend\Mvc\MvcEvent))
#6 C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php(468): call_user_func(Array, Object(Zend\Mvc\MvcEvent))
#7 C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php(207): Zend\EventManager\EventManager->triggerListeners('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
#8 C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\Mvc\Controller\AbstractController.php(116): Zend\EventManager\EventManager->trigger('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
#9 C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\Mvc\DispatchListener.php(113): Zend\Mvc\Controller\AbstractController->dispatch(Object(Zend\Http\PhpEnvironment\Request), Object(Zend\Http\PhpEnvironment\Response))
#10 [internal function]: Zend\Mvc\DispatchListener->onDispatch(Object(Zend\Mvc\MvcEvent))
#11 C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php(468): call_user_func(Array, Object(Zend\Mvc\MvcEvent))
#12 C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\EventManager\EventManager.php(207): Zend\EventManager\EventManager->triggerListeners('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
#13 C:\WT-NMP\WWW\marketplace\vendor\zendframework\zendframework\library\Zend\Mvc\Application.php(313): Zend\EventManager\EventManager->trigger('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
#14 C:\WT-NMP\WWW\marketplace\public\index.php(17): Zend\Mvc\Application->run()
#15 {main}

Is this the correct approach for reusable code across controllers? And if yes, what I'm missing?

Upvotes: 1

Views: 1091

Answers (1)

guessimtoolate
guessimtoolate

Reputation: 8632

The error is caused by this line:

namespace Application\Service\Authentication;

it needs to be:

namespace Application\Service;

That assuming you forgot to include the namespace in the service class itself and that it's correct. I think that the service gets confused with its factory, the wrong object get's instantiated (the service not the factory) and hence the error.

The approach is ok, although from what I'm reading on the zf2 github pages, injecting services into controllers from controller factories is more favorable nowadays (perhaps always been).

As for the function (so some reusable small pieces of codes, not full blown services etc) you might also consider using PHPs traits.

Upvotes: 4

Related Questions