How to test internal controllers without route in Symfony 2 - symfony

I am trying to reduce redundant code by refactoring template and controller code into reusable components, which I then use via the render(controller('AppBundle:Foo/Bar:baz')) construct inside my other templates.
Of course I would like to test these components. In the examples regarding functional testing, however, an actual route is required to make fake test requests. But my BarController here is purely internal and has no routes attached to it. How can I test this controller?
Creating dummy routes is not always possible, because some of the arguments are model objects that cannot be passed via URL. Am I approaching this the wrong way?

The service approach sounds nice, but I am simply doing this now:
self::$kernel->getContainer()->get('router')->getContext()->setParameter('_locale', 'en');
$controller = new MyController();
$controller->setContainer(self::$kernel->getContainer());
$response = $controller->myAction($arg1, $arg2, $argWhatever);
// assertions here
Seems to work just fine.

If the controllers are setup as services, then they can be easily tested much as any other class would be unit-tested. Even before Symfony 3.3 started to make them services by default, I had altered some of my own to allow them to be more easily tested like this.

Related

Symfony Forms manual submission of both GET and POST requests

Is there any way to get merged data from Request class? Because currently we are submitting forms manually for API controller that accepts both POST and GET queries (this is not an REST API because of legacy project).
$data = array_merge($request->query->all(), $request->request->all());
$form->submit($data);
Is there any way to write something cleaner instead of code below?
$data = array_merge($request->query->all(), $request->request->all());
I think that is not possible. (Maybe I'm wrong)
If you look at the source code of Request, you can see that when Symfony create the request, Symfony put the global variable $_GET in $this->query and $_POST in $this->request.
There is no Symfony variable that takes both.
If you need it in only one place, I think what you have done is fine.
If not, create a service that will or another solution that factors this code.
Another solution is to use the global variable $_REQUEST, because Symfony makes the merge, but it depends on your php configuration (request_order parameter of your php.ini).
But I do not think using Superglobals variables with Symfony is a good idea ... (Besides symfony overwrites them)

Symfony2: Best way for logging from anywhere

I am working on my first Symfony project. I wonder what is the best / recommendet method to write log messages from anywhere in my code.
So far I used Monolog which works great when being used in a controller:
public function indexAction() {
$logger = $this->get('logger');
$logger->info('I just got the logger');
$logger->error('An error occurred');
// ...
}
But how can I use this code from any classe/code from my project? Doctrine entity classes for example cannot use $this->get('logger') to create the logger. How can I access the service in these classes? Or what other methode to log message is recommended in these cases?
EDIT: Of course I could create the logger in any controller and pass it down to all other classes. But this would be quite very cumbersome. There has to be a better way.
IMO, a first approach could be the creation of Event Listeners for specific actions in order to log only what you have decided to.
Have a look to this chapter : http://symfony.com/doc/current/cookbook/event_dispatcher/event_listener.html
Hope it will help you.

Where can Symfony services be useful?

There is the example of creating and using a service in the official documentation. At start we create some class, then register it in config/services.yml an then we can use it in our code like this:
$result = $this->get('app.myservice')->myMethod($arg);
//(In the [example][1] it is little bit other code:)
//$slug = $this->get('app.slugger')->slugify($post->getTitle());
But WHAT FOR? while I can just do the SAME like this:
use MyServiceNamespace/MyService
//...
$result = (new MyService())->myMethod($arg);
Where is profit of using Services? Is this just syntax sugar?
Nope. Far from syntax sugar.
You need to have a working understanding of what dependency injection means. Perhaps start by skimming through here: http://symfony.com/doc/current/book/service_container.html
Let's suppose your service needs a doctrine repository to do it's job. Which is better?
class MyController
{...
$userManager = $this->get('user.manager');
OR
$userRepository = $this->getDoctrine()->getManager()->getRepository('MyBundle::User');
$userManager = new UserManager($userRepository);
Your choice but once you have worked through the mechanics of how to add a service then you will never look back.
I should also point out that your sluglfy example requires a use statement and ties you code directly to a specific implementation. If you ever need to adjust your slugification then you need to go back and change all the places where it is used.
// These lines make your code more difficult to maintain
use Something\Slugify;
$slugify = new Slugify();
AS Opposed to
$slugify = $this->get('slugify');
'tIn this case, it's not really relevant. But from a simple design concern, services allow to make a better dependency management.
For instance, if you declare a service relaying on another one, then you won't have to instanciate both of them. Symfony will take care of it.
And since your declaration is centralized, any modification on the way you decide to create your service (= declare it), you won't have to change all the references to the services you changed since symfony will take care of the way it's instanciated when needed.
Another point is the scope of services. This information might be checked, but I think symfony instanciate service once (Singleton) which mean a better memory usage.

Symfony2: Access Request object in Entity

I'd like to know how to access the Request object in an entity (Symfony2) to modify the user locale.
If someone has found a solution for my problem, please let me know.
It's not possible. This is by design: the entity is just a simple object that should know nothing about the request - it's the responsibility of the controller to interpret the request, and manipulate the entity based on that.
Something like:
//inside your controller:
public function fooBarAction(Request $request)
{
$entity = // get entity
$entity->setLocale($request->getSession()->getLocale());
}
The above is just example code, it won't work if you just copy and paste it. It's just to demonstrate the general idea. The entity should just be a very simple object, who's only responsibility is to hold some data. It shouldn't know where the data is coming from - that keeps it flexible (if you want to set the locale based on something else, you only have to change your controller, not all your entities).
It is possible, but...
What you can but never should do is inject the Request object into the entity (Practically turning your entity into service, see here). Also, even worse idea (but which people still do), you could inject the whole container and get Request from there. The reason why you shouldn't do it is you never should have any code that deals with business rules or any system code in your entities.
You can switch your locale directly in your routes by using _locale custom variable (accessible also from the Request). Or you can create a kernel listener, which will do the required functionality for you. This way you keep your code testable and decoupled.

How to pass arguments to controller from route in Symfony2

I'm working on a Symfony2 project and am trying to figure out how to pass parameters from the route configuration to the controller. I know I can configure default values in the route configuration, and retrieve the values in the controller using the appropriate var name in the function declaration, but that isn't exactly what I want.
My use case is the following. I have a standard method in my controller that I want to access from 2 or 3 different routes. Depending on which route is being called, I want to "configure" the method differently. I can accomplish this in a few ways:
In my controller, check the route name using `$this->container->get("request")->get("_route"), but that is ugly, and then I am hardcoded to the route name. Moves configuration to the controller, which should just be logic - not configuration.
Create a base controller class, and subclass each method for my different routes. Each subclassed method would then have the necessary configuration within the method. Cleaner soln than #1, but still "heavy" in the sense of having multiple classes for a simple need and still pushes configuration data into the business logic.
Put configuration data into the route configuration. In the controller, access the configuration data as required. Ideal solution, but don't know how.
I can use the route default array to specify my arguments, but then must make sure to use a regex to ensure that the params are not overridden at the URL level (security risk). This is functional, but still kinda cludgy and not a pretty hack.
I presume that there must a better way to do this, but I can't seem to figure it out. Is there a way to access the routing object from the controller, and access the different configuration parameters?
You can pull the actual route from the router service. Something like:
$routeName = $this->container->get("request")->get("_route");
$router = $this->container->get("router");
$route = $router->getRouteCollection()->get($routeName);
Not sure if this would be such a great design though. Consider passing a $configName to your controller method, adding a parameter with the same name in a config file then using getParameter to access it. That would eliminate the route stuff from the equation.
Something like:
zayso_arbiter_import:
pattern: /import
defaults: { _controller: ZaysoArbiterBundle:Import:index, configName: 'someConfigName' }
public function importAction(Request $request, $configName)

Resources