Symfony2 get service or get container service - web-services

i have just implemented my first service in Symfony2.
I noticed that, within a controller method, whether i call the service so
$this->container->get('main.service');
or so
$this->get('main.service');
there is no difference.
I get the service equally with both.
Where are the differences?

There's no difference if you're extending the Base Controller provided by Symfony.
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class YourController extends Controller
If you take a deeper look at the implementation of the Symfony\Bundle\FrameworkBundle\Controller\Controller, you may notice that it provides a get() helper which do exactly the same call as what you did first (getting your service through the container).
So, then,
There's no difference as $this->get('something') simply sencapsulates a call to $this->container->get('something').
Here's the implementation of the get() method you're calling when doing $this->get('main.service');
/**
* Gets a service by id.
*
* #param string $id The service id
*
* #return object The service
*/
public function get($id)
{
return $this->container->get($id);
}

Related

How to use PhpUnit/DbUnit with a real Doctrine EntityManager for functional testing

I'm using PhpUnit/DbUnit to create a set of 5 to 10 fixture records. I use in-memory sqlite.
I successfully can use a Doctrine\DBAL\Connection to access it, so I can use methods like ->insert( $tableName, $data ); for my tests.
Now I want to consume the Doctrine EntityManager so I can create an entity and call ->persist().
In unit-testing I used to mock the EntityManager and asserted an expectation to call persist.
But for functional-testing I want to check the final result written to the DB, even go further and re-use the result of the writing.
I therefore need to create a real EntityManager but consuming the DbUnit connection.
I've seen that creting a new EntityManager takes 3 arguments, but still the creator is protected:
/**
* Creates a new EntityManager that operates on the given database connection
* and uses the given Configuration and EventManager implementations.
*
* #param \Doctrine\DBAL\Connection $conn
* #param \Doctrine\ORM\Configuration $config
* #param \Doctrine\Common\EventManager $eventManager
*/
protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
{
[...]
I don't know if I'm expected to create a subclass, or maybe use an already subclassed EntityManager or how should I proceed.
So question:
How can I setup a real Doctrine\ORM\EntityManager within a PhpUnit/DbUnit test class using the low level Doctrine\Dbal\Connection that is already bound to the DbUnit connection?
Note: I'm inside a symfony3 project, so mapping files are in the expected places of symfony.

Symfony Doctrine entity manager and repository

I understand the benefit or repository pattern but I just can't understand in Symfony3 Doctrine there are Doctrine\ORM\EntityManager and \Doctrine\ORM\EntityRepository
What are the difference between the two?
Is repository should be injected to controller or entity manager?
Edit
The correct question should be: What's the proper way to access a repository from a controller?
Should a repository be injected to a controller as a service?
Should a repository be injected to another service as a service?
Should entity manager contain any query at all?
Edit
The correct question should be: should a service contain a query at all? Which #MateuszSip already explained, it could be done by injecting Entity Manager
Should a custom function like getAvailableManagers be put in
repository or services? (Where manager is a repository and there
are some logic in determining available manager)
How about a more generic function like findAllManager, should it be in repository or entity manager?
Currently I'm using Symfony3. Thank you very much
Cheers,
Edit
Talking to #MateuszSip (thanks mate), I decided to make my question clearer with an example below. Please note that below code are not representing real problem
controller
Class ManagementController
{
public function assignManager($projectType)
{
// Grabbing a service
$s = $this->get('mycompany_management_management_service')
$managers = $s->findAvailableManagers();
$managers = $s->checkCapability($managers, $projectType);
return $managers
}
}
repository
class ManagerRepository extends \Doctrine\ORM\EntityRepository
{
public function findAvailableManagers()
{
...
return $managers
}
public function checkCapability($managers, $type)
{
...
return $capableManagers
}
}
services
class ManagementService
{
... I am not sure what should be here.
}
EntityManager is used to manage doctrine-related objects, so:
you can persist an entity object (it's now managed by doctrine, and ready to save)
you can remove an entity object (so it'll be deleted later)
you can flush, and it'll trigger pending operations
you can get a repository (to get objects you'll need) or use a generic api to get an object by a primary key
etc.
It's a class that manages a state of objects and their relation to the database.
Repository is a pattern that standarizes an access to the entites.
If your app is complex, you should inject a separate service(s) to your controller. So there's a UserSaver service (as an example) that use entityManager to create/update a user and UserFinder (or something well-named) using UserRepository which's responsible of fetching user by defined criterias.
You can create a query using entity manager, but em itself cannot contain queries.
In my opinion, define a method inside a service, and a corresponding method in your UserRepository. At this moment, all of what you want should be fetched by a database, but it can change later.
In repository. Methods like: findByRole(role=manager), findIsActive, findOneBySecurityNumber relies to a repository.

Symfony2: Mocked service is set in the container but not used by the controller (it still uses the original service)

I'm writing the functional tests for a controller.
It uses a class to import some data from third party websites and to do this I wrote a class that I use into Symfony setting it a service.
Now, in my functional tests, I want to substitute this service with a mocked one, set it in the container and use it in my functional tests.
So my code is the following:
// Mock the ImportDataManager and substitute it in the services container
$mockDataImportManager = $this->getMockBuilder('\AppBundle\Manager\DataImportManager')->disableOriginalConstructor()->getMock();
$client->getContainer()->set('shq.manager.DataImport', $mockDataImportManager);
$client->submit($form);
$crawler = $client->followRedirect();
As I know that between each request the client reboots the kernel and I have to set again the mocked class, I set the mock immediately before the calling to $client->submit.
But this approach seems not working for me and the controller still continue to use the real version of the service instead of the mocked one.
How can I use the mocked class to avoid to call the remote website during my functional test?
If I dump the set mocked service, I can see it is correctly set:
dump($client->getContainer()->get('shq.manager.DataImport'));die;
returns
.SetUpControllerTest.php on line 145:
Mock_DataImportManager_d2bab1e7 {#4807
-__phpunit_invocationMocker: null
-__phpunit_originalObject: null
-em: null
-remotes: null
-tokenGenerator: null
-passwordEncoder: null
-userManager: null
}
But it is not used during the $form->submit($form) call and, instead, is used the original service.
UPDATE
Continuing searching for a solution, I landed on this GitHub page from the Symfony project, where a user asks for a solution to my same problem.
The second call doesn't use the mocked/substituted version of his class, but, instead, the original one.
Is this the correct behavior? So, is it true that I cannot modify the service container on a second call to the client?
Yet, I don't understand why the service is not substituted in the container and I haven't a real solution to that problem.
Anyway I found some sort of workaround, in reality more correct as solution (also if it remains unclear why the service is not substituted and this is a curiosity I'd like to solve - maybe because the $client->submit() method uses the POST method?).
My workaround is a simple test double.
I create a new class in AppBundle/Tests/TestDouble and called it DataImportManagerTestDouble.php.
It contains the unique method used by the controller:
namespace AppBundle\Tests\TestDouble;
use AppBundle\Entity\User;
class DataImportManagerTestDouble
{
public function importData(User $user)
{
return true;
}
}
Then, I instantiate it in the config_test.yml (app/config/config_test.yml) file in the following way:
services:
shq.manager.DataImport:
class: AppBundle\Tests\TestDouble\DataImportManagerTestDouble
This way, during the tests, and only during the tests, the class loaded as service is the TestDouble and not the original one.
So the test pass and I'm (relatively) happy. For the moment, at least.

How to unit test if function has been called? Dependency injection?

I'm creating a simple RESTful API in PHP for practice. I'm trying to write as testable code as possible. After reading many tutorials and watching a few videos, I still feel at a loss on how to design this.
Basically, I have set up a Router class. It is responsible for mapping url paths to controller methods.
It's easy to test the router's state after adding a route.
But, how do I test if the proper class->function(params) has been called in respond()?
I'm using PHPUnit, and I've been reading about mocks. I don't know how to use them in this context.
Currently, respond() parses a given path and request method, and calls the mapped method.
Here is my current design:
private $routes;
public function __construct() {
$routes = array();
}
/**
* Gets all current routes
*/
public function getRoutes();
/**
* Sets all routes
*/
public function setRoutes($routes);
/**
* Routes GET request
*/
public function get();
/**
* Routes POST request
*/
public function post();
/**
* Routes PUT request
*/
public function put();
/**
* Routes DELETE request
*/
public function delete();
/**
* Sets up default paths for a given resource
*/
public function resource();
/**
* Respond to request
* #return mixed JSON of resource data
*/
public function respond($req_method, $request);
/**
* Returns mapped call info from request method and path
* #return mixed An array of the call and params
*/
private function parse($req_method, $request);
As the comments have indicated, this would be a good use of a spy or mocking system. PHPunit has some ability to create and test for mocks, but I prefer to use a different library - Mockery.
This code will create a class and test that that when you call average(), it's called three times, and then also returns a given value.
Your code would call respond(), after setting up a mock that shouldReceive('get')->once() (for example). The m::close in the teardown will verify that get() was called, just one time, and would fail the test if it was not.
<?php
use \Mockery as m;
class TemperatureTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
m::close();
}
public function testGetsAverageTemperatureFromThreeServiceReadings()
{
$service = m::mock('service');
$service->shouldReceive('readTemp')->times(3)->andReturn(10, 12, 14);
$temperature = new Temperature($service);
$this->assertEquals(12, $temperature->average());
}
}
Since you would be calling a real class to do work in respond(), you will need a 'partial mock'
$restful= m::mock('RestfulController[get]');
$restful->shouldReceive('get')->once();

Zend Framework 2 + Doctrine: get Entity Manager in Model

Edit 1: it seems like I didn't explain myself very well. Class Foo is not an entity. Just a general purpose model that I would like to have an access to the entity manager.
Edit 2: I don't think there is an answer to my question. Basically, I wanted a class that can have access to the EntityManager without this class being called by the service manager, simply due to the fact that it may be called by a class who is also not called by the service manager. In other words, I was trying to achieve what Zend_Registry used to achieve in ZF1. I'll have to find another way of doing what I am trying to do.
I am trying to access Doctrine's entity manager in a model, in a similar way as it done in a controller:
$this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
The ZF2 manual (http://framework.zend.com/manual/2.0/en/modules/zend.service-manager.quick-start.html) says:
By default, the Zend Framework MVC registers an initializer that will inject the ServiceManager instance, which is an implementation of Zend\ServiceManager\ServiceLocatorInterface, into any class implementing Zend\ServiceManager\ServiceLocatorAwareInterface.
So I created a the following class:
<?php
namespace MyModule\Model;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class Foo implements ServiceLocatorAwareInterface
{
protected $services;
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->services = $serviceLocator;
}
public function getServiceLocator()
{
return $this->services;
}
public function test()
{
$em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
}
}
Then, from another class I call this class as such:
$foo = new \MyModule\Model\Foo();
$foo->test()
which throws the following error:
PHP Fatal error: Call to a member function get() on a non-object
So, I guess I am missing something somewhere, but what? Where? How? Perhaps there is an easier to access the entity manager?
Thanks!
From your question, I see that you have mainly two misunderstandings, one about your design strategy (injecting an EntityManager on your model) and one about how things work with the service manager (ServiceLocatorAwareInterface). In my answer I'll try to focus on the second one.
Initializers are php closures that are called over each instance accessed from the Service Manager before this one returns it to you.
Here is an example of an Initializer :
// Line 146 - 150 of Zend\Mvc\Service\ServiceManagerConfig class + comments
$serviceManager->addInitializer(function ($instance) use ($serviceManager) {
if ($instance instanceof ServiceManagerAwareInterface) {
$instance->setServiceManager($serviceManager);
}
});
As you can see each time Service Manager is asked to return an instance/object that implements the ServiceManagerAwareInterface interface, it will setup/inject the Service Manager instance to it.
By the way in your previous code you omitted to implement correctly the interface as you didn't define the setServiceManager method. However, this is not your only problem.
First, if you want the Service Manager to inject itself in your Model, you need to call/construct your model instance from it (during this process it will call the initializers) through a factory for example if your class has complex dependencies.
[EDIT]
Example:
In your MyModule
namespace MyModule;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
use MyModule\Model\Foo;
class Module implements ServiceProviderInterface{
//Previous code
public function getServiceConfig()
{
return array(
'instances' => array(
'myModelClass' => new Foo(),
),
);
}
Now, when you need a Foo instance you should call the Service Manager:
$serviceManager->get('myModelClass');
Don't forget defining setServiceManager method, otherwise your'e not correctly implementing the ServiceManagerAwareInterface!
I think, the only thing you’re missing, is to add your model class to the list of invokables and retreive it through the service manager.
So basically add this to your module.conf.php:
return array(
'service_manager' => array(
'invokables' => array(
'MyModule\Model\Foo' => 'MyModule\Model\Foo',
),
),
);
And instantiate your model object like this (if in a controller):
$foo = $this->getServiceLocator()->get('MyModule\Model\Foo');
$foo->test();