The security of my Symfony 4 application is using #security annotations in controllers :
/**
* #Route("/cat/list", name="cat_list")
*
* #Security("is_granted('ROLE_XYZ'")
*/
public function listAction()
{
// [...]
}
I am building a menu with twig from a list of route names :
{% for route_name in ["cat_list","cat_map", ,"cat_trips"] %}
<a href="{{ path(route_name) }}"/> {{ route_name|trans }} </a>
{% endfor %}
I would like to add a security check to only display the routes my user have access, something like that :
{% for route_name in ["cat_list","cat_map", ,"cat_trips"] %}
{% if can_access_route(route_name) %}
<a href="{{ path(route_name) }}"/> {{ route_name|trans }} </a>
{% endif %}
{% endfor %}
Is there something built in Symfony for that ? Or how would you build is_route_granted() ?
Related
I have an editor with a set of buttons, and I want to display only a set of buttons based on twig::render variables.
If I include all I want it to display are buttons available, if I include individual button keys I want to display only that ones.
echo TwigLoader::render('#ui/editor.html.twig'['toolbar'=>['all']]);
echo TwigLoader::render('#ui/editor.html.twig'['toolbar'=>['font','size']]);
For the template I'm using the following code:
{% set toolbar_tools = [
{'font':'<select class="ql-font"></select>'},
{'size':'<select class="ql-size"></select>'}]
%}
<div id="button-container">
<span class="ql-formats">
{% for tool, key in toolbar_tools %}
{{ tool.key|raw}}
{% endfor %}
</span>
</div>
I'm getting an empty container.
Is this a good strategy or there are better ways?
Seems you`re looking for something like this:
{% set toolbar_tools = {
'font':'<select class="ql-font"></select>',
'size':'<select class="ql-size"></select>'
}
%}
<div id="button-container">
<span class="ql-formats">
{% if toolbar|length > 0 %}
{% for t in toolbar %}
{% if t == 'all' %}
{# show all options #}
{% for tool in toolbar_tools %}
{{ tool|raw }}
{% endfor %}
{% else %}
{# show defined options #}
{{ attribute(toolbar_tools, t)|raw }}
{% endif %}
<br />
{% endfor %}
{% endif %}
</span>
</div>
Hope you will be fine with that.
I am using Drupal and have twig for html template. I am super new to this project and see that the have a controller with a function that queries a database and then they return that query for the course page attributes, and I see where the attributes are displayed in the respective course.twig.html.
What I don't see is how they are connected and how the twig.html knows where its attributes are coming from. I am trying to add some more attributes to the page and don't see how this project is passing the mysql queries to the twig template.
{#
/**
* #file
* Default theme implementation to display a node.
*
* Available variables:
* - node: Full node entity.
* - id: The node ID.
* - bundle: The type of the node, for example, "page" or "article".
* - authorid: The user ID of the node author.
* - createdtime: Time the node was published formatted in Unix timestamp.
* - changedtime: Time the node was changed formatted in Unix timestamp.
* - label: The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
* of a given child element.
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: Themed creation date field.
* - author_name: Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
* The attributes.class element may contain one or more of the following
* classes:
* - node: The current template type (also known as a "theming hook").
* - node--type-[type]: The current node type. For example, if the node is an
* "Article" it would result in "node--type-article". Note that the machine
* name will often be in a short form of the human readable label.
* - node--view-mode-[view_mode]: The View Mode of the node; for example, a
* teaser would result in: "node--view-mode-teaser", and
* full: "node--view-mode-full".
* The following are controlled through the node publishing options.
* - node--promoted: Appears on nodes promoted to the front page.
* - node--sticky: Appears on nodes ordered above other non-sticky nodes in
* teaser listings.
* - node--unpublished: Appears on unpublished nodes visible only to site
* admins.
* - title_attributes: Same as attributes, except applied to the main title
* tag that appears in the template.
* - content_attributes: Same as attributes, except applied to the main
* content tag that appears in the template.
* - author_attributes: Same as attributes, except applied to the author of
* the node tag that appears in the template.
* - title_prefix: Additional output populated by modules, intended to be
* displayed in front of the main title tag that appears in the template.
* - title_suffix: Additional output populated by modules, intended to be
* displayed after the main title tag that appears in the template.
* - view_mode: View mode; for example, "teaser" or "full".
* - teaser: Flag for the teaser state. Will be true if view_mode is 'teaser'.
* - page: Flag for the full page state. Will be true if view_mode is 'full'.
* - readmore: Flag for more state. Will be true if the teaser content of the
* node cannot hold the main body content.
* - logged_in: Flag for authenticated user status. Will be true when the
* current user is a logged-in member.
* - is_admin: Flag for admin user status. Will be true when the current user
* is an administrator.
*
* #see template_preprocess_node()
*
* #todo Remove the id attribute (or make it a class), because if that gets
* rendered twice on a page this is invalid CSS for example: two lists
* in different view modes.
*
* #ingroup themeable
*/
#}
{# {{ kint() }} #}
<article id="node-{{ node.id }}" {{ attributes }}>
{{node}}
{{ title_prefix }}
{% if not page %}
<h2{{ title_attributes }}>
{{ label }}
</h2>
{% endif %}
{{ title_suffix }}
{% if node.field_packaging.value == '1' %}
{% set image = content.field_image %}
{% set ce = content.field_tax_credit_hours %}
{% set goal = content.field_goal %}
{% set target_audience = content.field_audience %}
{% set objectives = content.field_objectives %}
{% set accreditation = content.field_accreditation %}
{% set disclosure = content.field_disclosure_statement %}
{# {% set references_old = content.field_references %} #}
{% set references = content.field_references_par %}
{% set appendix = content.field_appendix %}
{% set faculty = content.field_faculty %}
{% set related_courses = content.field_related_courses %}
{# set suggested_courses = content.field_suggested_courses #}
{% set additional = content.field_callout %}
{% set expiration = node.field_expiration.value %}
<div class="course-summary row">
{% if image|render %}
<div class="course-image small-6 small-offset-3 medium-4 medium-offset-0 columns">
{{ image }}
</div>
<div class="small-12 medium-8 columns">
{% else %}
<div class="small-12 columns">
{% endif %}
<div class="course-introduction">
<p>Welcome to <em>{{ label }}</em>.</p>
</div>
{% if not resource %}
{% if ce.0|render %}
<small class="credit-hours inline-label">Credit hours: {{ ce.0 }} CE</small>
{% endif %}
{% endif %}
<div class="enroll">
{% if signIn == "yes" %}
{% if regis == true %}
Go
{% else %}
Enroll
{% endif %}
{% else %}
Enroll
{% endif %}
</div>
</div>
</div>
{% if goal|render or objectives|render %}
<ul class="tabs some-tabs" data-responsive-accordion-tabs="tabs small-accordion medium-tabs" data-allow-all-closed="true" data-multi-expand="true" id="course-tabs">
<li class="tabs-title is-active">Overview</li>
{% if appendix|render %}
<li class="tabs-title">Appendix</li>
{% endif %}
{% if references|render %}
<li class="tabs-title">References</li>
{% endif %}
{% if faculty|render %}
<li class="tabs-title">Faculty</li>
{% endif %}
</ul>
<div class="tabs-content" data-tabs-content="course-tabs">
<div id="overview" class="tabs-panel is-active course-overview">
{{ additional|render ? additional }}
{% if goal|render %}
<h2 class="field-label">{{ node.field_goal.fielddefinition.label }}</h2>
{{ goal }}
{% endif %}
<h2 class="field-label">{{ node.field_audience.fielddefinition.label }}</h2>
{% if target_audience|render %}
{{ target_audience }}
{% else %}
<p>interested health-care professionals.</p>
{% endif %}
{% if objectives|render %}
<h2 class="field-label">{{ node.field_objectives.fielddefinition.label }}</h2>
<p>After completing the activities of this module, you will be able to:</p>
{{ objectives }}
{% endif %}
{% if expiration|render %}
<p>Please note this module expires on <strong>{{ expiration|date('n/j/Y') }}</strong>.</p>
{% endif %}
{% if accreditation|render or disclosure|render %}
<div class="course-supplements">
{% if accreditation|render %}
<h2 class="supplement-title">Accreditation Statement</h2>
<div id="accreditation" class="callout callout-arrow is-hidden" data-toggler=".is-hidden">
{% for i, value in accreditation %}
{% set acc_item = node.field_accreditation[i].entity %}
{% if acc_item %}
<h3>{{ acc_item.title.value }}</h3>
{% autoescape false %}
{{ acc_item.body.value|replace({'{{ #.## }}': ce.0|escape }) }}
{% endautoescape %}
{% endif %}
{% endfor %}
<button class="close-button" data-toggle="accreditation">×</button>
</div>
{% endif %}
{% if disclosure|render %}
<h2 class="supplement-title">Disclosures</h2>
<div id="disclosure" class="callout callout-arrow is-hidden" data-toggler=".is-hidden">
{{ disclosure }}
<button class="close-button" data-toggle="disclosure">×</button>
</div>
{% endif %}
</div>
{% endif %}
</div>
{% if appendix|render %}
<div id="appendix" class="tabs-panel course-appendix">
{% if appendix %}
<ul class="tabs tabs-style-text" data-tabs id="course-appendix-tabs">
{% for i, value in node.field_appendix.value %}
{% set ref_title = node.field_appendix[i].entity.field_title.value %}
{% if ref_title %}
<li class="tabs-title{{ i == 0 ? ' is-active'}}">{{ ref_title }}</li>
{% endif %}
{% endfor %}
</ul>
<div class="tabs-content" data-tabs-content="course-appendix-tabs">
{% for i, value in node.field_appendix.value %}
<div id="{{ node.field_appendix[i].entity.field_title.value|clean_class }}" class="tabs-panel{{ i == 0 ? ' is-active'}}">
{% autoescape false %}
{{ node.field_appendix[i].entity.field_content.value }}
{% endautoescape %}
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% endif %}
{% if references|render %}
<div id="references" class="tabs-panel course-references">
{% if references %}
<ul class="tabs tabs-style-text" data-tabs id="course-references-tabs">
{% for i, value in node.field_references_par.value %}
{% set ref_title = node.field_references_par[i].entity.field_title.value %}
{% if ref_title %}
<li class="tabs-title{{ i == 0 ? ' is-active'}}">{{ ref_title }}</li>
{% endif %}
{% endfor %}
</ul>
<div class="tabs-content" data-tabs-content="course-references-tabs">
{% for i, value in node.field_references_par.value %}
<div id="{{node.field_references_par[i].entity.field_title.value|clean_class}}" class="tabs-panel{{ i == 0 ? ' is-active'}}">
{% autoescape false %}
{{ node.field_references_par[i].entity.field_content.value }}
{% endautoescape %}
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% endif %}
{% if faculty|render %}
<div id="faculty" class="tabs-panel course-faculty">
<div class="sections">
{{ faculty }}
</div>
</div>
{% endif %}
</div>
{% endif %}
{% if related_courses|render %}
{% set ancillary_1 = node.field_related_courses.fielddefinition.label %}
{% set ancillary_2 = 'Guidance' %}
{# set ancillary_2 = node.field_suggested_courses.fielddefinition.label #}
<ul class="sections sections-border accordion mobile-accordion stacked-tabs" data-accordion data-allow-all-closed="true" data-multi-expand="true">
<li class="section accordion-item" data-accordion-item>
{{ ancillary_1 }}
{% if related_courses|render %}
<div class="tiles mobile-accordion-content" data-tab-content>
<h2 class="field-label section-title hide-for-small-only">{{ ancillary_1 }}</h2>
<div class="list-items list-format-3">
{{ related_courses }}
</div>
</div>
{% endif %}
</li>
<li class="section accordion-item" data-accordion-item>
{{ ancillary_2 }}
<div class="tiles mobile-accordion-content" data-tab-content>
<h2 class="field-label section-title hide-for-small-only">{{ ancillary_2 }}</h2>
<div class="list-items list-format-1 list-type-guidance">
{{ drupal_view('content_feed', 'guidance') }}
</div>
</div>
</li>
</ul>
{{ drupal_view('content_feed', 'guidance_modal') }}
{% endif %}
{% else %}
{{ content.body }}
{% endif %}
</article>
You should search for preprocess hooks (function yourmodule_preprocess...). If you are using drupal8 you can set a new variable like this:
$vars['myvar'] = 'test';
In twig, can be called like this
{{ myvar }}
Important: it will not work in every function. I use to work it with preprocess functions, but thanks to #leymannx, we know it works with other hooks too:
"Not only preprocess hooks can pass variables to templates. Implement
hook_theme and then in your controler theme the output and pass
variables along to a template"
When you render a twig template in the controller, you can also pass some variables as data. If you want to show that data in the twig template, you call them by their name inside twig functions and language constructs.
That's it in general.
I can not help you more because your question is very generic.
To render TOC (categories tree) inside the base.twig view I call the render() function passing it the corresponding action url:
{% block sidebar %}
{{ render(url('toc_documents_categories')) }}
{% endblock %}
The matching partial view for the '/toc/documents' action (_toc.documents_categories.twig) is defined as follows:
{% set category_id = (current_uri|split('/'))[4] %}
{% macro recursiveCategory(category, active_category_id) %}
<li>
{% if category.children|length %}
<a><span class="icon icon-plus"></span>{{ category.name_displayed }}</a>
{% else %}
{% set active_class = active_category_id == category.id ? 'active' %}
{% set url = app.url_generator.generate('documents_by_category', {category_id: category.id}) %}
<a href="{{ url }}" class="{{ active_class }}">
{{ category.name_displayed }}
</a>
{% endif %}
{% if category.children|length %}
<ul>
{% for child in category.children %}
{{ _self.recursiveCategory(child, active_category_id) }}
{% endfor %}
</ul>
{% endif %}
</li>
{% endmacro %}
{% if categories %}
<div id="categories">
<ul>
{% for category in categories %}
{{ _self.recursiveCategory(category, category_id) }}
{% endfor %}
</ul>
</div>
{% endif %}
As you can see I'm extracting current category's id by parsing current url. This is preceded by setting the current_uri global:
$app->before(function(Request $request) use ($app) {
$app['twig']->addGlobal('current_uri', $request->getRequestUri());
});
Accessing the route information (global.request.attributes.get('_route')) inside the partial view shows the corresponding subrequest route name and not the actual request route name (master request).
Is there a way to avoid manually parsing the current uri and to get the current request route params inside the partial view?
Here's the solution.
render() issues a subrequest, so you have to use the master request context:
use Symfony\Component\HttpFoundation\Request
$app->get('/documents_categories', function(Request $request) use($app) {
$master_request = $app['request_stack']->getMasterRequest();
$current_route = $master_request->get('_route');
$active_category_id = null;
if($current_route === 'documents_by_category') {
$active_category_id = $master_request->get('_route_params')['category_id'];
}
// ... do things: parse toc tree ...
return $app['twig']->render('_toc.documents.categories.twig', array(
"categories" => $toc_tree,
"active_category_id" => $active_category_id
));
})->bind('toc_documents_categories');
Then inside the partial view you have to only reference the passed active_category_id parameter:
{% if categories %}
<div id="categories">
<ul>
{% for category in categories %}
{{ _self.recursiveCategory(category, active_category_id) }}
{% endfor %}
</ul>
</div>
{% endif %}
Thanks to #keyboardSmasher for 'Why not pass the category_id in the render function' comment. Yet I'm not sure if I did it the way he assumed.
I try to override FOS bundle.
To do this I have:
UserBundle that I have created when intalling FOS. It have my User.php file.
UserBundle.php:
<?php
namespace gestEntrSym\UserBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class UserBundle extends Bundle
{
public function getParent() {
return 'FOSUserBundle';
}
}
views/Default/layout.html.twig
{% extends '::base.html.twig' %}
{% block title %}Acme Demo Application{% endblock %}
{% block content %}
{{ block('fos_user_content') }}
{% endblock %}
then I have app/Ressources/Views/base.html.twig
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<div>
{% if is_granted("IS_AUTHENTICATED_REMEMBERED") %}
{{ 'layout.logged_in_as'|trans({'%username%': app.user.username}, 'FOSUserBundle') }} |
<a href="{{ path('fos_user_security_logout') }}">
{{ 'layout.logout'|trans({}, 'FOSUserBundle') }}
</a>
{% else %}
{{ 'layout.login'|trans({}, 'FOSUserBundle') }}
{% endif %}
</div>
{% for type, messages in app.session.flashBag.all %}
{% for message in messages %}
<div class="{{ type }}">
{{ message|trans({}, 'FOSUserBundle') }}
</div>
{% endfor %}
{% endfor %}
<div>aaa
{{ block('fos_user_content') }}
</div>
</body>
</html>
I have now in the page just a link "Connexion", which just link to the page login. I want to have all the inputs in my layout page.
How can I do that?
Thanks
Best regards
If you want to override your login template, create the folder
app/Resources/FosUserBundle
and then respect the structure of the vendor folder which you won't toutch, so your overriden login wil be here :
app/Resources/FosUserBundle/Views/Security/login.html.twig
Then if you want to include that template in base,
{% include('FOSUserBundle:Security:login.html.twig') %}
I would like to replace:
{{ form_errors(form.name) }}
{{ form_widget(form.name, { 'attr': {'placeholder': 'Nom'} }) }}
By:
{{ form.name|field('Nom') }}
How could I do that? I tried to do it in a Twig extension but I don't have access to the form_widget function.
Edit: I could do it with the form.name properties (that include the parent form) but I would repeat symfony code, it would be a very ugly big hack
Makes more sense if you ask me to move the attr to your form class:
class SomeForm extends AbstractType {
//.....
$builder->add('name', 'text', array('attr' => array('placeholder'=>'Nom')));
}
Since i guess you need some custom rendering for some of your fields you can check:
http://symfony.com/doc/2.0/cookbook/form/form_customization.html#how-to-customize-an-individual-field
You could also create a new type and customize it as explained here:
http://symfony.com/doc/2.0/cookbook/form/form_customization.html#what-are-form-themes
You could even change the default way of rendering and ask symfony to render your placeholder tag by default using the field's label string (the details of enabling the form theme globally are covered by the link referenced above):
{% block text_widget %}
{% set type = type|default('text') %}
<input type="text" {{ block('widget_attributes') }} value="{{ value }}" />
{% endblock field_widget %}
{% block widget_attributes %}
{% spaceless %}
{% for attrname,attrvalue in attr %}{{attrname}}="{{attrvalue}}" {% endfor %} placeholder="{{ label|trans }}"
{% endspaceless %}
{% endblock widget_attributes %}
{% block form_row %}
{% spaceless %}
<div class="my-class">
{{ form_errors(form) }}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
So you would limit yourself to a form_row(form.name) using the theming that symfony provides.
Symfony's aproach looks "very" DRY/DIE to me.
Hope it helps.