I want to have a URL that returns a simple JSON object. I am trying to use Twig to generate the JSON object:
{
"urls": [
{% for child in page.root %}
"{{ child.url }}"{% if not loop.last %},{% endif %}
{% endfor %}
]
}
The carriage returns will not remain in place though, and I keep getting a result that looks like this:
{'urls':['../ants/','../brick-report/','../the-pollution-intervention/','../barclay/','../broken-advertising/','../aldat-n-densom/','../thisisart/','../there-she-goes-again/']}
which Jquery will not parse with it's ajax or getJSON methods. It's totally ignoring this JSON. How might I convince Twig to put the right whitespace in place? I've looked at the manual and it only seems concerned with NOT inserting whitespace.
This works for me (twig template):
var parsedJSON = JSON.parse('{{ ['one', 'two', 'three']|json_encode|e('js') }}');
And this:
console.log(parsedJSON);
outputs:
Array ["one", "two", "three"]
in browser's console.
Twig has a filter for this.
json_encode, it uses PHP json_encode function.
for your case:
{{ {'urls': page.root}|json_encode }}
will output
{"urls":["..\/ants\/","..\/brick-report\/","..\/the-pollution-intervention\/","..\/barclay\/","..\/broken-advertising\/","..\/aldat-n-densom\/","..\/thisisart\/","..\/there-she-goes-again\/"]}
the code is tested and works. For more information take a look at the Twig Documentation for json_encode.
Generally it would make more sense to make controller return json directly, by returning JsonRespnse object
But if you really need to output JSON in Twig and assign it to variable, you can also use:
let foo = {{ bar|json_encode|raw }}
Don't use Twig to generate your json response.
In your controller, use:
return new Response(json_encode($var));
Sample:
public function sampleAction()
{
$urls = array('../test', '../something', '../sample');
return new Response(json_encode($var));
}
If URLs are generated from Symfony2 routes, you can use:
public function sampleAction()
{
$urls = array(
$this->generateUrl('my_test'),
$this->generateUrl('my_something'),
$this->generateUrl('my_sample'),
);
return new Response(json_encode($var));
}
Try wrapping your template in an autoescape block:
{% autoescape 'js' %}
{ "href": "{{ my_url }}" }
{% endautoescape%}
Thats easy if you extend twig.
First, create a class that will contain the extension:
<?php
namespace Acme\DemoBundle\Twig\Extension;
use Symfony\Component\DependencyInjection\ContainerInterface;
use \Twig_Extension;
class VarsExtension extends Twig_Extension
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getName()
{
return 'some.extension';
}
public function getFilters() {
return array(
'json_decode' => new \Twig_Filter_Method($this, 'jsonDecode'),
);
}
public function jsonDecode($str) {
return json_decode($str);
}
}
Basically the $.getJson() method requires json but ther is a string
so you can use $.get() to get the response and use the parser to parse the string to JSON
$.get("ffff",function(data){
// user parser
JSON.parse();
});
Related
I have a PHP code to add a new class for my Twig template in my common controller in: "opencart\htdocs\catalog\controller\common\cart.php"
The code should check if the Device is Mobile or not.
function onStart()
{
// Anonymous Class only working on PHP7
$this['code'] = new class {
public function MobileDetect() {
return preg_match("/(android|avantgo|blackberry|bolt|boost|cricket|docomo
|fone|hiptop|mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i"
, $_SERVER["HTTP_USER_AGENT"]);
}
};
}
But now I don´t know how to address that function correctly from my twig side at:
opencart\htdocs\catalog\view\theme\default\template\common\cart.twig
I tried something like this, but it didn´t seem to work:
{% if code.MobileDetect() is defined %}
If a device is mobile I want to use a completely different HTML construct.
What you need to do is create your own Twig function:
https://twig.symfony.com/doc/3.x/advanced.html#functions
So using their examples you should be able to do something like
$function = new \Twig\TwigFunction('MobileDetect', function () {
return preg_match("/(android|avantgo|blackberry|bolt|boost|cricket|docomo
|fone|hiptop|mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i"
, $_SERVER["HTTP_USER_AGENT"]);
});
$twig->addFunction($filter);
Then call it like
{% if MobileDetect() %}
Page code:
{% partial 'content/main' %}
Partial:
[services]
{% component 'services' %}
Component:
public function prepareVars()
{
$this->page['servicesList'] = $this->getProperty(); // function returns 123
}
Component template:
{{ servicesList }} //does not display anything =(
Why is not the variable being passed?
Hmm seems something odd, not sure about your onRun method in component
prepareVars will not call automatically we need to call it manually.
did you add prepareVars inside onRun as when page life-cycle called , onRun is called automatically so we need to add prepareVars there as well, so its code get executed.
public function onRun()
{
$this->prepareVars();
}
public function prepareVars()
{
$this->page['servicesList'] = $this->getProperty(); // function returns 123
}
if you are already doing this then please notify it in comment so we can look further.
Is there any way to use something like this?
$foo = "{{ object|filter }}";
Because I'm trying to write a dynamic image converter that needs to output something like the example, but when in my twig I use {{ foo }}, it just outputs a raw string {{ object|filter }} instead of executhing the filter on the object as intended.
I've tried to use {{ foo | raw }} but same result.
What I'm trying to do exactly
CONTROLLER
$image = $em->getRepository('AcmeDemo:Media')->find($id);
$image_src = sprintf("{{ %s | imagine_filter('%s') }}", $image->getWebPath(), 'front_small');
return $this->render('image.html.twig', array(
'image_src' => $image_src
));
TWIG
<img src="{{ image_src }}"/>
So, I have a twig function inside a PHP variable $image_src, that Twig function could be, once formatted with sprintf {{ '/uploads/foo.jpg' | imagine_filter('front_small') }}.
That is a string for now, because it's inside a php variable $image_src, that variable is sent to my Twig template with the name image_src so, for now it is a string as I've said, if I do
My variable contains "{{ image_src }}" It will output a string that says:
My variable contains "{{ '/uploads/foo.jpg' | imagine_filter('front_small') }}"
Because, as I've said, image_src is just a string, but I want to acutally execute inside my Twig, the string that contains image_src, because yes, it is a string (to the eyes of the compiler) but we all know it is or it is pretended to be a Twig function (because of the syntax).
So, why | raw will not work?, because it is inteded to be used with strings containing HTML code, if it were HTML syntax it would work, but it's a Twig syntax, so It doesn't work.
Resuming, there should be a | compile twig function that executes Twig code inside a variable like | raw does with HTML, but, as this function doesn't exists, I'm wondering if there's a way to achieve it...
As #joshua said, it's like a Javascript eval.
I hope I've explained good what is the problem and what I need.
EDIT
I've used my own twig extension Compile in order to achieve what I needed.
class CompileExtension extends \Twig_Extension
{
public function getFilters()
{
return array(
'compile' => new \Twig_Filter_Method($this, 'compile', array(
'needs_environment' => true,
'needs_context' => true,
'is_safe' => array('compile' => true)
)),
);
}
public function compile(\Twig_Environment $environment, $context, $string)
{
$loader = $environment->getLoader();
$compiled = $this->compileString($environment, $context, $string);
$environment->setLoader($loader);
return $compiled;
}
public function compileString(\Twig_Environment $environment, $context, $string)
{
$environment->setLoader(new \Twig_Loader_String());
return $environment->render($string, $context);
}
public function getName()
{
return 'compile';
}
}
UPDATE
Accepting #Benjamin Paap answer because it does exactly what I wanted in this case with better code, but my custom Twig class works for every situation.
What you want to do is not possible in twig without a TwigExtension which renders your string separately.
But looking at your code you're trying to use the LiipImagineBundle the wrong way. It seems tempting to use it this way, but the correct way to generate a url for your thumbnails would be this:
class MyController extends Controller
{
public function indexAction()
{
// RedirectResponse object
$imagemanagerResponse = $this->container
->get('liip_imagine.controller')
->filterAction(
$this->request, // http request
'uploads/foo.jpg', // original image you want to apply a filter to
'my_thumb' // filter defined in config.yml
);
// string to put directly in the "src" of the tag <img>
$cacheManager = $this->container->get('liip_imagine.cache.manager');
$srcPath = $cacheManager->getBrowserPath('uploads/foo.jpg', 'my_thumb');
// ..
}
}
https://github.com/liip/LiipImagineBundle#using-the-controller-as-a-service
I'm using OctoberCms and trying to return a page content from an ajax request. For example, when clicking some internal link, i want to get from ajax the page object like the twig {% page %}.
public function onInternalLink(){
$href = post('href');
return [
'title'=>'', //here i want {{ page.title }}
'content' => '', //and here {% page %} like this variable in layout.
];
}
}
my js code is
$.request('onInternalLink', {
data: {href: u}, // var u is the requested url to return
success: function() {
console.log('Almost october');
}
})
}
I tried to create new CmsObject and try to use parseMarkup() method, and try pageCycle() with no success.
I didn't find a way to get the {% page %} object from the php script, is there way to do something like this?
in your PHP, you can use $this->page to access the current page. So your php would become:
public function onInternalLink() {
$href = post('href');
return [
'title'=> $this->page->title,
'content' => $this->getContentsFromFile($this->page->baseFileName),
];
}
All you would need after this would be to write the logic to fetch html content from the baseFileName of the page (I have wrapped this as $this->getContentsFromFile() in the example above).
There are more variables provided by $this-> page - Read about them here - https://octobercms.com/docs/cms/pages#page-variables
I have a system that uses Symfony, and is connected to a (citizen ct-s2000) POS printer.
What I currently do is render the string to send to the printer, using the twig service:
$this->templatingService->render('SamPosBundle:Ticket:template1.html.twig', array('order' => $order))
and send this to the printer using fwrite, after that I feed the paper 1 line and cut the paper using:
fwrite($handle, chr(hexdec('0A')));
fwrite($handle, chr(hexdec('1B')).chr(hexdec('69')));
This all works like a charm, however.
Now I am looking for a way to send the escape codes from WITHIN the twig template
so that I can use the codes to underline etc., and finally cut the paper, from inside the twig template.
I'm sure this would involve a twig extension to create an additional filter, which I know how to make, I just don't know WHAT EXACTLY it should do or how to go about the conversion from twig to escape code which would be picked up by fwrite
I've been looking for 2 days, and I really can't seem to figure this out on my own, so any help would be greatly appreciated.
Configure your twig extension:
services:
your.twig.pos_printer_extension:
class: Your\CustomBundle\Twig\POSPrinterExtension
tags:
- { name: twig.extension }
Create your extension:
<?php
namespace Your\CustomBundle\Twig;
class POSPrinterExtension extends \Twig_Extension
{
public function getGlobals()
{
return [
'some_constant' => chr(hexdec('0A'))
];
}
public function getFilters()
{
return [
'bold' => new \Twig_Filter_Method($this, 'bold')
];
}
public function bold($text)
{
return chr(hexdec('0B')) . $text . chr(hexdec('0A'));
}
}
And finally use it in your twig templates:
{{ some_constant }}
{{ receipt.amount | bold }}
You can apply filters to an entire block too:
{% filter bold %}
Dear {{ name }},
{% endfilter %}
Obviously I don't know the correct escaped chars but you got the idea right?
UPDATE (I'm writing this to avoid downvotes)
My example is using Twig_Filter_Method which is deprecated since 1.12 (to be removed in 2.0), you should be using Twig_SimpleFilter instead.
Its alive, just the syntax for the getFilters() was slightly different:
public function getGlobals()
{
return [
'ticket_cut' => chr(hexdec('1B')).chr(hexdec('69'))
];
}
public function getFilters()
{
return array(
new \Twig_SimpleFilter('ticketBold', array($this, 'ticketBold')),
);
}
public function ticketBold($string)
{
return chr(hexdec('1B')).chr(hexdec('45'))."1".$string.chr(hexdec('1B')).chr(hexdec('45'))."0";
}
Thx for pointing me in the right direction!