How can I test my factory with the entity manager? I have an error because I need to make my container return an instance of a class created from doctrine ( I do not even know what there is returned).
How can I create a test that I can make pass?
// factory i want to test
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$googleAppOption = $container->get(GoogleAppOptions::class);
$em = $container->get('doctrine.entity_manager.orm_default');
return new GoogleTokenHandler($googleAppOption, new GoogleTokenClient(), $em);
}
//test function
public function testReturnsTokenHandlerInstance()
{
$googleOptionsFactory = new GoogleOptionsFactory();
$googleOptions = $googleOptionsFactory($this->container->reveal(), null);
$this->container->get(GoogleAppOptions::class)->willReturn($googleOptions);
$googleTokenHandlerFactory = new GoogleTokenHandlerFactory($this->container);
$tokenHandler = $googleTokenHandlerFactory($this->container->reveal(), null);
$this->assertInstanceof(GoogleTokenHandler::class, $tokenHandler);
}
Th fact that this is hard to test is a good sign that there is something smelly about this. In your case it's quite obviously the container being injected and then being used to locate services to work upon. I would recommend rewriting this class to inject both the OptionsFactory (or even better just the options) and the EntityManager as well as the dynamically created GoogleClient in the constructor. What you would arrive at is an invoke that pretty much looks like this:
return new GoogleTokenHandler(
$this->optionsFactory,
$this->tokenClient,
$this->entityManager
);
As you can see you neither use the $requestedName nor the optional $options being passed to your __invoke. That's a bit odd, but that won't bother us with the tests. Now you can simply mock out the services in your test and check whether invoke returns the correct instance:
public function testFactoryInvokeReturnsInstance()
{
$optionsFactory = $this->prophesize(OptionsFactory::class);
$tokenClient = $this->prophesize(GoogleTokenClient::class);
$entityManager = $this->prophesize(EntityManager::class);
$factory = new MyFactory(
$optionsFactory->reveal(),
$tokenClient->reveal(),
$entityManager->reveal()
);
$this->assertInstanceOf(GoogleTokenHandler::class, $factory->__invoke());
// Alternatively you can use the __invoke-magic directly:
$this->assertInstanceOf(GoogleTokenHandler::class, $factory());
}
You could do the same with your class but basically you would have to add a Container and then stub out the get-method for all of the services being fetched from it. For example you are missing the entity manager in your snippet. Should the GoogleTokenClient being created in your method require some arguments/options there is no way to mock that behavior and in fact you won't be able to switch it out without changing the code. Whereas by injecting it in the constructor you can just re-configure your container to pass in a different object.
For posterity, your complete factory would probably look something like this:
class Factory {
private $optionsFactory;
private $tokenClient;
private $entityManager;
public function __construct(GoogleTokenClient $tokenClient, ...)
{
$this->tokenClient = $tokenClient;
...
}
public function __invoke() { return new GoogleTokenHandler(...); }
}
Related
In ZF2, I have a factory for a multicheckbox (simplified)
class MultiCheckboxFactory
{
public function __invoke(FormElementManager $formElementManager)
{
$multiCheck = new MultiCheckbox();
$serviceManager = $formElementManager->getServiceLocator();
$mapper = $serviceManager->get('Path\To\The\Mapper\SomeMapper');
$resultFromQuery = $mapper->findText('text');
// further setting up of the multicheckbox based on $resultFromQuery
return $multiCheck;
}
}
I want the multicheckbox to render different content depending on $resultFromQuery that comes from the mapper's findText() method.
I thought of passing a variable to the __invoke(FormElementManager $formElementManager, $someText). But the problem is that when I call the multicheckbox from the service manager like this:
$element = $formElementManager->get('Path\To\Factory\Alias\Multicheckbox');
I don't see how to pass an additional variable. Any help?
Have a look at MutableCreationOptionsInterface, this allows your factory to receive runtime options which you pass through the serviceManager get() method.
use Zend\ServiceManager\MutableCreationOptionsInterface;
use Zend\ServiceManager\MutableCreationOptionsTrait;
class MultiCheckboxFactory implements MutableCreationOptionsInterface
{
use MutableCreationOptionsTrait;
public function __invoke(FormElementManager $formElementManager)
{
$options = $this->getCreationOptions();
var_dump($options);
$multiCheck = new MultiCheckbox();
....
}
}
Now you can pass options:
$element = $formElementManager->get('Path\To\Factory\Alias\Multicheckbox', ['foo' => 'bar']);
Update: MutableCreationOptionsTrait is no longer available in ZF3: https://docs.zendframework.com/zend-servicemanager/migration/#miscellaneous-interfaces-traits-and-classes
The simplest way to do this now appears to be
$element = $formElementManager->build('Path\To\Factory\Alias\Multicheckbox', ['foo' => 'bar']);
though this will give you a discrete (not shared) instance every time.
I have this code in my controller, it takes 'procedure_type' from the request and checks to see if a ProcedureType with that name exists. If it does it uses the object, if not it creates a new ProcedureType, then return the new object to use.
// Check the typed in ProcedureType against existing types.
$procedureTypes = $entityManager->getRepository('IncompassSurgeryBundle:ProcedureType')->findBy(array('name' => $request->request->get('procedure_type'), 'vendor' => $vendorId));
if (empty($procedureTypes)) {
// Create Procedure Type
$procedureType = new ProcedureType();
$procedureType->setVendor($vendor)
->setName($request->request->get('procedure_type'))
->setCreated(new \DateTime())
->setUpdated($procedureType->getCreated());
$entityManager->persist($procedureType);
} else {
$procedureType = $procedureTypes[0];
}
I don't think this is the best way to do this, I'd like to move the code into a function, say checkProcedureType(), but I don't know where the best place is to put that. I don't think it could go in the Entity or Repository classes, and moving it to a private function in the controller doesn't feel right.
I'm sure there is a class type that I'm not aware of, that extends the Entity. Or maybe I should just put these functions in my entity classes.
Service are the answer to almost everything in Symfony 2. Create a service like this :
namespace Your\Bundle\Service;
class ProcedureService // Call this the way you want
{
protected $entityManager;
public function __construct($entityManager)
{
$this->entityManager = $entityManager;
}
public function callMeTheWayYouWant($vendorId, $vendor)
{
// Check the typed in ProcedureType against existing types.
$procedureTypes = $this->entityManager->getRepository('IncompassSurgeryBundle:ProcedureType')->findBy(array('name' => $request->request->get('procedure_type'), 'vendor' => $vendorId));
if (empty($procedureTypes)) {
// Create Procedure Type
$procedureType = new ProcedureType();
$procedureType->setVendor($vendor)
->setName($request->request->get('procedure_type'))
->setCreated(new \DateTime())
->setUpdated($procedureType->getCreated());
$this->entityManager->persist($procedureType);
} else {
$procedureType = $procedureTypes[0];
}
// The rest of your code
}
}
In your services.yml file :
your_service:
class: Your\Bundle\Service\ProcedureService
arguments: [#doctrine.orm.entity_manager]
Then use it in your controller :
$this->get('your_service')->callMeTheWayYouWant($vendorId, $vendor);
If logic is somehow related to acessing database I always go for repository. However, if cases like yours, I tend to analyze it's dependency map.
Does your code repeats in some other method within same class, only?
If so, go for private method.
Is this part of code reused somewhere else but does not rely on some services?
You could externalize logic by creating separate class and static method which executes the code. Beware: Tends to get messy really quick
Finally, does your code rely on services/configuration?
Create a separate service, inject the services/configuration and invoke it's method. Adds a bit of overhead, if your abuse it, but you should be fine
Personally, in your example, I would go for private method, but that's just my opinion.
I am new to Autofac and IOC concept. I have following code which I am not getting or understanding what it is doing.
`
public void AddComponentInstance<TService>(object instance, string key = "", ComponentLifeStyle lifeStyle = ComponentLifeStyle.Singleton)
{
AddComponentInstance(typeof(TService), instance, key, lifeStyle);
}
public void AddComponentInstance(Type service, object instance, string key = "",ComponentLifeStyle lifeStyle = ComponentLifeStyle.Singleton)
{
UpdateContainer(x =>
{
var registration = x.RegisterInstance(instance).Keyed(key, service).As(service).PerLifeStyle(lifeStyle);
});
}
public void UpdateContainer(Action<ContainerBuilder> action)
{
var builder = new ContainerBuilder();
action.Invoke(builder);
builder.Update(_container);
}
public static class ContainerManagerExtensions
{
public static Autofac.Builder.IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> PerLifeStyle<TLimit, TActivatorData, TRegistrationStyle>(this Autofac.Builder.IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> builder, ComponentLifeStyle lifeStyle)
{
switch (lifeStyle)
{
case ComponentLifeStyle.LifetimeScope:
return HttpContext.Current != null ? builder.InstancePerHttpRequest() : builder.InstancePerLifetimeScope();
case ComponentLifeStyle.Transient:
return builder.InstancePerDependency();
case ComponentLifeStyle.Singleton:
return builder.SingleInstance();
default:
return builder.SingleInstance();
}
}
}
`
From above code what I understood is that, We are registering the Singleton Instance in Container and we are updating the container. I searched online For IRegistrationBuilder interface example but I could not get any satisfying answer.
Can anyone please help me to understand the concept of IRegistrationBuilder.
I am referring this code from NopCommerce application.
Thanks in Advance.
IRegistrationBuilder is application of builder design pattern within autofac. Look at the line:
x.RegisterInstance(instance).Keyed(key, service).As(service).PerLifeStyle(lifeStyle);
this chain of methods defines registration of istance of certain object. Each of the methods used sets properties used for proper registration. Each of the methods returns builder object which implements IRegistrationBuilder - it holds all those properties. Because PerLifeStyle accepts as first parameter IRegistrationBuilder you can use it in chain above to change builder properties - in case of PerLifeStyle to affect instantiation of the object. Because PerLifeStyle returns IRegistrationBuilder you may use it in the middle of methods invokation chain like:
x.RegisterInstance(instance).PerLifeStyle(lifeStyle).Keyed(key, service).As(service)
I'm currently using SOA, I've a bunch of Service, (ArticleService, CommentService, UserService, etc..)
I also have a ConfigurationService which is filled from an XML configuration file.
I'm using Zend Framework.
THis configuration service is needed in some of my service, and I'm using dependency injection, is it a good practice, to add ConfigurationService in constructor of most my Service to be able to fetch global configuration?
Thank you for your feedbacks.
I would say, no, don't pass the config container - neither as a service nor as an array nor a Zend_Config instance - in the constructor of your other services. I would keep the injection (whether by constructor or by setter) for those services focused on the actual objects/collaborators/data they actually need.
So, for example, an ArticleService might depend upon an ArticleRepository interface/object or on an ArticleMapper or on a db adapter. Let the constructor/setter signatures for the ArticleService reflect what it truly needs.
Instead, what I would do is during Bootstrap, create some kind of factory object - perhaps as an application resource - that accepts in its constructor your config data/object/service (or even better, the bootstrap instance itself, from which you could get, not just your config data, but also any application resources, like a db adapter, that were created during the bootstrap process). Then write methods on your factory object that create/deliver the other services you need. Internally, the factory maintains a registry of already created services so that it can lazy-create instances where required.
A snippet of what I have in mind might be as follows:
Bootstrap snippet:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initFactory()
{
$factory = new My_Factory($this);
return $factory;
}
}
Then the factory:
class My_Factory
{
protected $_registry;
protected $_bootstrap;
public function __constructor($bootstrap)
{
$this->_bootstrap = $bootstrap;
}
public function getDbAdapter()
{
if (!isset($this->_registry['dbAdapter']){
$this->_bootstrap->bootstrap('db'); // probably using app resource
$this->_registry['dbAdapter'] = $This->_bootstrap->getResource('db');
}
return $this->_registry['dbAdapter'];
}
public function getArticleService()
{
if (!isset($this->_registry['articleService']){
$dbAdapter = $this->getDbAdapter();
$this->_registry['articleService'] = new My_ArticleService($dbAdapter);
}
return $this->_registry['articleService'];
}
public function getTwitterService()
{
if (!isset($this->_registry['twitterService']){
$options = $this->_bootstrap->getOptions();
$user = $options['twitter']['user'];
$pass = $options['twitter']['pass'];
$this->_registry['twitterService'] = new My_TwitterService($user, $pass);
}
return $this->_registry['twitterService'];
}
}
Then in a controller, you could grab an ArticleService instance:
class SomeController extends Zend_Controller_Action
{
protected $_factory;
public function init()
{
$this->_factory = $this->getInvokeArg('bootstrap')->getResource('factory');
}
public function someAction()
{
$articleService = $this->_factory->getArticleService();
$this->view->articles = $articleService->getRecentArticles(5); // for example
}
}
The upshot here is that each service explicitly identifies the collaborators it needs and the factory is a single place that takes care of creating/injecting all those collaborators.
Finally, I confess that I am just spitballing here. To me, this is essentially a rudimentary dependency injection container; in that sense, using a fully-featured DIC - perhaps the Symfony DIC or the new Zend\Di package in ZF2 - might be better. But after many months of struggling with all the best-practice recommendations to inject your dependencies, this is what I have come up with. If it's goofy or just plain wrong, please (please!) straighten me out. ;-)
I would like to be able to run tests on my fake repository (that uses a list)
and my real repository (that uses a database) to make sure that both my mocked up version works as expected and my actual production repository works as expected. I thought the easiest way would be to use TestCase
private readonly StandardKernel _kernel = new StandardKernel();
private readonly IPersonRepository fakePersonRepository;
private readonly IPersonRepository realPersonRepository;
[Inject]
public PersonRepositoryTests()
{
realPersonRepository = _kernel.Get<IPersonRepository>();
_kernel = new StandardKernel(new TestModule());
fakePersonRepository = _kernel.Get<IPersonRepository>();
}
[TestCase(fakePersonRepository)]
[TestCase(realPersonRepository)]
public void CheckRepositoryIsEmptyOnStart(IPersonRepository personRepository)
{
if (personRepository == null)
{
throw new NullReferenceException("Person Repostory never Injected : is Null");
}
var records = personRepository.GetAllPeople();
Assert.AreEqual(0, records.Count());
}
but it asks for a constant expression.
Attributes are a compile-time decoration for an attribute, so anything that you put in a TestCase attribute has to be a constant that the compiler can resolve.
You can try something like this (untested):
[TestCase(typeof(FakePersonRespository))]
[TestCase(typeof(PersonRespository))]
public void CheckRepositoryIsEmptyOnStart(Type personRepoType)
{
// do some reflection based Activator.CreateInstance() stuff here
// to instantiate the incoming type
}
However, this gets a bit ugly because I imagine that your two different implementation might have different constructor arguments. Plus, you really don't want all that dynamic type instantiation code cluttering the test.
A possible solution might be something like this:
[TestCase("FakePersonRepository")]
[TestCase("TestPersonRepository")]
public void CheckRepositoryIsEmptyOnStart(string repoType)
{
// Write a helper class that accepts a string and returns a properly
// instantiated repo instance.
var repo = PersonRepoTestFactory.Create(repoType);
// your test here
}
Bottom line is, the test case attribute has to take a constant expression. But you can achieve the desired result by shoving the instantiation code into a factory.
You might look at the TestCaseSource attribute, though that may fail with the same error. Otherwise, you may have to settle for two separate tests, which both call a third method to handle all of the common test logic.