XF 2.0 How do I extend the canEdit function?

AndyB

Well-known member
In an add-on I'm creating, I would like to allow an easy way to override the time limit for editing a post. So it looks like I need to extend the canEdit function located here:

src/XF/Entity/Post.php

The code I'm wanting to extend is this:

PHP:
    public function canEdit(&$error = null)
    {
        $thread = $this->Thread;
        $visitor = \XF::visitor();
        if (!$visitor->user_id || !$thread)
        {
            return false;
        }

        if (!$thread->discussion_open && !$thread->canLockUnlock())
        {
            $error = \XF::phraseDeferred('you_may_not_perform_this_action_because_discussion_is_closed');
            return false;
        }

        $nodeId = $thread->node_id;

        if ($visitor->hasNodePermission($nodeId, 'editAnyPost'))
        {
            return true;
        }

        if ($this->user_id == $visitor->user_id && $visitor->hasNodePermission($nodeId, 'editOwnPost'))
        {
            $editLimit = $visitor->hasNodePermission($nodeId, 'editOwnPostTimeLimit');
            if ($editLimit != -1 && (!$editLimit || $this->post_date < \XF::$time - 60 * $editLimit))
            {
                $error = \XF::phraseDeferred('message_edit_time_limit_expired', ['minutes' => $editLimit]);
                return false;
            }

            if (!$thread->Forum || !$thread->Forum->allow_posting)
            {
                $error = \XF::phraseDeferred('you_may_not_perform_this_action_because_forum_does_not_allow_posting');
                return false;
            }

            return true;
        }

        return false;
    }

My add-on has a file called Listener.php

PHP:
<?php

namespace Andy\ChangeLimit;

use XF\Mvc\Entity\Entity;

class Listener
{
    public static function threadEntityCanEdit(\XF\Mvc\Entity\Entity $em)
    {
        echo 'test';
    }  
}

This is the Code event listener

1505521972242.webp

When I click the Edit link below a post I'm expecting to see the error message due to the echo command, but this is not working due to me not understanding how to properly extend the canEdit function.
 
Last edited:
Thank you, katsulynx.

My first step is to create the Class extension, is this correct?

1505523537849.webp
 
I found the problem, I need to extent this:

XF\Pub\Controller\Post

public function actionEdit(ParameterBag $params)

I know how to do that.

Will report back in a bit.
 
It's basically the same as in XF1, but without the overhead of having to write the listener yourself. If you need an example, I've used it in my Editor Manager to extend the XenForo BB Code renderer and ruleset, but it's really just the same as in XF1.
 
So I managed to extend the actionEdit.

PHP:
<?php

namespace Andy\ChangeLimit\XF\Pub\Controller;

use XF\Mvc\ParameterBag;

class Post extends XFCP_Post
{
    public function actionEdit(ParameterBag $params)
    {
        // get parent     
        $parent = parent::actionEdit($params);
     
        {what code should I put here?}
     
        // return parent
        return $parent;
    }

The XenForo code is this:

PHP:
    public function actionEdit(ParameterBag $params)
    {
        $post = $this->assertViewablePost($params->post_id, ['Thread.Prefix']);
        if (!$post->canEdit($error))
        {
            return $this->noPermission($error);
        }

How can I make the $post->canEdit be true allowing what would normally not allow the user to edit to edit?
 
Looks like extending the public function actionEdit is not the correct way to go. Going back to what I posted in post #1, I think I need to extend the public function canEdit.
 
Did you try to extend \XF\Entity\Post with the class proxy?

How do I do this?

I assume I need to create a file in this folder:

Andy/ChangeLimit/XF/Entity/

Do I create a file called Post.php or Listener.php

Then do I use the Code event listener or the Class extensions?
 
Okay I was able to extend the \XF\Entity\Post with the class proxy.

File structure is:

Andy/ChangeLimit/XF/Entity/Post.php

PHP:
<?php

namespace Andy\ChangeLimit\XF\Entity;

class Post extends XFCP_Post
{
    public function canEdit(&$error = null)
    {  
        $thread = $this->Thread;
        $visitor = \XF::visitor();
        if (!$visitor->user_id || !$thread)
        {
            return false;
        }

        if (!$thread->discussion_open && !$thread->canLockUnlock())
        {
            $error = \XF::phraseDeferred('you_may_not_perform_this_action_because_discussion_is_closed');
            return false;
        }

        $nodeId = $thread->node_id;

        if ($visitor->hasNodePermission($nodeId, 'editAnyPost'))
        {
            return true;
        }

        if ($this->user_id == $visitor->user_id && $visitor->hasNodePermission($nodeId, 'editOwnPost'))
        {
            $editLimit = $visitor->hasNodePermission($nodeId, 'editOwnPostTimeLimit');
            if ($editLimit != -1 && (!$editLimit || $this->post_date < \XF::$time - 60 * $editLimit))
            {
                $error = \XF::phraseDeferred('message_edit_time_limit_expired', ['minutes' => $editLimit]);
                return false;
            }

            if (!$thread->Forum || !$thread->Forum->allow_posting)
            {
                $error = \XF::phraseDeferred('you_may_not_perform_this_action_because_forum_does_not_allow_posting');
                return false;
            }

            return true;
        }

        return false;
    }
}

and the Class extension page:

1505539290592.webp
 
At this point the entire public function canEdit has been simply copied. I understand that this is overwriting the function and not desirable because other add-ons that would possibly also extend this fuction would not work. How do I get around this issue?
 
Last edited:
I think I got it.

PHP:
<?php

namespace Andy\ChangeLimit\XF\Entity;

class Post extends XFCP_Post
{
	public function canEdit(&$error = null)
	{
		$parent = parent::canEdit($error);
		
		{add my code here}
		
		return $parent;
	}
}

Where it says add my code here, I would have code to see if the user has been granted an extended period to edit the post, if they have I return true.
 
That is the correct way to achieve what you want.
The class proxy sysem basically hasn't changed since 1.X, but you do no have to create listeners (like in 1.X) any longer to extend classes - you just tell the system directly which classes you want to extend .

What happens when you create a class extension XF\Entity\Post => Andy\ChangeLimit\XF\Entity\Post (and assuming that this is the only extension for that class) is that XF will create an alias named Andy\ChangeLimit\XF\Entity\XFCP_Post for XF\Entity\Post and use Andy\ChangeLimit\XF\Entity\Post instead of the original XF\Entity\Post when instantiating an object.
 
Top Bottom