Get symfony route from controller action annotations - symfony

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;
}
}

Related

Symdony5.3 - How to pass parameters from a Controller to a Service because the service calls a repo query?

I am working on a project where Symfony serves as API backend (with ApiPlatform) and Angular the Front End and the lead decided we will use Services and to create a function inside called updateData().
In my Service:
public function updateData(array $dates, Hotel $hotel): ?array
{
$bookings= $this->em->getRepository(Booking::class)->findAllByIdAndDate($id, $date);
foreach ($bookings as $booking) {
...
}
...
}
In my controller:
/**
* #Route("/update_data", name="update_data")
*/
public function index(UpdateData $updateData)
{
$this->em = $this->getDoctrine()
->getManager()
->getRepository(Hotel::class);
$date = new \DateTime('2021-06-13');
$id = 1;
$hotel = $this->em->find($id);
$message = $updateData->updateData([$date], $hotel);
}
My question is how can I receive the data here and pass the parameters from this controller to the service?
Thanks
In order to update the data for a specific hotel, you can use url parameters or query parameters to customize your controller.
for example, you could use a URL like this: /update_data/1?date=2021-06-13
Then your code would be using Symfony route parameters and parameter conversion.
Here is a quick example of what this would look like.
/**
* #Route("/update_data/{id<\d+>}", name="update_data")
*/
public function update_data(Hotel $hotel, Request $request): Response
{
// the $hotel variable is autoconverted using parameter conversion
$date = new \DateTime($request->query->get('date'));
$message = $updateData->updateData([$date], $hotel);
// rest of your code.
}

Request-URI Too Long Symfony Controller

I'm trying to get all the errors from all the queries I do in my project and redirect this errors to a controller called "error" that will treat theses errors as I want. The problem looks like when I redirect all the information goes in the url generated by the function via GET.
I suppose that if this information is sent via POST will disappear this problem but I'm not using obviously any form inside the controller. So, how can I say to the redirect function that these information shouldn't go with the url and instead should go via POST?
Is possible what I'm trying to do?
Inside Controllers:
try {
$results = $queries->aQuery();
} catch (ErrorException $errorException) {
return $this->redirect($errorException->redirectResponse);
}
Inside the service query:
public function aQuery(){
$query="SELECT * FROM blabla ...";
try {
$stmt = $this->DB->->prepararQuery($query);
$stmt->execute();
$results = $stmt->fetchAll();
} catch (DBALException $DBALException) {
$errorException = new ErrorException($this->router->generate('error',
[
'errorQuery' => $query,
'errorData' => "0 => '".$data1."', 1 ....",
'errorOrigin' => 'a place',
'errorResponseText' => $DBALException->getMessage()
]
));
throw $errorException;
}
}
The ErrorException:
class ErrorException extends \Exception
{
/**
* #var \Symfony\Component\HttpFoundation\RedirectResponse
*/
public $redirectResponse;
/**
* ErrorException constructor.
* #param \Symfony\Component\HttpFoundation\RedirectResponse $redirectResponse
*/
public function __construct(string $redirectResponse)
{
$this->redirectResponse = $redirectResponse;
}
}
If what you are trying to achieve is a centralized way to handle exceptions have a look at https://symfony.com/doc/4.0/event_dispatcher.html#creating-an-event-listener and use kernel.exception event
public function onKernelException(GetResponseForExceptionEvent $event)
{
if (! $event->getException() instanceof ErrorException) {
return;
}
// handle your custom ErrorException
$response = new Response();
$response->setContent($event->getException()->getMessage());
// sends the modified response object to the event
$event->setResponse($response);
}

Testion controler method in symfony (phpUnit)

i need some help i want to write a unit test about a controler method , i have searched for examples and tested a lot of method's but none of them has worked:
Here is my controller:
class ComputerController extends Controller
{
/**
* #Route("/list-computers.html", name="back_computer_list")
* #return RedirectResponse|Response
*/
function listComputerAction()
{
$ad = $this->get("ldap_service");
$computers = $ad->getAllComputer();
return $this->render('BackBundle:Computer:list.html.twig', array(
"computers" => $computers,
));
}
I have tried to test it with mock like this:
class ComputerController extends Controller
{
/**
* #var EngineInterface
*/
private $templating;
public function setTemplating($templating)
{
$this->templating = $templating;
}
and i have created a test method:
class ComputerControllerTest extends TestCase {
public function testlistComputerAction(){
$templating = $this->getMockBuilder('BackBundle\Controller\ComputerController')->getMock();
$computers = [1,2];
$templating->expects($this->once())
->method('render')
->with('BackBundle:Computer:list.html.twig', array(
"computers" => $computers))
->will($this->returnValue( $computers));
$controller = new ComputerController();
$controller->setTemplating($templating);
$this->assertEquals('success', $controller->listComputerAction());
}
When i start executing phpunit , i have this warning"Trying to configure method "render" which cannot be configured because it does not exist, has not been specified, is final, or is static"
I would be thankful if someone has an idea about this
I tried to Test a method in ldapService : Here is the method's of the service that i want to test
/**
* #return bool|resource
*/
public function getLdapBind()
{
if (!$this->ldapBind) {
if ($this->getLdapConnect()) {
$this->ldapBind = #ldap_bind($this->ldapConnect, $this->ldapUser, $this->ldapPass);
}
}
return $this->ldapBind;
}
/**
* #param $ldapUser
* #param $password
* #return bool
*/
function isAuthorized($ldapUser, $password)
{
$result = false;
if ($this->ldapConnect) {
$result = #ldap_bind($this->ldapConnect, $ldapUser, $password);
}
return $result;
}
Here is the test (using Mock):
<?php
namespace BackBundle\Tests\Service;
use PHPUnit\Framework\TestCase;
use BackBundle\Service\LdapService;
use PHPUnit_Framework_MockObject_InvocationMocker;
class LdapServiceTest extends TestCase {
public function testgetLdapConnect()
{
// $LdapService = new LdapService();
$ldapMock = $this->getMockBuilder( 'LdapService')->setMethods(['getLdapBind'])->disableOriginalConstructor()->getMock();
$ldapMock->expects($this->once())
// ->method()
->with(array('ldap_bind', 'mike', 'password'))
->will($this->returnValue(true));
$ldapMock->isAuthorized('mike', 'password');
}
}
But i have a warning that i can't resolve : "Method name matcher is not defined, cannot define parameter matcher without one"
If someone , has an idea about that please
Honestly, there is nothing useful to test in that three-line controller. #1 is the service container, and #3 is the Twig subsystem. Line #2 can be unit tested on it's own.
With more complex controllers, I have found that making them a service where all the dependencies are passed in, either by constructor, or into the action itself does make slightly more complex controllers quite easy, but very few need that anyway.

How to load 'isSubmitted()-method' (defined in service controller) into the main controller?

I've put a registration form in a method so, that I can use it in different places.
My service registration controller looks like this:
public function loadRegisterForm()
{
$user = new User();
$form = $this->createForm(RegistrationType::class, $user);
$form->handleRequest($this->request);
$errors = "";
if ($form->isSubmitted())
{
if ($form->isValid())
{
$password = $this->get('security.password_encoder')
->encodePassword($user, $user->getPlainPassword());
$user->setPassword($password);
$user->setIsActive(1);
$user->setLastname('none');
$user->setCountry('none');
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
}
else
{
$errors = $this->get('validator')->validate($form);
}
}
$parametersArray['form'] = $form;
$parametersArray['errors'] = $errors;
return $parametersArray;
}
services.yml looks like this:
register_form_service:
class: ImmoBundle\Controller\Security\RegistrationController
calls:
- [setContainer, ["#service_container"]]
And the main controller where I load the service controller:
private function indexAction()
{
/**
* Load register form
*/
$registerForm = $this->get('register_form_service');
$registerParameters = $registerForm->loadRegisterForm();
$registerParameters['form']->handleRequest($request);
return $this->render(
'ImmoBundle::Pages/mainPage.html.twig',
array(
'register_form' => $registerParameters['form']->createView(),
'errors' => $registerParameters['errors'],
)
);
}
The form itself is well rendered, so there is no problem. However nothing happens if I try to submit the form. I know that I should add the following line to the main controller
if ($registerParameters['form']->isSubmitted())
{
// add to db
}
But is there any way to do it only in a service controller?
You do not need a service definition to inject the container into your controller. If the controller extends Symfony\Bundle\FrameworkBundle\Controller\Controller all services are accesible via ->get(). Next to that, $form->isValid() already checks whether the form is submitted.
Why is your action private? It should be public, and it need to get the Request object as it's first parameter:
public function indexAction(Request $request)
{
$user = new User();
$form = $this->createForm(RegistrationType::class, $user);
$form->handleRequest($request);
if ($form->isValid()) {
// Do something here
}
}
See http://symfony.com/doc/current/book/forms.html#handling-form-submissions

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.

Resources