Jump to content

I'm very excited to be posting my first blog entry for IPS, and thrilled that this is what I get to post.

When we started planning the new development tools for v5, we looked at existing resources - from the marketplace, from some contributors, and from our own managed clients - and asked, what is it that developers find themselves doing the most often? Matt’s previous blog entry gave a brief summary of some of those functions. Today’s blog entry is going to focus on one of our powerful new tools, Listeners.

One common reason for a code hook was to execute custom code when a specific action occurs. For example, when a topic is created, or when a new reply is posted. Listeners allow you to execute your code at key points in the workflow, without the worry of finding exactly the right hook location.

Here is an excerpt from the BlogComment listener in our Cloud application:

Could contain: Electronics, Screen, Computer Hardware, Hardware, Monitor, Computer, Pc, Page, TV, Business Card

 

Creating Listeners

Let’s start with the application’s Developer Center.

Could contain: Page, Text

We’ve added a new tab for Listeners. This tab lists all your existing listeners, as well as the class on which it is listening.

You’ll notice that each listener can only observe a single class. While this may seem slightly tedious, the idea here was that as a developer, you should be conscious of what class you are working with. It also eliminates the need to check what type of object is being passed preventing accidents and unintended consequences when missing class checks.

When you add a listener, there are several listener types available. We will discuss each one in detail.

Could contain: Page, Text, Computer, Electronics, Pc, White Board

 

Content Listener

This listener is fired on an Item or Comment (or Review) class. When adding a Content Listener, you must specify the class you are observing. When you hit Save, there is a validation check in place to ensure that the class exists, and that it is a valid class for the selected listener type.

Content Listeners have the following methods available. All methods are included in the default listener file that is generated.

  • onLoad
    Triggered when an object is loaded (in Content::constructFromData)

NOTE: Be careful! This event could be fired at unexpected times. If you’re executing code here, you may want to check the dispatcher instance to verify that your code is running where you expect.

  • onBeforeCreateOrEdit
    Fired when a form is submitted, before it is saved. This is the equivalent of Item::processBeforeCreate and Item::processBeforeEdit. This method includes a parameter to indicate whether this is a create or edit.
  • onCreateOrEdit
    Fired after a form is saved. This is the equivalent of Item::processAfterCreate and Item::processAfterEdit. This method includes a parameter to indicate whether this is a create or edit.
  • onDelete
    Fired after an object is deleted.
  • onStatusChange
    Fired when any moderation action occurs. For example, when an item is pinned/unpinned, locked/unlocked. The moderation action is passed as a parameter so that your code can take that into account.
  • onMerge
    Triggered AFTER an item is merged.
  • onItemView
    Triggered when an item is viewed and the view count is incremented.

 

Invoice Listener

An Invoice listener is fired only on the \IPS\nexus\Invoice class. This listener does not require you to specify a class to extend.

The Invoice listener includes a single method, onStatusChange. This is fired when the invoice is saved and the status changes (pending/paid/expired/canceled).

 

Member Listener

The Member listener will be familiar to many of you. We have taken the MemberSync extension and moved it in its entirety to a listener, as it was a better fit for this structure. All the previous methods that were available are still available here. We have also added the following new methods:

  • onJoinClub
    Fired when a member joins a club. If approval is required, this is fired after they are approved.
  • onLeaveClub
    Fired when a member leaves or is removed from a club.
  • onEventRsvp
    Fired when a member responds to an event. The response is included as a parameter to this method.

 

Commerce Package Listener

The Commerce Package listener is fired on any implementation of \IPS\nexus\Invoice\Item. You must specify the class that you are observing.

The methods are the same as those that are available in an item extension.

  • onCancel
  • onChange
  • onDelete
  • onExpireWarning
  • onExpire
  • onInvoiceCancel
  • onPaid
  • onPurchaseGenerated
  • onReactivate
  • onRenew
  • onTransfer
  • onUnpaid

 

Some Technical Notes

  • All listener files will be generated in a “listeners” directory within your application.
  • Your application’s data directory will include a listeners.json file that defines all your listeners. The json file is automatically generated when you add/remove a listener.
  • All listener methods are optional. The default class that is generated will include all available methods, but they do not have to be present in your file.
  • All listener methods are return type void.
  • If a listener method fails, an exception will be thrown when IN_DEV is enabled. In production, the exception will be logged with a reference to the listener class and the event on which the exception occurred.

 

Firing Events

Your code can fire any existing event using the Event::fire method.

Example:

Event::fire( 'onBeforeCreateOrEdit', $comment, array( $values ) );

The Event::fire method is called statically and accepts an event name, the object on which the event will be fired, and an array of additional parameters (varies according to the event that you are triggering).

This concludes our introduction to Listeners. We do intend to implement additional listener types and events based on your feedback and as the need arises.

User Feedback

Recommended Comments

 

@Esther E.

Just to confirm: will this return all data from the invoice? I mean, I need at least the i_items, to see if the invoice belongs to a purchase of a Downloads file.

Thank you.

Listeners don't return any data at all. I'm not quite following the question, can you please clarify? 

Adriano Faria

Clients
 

Listeners don't return any data at all. I'm not quite following the question, can you please clarify? 

I need to move users to another group when they make a purchase a file in Downloads. Is there any way to get that information?

An achievement rule could be an easy way to do it but there isn’t such a rule currently.

 

I need to move users to another group when they make a purchase a file in Downloads. Is there any way to get that information?

An achievement rule could be an easy way to do it but there isn’t such a rule currently.

You want to use the commerce package listener, not an invoice listener.

Adriano Faria

Clients
 

You want to use the commerce package listener, not an invoice listener.

Ok. Somehow I thought it would be tied to a product (package) due to its name. Guess I’m wrong?

Thanks.

 

Ok. Somehow I thought it would be tied to a product (package) due to its name. Guess I’m wrong?

Thanks.

Yes, it's fired on \IPS\nexus\Invoice\Item. you specify the item type you want to listen on, so in your case you'd create a listener on downloads\extensions\nexus\Item\File.

Adriano Faria

Clients
 

Did you managed it or got a reply?

This:

But I didn't try it yet.

DawPi

Clients
(edited)

Woah, totally forgot it. I'll give it a chance, thanks!

Edited by DawPi

DawPi

Clients
 

You could use this approach

 

Works! Thanks!

 

Can I ask a question? What if I or other developers use it more frequently to maintain different types of mods? Will it slow IC5 down too much?

 

 

Adriano Faria

Clients

@Esther E. I’m not sure there’s a way to do that, so please let me know.

Is there a way to know when a new version was uploaded to a file, If not, could you please add a way to do it?

Thank you.

onCreateOrEdit works here too
\IPS\downloads\File::processAfterNewVersion

		$this->ui( 'formPostSave', array( $values ) );		
		/* Fire event for listeners */
		Event::fire( 'onCreateOrEdit', $this, array( $values ) );
		Webhook::fire( 'downloads_new_version', array( $this ) );

Adriano Faria

Clients
(edited)
 

onCreateOrEdit works here too
\IPS\downloads\File::processAfterNewVersion

		$this->ui( 'formPostSave', array( $values ) );		
		/* Fire event for listeners */Event::fire( 'onCreateOrEdit', $this, array( $values ) );
		Webhook::fire( 'downloads_new_version', array( $this ) );

Daniel, $this in the onCreateOrEdit will be the file data, right?

EDIT: never mind. The current changelog is in the files table.

Edited by Adriano Faria

IPBSkins

Clients
 

Sooo maybeeee you could add BIG RED TRIGGER to enable hooks with all the risk and consequences ceded to the owner of the forum?

It would be an excellent compromise.

@Matt since you have replied quite often under this post, and although a lot of time has passed, were compromise solutions accepted or as suggested in the quoted message?

I have long refrained from studying v5, but some functions that were solved simply by a hook, now need to be duplicated by the standard one, or it is impossible.

For example, earlier, to add additional social networks to the footer, you just needed to add a hook for the addSocialNetworks method of the SocialProfiles class, I don't think you will add additional services, the same Telegram and other services.

Further, the same applies to embedding videos from third-party resources, also without any problems customEmbed class IPS\Text\Parser you could add 3 video hosting services, and no perversions.

Or, on the contrary, disable the preview of internal links to reduce the load, simply by redefining internalEmbed. Also, for example, all sorts of harmless things, like in version 4 you can redefine the formatting of dates using \IPS\DateTime was extremely simple, although I admit it was not always necessary.

Again, this is not even a question of habit or convenience of development, here are additional overhead costs for development and additional logical heaps, and most importantly possible serious limitations in the future. If you look at the retrospective about the marketplace in the comments under this post, the refusal of self-hosted does not seem like an incredible scenario, because Cloud is the basis (and the main reason for abandoning the hook system, despite the horror of Monkey Patching and "care" for the IDE) and, as they wrote, it is better to focus on several clients.

Personally, I see and advise all remaining clients with an active license (up to 10 resources) to stay on version 4 as much as possible, or switch to other products. Some clients are very principled and high-quality customization is very important to them, there is no enthusiasm for large manuals and for manual editing of the source code as it was before IPB 3. From a business point of view, IPB/IPS has never been a business for me, since 2008 it has only been a hobby until now, now commercial work is only with well-known frameworks or CMS.

I will of course try to convey to clients that they need to come to terms with and accept the fact that this cannot be modified.

chopin

Clients

Ok with this new system, I'm wondering if I can achieve the same functionality I currently have. Let me explain what I'm doing:

  • With mp3 uploads, I have my own mp3 player, because it accounts for multiple movements (multiple tracks). I also coded in a nice frontend to allow embedded pdfs using google pdf viewer.

  • My method overrides the default mp3 player behavior using template hooks. It also removes the "embedded attachments, such as pdf uploads".

Since I'm making template edits, I wonder if Listeners is what I need? Would it be a content listener? Or is there no longer a way to make a template edit replacement (by inserting custom functionality)?

chopin

Clients

Hi @Matt, I'm a little late to the game, but it appears that making template edits is no longer possible. I needed some type of way to read mp3 files, and auto embed a custom mp3 player into a post (I use soundmanager). But I also needed a way to take pdfs and have them clickable via a Google pdf reader.

If this is no longer possible with v5, then I will accept it (less work on my end to maintain something ha!), but I just want to make sure before I do the upgrade.

chopin

Clients

Man, if you could extend your app to work in topics and posts, I'd hold off on upgrading, and wait to purchase your app lol. Here's an example of how I currently am implementing mp3 tracks and pdf embeds:

Example Topic

The pdf display is just a simple click, that takes the user to the embedded pdf file. The mp3 player I have is soundplayer, but could be whatever player that allows multi tracks. Let me know if you'd be up for extending your app. The less maintenance I have to do with invision, the better since I am working on another large software product.

Adriano Faria

Clients
 

Man, if you could extend your app to work in topics and posts, I'd hold off on upgrading, and wait to purchase your app lol

Not enough space there.

chopin

Clients

I kind of have a problem with the current mp3 uploads. The default mp3 uploads don't have any way of labeling what the mp3 is. And I'm not seeing a way to customize this without hacking the actual template files (because I am not seeing a way to replace tags). So I'm left with this:

Can the developers look into:

  • Embedded mp3 players that handles tracks?

  • A way to embed pdfs so that a click doesn't download the file?

The way my community works, is that we review music in specific forums. And it's very common to attach multi-movement works in a topic or a post, along with a pdf score.

Maybe I can get lucky here and the developers can code this in for me? 😀

 

I kind of have a problem with the current mp3 uploads. The default mp3 uploads don't have any way of labeling what the mp3 is. And I'm not seeing a way to customize this without hacking the actual template files (because I am not seeing a way to replace tags). So I'm left with this:

Can the developers look into:

  • Embedded mp3 players that handles tracks?

  • A way to embed pdfs so that a click doesn't download the file?

The way my community works, is that we review music in specific forums. And it's very common to attach multi-movement works in a topic or a post, along with a pdf score.

Maybe I can get lucky here and the developers can code this in for me? 😀

You would need to post within the feedback area if you wish to see something like this appear within the core platform