0

I am still struggling in instantiating a service from a ZF2 module outside of Zend Framework (in a blank .php).

I want to achieve:

Instantiate + invoke a ZF2 service method from outside ZF by the use of the ServiceManager and possibly DI.

What I have now: (UPDATED 4/10/2013)

Following up on the comments below I have done more research,particularly:

I've opted to trim out all the DI and ModuleManager things and try to autoload (works fine now) and instantiate (does not) a service.

1 - Autoload the requested classes using a Classmap and instantiate servicemanager in a stand-alone .PHP file

// Autoload ZF and ProductImage module via classmap
Zend\Loader\AutoloaderFactory::factory(array(
        'Zend\Loader\StandardAutoloader'   => array(
            'autoregister_zf' => TRUE,
        ),
        'Zend\Loader\ClassMapAutoloader'   => array(
            '/home/frequency/domains/scrftcdn/public_html/ft/shop/php/zendframework/module/ProductImage/autoload_classmap.php',
        )
    )
)

// Hard-coded servicemanager configuration (will come from $module->getConfig once this works)
$smc = new \Zend\ServiceManager\Config(
    array(
        'service_manager' => array(
            'factories'       => array(
                'ProductImage\Model\ProductImage'   => 'ProductImage\Factory\ProductImageFactory',

            )
        ),
    )
);

// Instantiate the service manager
$sm = new \Zend\ServiceManager\ServiceManager($smc);

//Load the service via the service manager
$service = $sm->get('ProductImage\Model\ProductImage'); // <throws exception
die();

2 - The exception

 [error] [client 192.168.6.52] PHP Fatal error: 
 Uncaught exception 'Zend\\ServiceManager\\Exception\\ServiceNotFoundException' with message 'Zend\\ServiceManager\\ServiceManager::get was unable to fetch or create an instance for ProductImage\\Model\\ProductImage' in /usr/lib/zendframework/library/Zend/ServiceManager/ServiceManager.php:495
Stack trace:\n#0 /home/frequency/domains/wpfreqad/public_html/wp-content/themes/frequency/manage-product-images/functions.inc.php(48): Zend\\ServiceManager\\ServiceManager->get('ProductImage\\Mo...')
    #1 /home/frequency/domains/wpfreqad/public_html/wp-content/themes/frequency/functions.inc.php(14): require_once('/home/frequency...')\n
    #2 /home/frequency/domains/wpfreqad/public_html/wp-content/themes/frequency/functions.php(14): require_once('/home/frequency...')\n
    #3 /home/frequency/domains/wpfreqad/public_html/wp-settings.php(293): include('/home/frequency...')\n
    #4 /home/frequency/domains/wpfreqad/public_html/wp-config.php(90): require_once('/home/frequency...')\n
    #5 /home/frequency/domains/wpfreqad/public_html/wp-load.php(29): require_onc in /usr/lib/zendframework/library/Zend/ServiceManager/ServiceManager.php on line 495

3 - ProductImage\autoload_classmap.php

    <?php
    // Generated by ZF2's ./bin/classmap_generator.php
    return array(
        'ProductImageTest\Service\ProductImageServiceTest'         => __DIR__ . '/test/ProductImageTest/Service/ProductImageServiceTest.php',
        'ProductImage\Module'    => __DIR__ . '/Module.php',
        'ProductImage\Factory\ProductImageFactory'                => __DIR__ . '/src/ProductImage/Factory/ProductImageFactory.php',
        'ProductImage\Model\ProductImage'                          => __DIR__ . '/src/ProductImage/Model/ProductImage.php',

    );

4 - ProductImage\Module.php

class Module implements \Zend\ModuleManager\Feature\ConfigProviderInterface
{
    /* Invoked by Module Manager */
    public function getConfig()
    {
        return include __DIR__ . '/config/module.config.php';
    }
}

5 - ProductImage\config\module.config.php

<?php
return array(
    'service_manager' => array(
        'factories'  => array(
            'ProductImage\Model\ProductImage'           =>  'ProductImage\Factory\ProductImageFactory',
        ),
    ),
);

I hope that's the right approach and not too far off the right way..

Laurent
  • 33
  • 1
  • 5
  • possible duplicate of [ZF2 Dependency Injection of Module Service without Bootstrap.php](http://stackoverflow.com/questions/19134079/zf2-dependency-injection-of-module-service-without-bootstrap-php) – Jurian Sluiman Oct 03 '13 at 09:54
  • You are mixing all sorts of concepts. Autoloading and the autoloader classmap has nothing to do with services and dependency injection. Furthermore Zend\Di is completely different than Zend\ServiceManager. Then, you are configuring services via a module but you don't use any Zend\ModuleManager in your standalone script. And last, you instantiate a Zend\Di class by just `new Zend\Di\Di` and expect it to be fully configured. Please read some documentation about ZF2 and use the quick start. Then ask a question about a specific problem. – Jurian Sluiman Oct 03 '13 at 09:56
  • Thanks @JurianSluiman. Clearly I am starting off with ZF2 and trying to find a way of making use of the different functionalities. I feel that the documentation lacks the kind of detail I need. Could you nudge me in the right direction to find a full example of how to make use of the ModuleManager? – Laurent Oct 03 '13 at 12:52
  • have you tried the quick start? That helps a lot if you're starting with ZF2: http://framework.zend.com/manual/2.2/en/user-guide/overview.html – Jurian Sluiman Oct 03 '13 at 14:20
  • I have indeed. I've gone over it a few times and built the sample app. There are still fundamental things missing for me since I don't want to make use of the MVC but rather use Zend to build a back-end service layer. For example, can you have a module without an application and load the module by itself into a non-ZF app? – Laurent Oct 03 '13 at 15:41
  • Yes, you can use the Zend\ModuleManager. You have to pass on a modules config (see application.config.php) and perform some steps already done in Zend\Mvc\Application as well (check the module loader in `init()` there). Then you have to pull the service manager (as done in `init()` as well and get the config. But I don't know why you want that, because it's quite a hassle – Jurian Sluiman Oct 04 '13 at 07:10
  • I stripped out all the garbage about DI and ModuleManager. It makes more sense (IMO) to just autoload the classes and invoke the services using the ServiceManager. – Laurent Oct 04 '13 at 15:33

1 Answers1

2

I've finally found a solution. Jurian's hints to using the actual application have put me on the right track! :)

1 - /zendframework/config/application.config.php.

Everything is default, just make sure the module is added. I commented the 'application' module as I don't see any use for it (as of now). I also had to change the path to the config files from './module' to __DIR__ . '../module' as it was looking in the wrong directory (took me a while to find that one).

<?php
return array(
   // ...
 'modules' => array(
        'ProductImage', /* ProductImage module */
//        'Application',
    ),
// ...
'module_listener_options' => array(
    'module_paths' => array(
        __DIR__ . '/../module',
        __DIR__ . '/../vendor',
    ),

2 - configuration

make sure the modules are configured right, and also that ZF2 Path is set up correctly. In my case, run through the quick start on RTD (http://zf2.readthedocs.org/en/latest/ref/installation.html). I had the ZF2_PATH exception and change the httpd.conf via WHM.

3 - Read more on RTD

In particular on how you can bootstrap the application: http://zf2.readthedocs.org/en/latest/modules/zend.mvc.intro.html#zend-mvc-intro

Which after very little debugging produced me the following code to access a neatly configured $sm instance.

//wherever the ZF2 application skeleton is, include the autoloader
require_once '/home/path/to/the/ZF2/application/directory/init_autoloader.php';

use Zend\Loader\AutoloaderFactory;
use Zend\Mvc\Application;
use Zend\Mvc\Service\ServiceManagerConfig;
use Zend\ServiceManager\ServiceManager;

// setup autoloader
AutoloaderFactory::factory();

// get application stack configuration
$configuration = include '/home/path/to/the/ZF2/application/directory/config/application.config.php';

//var_export($configuration);
// The init() method does something very similar with the previous example.
$app = Application::init($configuration);
$sm = $app->getServiceManager();
$pi =  $sm->get('ProductImage\Service\ProductImageService');
var_export($pi);
die();

I do not like the fact that the configuration needs to be specified in addition to the init_autoloader path. I avoid this implementation from being copied and pasted all over the place, I am considering integrating the $sm instantiation into the init_autoloader.php in the future so that the path of the configuration file does not have to be specified whenever a ProductImage service needs to be invoked.

Community
  • 1
  • 1
Laurent
  • 33
  • 1
  • 5