How to use access constants in twig file Symfony2 - php

Hi I have a class following:
class allConstants {
//PREDEFINED ALL FIXED GROUPS USING IN ACCOUNT MODULE
const GROUP_BANK_ACCOUNT = 'Bank Accounts';
const GROUP_CURRENT_ASSETS = 'Current Assets';
const GROUP_LOAN_LIBILITIES = 'Loan (Liabilities)';
const GROUP_BANK_OD_ACCOUNT = 'Bank OD a/c';
const GROUP_CASH_IN_HAND
}
So I want to access these constants into twig file. So when I am using like following in twig :
constant('\Edu\AccountBundle\Constants\allConstants::GROUP_BANK_ACCOUNT');
its showing an refrence erro that "constant" not define.
Please guide how to make it work. I am using symfony 2.3.7
Thanks in advance

{% if gropu is constant('allConstants::GROUP_BANK_ACCOUNT') %}
the status attribute is exactly the same as allConstants::GROUP_BANK_ACCOUNT
{% endif %}
test constants from object instances
{% if gropu is constant('GROUP_BANK_ACCOUNT', allConstants) %}
the status attribute is exactly the same as allConstants::GROUP_BANK_ACCOUNT
{% endif %}

The code posted by Muhammad is right:
{% if group is constant('GROUP_BANK_ACCOUNT', allConstants) %}
the status attribute is exactly the same as allConstants::GROUP_BANK_ACCOUNT
{% endif %}
But you can use like this only with Twig >=1.12.1; with lower version, you can just use it from static classes, like this:
constant('allConstants::GROUP_BANK_ACCOUNT')

Related

How to restrict access to untrusted code in Twig include function with sandboxing

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

Twig print available from string

How to print available form string in twig
In my code php
$data['fruits'] = array('apple', 'banana', 'orange');
$data['help_apple'] = 'This is help apple';
$data['help_banana'] = 'This is help for banana';
$data['help_orange'] = 'This is help for orange';
In twig template
{% for fruit in fruits %}
{{ "help_" ~ fruit }}
{% endfor %}
The print screen is help_apple, help_banana, help_orange
How to print correct data i need for help_ fruit key ?
You need to use the attribute function with _context. Tested on twigfiddle.com. Hope this helps.
{% for fruit in fruits %}
{# Here is how you do it #}
{{ attribute(_context, 'help_'~ fruit) }}
{% endfor %}
The _context variable holds all variables in the current context. Instead of using the attribute function, you can access values of the _context array with the regular bracket notation as well:
{% for fruit in fruits %}
{{ _context['help_' ~ fruit] }}
{% endfor %}
I would personally do it this way as it's more concise and in my opinion clearer.
You might want to check for undefined variables when accessing values of the _context array. I have written about it in my answer to this question: Symfony2 - How to access dynamic variable names in twig.
You also asked whether something like this is possible:
{% set attribute(context, 'help' ~ fruit, "value") %}
That's not possible. If you want to set variables with dynamic names, you need to create a Twig extension. Take a look at my answer to this question: How to set a variable name with dynamic variables?
But, like #user9189147 mentioned, it would be easier and in my opinion clearer if you instead created a new array to hold the help values. Then you wouldn't need to create an extension.
$data['fruits'] = ['apple', 'banana', 'orange'];
$data['help'] = [];
$data['help']['apple'] = 'This is help apple';
$data['help']['banana'] = 'This is help for banana';
$data['help']['orange'] = 'This is help for orange';
{% for fruit in fruits %}
{{ help[fruit] }}
{% endfor %}
Then you can set new values to the help values in Twig using the merge filter, like this (though I don't know why you would want to do it in Twig):
{# Set single value #}
{% set help = help|merge({
banana: 'New help for banana',
}) %}
{# Or multiple values #}
{% set help = help|merge({
apple: 'An apple a day keeps the doctor away',
orange: 'Orange is the new black',
}) %}

Custom dynamic Twig template that extends Twig_Template

TL;DR: I am currently struggling with the idea how to elegantly generate CRUDs/GRID using Twig.
Long story:
I have a Phalcon app with AngularJs, templating system is Twig.
PHP is suppose to prepare a template for CRUD that contains:
List od entities, table that contains proper headers, columns, row items, action buttons
Simple and advanced search
Mass actions block
Main buttons - Add/Import/Export etc.
AngularJs is responsible for:
Paginating results in 2 modes: Ajax Loaded entities, All entities at once
Changing number of entities per page
Displaying various forms in modals - Add/Edit/Import
Filtering entities - simple and advanced search
Everything is working right now but I am not particularly fond of how it works.
For example a simple entity with few fields needs a following template:
{% extends 'index.twig' %}
{% block containerAttr %}ng-controller="InventoryController as ctrl"{% endblock %}
{% set ctrlName = 'ctrl' %}
{% set columnWidth = 'col-xs-12' %}
{% set tableClass = 'table table-bordered table-striped table-hover' %}
{% block header %}
{% include '#crud/crud/header.twig' %}
{% endblock %}
{% block content %}
{% embed '#crud/crud/main-box.twig' %}
{% block tableHeader %}
{% autoescape false %}
{{ crud.tableHeader('Id', 'id') }}
{{ crud.tableHeader('Nazwa', 'name') }}
<th class="col-xs-1">Actions</th>
{% endautoescape %}
{% endblock %}
{% block tableRow %}
<td ng-bind="e.id"></td>
<td ng-bind="e.name"></td>
{% endblock %}
{% endembed %}
{% embed '#crud/crud/form.twig' %}
{% block modalBody %}
{% autoescape false %}
<div class="row">
{{ crud.input('ctrl.entity.name', 'Name', 12) }}
</div>
{% endautoescape %}
{% endblock %}
{% endembed %}
{% embed '#crud/crud/upload.twig' %}{% endembed %}
{% embed '#crud/crud/advancedSearch.twig' %}{% endembed %}
<script>
window.xdata = {{ xdata | json_encode | raw }};
</script>
{% endblock %}
crud in this template is responsible for generating form fields compatible with AngularJs.
Idea is: To create new CRUDs/Grids with the least amount of work required. While still giving a room for some flexibility.
Right now to make a CRUD/Grid inside my application there is a really little work required:
PHP Controller needs to contain only one line:
class SubCategoryController extends CrudBase
{
protected $entityClass = InventoryCategory::class;
}
Thanks to extending it is really easy to customize every part of it.
Model needs to have just a few fields:
class InventoryCategory extends ModelBase
{
/** #var integer */
public $id;
/** #var string */
public $name;
public function initialize()
{
$this->setSource('inventory_subcategory');
$this::setup(['castOnHydrate' => true]);
}
}
Even the AngularJs controller contains only URLs and one line:
class InventoryCategoryController extends CrudBase {
constructor($injector, $scope) {
super($injector, $scope);
this.urlSave = '/inventory/category/save';
this.urlImport = '/inventory/category/import';
this.urlExport = '/inventory/category/export';
this.urlDelete = '/inventory/category/delete';
this.init({
advancedSearch: false
});
}
}
angular.module('App').controller('InventoryCategoryController', InventoryCategoryController);
Yes I use ES6, application is not compatible with older browsers anyways and it is admin panel so I do not care about older browsers.
But now only templates remains a tedious work to copy it over and change it. Not to mention they do look pretty ugly.
So my idea was to use Annotation Reader (Phalcon has one) to read fields from Model, then transform it into a base configuration, check if there is custom configuration in json and merge it. Then based on configuration, generate this whole template on the fly.
So the grand question is:
I was wondering if I can create some class that extends Twig_Template to generate this template on the fly?
I have seen Twig cache and it should be pretty easy but then how can i use it? How can i render it? Will extend still work?

Display split results in Symfony2 twig

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

How to override Show field in sonata admin

I want show the list of multiple attributes Name => value in a table overriding single field of only for PortsAdmin in ShowMapper
Ports Entity mapped with PortsAttributes Entity.
Relation of entity is OneToMany Ports with multiple attributes.
Admin View (Edit Action)
Show Action
I want change attribute view same as edit Action.
You can create a custom template for the PostAttributes:
Example:
/* ShowMapper in admin */
$showMapper->add('attributes', null, array(
'template' => 'YOUR_TEMPLATE.html.twig' // <-- This is the trick
));
In your template, you can extend the base show field (SonataAdminBundle:CRUD:base_show_field.html.twig or #SonataAdmin/CRUD/base_show_field.html.twig for symfony > 4.0), and override the field block. The variable named value stores the data in twig.
Example:
YOUR_TEMPLATE.html.twig
{% extends 'SonataAdminBundle:CRUD:base_show_field.html.twig' %}
{# for sf > 4.0 #}
{# {% extends '#SonataAdmin/CRUD/base_show_field.html.twig' %} #}
{% block field %}
{% for val in value %}
{{ val.name }} - {{ val.value }} {# I'm just guessing the object properties #}
<br/>
{% endfor %}
{% endblock %}
#SlimenTN you can try changing this line in template file:
{% extends 'SonataAdminBundle:CRUD:base_show_field.html.twig' %}
with this:
{% extends '#SonataAdmin/CRUD/base_show_field.html.twig' %}
The rest of code seems ok (I have the same in a SF4 project)

Categories