Symfony 2.3: missing _controller attribute in request object of rendered controller - symfony

I have a custom TemplatingProvider Service which I use in my controllers to output the view.
namespace Acme\FrontEndBundle\Templating;
class TemplatingProvider
{
private $templating;
private $request;
function __construct($templating, $request)
{
$this->templating = $templating;
$this->request = $request;
}
function getTemplate($name)
{
$controller = $this->request->attributes->get('_controller');
preg_match('/Controller\\\([a-zA-Z]*)Controller/', $controller, $matches);
$controller = 'AcmeFrontEndBundle:' . $matches[1] . ':';
$template = $controller . $name;
// ...
On a normal request this works fine, but not on subrequest like when I render a controller in a template with twigs render(controller(...)) function.
It seems that $this->request->attributes->get('_controller') is NULL. I understand that for _route since the controller isn't accessed through one but why is _controller not set and how can I get around that?
I know that the use of render(path(...)) in twig would solve this, but this is no option for me, I really need render(controller(...)).
Thanks in advance for any advices.
UPDATE:
Thanks to Vadim Ashikhmans answer I found the solution:
Inject `#service_container into the service and then use the container to get the request and there you have it. But with a little obstacle which i solved in a helper function:
function getController()
{
$controller = $this->container->get('request')->get('_controller');
// on mainrequest (calling the controller through its route)
// $controller follows the namespacelike schema: Vendor\Bundle\Controller\ControllerController:actionAction
preg_match('/Controller\\\([a-zA-Z]*)Controller/', $controller, $matches);
if (isset($matches[1]))
{
$controller = 'AcmeFrontEndBundle:' . $matches[1] . ':';
}
else
{
// on subrequests (e.g. render(controller(...)) in a template)
// $controller looks like Bundle:Controller:action
preg_match('/:([a-zA-Z]*):/', $controller, $matches);
$controller = 'AcmeFrontEndBundle:' . $matches[1] . ':';
}
return $controller;
}
Thanks you very much! :)

I suppose _controller attribute is empty because for every sub requests current request object is duplicated, so in subrequest TemplateProvider tries to operate on old data.
You could try to pass the container to TemplateProvider constructor and retrieve request object in getTemplate method.

Related

Service Uploader Missing Argument Exception

I created an upload service to use it in different controllers in my code.
But i get an exception now like this when i want to access to the page for add a new gig :
Controller
"Booking\RoosterBundle\Controller\ArtistController::addGigAction()"
requires that you provide a value for the "$fileUploader" argument.
Why i'm getting this ? the value should be $file but i need to access to my form first and submit the file ... hope someone could help me. thanks a lot in advance
here is my service :
<?php
namespace Booking\RoosterBundle\Uploader;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class FileUploader
{
private $targetDir;
public function __construct($targetDir)
{
$this->targetDir = $targetDir;
}
public function upload(UploadedFile $file)
{
$fileName = md5(uniqid()).'.'.$file->guessExtension();
$file->move($this->getTargetDir(), $fileName);
return $fileName;
}
public function getTargetDir()
{
return $this->targetDir;
}
}
Here my controller :
public function addGigAction(Request $request , $id , FileUploader $fileUploader ){
...
$gig = new Gig();
$form = $this->createForm(GigType::class, $gig);
if ($request->isMethod('POST') && $form->handleRequest($request)->isValid()) {
$file = $gig->getFlyer();
$fileName = $fileUploader->upload($file);
$gig->setFlyer($fileName);
$em->persist($gig);
$em->flush();
...
}
And here my service declaration in my bundle
booking_rooster.uploader:
class: Booking\RoosterBundle\Uploader\FileUploader
arguments:
$targetDir: '%upload_directory%'
This is not how you call a service !
Don't pass it as argument , call it like this :
$container->get('booking_rooster.uploader');

Get symfony route from controller action annotations

I have a controller action like this:
/**
* #Route("/post/delete/{id}", name="delete_post_modal")
*/
public function deleteAction(Post $post)
{
// ...
}
The annotation #Route tells symfony to execute method deleteAction when route matches delete_post_modal.
All of this works fine.
Question: Is there a way to reverse this functionality and get the route name from method name?
From the example above:
I have: PostController::deleteAction() (or self::deleteAction)
I need to get: delete_post_modal
thanks!
try this
update
$router = $this->container->get('router');
foreach ($router->getRouteCollection()->all() as $route => $params)
{
$defaults = $params->getDefaults();
if ( strpos($defaults['_controller'],'PostController::deleteAction') ) {
$myroute = $route;
break;
}
}

Symfony2 REST Translation from database

I am facing very difficult problem to handle my situation. Im saving title in database for en the name is title and for the translation column the name is bntitle.
now im use FosRest with jms serializer to provide the api response. but i can't find a way to send respond based on local. because it always calls the
getTitle()
method to get the title, my question is if local is en then the title key will be getTitle() if local is bn title should call getBnTitle();
this the controller:
public function getAction(Content $entity, Request $request)
{
$locale = $request->getLocale();
$data = array();
$data['_embedded']['content'] = $entity;
eturn $data;
}
how can I do that?
This is not the best way to handle the translation for sure but if you just need this for the title attribute you can pass the local to the entity as an argument and then in getTitle() method you do the test.
public class YourEntity{
private $locale ;
//......
public function setLocale($locale){
$this->locale = $locale
}
public function getTitle(){
// your test here
if ( $locale === 'bn' ) return $this->getBnTitle();
return $title ;
}
Then in your controller :
public function getAction(Content $entity, Request $request)
{
$locale = $request->getLocale();
// pass local to entity
$entity->setLocale($locale);
$data = array();
$data['_embedded']['content'] = $entity;
eturn $data;
}
Edit :
If you want a better solution there is many doctrine extensions that do the translation one of them is this
https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/translatable.md

Doctrine2 Filter Parameter empty value twig extensions

In my application a company has their own subdomain. Im listening to kernel request event and setting the Company Filter(Doctrine Filter) parameter based on the company matching the subdomain.
public function setCompanyFilter($companyId)
{
/** #var EntityManager $entityManager */
$entityManager = $this->container->get('doctrine')->getManager();
$filters = $entityManager->getFilters();
$companyFilter = $filters->isEnabled('company_filter')
? $filters->getFilter('company_filter')
: $filters->enable('company_filter');
$companyFilter->setParameter('company', $companyId);
}
The issue im having is that on twig extensions(filter/functions) the parameter is not setted. If i set the value before execute a filter/function everything works as expected.
Is there any way to execute some code before every twig filter/function/tag? Like listening to an twig event? Or how can i solve this issue without calling the setCompanyFilter on every twig filter/function/tag.
Thanks
Why not set the custom value in the same event (i.e. kernel.request) that you are already listening to?
I assume you are using a custom twig extension. If not extend the filter/function you are already using and do the same:
<?php
// src/AppBundle/Twig/AppExtension.php
namespace AppBundle\Twig;
class AppExtension extends \Twig_Extension
{
private $customParameter;
public function getFilters()
{
return array(
new \Twig_SimpleFilter('price', array($this, 'priceFilter')),
);
}
public function priceFilter($number, $decimals = 0, $decPoint = '.', $thousandsSep = ',')
{
$price = number_format($number, $decimals, $decPoint, $thousandsSep);
$price = '$'.$price;
return $price;
}
public function getName()
{
return 'app_extension';
}
public function setCustomParameter($parameter)
{
$this->customParameter = $parameter;
}
}
Inject the twig extension into your current listener and then call the method setCustomParameter, inject your custom parameter for use later in the request lifecycle, and then just call the filter/function as your normally would in your existing twig template.

How to set a header and render a twig template without renderView() method in symfony2.X controller

How would one go about setting a header (Content Type) and rendering a twig template without renderView() method in symfony2.X controller?
I'm not sure if the accepted answer is valid anymore, or if ever was. Anyhow, here's a couple ways of doing it. I've got an XML, and JSON sample for you here.
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
class DefaultController extends Controller{
public function indexAction($x = 0)
{
$response = new Response(
$this->renderView('AcmeMyBundle:Default:index.html.twig', array('x'=>$x)),
200
);
$response->headers->set('Content-Type', 'text/xml');
return $response;
}
//...
or for JSON response
//...
public function indexAction( $x = 0 )
{
$response = new JsonResponse(
array('x'=>$x)
);
return $response;
}
You can do it returning the response as rendered view (check this sample)
public function indexAction()
{
// a parameter which needs to be set in twig
$variable = 'This is sample assignment';
$current_user = $this->user; // assume you defined a private variable in your class which contains the current user object
$response = new Response(
'AcmeMyBundle:Default:myTemplate.html.twig',
['parameter1' => $variable],
['user' => $current_user]
);
return $response;
}
If your response has a specific header info you can easily set by $response->header->set(...);

Resources