Documentation on campaign decision outdated? If so, How to trigger a decision from a custom API endpoint?

Hi everybody!

I’m writing a decision plugin and facing undefined method error for CampaignModel.triggerEvent,

Here is the relevant documentation section:
https://developer.mautic.org/?php#extending-campaigns

The section calling triggerEvent

I have an hello world plugin for ease reproduction of problems and I updated it to reproduce this: GitHub - dhilst/HelloWorldBundle: Mautic plugin hello world with custom action

In the real case I have a chatbot and the lead will trigger decision as he/she talks to the bot, my backend will do a request to a custom API at Mautic to signal that a decision was taken by the lead. At this API I get the campaign.model and try to call ->triggerEvent(...) as shown in the documentation. This is where I got an Undefined method error. I opened the CampaignModel class and there is no such triggerEvent there, so I’m thinking that the documentation is outdated. I willing to update the documentation once I find a way to solve my problem first, so I can use it as example.

I call trigger event here,

Here is the error
{"errors":[{"message":"Attempted to call an undefined method named \u0022triggerEvent\u0022 of class \u0022Mautic\\CampaignBundle\\Model\\EventModel\u0022.","code":500,"type":null}],"

Next I looked for an example of an decision being triggered on Mautic code, I decided to use email open decision because I’m using it daily. From what I could follow from code:

  • It has a controller that receives the tracking pixel request
  • It dispatches an EMAIL_HIT event
  • EMAIL_HIT event is handled by QueueSubscriberEvent, I think this is a good pratice to not handle the event while blocking the request,
  • onEmailHit calls EmailModel.hitEmail
  • hitEmail does lots of tracking things but what seems to important to me is this ->dispatcher->dispatch(EmailEvents::EMAIL_ON_OPEN, ...) call
  • EMAIL_ON_OPEN is handled by EmailBundle\...\CampaignSubscriber.onEmailOpen() and this 'email.open' is the same 'email.open' that was registered with addDecision so think this is how the campaign knows that this decision were triggered right?

So in the end I need to call realTimeExecutioner->execute('<my decision string id>, $passthrough, $channel, $channelId) to tell Mautic that this decision were taken by the lead, right? Here I have some questions:

  • Does channel can be anything other than email? In my real world case I have a chatbot and the user will trigger decisions as he/she progress over the chat. I have no chatbot channel in Mautic, and don’t want to add one as it will not be used to send messages etc, I don’t need one right? I mean, it’s safe to pass any string here as long is not ‘email’, or another channel natively used by Mautic, right?
  • What is $passthrough at all?
  • And what is the purpose of the $channelId? What is a good example for it?

Okay I will answer my for documentation purposes and maybe if I’m doing something wrong the developers can correct me.

I hat to fetch the lead and set it in the tracking service, this is needed so that the realtime executioner knows that lead this event is for. debtorid is a custom field that we use and is the id on our backend database. I send it on the request and use it to fetch the lead from mautic database.

Then I call realTimeExecutioner. I will use a queue on my backend so no need to use queue in Mautic too. It would be nice if we have a cleaner interface for simple plugins to use but this is not bad at all.

Is this approach fine enough to be added to the documentation?

Cheers

Okay I have updates on this.

I my case I have an input in my form and I must only trigger events if the parameter in the request is the same as the parameter in the form. I think this would be pretty common in most of the cases.

I refactored my example code to and replace parameters to placeholders that everybody can understand, replaced debtorid by leadId and checkpoint by myparameter, this would be easier for other users to follow and is better suited for an example.

The strategy is basically the same, the difference is that now I have an arbitrary number parameter in decision form

And I send the same myparameter in the request, here is an example using curl

  • In API controller I use $leadId.$myparameter as channel id, and pass this to $realTimeExecutioner->execute(..., $channelId)
  • In the decision handler at CampaignSubscriber.php I take the lead id from the event and the My parameter from the form, and use these to create a channel id too. Then I retrieve the $channelId from RealtimeExecutioner at $event->getLog()->getChannelId()
  • I use both channel id to decide between calling $event->setResult(true) or $event->setResult(false)

With this I could accomplish the task of triggering an event based on comparing some input in the decision form and the request, but for me it seems that I’m misusing the channel id.

In RealTimeExecutioner it checks for the channel id and only executes if it matches, the problem here is that my campaign event doesn’t have channel id setted and I don’t really know how to set it since it would be distinct for each {lead, my parameter}, tuple.

Am I misusing the channel id? And should I use passtrough for doing the same thing?

Now diving more in the code, here is the controller

And here is the decision handler, I think these are the more important parts of the code

Everything is the github at GitHub - dhilst/HelloWorldBundle at make-decision-work (not master!)