XF 2.1 Save again to same entity during _postSave

AndrewSimm

Well-known member
I am working on a Quote addon that allows users to post quotes and authors to a page. Once the user submits the quote, author, etc I check if the author currently exists in the author table and add it if it does not. This part works with no issues. Last, once the author exists in the authors table I want to update the quote table with the author id from the authors table. I am getting am message telling me to use "forceSet" and I am not exactly sure what this does or if I should be using it. I also don't know how to use it.

PHP:
    protected function _postSave()
    {

        $author_name = $this->author;
        $quoteId = $this->quote_id;
        $repo = $this->repository('Andrew\Quotes:Author');
        $finder = $repo->findAuthor();
        $author = $finder->where('author',$author_name)->fetchOne();

        $authorId = '';

        if(!empty($author))
        {
            $authorId = $author->author_id;
        }

        $this->updateAuthor($author, $author_name, $authorId);

        $this->updateQuoteAuthorId($quoteId, $author_name, $authorId);

        $this->_postSaveBookmarks();
    }

    protected function updateQuoteAuthorId($quoteId, $author_name, $authorId)
    {
        if(empty($authorId))
        {
            $this->updateBasedOnAuthorName($author_name, $quoteId);
        }
        else
        {
            $this->updateBasedOnAuthorId($authorId, $quoteId);
        }
    }

    protected function updateBasedOnAuthorName($author_name, $quoteId)
    {
        $repo = $this->repository('Andrew\Quotes:Author');
        $finder = $repo->findAuthor();
        $author = $finder->where('author',$author_name)->fetchOne();

        $authorId = $author->author_id;

        $repo = $this->repository('Andrew\Quotes:Quote');
        $finder = $repo->findQuote();
        $quote = $finder->where('quote_id', $quoteId)->fetchOne();

        $save = $quote;
        $save->author_id = $authorId;
        $save->save();
    }

    protected function updateBasedOnAuthorId($authorId, $quoteId)
    {
        $repo = $this->repository('Andrew\Quotes:Quote');
        $finder = $repo->findQuote();
        $quote = $finder->where('quote_id', $quoteId)->fetchOne();

        $save = $quote;
        $save->author_id = $authorId;
        $save->save();
    }
 

DragonByte Tech

Well-known member
I would recommend looking into \XF::runLater() :)

You can replace your entire postSave function with this:
PHP:
\XF::runLater(function()
{
    /** @var \Andrew\Quotes\Entity\Author $author */
    $author = $this->repository('Andrew\Quotes:Author')
        ->findAuthor()
        ->where('author', $this->author)
        ->fetchOne()
    ;

    $authorId = $author ? $author->author_id : '';

    $this->updateAuthor($author, $this->author, $authorId);
    $this->updateQuoteAuthorId($this->quote_id, $this->author, $authorId);

    $this->_postSaveBookmarks();
});
Because the closure receives the context it was defined in, $this still works as a reference to the entity itself.

Be warned; this means the entity will be updated on shutdown (e.g. after literally everything else has ran, just before the database disconnects at the end of the request), so if you rely on the new author ID anywhere else in the flow of your code, then this method does not work.

If you need this, then you should instead use a Service to update your entity, which enables you to run code that happens after the entity has been updated / saved / cleaned up.
 
Top