Writing to secondary table when thread is created...

digitalpoint

Well-known member
So I have a table that I need to write stuff to when a new thread is created (very similar to how polls are created in a different table when needed)...

I extended the XenForo_DataWriter_Discussion_Thread class, and added my table/fields to the _getFields() method... more or less works well... it creates a record in my custom table with the new thread_id (exactly what I want to do), but all the other fields are just set as default (blank or 0).

The problem is I can't find a good place within the XenForo_ControllerPublic_Forum::actionAddThread() method to set my fields for my secondary table... it would need to be somewhere between the $writer object being created and the $writer->save(); method being called.

Maybe extend the $writer->preSave() method and do it all in there?
 
Yeah, was mucking around with it a bit... ended up throwing an error about not being able to set something after preSave() was called... apparently preSave is getting called twice for some reason (didn't trace around why that would be). But running my stuff on preSave() only if it hasn't already run (and then setting a flag that it's run afterwards) seems to do the trick.

Still seems odd that XF is running preSave() twice, but w/e...
 
preSave is called twice, because save() calls also preSave...

BUT the second time it shouldn't run, because the first run sets $dw->__preSaveCalled to true, which is checked inside of presave

PHP:
    /**
    * Public facing handler for final verification before a save. Any verification
    * or complex defaults may be set by this.
    *
    * It is generally not advisable to override this function. If you just want to
    * add pre-save behaviors, override {@link _preSave()}.
    */
    public function preSave()
    {
        if ($this->_preSaveCalled)
        {
            return;
        }

        $this->_preSaveDefaults();
        if (!$this->_importMode)
        {
            $this->_preSave();

            if (!$this->_existingData)
            {
                $this->_resolveDefaultsAndRequiredFieldsForInsert();
            }
            else
            {
                $this->_checkRequiredFieldsForUpdate();
            }
        }
        else if (!$this->_existingData)
        {
            $this->_resolveDefaultsAndRequiredFieldsForInsert(false);
        }

        $this->_preSaveCalled = true;
    }

so if you overwrite/extend preSave, you could also check if _preSaveCalled is set and if yes, do nothing..;)
 
Yep... That's what I'm doing. Kind of hackish to put code that should be in a controller inside the DataWriter, but at least it gets the job done I suppose...
 
Now if only XenForo_DataWriter_Discussion::_preSave() wasn't a "final" method...

Sometimes I really hate the final keyword on methods.
 
Oh, I guess I should have looked around a bit more. lol

I love the XenForo code, but when I'm done with all this rewriting stuff I'm taking a vacation (been spending about 60 hours/week on XenForo stuff the last month). :)
 
It would be nice to have a better way to do this. Throwing all the stuff that should be in the controller into the datawriter is silly and really ugly. As it is, we need to check the controller and action and only extend the datawriter if we are within the correct action...

PHP:
if (isset($GLOBALS['fc']))
{
	// Only want to do this when creating a new thread - blah
	if ($GLOBALS['fc']->route()->getControllerName() === 'XenForo_ControllerPublic_Forum' && $GLOBALS['fc']->route()->getAction() === 'add-thread')
	{
		if ($class === 'XenForo_DataWriter_Discussion_Thread')
		{
			$extend[] = 'DigitalPointMarketplace_DataWriter_Discussion_Thread';
		}
	}
}

We have to do that because what we are doing involved input from the thread creation form, which simply won't be there when the datawriter is possibly initiated for other things.

Then within the datawriter we are needing to initiate the XenForo_Input class and do all the stuff we are actually trying to do...

PHP:
class DigitalPointMarketplace_DataWriter_Discussion_Thread extends XFCP_DigitalPointMarketplace_DataWriter_Discussion_Thread
{
	public function _discussionPreSave()
	{
		parent::_discussionPreSave();
				
		$input = new XenForo_Input($GLOBALS['fc']->getRequest());
		$this->set('something', $input->filterSingle('input_field', XenForo_Input::UINT));
	}
}

It works... but omg it's quite ugly and hackish... lol
 
You're crazy... creating a input class within the datawriter... using $GLOBALS, etc... makes me want to cry. :)
me too, but it's nicer as my primitive solutions (because i'm overwriting the complete methods for my boards => and that's only available for 1 add-on so i had to mix several add-on codes...
it's working and doesn't have too much overhead, but with this way it's impossible to release the add-ons:D

my last plan was to overwrite the method and create 1 event sending the controller (to have access to input + controller helpers) + dw object as params.
So i wouldn't need to worry about the xf upgrades.. only 1 diff change per controller necessary
 
Top Bottom