2

I'm building a plugin which needs to add users to a users-type field when they edit the entry on the front-end. It works well when the post is created, adding the original author to the field, and again when the same user edits the post. However, when another user edits the post everything comes to a standstill for a minute and users are taken not to the landing page, but to a page containing nothing other than a "1". Checking the back-end, it has added the second user to the field, though.

Can anyone suggest to me from the code below why adding a second (haven't tested any more than that yet) user brings things the server to its knees?

public function init()
{
    parent::init();

    // ON SAVE ENTRY
    craft()->on('entries.saveEntry', function(Event $event) {

        $entry = $event->params['entry'];
        $user = craft()->userSession->getUser();
        $notifyMe = craft()->request->getPost('notifyme');          

        // CHECK THIS IS THE FORUM SECTION
        if ($entry->sectionId == 16) {
            craft()->notifier->addAnotherUserToNotify($entry, $user, $notifyMe);
        }           
    });
}

And here is the function:

// ADD ANOTHER USER TO A POST'S NOTIFICATION LIST
public function addAnotherUserToNotify($entry, $user, $notifyMe) 
{
    if ($notifyMe == "yes") {

        // GET IDs OF USERS ALREADY LISTED TO BE NOTIFIED
        $usersToNotify = $entry->usersToNotify->ids();
        if ( ! in_array( $user->id, $usersToNotify ) ) {
            // ADD THE CURRENT USER TO THE ARRAY OF USERS TO BE NOTIFIED
            $usersToNotify[] = $user->id;
        }           

        // UPDATE THE ENTRY'S FIELD WITH THIS UPDATED ARRAY
        $entry->getContent()->setAttribute('usersToNotify', $usersToNotify);

        // SAVE ENTRY
        craft()->entries->saveEntry($entry);

    }

}

The code is inspired by Update User "Field Type" for Entry in Plugin

2
  • Can you post the (relevant) code from that addAnotherUserToNotify method, my guess is you've created an endless loop with calling saveEntry within the entries.saveEntry event listener.
    – carlcs
    Commented Mar 30, 2016 at 8:38
  • Sorry, I thought I'd added that but lost it while faffing with the formatting. Added. Commented Mar 30, 2016 at 8:44

2 Answers 2

5

You've created an endless loop with calling saveEntry within the entries.saveEntry event listener. You can fix it with implementing a static variable.

craft()->on('entries.saveEntry', function(Event $event) {
    static $recursionLevel = 0;

    if ($recursionLevel == 0) {
        $recursionLevel++;

        // `saveEntry` in `addAnotherUserToNotify` triggers another
        // `entries.saveEntry` event
    }
});
0
1

Here's another way to avoid the "saveEntry" infinite loop. I like to have a method in a service class that my plugin that can reuse over and over again to update entry values. As you can see, we avoid unnecessary statics and clutter in the plugin init() method. The main thing to point out is the use of "saveElement()" instead of "saveEntry()" which is the key to not triggering the saveEntry event endlessly.

From the main plugin file:

/**
 * Plugin Init
 */
public function init()
{
    parent::init();

    // triggers
    craft()->on('entries.saveEntry', array($this, '_processUsersToNotify'));
}

/**
 * Process Users To Notify
 *
 * @param Event $event
 */
public function _processUsersToNotify(Event $event)
{
    $entry = $event->params['entry']->attributes;

    $entryData = [
        'fieldSlug1' => 'lorem ipsum',
        'usersToNotify' => [1,2,3,4,5],
    ];

    // using a service method (replace pluginName/serviceName accordingly)
    craft()->pluginName_serviceName->updateEntry($entry['id'], $entryData);
}

Then in your service file:

/**
 * Update Entry Data
 */
public function updateEntry($entryId, $data)
{
    // placeholder for phase 2 feature
    $entry = craft()->entries->getEntryById($entryId);

    // set attrs
    $entry->getContent()->setAttributes($data);

    if ($entry->validate())
    {
        craft()->elements->saveElement($entry);
    }
    else
    {
        return $entry->getErrors();
    }

    return true;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.