简体   繁体   中英

ZF2 Service Manager: How to get a namespace class instance?

Building on my previous question: ZF2 Autoloader: Use factory for base class on extended classes as well

I'm trying to get an instance of a subclass of a class I've attached an abstract factory for in my service manager config. I know the factory is being called, because I've got an echo in it that is working. The problem I seem to be running into though is that I don't know how to ask the service manager for my class and get it properly.

When I make this call:

$x = $serviceManager->get('some\class\baseClass');

I get:

Error: Zend\ServiceManager\ServiceManager::get was unable to fetch or create an 
       instance for some\class\name

And when I output the name that is being passed into the factory, it is missing the slashes like so:

someclassbaseclass

Class File

use Zend\ServiceManager\AbstractFactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class baseClassFactory implements \Zend\ServiceManager\AbstractFactoryInterface
{
    public function canCreateServiceWithName (ServiceLocatorInterface $locator, $name, $requestedName = '')
    {
        return ('baseClass' === $name || is_subclass_of($name, 'baseClass'));
    }

    public function createServiceWithName (ServiceLocatorInterface $locator, $name, $requestedName = '')
    {
        $db = $locator->get('db');
        $query = new $name($db);
        return $query;
    }
}

Configuration

$serviceManager => array(
    'abstract_factories' => array(
        'baseClassFactory',
    ),
);

EDIT

After testing this code, I've worked out all the bugs. This is the code behind a correct factory accounting for namespaces:

namespace some\class;

use Zend\ServiceManager\AbstractFactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class baseClassFactory implements \Zend\ServiceManager\AbstractFactoryInterface
{
    public function canCreateServiceWithName (ServiceLocatorInterface $locator, $name, $requestedName = '')
    {
        $baseClassName = 'some\class\baseClass';
        return ($baseClassName === $requestedName || is_subclass_of($requestedName, $baseClassName));
    }

    public function createServiceWithName (ServiceLocatorInterface $locator, $name, $requestedName = '')
    {
        // This class and sub-classes need a database connection
        $db = $locator->get('db');

        // Use the fully qualified path to the class so it inits correctly
        $createName = '\\' . $requestedName;

        // Get the system class instance
        $class = new $createName($db);

        // Pass it back to the user
        return $class;
    }
}

The registered service name some\\class\\baseClass is internally formatted by the service manager. The formatting is simply to lowercase and remove any non-alphanumeric characters, which results in someclassbaseclass .

When you create an abstract factory, you have the choice of both the name you requested in the $serviceManager->get($requestedName) method call and also the service manager's internal name $name ( someclassbaseclass ).

So the only change would be to replace the uses of $name with $requestedName .

use Zend\ServiceManager\AbstractFactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class baseClassFactory implements AbstractFactoryInterface
{
    public function canCreateServiceWithName (ServiceLocatorInterface $locator, $name, $requestedName)
    {
        return ('baseClass' === $requestedName || is_subclass_of($requestedName, 'baseClass'));
    }

    public function createServiceWithName (ServiceLocatorInterface $locator, $name, $requestedName)
    {
        $db = $locator->get('db');

        return new $requestedName($db);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM