Quantcast

Inherited services and factories

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Inherited services and factories

macest
I have a couple of instances where I have a Service from one Module which extends a Service from another. However it also needs the flexibility to not require the extending module on some projects. Using DI this worked quite well:

Service 1:
namespace Module1\Service;

class MyService1 {…}

Config 1:
'di' => array(
	'instance' => array(
		'alias' => array(
			'myService' => 'Module1\Service\MyService1',
		),
		'myService' => array(
			'injectSomething' => 'Something',
		),
	),
),

Service 2:
namespace Module2\Service;

use Module1\Service\Service1;

class MyService2 extends Service1 {…}

Config 2:
'di' => array(
	'instance' => array(
		'alias' => array(
			'myService' => 'Module2\Service\MyService2',
		),
		'myService' => array(
			'injectSomethingElse' => 'SomethingElse',
		),
	),
),

The problem comes when using the ServiceManager. To inject stuff from both modules I would need two separate factories, however then I have the problem of dependencies needing injecting on both.

Inheriting off the first module's factory won't work because it would create an instance of the first module's service rather than the second module's extended instance of the first.

Factory 1:
class Service1Factory implements FactoryInterface
{
	public function createService( ServiceLocatorInterface $serviceLocator )
	{
		$service = new Service1();
		$service->setSomething( 'Something' );
		return $service;
	}
}

Factory 2:
use Module2\Service\Service1Factory;

class Service2Factory extends Service1Factory
{
	public function createService( ServiceLocatorInterface $serviceLocator )
	{
		$service = parent::createService( $serviceLocator ); // doh, wrong instance
		$service->setSomethingElse( 'SomethingElse' );
		return $service;
	}
}

The inheritance solution does work however if I create a stub/endpoint service class within my application class which the factory instantiates and it has the correct inheritance:

Application\Service\MyService > Module2\Service\Service2 > Module1\Service\Service1
or
Application\Service\MyService > Module1\Service\Service1

I don't think this is a great solution as it forces the need to create them within the application module for each project to get it working. Using this solution has further escalating issues from inherited objects (such as forms) in both modules needing injecting into the service instance. Do I do the same thing for the forms and create a stub/endpoint form in the application module as well? It starts getting a bit bloated and untidy.

Form1 (injected into Service1):
namespace Module1\Form;

class Form1 {…}

Form2 (Injected into Service2):
namespace Module2\Form;

use Module1\Form\Form1;

class Form2 extends Form1 {…}

Any thoughts?
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Inherited services and factories

richard
This post has NOT been accepted by the mailing list yet.
This post was updated on .
One  way to solve this would be to use a common factory for the super type and all extended services. You could then implement some logic based around configuration that decided which instance to create and what to set. This would break the module separation rule though.

Another solution could be to add an array to the supertype which extending service factories add to, i.e

super type factory
protected $array = array('create class'=>'supertype','inject' => array( 'class 1','class 2' ) );


function createService( ServiceLocatorInterface $serviceLocator )
{
    $service = new $this->array['class'];
    foreach($this->array['inject'] as $class){ $service->set($locator->get($class); }
    return $service;
}


then the extended factory createService method could look similar to:

function createService( ServiceLocatorInterface $serviceLocator )
{
      $this->array['class'] = 'theExtendedClass';
      $this->array['inject'][] = 'anotherService';
      return parent::createService($locator);
}

regards
Loading...