Search code examples
symfonyphp-5.4foscommentbundle

FOSCommentBundle access control replying,deleting and editing Comments


I have successfully installed FOSComentBundle on my symfony2.3 project. I have integrated FOSCommentBundle with FOSUserBundle, then I added the role based ACL security.I have seen that the actions that can be controlled are :create,view,delete,edit. I want to show the reply button only for admin, But I haven't found how to add access role to the reply event. This is my config file:

acl: true
service:
    acl:
        thread:  fos_comment.acl.thread.roles
        comment: fos_comment.acl.comment.roles
        vote:    fos_comment.acl.vote.roles
    manager:
        thread:  fos_comment.manager.thread.acl
        comment: fos_comment.manager.comment.acl
        vote:    fos_comment.manager.vote.acl
acl_roles:
    comment:
        create: IS_AUTHENTICATED_ANONYMOUSLY
        view: IS_AUTHENTICATED_ANONYMOUSLY
        edit: ROLE_ADMIN
        delete: ROLE_ADMIN
    thread:
        create: IS_AUTHENTICATED_ANONYMOUSLY
        view: IS_AUTHENTICATED_ANONYMOUSLY
        edit: ROLE_ADMIN
        delete: ROLE_ADMIN
    vote:
        create: IS_AUTHENTICATED_ANONYMOUSLY
        view: IS_AUTHENTICATED_ANONYMOUSLY
        edit: ROLE_ADMIN
        delete: ROLE_ADMIN

Is there any class that I have to override? Is there any docs for the reply button?


Solution

  • After looking into the FOSCommentBundle, I have found a solution for my problem :

    1. first, you have to override the RoleCommentAcl : by creating a folder named Acl into MyBundle. Inside this folder I create a php class named RoleCommentAcl :

    namespace MyProject\MyBundle\Acl;
    
    use FOS\CommentBundle\Acl\RoleCommentAcl as BaseRoleCommentAcl;
    use FOS\CommentBundle\Model\CommentInterface;
    use FOS\CommentBundle\Model\SignedCommentInterface;
    use Symfony\Component\Security\Core\SecurityContextInterface;
    
    class RoleCommentAcl extends BaseRoleCommentAcl {
    
    /**
     * The current Security Context.
     *
     * @var SecurityContextInterface
     */
    private $securityContext;
    
    /**
     * Constructor.
     *
     * @param SecurityContextInterface $securityContext
     * @param string                   $createRole
     * @param string                   $viewRole
     * @param string                   $editRole
     * @param string                   $deleteRole
     * @param string                   $commentClass
     */
    public function __construct(SecurityContextInterface $securityContext, $createRole, $viewRole, $editRole, $deleteRole, $commentClass
    ) {
        parent::__construct(
                $securityContext, $createRole, $viewRole, $editRole, $deleteRole, $commentClass);
    
        $this->securityContext = $securityContext;
    }
    
    /**
     * Checks if the Security token has an appropriate role to edit the supplied Comment.
     *
     * @param  CommentInterface $comment
     * @return boolean
     */
    public function canEdit(CommentInterface $comment) {
        // the comment owner can edit the comment whenever he want.
        if ($comment instanceof SignedCommentInterface) {
            if ($comment->getAuthor() == $this->securityContext->getToken()->getUser()) {
                return true;
            }
        }
        return parent::canEdit($comment);
    }
    
    /**
     * Checks if the Security token is allowed to delete a specific Comment.
     *
     * @param  CommentInterface $comment
     * @return boolean
     */
    public function canDelete(CommentInterface $comment) {
         // the comment owner can delete the comment
        if ($comment instanceof SignedCommentInterface) {
            if ($comment->getAuthor() == $this->securityContext->getToken()->getUser()) {
                return true;
            }
        }
        return parent::canDelete($comment);
    }
    
    /**
     * Checks if the Security token is allowed to reply to a parent comment.
     *
     * @param  CommentInterface|null $parent
     * @return boolean
     */
    public function canReply(CommentInterface $parent = null) {
    
        if ($parent instanceof SignedCommentInterface) {
              //only the comment owner or the admin can reply to the comment.
            if ($parent->getAuthor() == $this->securityContext->getToken()->getUser() ||
                    $this->securityContext->isGranted('ROLE_ADMIN')) {
                return true;
            }
        }
         if($parent !=null) {
           // if the user have no access to reply then return false.
              return false;
         }  
       //this ligne allow all users to post new comments.
        return parent::canCreate();
    }
    

    }

    2. Then you have to add into services.xml the access permissions:

    <?xml version="1.0" ?>
    
    <container xmlns="http://symfony.com/schema/dic/services"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
    <services>
        <service id="myproject.name_bundle.acl.comment.roles" class="MyProject\MyBundle\Acl\RoleCommentAcl" public="false">
            <argument type="service" id="security.context" />
            <argument>IS_AUTHENTICATED_ANONYMOUSLY</argument> <!-- Create role -->
            <argument>IS_AUTHENTICATED_ANONYMOUSLY</argument> <!-- View role -->
            <argument>ROLE_ADMIN</argument> <!-- Edit role -->
            <argument>ROLE_ADMIN</argument> <!-- Delete role -->
            <argument>%fos_comment.model.comment.class%</argument>
        </service>
    </services>  </container>
    

    PS: If you are using service.yml you can translate this xml file into yaml but if you want to use the services.xml you have to change the configuration sets into the DependencyInjection of your bundle:

    $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
        $loader->load('services.xml');
    

    Open your page and you will notice that the reply will be accessed just by comment owner and admin users.Also the delete and Edit can be shown just for comment owner and admin.