I'm using OctoberCMS which uses Twig.
The way I retrieve user permissions is by getting the information in php then pass a twig variable.
Is there a way to do this using just Twig?
Permissions Docs
PHP
if (BackendAuth::check()) {
# Get User Info
$backend_user = BackendAuth::getUser();
# Superuser
$this['is_superuser'] = $backend_user->is_superuser;
# Permissions
$this['permissions_allow_edit'] = $backend_user->hasPermission(
[
'mycomponent.gallery.allow_edit'
]);
}
Twig
{% if is_superuser or permissions_allow_edit %}
//edit button
{% endif %}
Twig (Standalone)
//another way to backendauth check in twig?
if (BackendAuth::check()) {
$this['backend_user'] = BackendAuth::getUser();
}
//////
{% if backend_user.is_superuser or backend_user.permissions.mycomponent.gallery.allow_edit %}
//edit button
{% endif %}
{{ backend_user }} gives the user information array
{"id":2,"first_name":"Matt","last_name":"","login":"matt","email":"user#example.com","permissions":{"mycomponent.gallery.allow_edit":1},"is_activated":false,"activated_at":null,"last_login":"2017-03-11 09:59:48","created_at":"2017-02-11 10:32:14","updated_at":"2017-03-11 10:03:45","is_superuser":0}
{{ backend_user.permissions }} throws an "Array to string conversion" error.
{{ backend_user.permissions.mycomponent.gallery.allow_edit }} shows nothing.
How do I get the values inside the permissions array?
I have not tested this but you should be able to use the hasPermission method to check if backend user has a specific permission:
{% if backend_user.is_superuser or backend_user.hasPermission('mycomponent.gallery.allow_edit') %}
//edit button
{% endif %}
Related
As not expected I'm able to access non-witelisted functions.
Policy config:
$policy = new \Twig\Sandbox\SecurityPolicy(); // should disallow all
$sandbox = new \Twig\Extension\SandboxExtension($policy);
$twig->addExtension($sandbox);
Twig template:
{{ include(template_from_string(data), sandboxed=true) }}
where data contains the external code beeing restricted:
{% if totalAmount %}
total: {{ totalAmount|number_format }}
{% endif %}
As I understand the not very detailed docs, I shouldn't have access to either if, totalAmount and number_format. How to restrict that?
To enable a global sandbox mode u'd need to pass true as the second argument of the SandboxExtension constructor otherwise you'd need to use the {% sandbox %}-tag in places where you don't trust the code that is ran.
$policy = new \Twig\Sandbox\SecurityPolicy();
$sandbox = new \Twig\Extension\SandboxExtension($policy, true);
$twig->addExtension($sandbox);
{% sandbox %}
{% include(template_from_string(data) %}
{% endsandbox %}
I have 2 pages index.htm and links.htm and a partial sidebar.htm.
I'm trying to get my sidebar to display different content based on whether index.htm or links.htm is active.
Reading through the documentation it looks as if you can do this with the param.tab but I can't get it to work and not sure if this is the best way to accomplish this seeing as it's a partial.
sidebar.htm
description = "sidebar"
url = "/sidebar/:{% this.page.url %}"
==
{% if this.param.tab == 'links' %}
Display this if page = links
{% elseif this.param.tab == 'index' %}
Display this is page = index
{% endif %}
In blade I used - #elseif(isset($guidesslugs) && $guidesslugs->guidesslug == 'area-guide') but I'm not sure how to accomplish the same thing using twig or whether it's possible to used the param.tab on a partial?
There's multiple ways to do it.
First of all, partials may not have the url parameter into config section.
The Configuration section is optional for partials and can contain the
optional description parameter which is displayed in the back-end user
interface.
Partials - Introduction
You could use param if the sidebar has different content based on the same page. Example:
pages/home.htm
url = "/home/:type"
==
{% partial 'sidebar' type=this.param.type %}
partials/sidebar.htm
{% if type == 'foo' %}
{# foo type #}
{% elseif type == 'bar' %}
{# bar type #}
{% else %}
{# anything... #}
{% endif %}
When including partials you can pass variables, in this case, we injected type as this.param.type value. You could also access this.param (global) variable inside partial:
partials/sidebar.htm
{% if this.param.type == 'foo' %}
{# foo type #}
{% endif %}
If I understand your question, you have two different pages where each has his own distinct url so doesn't seems like a case for param property.
Use this.page variable.
You're able to access the page url defined into page configuration section by using:
{{ this.page.url }}
This property seems like hidden from docs.
So considering your structure:
pages/home
url = "/home"
layout = "default"
==
{% partial 'sidebar' %}
pages/links
url = "/links"
layout = "default"
==
{% partial 'sidebar' %}
partials/sidebar
{% if this.page.url == '/home' %}
{# home page #}
{% elseif this.page.url == '/links' %}
{# links page #}
{% else %}
{# other pages #}
{% endif %}
As I said, there's so many ways to do this by defining variables, passing parameters to partial and others.
I have a function in my Symfony controller which returns the following:
test+testString1+test2
TestController.php
public function getResultAction($fileName) {
$string1="test";
$string2="testString1";
$string3="test2";
$response = $string1."+".$string2."+".$string3;
return new Response($response);
}
In my twig I've rendered the function in my controller:
test.html.twig
{% set test %}
{{ render(controller('TestBundle:Test:getResult')) }}|split('+', 4)
{% endset %}
{{ test[0] }}
I'm using twig split filter so that I can display test, testString1 and test2 individually. But then whenever I attempt to display test[0], I receive the following error:
Impossible to access a key "0" on an object of class "Twig_Markup" that does not implement ArrayAccess interface in TestBundle:Test:test.html.twig
What's wrong with what I'm doing? I hope you could help me with this. Thanks
You miss the split filter inside the double brace as follow:
{% set test %}
{{ render(controller('TestBundle:Test:getResult')) |split('+', 4) }}
{% endset %}
Hovenever seems same problem with the set tag. From the doc:
The set tag can also be used to 'capture' chunks of text
Try with:
{%
set test=render(controller('TestBundle:Test:getResult'))|split('+', 4)
%}
Hope this help
I am trying to make a messaging system and I'm facing a small problem. I have a bigger template that displays my menu and my content. The menu includes the number of new messages, and the content can be any page(compose a new message, inbox, sent).
The problem is that I have to render each of the small templates by passing the number of new received messages to each of them, calling the doctrine each time and repeating code. Is there any way to send the number only to the parent template?
Here are my templates:
This is the parent containing the newmsg variable that gives me problems.
{% extends "::base.html.twig" %}
{% block body %}
inbox : {{ newmsg }}
sent
compose
{% endblock body %}
Here is an example of child template:
{% block body %}
{{ parent() }}
{% if messageList %}
{% for message in messageList %}
<li>title = {{ message.title|e }}</li>
<li>cont= {{ message.content|e }}</li>
<li>data= {{ message.date|date('d-m-Y H:m:s') }}</li>
<li>sender= {{ message.sender|e }}</li>
<hr>
{% endfor %}
{% else %}
<div>no messages</div>
{% endif %}
{% endblock body %}
The problem is that each child template is asking me for the newmsg variable
$messages = $this->getDoctrine()->getRepository('MedAppCrudBundle:Message');
$newMessagesNo = count($messages->findBy(array('seen' => '0', 'receiver' => $this->getUser())));
return $this->render(
'MedAppCrudBundle:UserBackend\Message:new.html.twig',
array(
'form' => $form->createView(),
'newmsg' => $newMessagesNo,
)
);
And I have to write this in every single controller. Any way I can shorten this problem?
You could implement a service that gives back the newmsg value and call it on your parent template. Then it would not be necessary to pass the variable.
You can add a service in your bundle's services.yml with something like:
services:
newmessages:
class: Full\Class\Name\NewMessagesService
arguments: ["#doctrine.orm.entity_manager"]
Then, implement the Full\Class\Name\NewMessagesService class. Keep in mind that this class will need a constructor that receives an EntityManager argument. Something like:
<?php
namespace Full\Class\Name;
class NewMessagesService{
private $entityManager;
public function __construct($entityManager){
$this->entityManager = $entityManager;
}
public function methodToCalculate(){
//Perform calculation and return result
}
}
Then, in your parent template, replace {{newmsg} with:
{{ newmessages.methodToCalculate() }}
I am using Abraham's TwitterOAuth library along with Twig to build a mini app where users authorize then search for tweets based on their input.
I can successfully dump the return from the API to my page, but when I try to isolate just the tweet text for each tweet returned I'm having no luck.
Here's the relevant code for my dashboard.php file:
$user = $connection->get("account/verify_credentials");
if(isset($_POST['query'])) {
$query = $_POST['query'];
$statuses = $connection->get("search/tweets", array("q" => "$query"));
echo $twig->render("dashboard.html", array("access_token" => $access_token, "user" => $user, "statuses" => $statuses));
} else {
echo $twig->render("dashboard.html", array("access_token" => $access_token, "user" => $user));
}
And then the problem code in my twig template:
{% if statuses %}
<ul>
{% for status in statuses %}
<li>{{ statuses.text|e }}</li>
{% endfor %}
</ul>
{{ dump(statuses) }}
{% endif %}
The {{ dump(statuses) }} works, but nothing is spit out inside the UL. I'm very new to all of this, so I've just been looking at Abraham's example code here, where he does this:
{% if user.status %}
{{ user.status.text }}
{% else %}
{{ user.description }}
{% endif %}
So I figured I could do the same thing, but it's not working for me. What am I missing?
Well I figured it out by comparing the example responses from the GET account/verify_credentials (the request being sent out in Abraham's user code) and the GET search/tweets.
If you compare the beginnings of the responses, you will notice that there is an extra level to traverse with the search/tweets response.
So instead of doing:
{% for status in statuses %}
<li>{{ statuses.text|e }}</li>
{% endfor %}
I did:
{% for status in statuses.statuses %}
<li>{{ statuses.text|e }}</li>
{% endfor %}
I realize the naming there isn't great, but to break it down for any other newbs like me: the first "statuses" is the variable I sent to twig, the second "statuses" is from the response I'm getting from the API.
In my original code there was nothing to loop through because I hadn't gone far enough down to reach the information about the individual tweets, I was basically trying to loop through the parent.