Call custom function of controller from ajax symfony2 - symfony

I've created the forms using Sonata Admin Bundle. Then I've created my own Controller (TestController) and override the CRUD controller,
I've added a new function in the TestController,
namespace IFI2\MainProjectBundle\Controller;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Bridge\Monolog\Logger;
use Sonata\AdminBundle\Controller\CRUDController as Controller;
//use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class TestController extends Controller
{
public function getProductPricesAction() {
file_put_contents("/Applications/XAMPP/htdocs/IFI2 CMS/Logs.txt","HELO",FILE_APPEND);
return new Response(json_encode($response));
}
}
Then I'm trying to access this function via my javascript Code,
<script type="text/javascript">
function test1() {
$.ajax({
type:"POST",
//dataType: "json",
url: '{{ path('main_project.admin.test')}}',
success: function(successMsg) {
alert("successMsg");
},
error: function(errorMsg) {
alert("errorMsg");
}
});
}
</script>
Here's my routing.yml,
main_project.admin.test:
pattern: /getProductPrices/
defaults: { _controller: IFI2MainProjectBundle:Test:getProductPrices}
I've already had services.yml entry for this entity,
main_project.admin.cobrand:
class: MainProjectBundle\Admin\TestAdmin
arguments: [~, MainProjectBundle\Entity\Test, "MainProjectBundle:Test"]
tags:
- {name: sonata.admin, manager_type: orm, group: admin, label: Test}
calls:
- [setTemplate, [edit, MainProjectBundle:Test:edit.html.twig]]
I'm getting the following error in my response,
There is no _sonata_admin defined for the controller MainProjectBundle\Controller\TestController and the current route main_project.admin.test
Kindly, help me how to embed it ?
Thanks,
Faisal Nasir

Add new route in your Admin method configureRoutes
protected function configureRoutes(RouteCollection $collection)
{
parent::configureRoutes($collection);
$collection->add('get_product_prices');
}
Remove your route main_project.admin.test
New route has $baseRouteName from your admin as prefix and has name:
base_route_name_get_product_prices
using
{{ path('base_route_name_get_product_prices') }}
//or with admin
{{ admin.generateUrl('get_product_prices') }}

In routing.yml add the following:
main_project.admin.test:
pattern: /getProductPrices/
defaults: { _controller: IFI2MainProjectBundle:Test:getProductPrices,"_sonata_admin": "main_project.admin.cobrand" }

Related

Two Routes for one Controller OR Two Routes for a group of actions

Here is the scheme of the required URLs:
/service/getBalance should map to CustomerController::getBalance
/service/addBalance should map to CustomerController::addBalance
/customer/getBalance should map to CustomerController::getBalance
/customer/addBalance should map to CustomerController::addBalance
Here is a simple controller
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class CustomerController extends Controller {
/**
* #Route("/getBalance")
*/
public function getBalanceAction(Request $request) {
}
/**
* #Route("/addBalance")
*/
public function addBalanceAction(Request $request) {
}
} // class CustomerController
Have tried the following ways. None of them worked.
# rounting.yml
v1:
resource: "#AppBundle/Controller/CustomerController.php"
prefix: /service
type: annotation
v2:
resource: "#AppBundle/Controller/CustomerController.php"
prefix: /customer
type: annotation
loading the same resource with different prefix always overrides the previous occurrence (the last one works). The following also doesn't work for the same reason and have the same behavior.
# rounting.yml
v1:
resource: "#AppBundle/Resources/config/routing_customer.yml"
prefix: /service
v2:
resource: "#AppBundle/Resources/config/routing_customer.yml"
prefix: /customer
# routing_customer.yml
getBalance:
path: /getBalance
defaults : { _controller: "AppBundle:Customer:getBalance" }
addBalance:
path: /addBalance
defaults : { _controller: "AppBundle:Customer:addBalance" }
Third not working option:
# rounting.yml
v1:
resource: "#AppBundle/Resources/config/routing_v1.yml"
prefix: / # evenr putting /service here instead of inside
v2:
resource: "#AppBundle/Resources/config/routing_v2.yml"
prefix: / # evenr putting /customer here instead of inside
# routing_v1.yml
getBalance:
path: /service/getBalance
defaults : { _controller: "AppBundle:Customer:getBalance" }
addBalance:
path: /service/addBalance
defaults : { _controller: "AppBundle:Customer:addBalance" }
# routing_v2.yml
getBalance:
path: /customer/getBalance
defaults : { _controller: "AppBundle:Customer:getBalance" }
addBalance:
path: /customer/addBalance
defaults : { _controller: "AppBundle:Customer:addBalance" }
I actually need to route / and /customer to the same controller:
/getBalance and /customer/getBalance.
I want to give two prefixes for a group of methods. How to do that in Symfony?
Conclusion from my trials, #goto's answer and #Cerad's comments:
The last Example above could have worked if I used different route names. Route names are unique though out the whole project (Not just unique in file). v1_getBalance and v2_getBalance.
The other solution is to use a custom loader as #goto described.
You could do routes this way:
#Route(
"/{subject}/getBalance",
requirements={
"subject": "customer|service"
}
)
in yml:
subject_getbalance:
path: /{subject}/getBalance
requirements:
subject: customer|service
The requirement is safer than nothing: it allows you to route another route like foo/getBalance on another controller (as it does not match the requirement)
EDIT: for your special case, as you need /getBalance to map to your route too you could do:
subject_getbalance:
path: /{subject}/getBalance
default: { _controller: YourBundle:Controller }
requirements:
subject: customer|service
default_getbalance:
path: /getBalance
default: { _controller: YourBundle:Controller, subject: customer }
Edit: the last idea is to a custom route loader (but I've never tried):
class ExtraLoader extends Loader
{
public function load($resource, $type = null)
{
/* ... */
$prefixes = [ 'default_' =>'','customer_' =>'/customer','service_' =>'/service']
// prepare a new route
$path = '/getbalance/{parameter}';
$defaults = array(
'_controller' => 'YourBundle:Actiona',
);
$requirements = array(
'parameter' => '\d+',
);
foreach($prefixes as $prefixName => $prefixRoute) {
$route = new Route($prefixRoute . $path, $defaults, $requirements);
$routes->add($prefixName . 'getBalance', $route);
}
This will allows you to have 3 routes generated:
default_getBalance: /getBalance
customer_getBalance: /customer/getBalance
service_getBalance: /service/getBalance

prefix sylius product show url with locale

I am using sylius v0.18. I want to prefix locale with product show urls.
sylius_core:
routing:
%sylius.model.product.class%:
field: slug
prefix: /p
defaults:
controller: sylius.controller.product:detailsAction
repository: sylius.repository.product
sylius:
template: SyliusWebBundle:Frontend/Product:show.html.twig
criteria: {slug: $slug}
permission: false
I can use a static word as the prefix in this configuration. but It does not work with _locale. prefix: /{_locale}/p
I found a solution, by overiding getRouteCollectionForRequest method in Sylius\Bundle\CoreBundle\Routing\RouteProvider class with the following configuration.
sylius_core:
routing:
%sylius.model.product.class%:
field: slug
prefix: /{_locale}/p
defaults:
controller: sylius.controller.product:detailsAction
repository: sylius.repository.product
sylius:
template: SyliusWebBundle:Frontend/Product:show.html.twig
criteria: {slug: $slug}
permission: false
parameters:
sylius.route_provider.class: App\AppBundle\Routing\Provider\RouteProvider
class RouteProvider extends BaseProvider
{
/**
* {#inheritdoc}
*/
public function getRouteCollectionForRequest(Request $request)
{
//Overide this method to match the url with _locale
}

MonologBundle FingerCrossedHandler: how to configure excluded_404s

I'm working on a Symfony 2.8.6 application and I tried to configure my Monolog as described here and here.
This is my Monolog config (bundle version 2.11.1):
monolog:
handlers:
main_critical:
type: fingers_crossed
action_level: error
handler: grouped
channels: ["!doctrine", "!event", "!php"]
excluded_404s:
- ^/
grouped:
type: group
members: [streamed, crash, buffered]
streamed:
type: rotating_file
max_files: 10
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: notice
crash:
type: rotating_file
max_files: 10
path: "%kernel.logs_dir%/%kernel.environment%.critical.log"
level: critical
buffered:
type: buffer
handler: swift
swift:
type: swift_mailer
from_email: noreply#xxxxxxx.com
to_email: user#xxxxx.com
subject: "[App] - Errore %kernel.environment%"
level: error
Monolog logs every 404 error, also missing assets like css and js.
How can avoid this?
Where I'm wrong?
Maybe the problem is related with my ExceptionListener?
/**
* #param GetResponseForExceptionEvent $event
*/
public function onKernelException(GetResponseForExceptionEvent $event)
{
//The logger object is my logger
$this->logger->log($event->getException(), $event->getRequest());
if (!$event->getRequest()->isXmlHttpRequest()) {
return;
}
$event->setResponse(new JsonResponse('message' => 'Ops. Houston we have a problem.'));
}
Thank you.
I post how I resolved. The problem isn't related with Monolog, but with my logger service.
Because I wrapped how to log exceptions, before I didn't pass the exception when I call
$logger->error('message error');
So when Monolog tries to enable the NotFoundActivationStrategy (file is located in /vendor/symfony/monolog-bundle/NotFoundActivationStrategy.php), this check fails:
public function isHandlerActivated(array $record)
{
$isActivated = parent::isHandlerActivated($record);
if (
$isActivated
&& $this->request
&& isset($record['context']['exception'])
&& $record['context']['exception'] instanceof HttpException
&& $record['context']['exception']->getStatusCode() == 404
) {
//blacklist is the pattern that you can set on config.yml at excluded_404s node
return !preg_match($this->blacklist, $this->request->getPathInfo());
}
return $isActivated;
}
So I resolved with
$this->logger->error('message', array('exception' => $exception));
Hope this helps someone.
You can filter errors in onKernelException method. See example below:
<?php
namespace AppBundle\Listener;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class AppExceptionListener
{
private $logger;
public function __construct($logger)
{
$this->logger = $logger;
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
if(!$exception instanceof NotFoundHttpException)
{
$this->logger->info('Error');
}
}
}

Gedmo\Translatable ignoring default locale that is set in config

I've decided to install "gedmo/doctrine-extensions" on Symfony to use Translatable.
It works fine, except that listener is ignoring default locale I've specified, always falling back to en_US.
Translatable is plugged in as service:
#config.yml
services:
gedmo.listener.translatable:
class: Gedmo\Translatable\TranslatableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ #annotation_reader ] ]
- [ setDefaultLocale, [ ru ] ]
- [ setTranslationFallback, [ true ] ]
And when I try to find() object in database it always fetches en_US instead of ru:
$test = $em->find('Vendor\Entity\Test', 1);
//outputs row with 'locale' = "en_US" from `ext_translations_test` table
Only if I specify language directly, like:
$test->setTranslatableLocale('ru');
$em->refresh($test);
It gives desired translation.
Is there any way to set default locale that will work?
UPDATE
Adding another call function in config.yml fixed the problem, altough now I'm not quite sure what setDefaultLocale() function actually does, as Gedmo\Translatable\TranslatableListener::$defaultLocale property provided with a most horrid commentary I've ever seen. Will try to find more...
services:
gedmo.listener.translatable:
class: Gedmo\Translatable\TranslatableListener
tags:
- { name: doctrine.event_subscriber, connection: default }
calls:
- [ setAnnotationReader, [ #annotation_reader ] ]
- [ setDefaultLocale, [ ru ] ]
- [ setTranslatableLocale, [ ru ] ]
- [ setTranslationFallback, [ true ] ]
According to: https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/symfony2.md
Note: if you noticed, there's Acme\DemoBundle\Listener\DoctrineExtensionListener you will need to create this listener class if you use loggable or translatable behaviors. This listener will set the locale used from request and username to loggable. So, to finish the setup create Acme\DemoBundle\Listener\DoctrineExtensionListener
Make sure you have setup the kernel listener as well.
namespace Acme\DemoBundle\Listener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class DoctrineExtensionListener implements ContainerAwareInterface
{
/**
* #var ContainerInterface
*/
protected $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
public function onLateKernelRequest(GetResponseEvent $event)
{
$translatable = $this->container->get('gedmo.listener.translatable');
$translatable->setTranslatableLocale($event->getRequest()->getLocale());
}
public function onKernelRequest(GetResponseEvent $event)
{
$securityContext = $this->container->get('security.context', ContainerInterface::NULL_ON_INVALID_REFERENCE);
if (null !== $securityContext && null !== $securityContext->getToken() && $securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
$loggable = $this->container->get('gedmo.listener.loggable');
$loggable->setUsername($securityContext->getToken()->getUsername());
}
}
}
And add the following to your config file:
services:
extension.listener:
class: Acme\DemoBundle\Listener\DoctrineExtensionListener
calls:
- [ setContainer, [ #service_container ] ]
tags:
# translatable sets locale after router processing
- { name: kernel.event_listener, event: kernel.request, method: onLateKernelRequest, priority: -10 }
# loggable hooks user username if one is in security context
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }

How to declare both method in routing.yml Symfony2?

I want to declare both methods GET and POST for a same route in my routing.yml.
According the documentation it's possible with annotations like that :
/**
* #Route("/edit/{id}")
* #Method({"GET", "POST"})
*/
But how to YAML ? I tried different things :
contact_envoi:
pattern: /contact-envoi
defaults: { _controller: AcmeDemoBundle:Default:contactEnvoi }
requirements:
sf_method: ['get','post']
and
...
requirements:
_method: { 'GET', 'POST' }
but it still doesn't work ... Please help, I found nothing in the documentation about that.
Thanks to Touki for his comment, it works!
I had to declare twice the same URL on two separate shares and each with their own method as explained here for Symfony 2.1 and here for Symfony 2.2.
contact:
path: /contact
defaults: { _controller: AcmeDemoBundle:Main:contact }
methods: [GET]
contact_process:
path: /contact
defaults: { _controller: AcmeDemoBundle:Main:contactProcess }
methods: [POST]
You can get the same route with the GET and POST methods.
contact:
path: /contact
defaults: { _controller: AcmeDemoBundle:Main:contact }
methods: ['GET','POST']
Then manage in your controller the method used.
public function contactAction(Request $request)
{
if ('POST' === $request->getMethod()) {
..
}
}
just remove the methods
contact:
path: /contact
defaults: { _controller: AcmeDemoBundle:Main:contact }

Resources