How to return Javascript in Symfony2? - symfony

Like on Ruby on Rails, you can return Javascript with some prerendering to dynamically update the client site through AJAX.
How do you return Javascript when calling some routes in Symfony2?
For example, when calling updateItemAppearanceAction through \item\{itemId}\update_appearance, return Javascript file updateItemAppearance.js.twig, with array("item"->$item)?
Thank you very much!

Within the action method called updateItemAppearanceAction:
Create a Rendered view
Instantiate a Response object, passing the rendered view in the Constructor.
Set the Content-Type in the Response Header of the Response Object's instance to text/javascript.
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
// example controller.
class DefaultController extends Controller
{
/**
* #Route("/updateItemAppearance.js", name="default_update_item_appearance_js")
*/
public function updateItemAppearanceAction()
{
$optionalParams = array('some'=>'param');
$renderedView = $this->renderView('AppBundle:Default:updateItemAppearance.js.twig'); // 1.
$response = new Response($renderedView, $optionalParams)); // 2.
$response->headers->set('Content-Type','text/javascript'); // 3.
return $response;
}
}
As a result, the javascript you write in updateItemAppearance.js.twig file can be embedded as a javascript file via the usual means.
<script src="/updateItemAppearance.js"></script>
Or using the twig path helper.
<script src="{{ path('default_update_item_appearance_js') }}"></script>

Well if you want to return data for your javascript you could do this in your "updateItemAppearance.js.twig"
var javascriptVar = "{{twigVar|json_encode()|raw('js')}}";
If you're using the JMSSerializer you could do
var javascriptVar = "{{twigVar|serialize('json')|raw('js') }}";
More info: twig docs, jms serializer docs

Related

What should be edited in routing.yml in symfony 3 to create a new route from annotation?

I am quite new to Symfony 3. I created the controller files in the AppBundle itself. No new bundle created. Now I am trying to route a new page and it gives an error. This is what I did.
In src\AppBundle\Controller\Patient\PatientController.php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
class DefaultController extends Controller
{
/**
* #Route("/patient", name="patient_homepage")
*/
public function patientHomeAction(Request $request)
{
// replace this example code with whatever you need
return $this->render('Patient/home.html.twig', array()
);
}
In the app\Resources\views\base.html.twig
Home
This gives an error as
"An exception has been thrown during the rendering of a template
("Unable to generate a URL for the named route "patient_homepage" as
such route does not exist.") in base.html.twig at line 118."
Do I need to do any changes in the app\config\routing.yml also? What am I missing here.
Try this
app:
resource: "#AppBundle/Controller/"
type: annotation
You have to enable route in app/config/routing.yml
app:
resource: "#AppBundle/Controller/Patient/"
type: annotation

Symfony2, how to render controller's action in a twig template if controller has a constructor

From the official documentation (http://symfony.com/doc/current/quick_tour/the_view.html#embedding-other-controllers) I learned how to embed a Controller in a Twig template.
The problem appears when the Controller has injected properties. Is there a way to use Twig's render(controller()) function with Controllers that have a constructor?
When I try following:
{{ render(controller(
'SomeBundle:Some:renderList',
{ 'request': app.request }
)) }}
I get this error:
Missing argument 1 for SomeBundle\Controller\SomeController::__construct()
Constructor for this Controller look like that:
public function __construct($container, SomeService $someService) {
parent::__construct($container);
$this->someService = $someService;
}
Injection of the container and someService is configured in service.yml.
So again, my question is: how to embed controller in Twig's template when this controller uses Dependency Injection?
UPDATE
I could do like so:
{{ render(app.request.baseUrl ~ '/some/route') }}
But I would like to avoid making routes.
UPDATE 2
Service definition from service.yml
some.controller:
class: SomeBundle\Controller\SomeController
arguments: ["#service_container", "#some.service"]
If you have defined your controller as a service, you need to "inject" it into twig in order to make it available and correctly instantiated.
I suggest to create twig global variable
#app/config/config.yml
twig:
globals:
cc: "#comparison.controller"
Then you can use one of the methods (actions?)
{{ cc.foo(aBarVariable) }}
Alternative answer
You could create a twig extension where you could inject your service in order to make it available for views
For controllers as service you just need to use the service name (#some.controller) and action (yourAction) rather than the controller shortcut (SomeBundle:Some:renderList) as you can see in the Sylius templates.
So it would be...
{{ render(controller('some.controller:yourAction')) }}
If you are Symfony 2.4+ you can make use of the request_stack to get the request rather than passing it in as an argument like..
$request = $this->container->get('request_stack')->getMasterRequest();

How to get route from twig extension class

class AdminExtension extends \Twig_Extension
{
// content...
}
I'm extending twig functionality by adding a class that adds new twig method. Inside this method I want to use current route. How can I do that?
I mean, for example, having:
www.someurl.com/prefix/controller1/aaa/bbb/ccc/ddd
I want to get controller1/aaa/bbb/ccc/ddd part inside the function I described.
Thanks!
You should register the extension as a service and then inject request_stack (as of Symfony 2.4) in the service:
my_extension:
class: ...
arguments: ["#request_stack"]
tags: [{ name: twig.extension }]
Then you can get the request by using RequestStack#getCurrentRequest() and you can get the current url by using Request#getUri().

symfony2: define several php constants in bundle

I need defined several PHP constants and i need use this constants in my bundle (controller, custom classes, entities..) Where best place to add this constants, that would be convenient for them to get?
Why not just create a class to store your constants and use the use statement to autoload it where needed?
Define your constants...
namespace My\CoolBundle\Constants;
class ConstantlyCool {
const DEFAULT_COOLNESS_LEVEL = "newbie";
const MAX_COOLNESS_LEVEL = "phpisuber01";
}
Now use them...
namespace My\CoolBundle\Controller;
use My\CoolBundle\Constants\ConstantlyCool;
class CoolController extends Controller {
public function awesomeAction() {
// Do cool stuff
$cool_level = ConstantlyCool::DEFAULT_COOLNESS_LEVEL;
return new Response(/* blah blah */);
}
}
The best solution for my is setting these constants in Bundle Class, like that:
<?php
namespace AppBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle
{
const SITE_NAME = 'Watchdev AR';
}
And use twig functions constant http://twig.sensiolabs.org/doc/functions/constant.html invoke them
In whatever twig file:
{{ constant('AppBundle\\AppBundle::SITE_NAME') }}
I think this solution follow the best practices that Symfony (without entity in this case) http://symfony.com/doc/current/best_practices/configuration.html
class sample
{const TEST_NUM= 10;}

What is the best way to translate JavaScript literal strings in Assetic assets?

I'm using Symfony2 to develop a application that is to be translatable. The application has Assetic enabled to minify and combine *.js and *.css files. However, I have a jQuery plugin I wrote, that has literal strings in it. For example, consider the following code:
$('<p>Are you sure you want to proceed?</p>').dialog({
buttons: {
"Yes" : function() {
// ...
},
"No" : function() {
// ...
}
}
});
In the above snippet, "Are you sure...", "Yes" and "No" will always be English, and I can't use Twig templating in the .js file to translate it using something like: {{ "yes"|trans }}
What I want to know is, what would be the best way to use Twig to leverage the built in Symfony2 translation mechanism, to translate the literal strings in my JS scripts.
Is there a way to create for example: myscript.js.twig files?
Is there a way to create for example: myscript.js.twig files?
It seems a bad idea.
You can check https://github.com/willdurand/BazingaExposeTranslationBundle
or create it yourself, for example include this in your template:
<script type="text/javascript">
var translations = {
// ...
'yes' : {{ 'yes' | trans }},
// ...
}
</script>
then if your javascript file is included just before </body> you can use translations variable in it.
Here is my solution (Tested on Symfony 4 and 5):
First, we create a controller that will create JS file with all translations according to the current variable locale:
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Yaml\Yaml;
/**
* Translation controller.
*/
class TranslationController extends AbstractController
{
/**
* #Route("/translation.js", name="translation")
*/
public function index(Request $request)
{
$locale = $request->getLocale();
$file = __DIR__.'/../../translations/messages.'.$locale.'.yaml';
$parsed = Yaml::parse(file_get_contents($file));
$translations = $this->renderView(
'translation/translation.js.twig',
array(
'json' => json_encode($parsed)
)
);
return new Response($translations, 200,
array('Content-Type' => 'text/javascript')
);
}
}
Then we create a TWIG template to render (/templates/translation/translation.js.twig):
var trans = JSON.parse('{{ json|raw }}');
We place our dynamic translation file in the template before other assets:
<script src="{{ path('translation') }}"></script>
For sample translation file /translations/messages.pl.yaml:
projects: Projekty
medium: Średnio
month:
january: Styczeń
february: Luty
We can display our translation in any JS file:
console.log(trans['month']['january']);
console.log(trans['medium']);
I hope it will be useful to someone
I was searching something to make twig.js work with translations which seems to me like the best solution. Still searching though.
In the meantime, I'm using this jsgettext which is a gettext implementation in Javascript, by Joshua I. Miller. I've uploaded back to github since the original repo is down.
<script language="javascript" src="/path/LC_MESSAGES/myDomain.json"></script>
<script language="javascript" src="/path/Gettext.js"></script>
You load your translation files into your DOM and jsgettext can parse it:
function _(msgid) { return gt.gettext(msgid); }
alert(_("some string"));
To get the path of your translation files from Symfony, you'll have to make some php/twig extension around the Translator service but it works great without duplicating your translation resources.

Resources