XF 2.3 Send Alert Via PHP

Ozzy47

Well-known member
In my addon, when a keyword is found in a PM/DM, it does a few things like create a thread, send an email, log the entry into the log.

Now I'd like to send an alert to users defined in our options ozzmodz_email_convo_monitor_alerts (which is an Username input option), Id like the alert to simply say something like "New conversation keyword detected". (maybe link it to the log which is at /pmdmkeywordlog/ )

I've tried messing with it but I am not getting anywhere.
 
You can send an alert with the \XF\Repository\UserAlertRepository::alert method. Make sure you implement an alert handler for the pertinent content type if necessary and then create the corresponding alert/push templates and phrases.
 
Okay, I am getting somewhere now. I have this in my PHP file now:
PHP:
        // Send Alerts
        if (!empty($alertUserIds))
        {
            /** @var \XF\Repository\UserAlert $alertRepo */
            $alertRepo = \XF::repository('XF:UserAlert');
        
            foreach ($alertUserIds as $userId)
            {
                /** @var \XF\Entity\User|null $alertUser */
                $alertUser = \XF::em()->find('XF:User', $userId);
        
                if ($alertUser && $alertUser->user_id != $message->user_id) // Don’t alert the sender
                {
                    // Debug: Confirm alert attempt
                    //\XF::log("Sending alert to user ID {$alertUser->user_id} ({$alertUser->username})");
        
                    $alertRepo->alert(
                        $alertUser,
                        0,
                        'System',
                        'conversation_message',
                        $messageId,
                        'ozzmodz_keyword_detected',
                        [],
                        ['usePush' => false]
                    );
                }
            }
        }

Then I extended XF\Alert\ConversationMessageHandler with OzzModz\ConversationMonitor\XF\Alert\ConversationMessageHandler in that file I have:
PHP:
<?php

namespace OzzModz\ConversationMonitor\XF\Alert;

class ConversationMessageHandler extends XFCP_ConversationMessageHandler
{
    public function getOptOutActions()
    {
        \XF::logError('Custom ConversationMessageHandler loaded!');
        return array_merge(parent::getOptOutActions(), [
            'ozzmodz_keyword_detected'
        ]);
    }

    public function getEntityWith()
    {
        return ['Conversation']; // ✅ Important
    }

    public function getContentText($alert)
    {
        \XF::logError('getContentText() triggered for alert ID: ' . $alert->alert_id);
        return \XF::phrase('ozzmodz_conversation_monitor_alert_text');
    }

    public function getContentLink($alert)
    {
        return \XF::app()->router('public')->buildLink(
            'conversations/message',
            $alert->Content
        );
    }
}

In my template I have:
HTML:
Keyword detected in a private conversation.

<a href="{$alert.link}">View</a>

I now get an alert bell, but no actual alert.
 
Guessing I might need this, content type and content type field, but not entirely sure, and if I do, have no idea how to do that. If changing the setup file, it would be needed in initial installation and on upgrading to 2.0.1
 
@Ozzy47 this helped me with a similar problem:

 
I saw that, but as I described above I am stuck with "A custom content type added to the xf_content_type and xf_content_type_field tables"

I don't know what to do there and I'm not certain I am doing the whole process right.
 
That's only necessary when adding a handler to a content type which does not already have one. The conversation_message content type already has a alert_handler_class field.

Also, the core getEntityWith method already eager-loads the Conversation relation, and the getContentText and getContentLink methods in your class extension are LLM hallucinations, so none of those should be necessary.
 
That's only necessary when adding a handler to a content type which does not already have one. The conversation_message content type already has a alert_handler_class field.

Also, the core getEntityWith method already eager-loads the Conversation relation, and the getContentText and getContentLink methods in your class extension are LLM hallucinations, so none of those should be necessary.

Okay, that confuses me even more. What do I have to change in my current file(s) to send the simple alert?
 
You can remove those methods, otherwise nothing. If you go to the full alert page (/account/alerts) do you see any errors? Did you name the alert template properly (alert_conversation_message_ozzmodz_keyword_detected)? Does the receiver have permission to view the conversation message?
 
If you go to the full alert page (/account/alerts) do you see any errors?
No there are no errors.

Did you name the alert template properly (alert_conversation_message_ozzmodz_keyword_detected)?
Yes, it's alert_conversation_message_ozzmodz_keyword_detected

Does the receiver have permission to view the conversation message?
No. I am scanning conversation messages as they are posted, and if there is a keyword detected I simply want to say in the alert, "Keyword detected in a private conversation." (which is in my template)
 
Alerts are hidden if the backing content is not viewable. Consider instead sending the alert for the user content type, and making the action conversation_message_ozzmodz_keyword_detected (renaming your template as necessary).
 
Got it working now. Had to change my template (name) to be less than 30 characters, then this worked:
PHP:
$alertRepo->alert(
    $alertUser,
    0,
    'System',
    'user',
    $message->user_id,
    'conv_keyword',
    [
        'conversation_id' => $message->conversation_id,
        'message_id' => $message->message_id
    ],
    ['usePush' => false]
);

And that works without extending anything.. Thank you Jeremy!!
 
Back
Top Bottom