I'am experiencing an issue with is_granted('') function in twig.
My current user has the following roles : ['ROLE_USER','ROLE_FOOBAR'], checked from the symfony profiler.
With this code : the admin link is printed (KO) :
{% if is_granted('ROLE_BACKOFFICE') or is_granted('ROLE_SYSTEM') %}
<li>
<a href="{{ path('sonata_admin_dashboard') }}">
ADMIN
</a>
</li>
{% endif %}
With this code : the admin link is NOT printed (OK) :
{% if app.user.hasRole('ROLE_BACKOFFICE') or app.user.hasRole('ROLE_SYSTEM') %}
<li>
<a href="{{ path('sonata_admin_dashboard') }}">
ADMIN
</a>
</li>
{% endif %}
I don't understand why the link is printed with is_granted ?
My role hierarchy seems ok, what's wrong with that code ?
If you look at vendor/friendsofsymfony/user-bundle/Model/User.php, it explains that the hasRole must not be used in this context :
/**
* Never use this to check if this user has access to anything!
*
* Use the SecurityContext, or an implementation of AccessDecisionManager
* instead, e.g.
*
* $securityContext->isGranted('ROLE_USER');
*
* #param string $role
*
* #return boolean
*/
public function hasRole($role)
{
return in_array(strtoupper($role), $this->getRoles(), true);
}
Here is a snippet of my role hierarchy from security.yml :
role_hierarchy:
ROLE_FOOBAR: ROLE_USER
...
ROLE_ADMIN: [ROLE_USER, ROLE_MANAGER]
I finally found the problem :
The problem came from an error inside a voter. I change this snippet :
if ($object != null && !$this->supportsClass(get_class($object))) {
return self::ACCESS_ABSTAIN;
}
to :
if (!$this->supportsClass(get_class($object))) {
return self::ACCESS_ABSTAIN;
}
Now, everything is fine, again. just lost my day ! I hope this could help.
Related
In my Drupal site, user profile has username, role and group Taxonomy term. There is a Article content type setup to take comments from users. Every time when a user comments, I would like to show as:
Submitted by: username, role, group
I tried to read the role and category fields through template_preprocess function as below:
function bartik_preprocess_comment(array &$variables) {
if (isset($variables['elements']['#view_mode'])) {
$variables['view_mode'] = $variables['elements']['#view_mode'];
}
else {
$variables['view_mode'] = 'default';
}
dd($variables);
}
But the dump does not show "group" field. Unsure what's missing.Rightnow, only the username is showing up. My comments.html.twig looks as below:
<div class="author-comments">
<p class="comment-submitted">{{ submitted }}</p>
<div{{ content_attributes.addClass('content') }}>
{% if title %}
{{ title_prefix }}
<h3{{ title_attributes }}>{{ title }}</h3>
{{ title_suffix }}
{% endif %}
{{ content }}
</div>
</div>
any help on how to pull out the role and category field and plug into the twig template? Thanks!
Alright, I'm able to figure this out. Below is my answer:
In mytheme.theme file:
/**
* Implements hook_preprocess_HOOK() for comment.html.twig.
*/
function mytheme_preprocess_comment(array &$variables) {
$user = \Drupal::currentUser();
$user_entity = \Drupal::entityTypeManager()
->getStorage('user')
->load($user->id());
$roles = $user->getRoles();
$variables['user_roles'] = $roles ;
}
This variable can be printed on comment.html.twig as: {{ user_roles }} as however needed.
I have one entity Article and an other entity Image with a bidrectional relation OneToMany and ManyToOne :
class Article
{
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Image", mappedBy="article")
*/
private $images;
}
class Image
{
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Article", inversedBy="images")
* #ORM\JoinColumn(nullable=true)
*/
private $article;
}
In my controller I use #paramconverter to get the article I want :
/**
* #Route("/blog/{slug}", name="article")
* #ParamConverter("article", class="AppBundle:Article")
*/
public function articleAction(Article $article)
{
return $this->render('default/article.html.twig', array(
'article' => $article,
));
}
Now my problem is that I want to identify the ONLY image with the attributes "main = true" in all the "article.images" I have.
What is the best solution?
In my wiew I can do somehting like this but it's not the best I think :
{% for image in article.images %}
{% if image.main %}
<img src="{{ asset( image.src ) }}" alt="{{ image.alt }}" title="{{ image.title }}">
{% endif %}
{% endfor %}
I'd like to use something like :
{{ article.mainImg }}
How can I achieve this please? And is this the best solution?
Doctrine provides a collection filter mechanism you could use to get the "main image":
public function articleAction(Article $article)
{
$criteria = Criteria::create()
->where(Criteria::expr()->eq("main", true))
->setMaxResults(1);
$mainImg = $article->getImages()->matching($criteria)->first();
return $this->render('default/article.html.twig', array(
'article' => $article,
'mainImg' => $mainImg
));
}
More information on filtering doctrine collections: Filtering collections
I did not test the code myself, but it should convey the idea of how it can be done.
That's something driving me crazy.
Take these snippets of code
class CommonController extends Controller
{
/**
* Create delete form
*
* #param int $id
*
* #return Form
*/
protected function createDeleteForm($id)
{
return $this->createFormBuilder(['id' => $id])
->add('id', \Symfony\Component\Form\Extension\Core\Type\HiddenType::class)
->getForm()
;
}
}
and
{% if delete_path is defined %}
<form id="delete" action="{{ path(delete_path, {id: entity.id}) }}" method="POST" class="pull-right" style="margin-top: -43px; margin-right: 10px;">
{{ form_widget(deleteForm) }}
<button type="submit" class="btn btn-default">{{ delete_form_submit_button|trans }}</button>
</form>
{% endif %}
Please pay attention, that's not pseudo-code, is real code I've found into an application a friend of mine asked me to fix.
My question is ... why CSRF token isn't showed in the view?
As a result my form submission are always invalid due to csrf token missing
More details
Symfony version: 2.8
Even if I use form_rest token still not be there so it's seems like is not generated at all but, under the hood, it should have been there (isValid())
EDIT
If I dump deleteForm, _token is there but if I try to use form_widget or form_row or form_rest it is not showed
If I don't use form_widget(deleteForm) or form_row(deleteForm.id), the token in showed.
I'm building a small-scale symfony project, as much for my own edification as anything else.
I have a Network class which extends Entity in a Doctrine ORM setup, and a bunch of users (also entities in a Doctrine setup). I've given some users the CREATE permission on the Network class, and that seems to be working. At least the exception is thrown when I expect it:
$securityContext = $this->get('security.context');
$objectId = new ObjectIdentity('class', 'Acme\\AcmeBundle\\Entity\\Network');
if(false === $securityContext->isGranted('CREATE', $objectId)) {
throw new AccessDeniedException("You do not have permission.");
}
But I'd like to check the permission in a twig template, something like this:
{% if is_granted('CREATE', 'Acme\\AcmeBundle\\Entity\\Network') %}
<li>
<a href="{{ path('network_new') }}">
Create a new entry
</a>
</li>
{% endif %}
My goal here is to only show the link if the user has permission to create a new network. But the is_granted() call seems to be returning true for all the users, not just the ones that I've explicitly granted CREATE to, or at least link is always appearing, even for users that have no ACL/ACE entries for the Network class.
It turns out that is_granted() expects an object as the second parameter. This is a Twig Extension that provides a classId() function to return an ObjectIdentifier object.
class ClassIdExtension extends \Twig_Extension
{
public function getFunctions()
{
return array(
'classId' => new \Twig_SimpleFunction('classId', array($this, 'classId'))
);
}
public function classId($class)
{
return new ObjectIdentity('class', $class);
}
public function getName()
{
return 'acme_classidextension';
}
}
Once it's registered as a service in Symfony, you can use it in Twig templates like so:
{% if is_granted('CREATE', classId('Acme\\AcmeBundle\\Entity\\Network')) %}
<li>
<a href="{{ path('network_new') }}">
Create a new entry
</a>
</li>
{% endif %}
And it works as expected.
Using symfony2 I load some entities and then try to iterate over them in a twig template.
However, instead of the variable content I am getting the following:
Resource id #23
My twig template looks like this:
<ol>
{% for post in posts %}
<li>
<div>
{{ post.content }}
</div>
</li>
{% endfor %}
</ol>
My controller code is:
$repository = $this->getDoctrine()
->getRepository('AppPostBundle:Post');
$reviews = $repository->findBy(
array('title' => 'my title'))
;
Maybe is too late for this answer (definitely it is LOL) but I recently had the same issue and the problem is that blob datatypes are treated as a buffer, so you have to read the info using buffer functions.
In your entity Post code you may add this method:
public function readContent(){
$content = '';
while(!feof($this->getContent())){
$content.= fread($this->getContent(), 1024);
}
rewind($this->getContent());
return $content;
}
Then in your views you may call the readcontent method instead of content:
<ol>
{% for post in posts %}
<li>
<div>
{{ post.readcontent }}
</div>
</li>
{% endfor %}
</ol>
Is better late than never :)
My entity name is : 'Test'
Blob type field is : 'Details'
in '/src/Vendorname/Bundlename/Entity/entityname.php'
**
* Get details
*
* #return string
*/
public function getDetails()
{
return $this->details;
}
/**
* Reading the blob type of content.
* #return data
*/
public function readDetails(){
$details = '';
while(!feof($this->getDetails())){
$details.= fread($this->getDetails(), 1024);
}
rewind($this->getDetails());
return $details;
}
and in '*.html.twig' file
{% for match in matches %}
{{match.readdetails}}
{%endfor%}