Get {% page %} object from php on ajax handler - php

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

Related

Using a PHP function in Twig

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() %}

Octobercms. How to prepare variable to component template?

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.

When does twig calls php function before loading or after loading DOM?

I am calling a php function from the twig template like
{% if ($someThing) {
{{ getValues() }}
}%}
{% if ($otherThing) {
{{ getMoreValues() }}
} %}
getValues() {
$cookie = /* gets cookie from request */;
fetchingValues($cookie);
}
getMoreValues() {
$cookie = ' /*gets same cookie as getValues() */
fetchingValues($cookie);
}
both functions getValues and getMoreValues further calls same function in the php code say fetchingValues($cookie).
This fetchingValues modifies the $cookie and sets it. Thing is after setting the cookie from getValues(). When fetchingValues gets called from getMoreValues it get $cookie as a empty string. or say getMoreValues getting $cookie as a empty string.
Any ideas why this is happening ?

Using Twig to generate JSON

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

Routing to embedded Modules/Bundles/Controllers in Symfony 2

I fully edited this post after doing research:
I'd like to realize a sidebar in the admin section which is integrated in every page, f.e. http://example.com/admin/index/:
class MyController extends Controller {
protected $modules = array();
public function __construct(){
$this->modules[] = "ModuleController:mainAction";
$this->modules[] = "OtherModuleController:mainAction";
}
public function indexAction(Request $request){
// do stuff here
return $this->render("MyBundle:My:index.html.twig",$data);
}
}
In the view should happen something like:
{% block modules %}
{% for module in modules %}
{% render module %}
{% endfor %}
{% endblock %}
So far so good, but these modules can contain forms which send post requests. I'd like to stay on the same page (http://example.com/admin/index/), so the action attribute of the form stays empty. The problem is: The post request will never be recognized by the Modules. So one idea was to hide a field in the according form that contains the name of the route, transform it to the according uri and send a sub request (in MyController):
public function indexAction(Request $request){
if($request->request->has('hidden_module_route')){
// collect all parameters via $request->request->keys()
$uri = $router->generate($request->request->get('hidden_module_route'), $parameters);
// 1: resolve the uri to the according controller and replace the target in the $this->modules array
// or 2: (after step 1)
$req = $request->create($uri, 'POST');
$subresponse = $this->get('kernel')->handle($req,HttpKernelInterface::SUB_REQUEST);
// inject the response into the modules and handle it in the view
}
[...]
}
That would work for me, but I'm not happy to have these responsibilities in the controller and it feels like there should be a better solution (one Idea is to register a kernel.controller listener that handles sub requests and injects the paths to the controller (which perhaps is marked via interface...)).
What do you think?
You could try to send the main request to your modules, so that they can bind the form with it.
{% block modules %}
{% for module in modules %}
{% render module with {'mainRequest': app.request} %}
{% endfor %}
{% endblock %}
And the module:
public function moduleAction(Request $request, Request $mainRequest)
{
$form = ...;
if ($mainRequest->isMethod('POST')) {
$form->bindRequest($mainRequest);
if ($form->isValid()) {
// You can have a beer, that worked
}
}
}

Categories