[TUTORIAL] ZOO Slack Integration with the ZOO Events System

[TUTORIAL] ZOO Slack Integration with the ZOO Events System

Welcome to the second tutorial in a series of tutorial blogs ZOOModsPlus will be releasing over the next few months. In this tutorial we are going to learn all about the ZOO Events System and how we can use it to integrate ZOO with other Joomla components as well as web APIs.

We're going to build a ZOO integration with Slack, that will send a message to Slack via a web-hook, each time a new ZOO item is created.

Get the code on GitHub    Create a Slack Webhook

Before we begin:

Let’s start by explaining what the ZOO events system is and how it works, before I show you how to code the new event plugin.

Events are little lifecycle hooks that fire when a user or admin makes an action within ZOO. These hooks allow us to fire custom functions in the background to do things like manipulate data or make a HTTP call.

For example, the “ITEM SAVED” event fires every time an admin saves a zoo item in the backend. This means we can run some custom code each time an item is saved. This custom code can do anything within the Joomla system allowing us to integrate ZOO with other Joomla components or even allowing us to connect with web API’s - the potential is limitless.

There is a large list of events that can be hooked into, ranging from Application events like adding menu items, element specific events like “download” and also comment specific events. For me, the most useful are the item events. We can run code when an item is saved, or has it’s state changed or even simply when it’s displayed.

With all that in mind, let’s go ahead and build a custom zoo event plugin that sends a Slack message when a new item is saved.

Step 1 - File/Folder Creation

Let's start by creating files for the plugin. 

The event plugin will exist inside the system folder. This is because, on a Joomla level, ZOO Event plugins are simply Joomla system plugins.

First create a folder called "zooeventslack" in "plugins/system/" and inside create 2 files; zooeventslack.xml and zooeventslack.php.

 

files

 

Step 2 - Barebones Code

Next we set up the basic XML code that tells Joomla about the new plugin. So in "zooeventsslack.xml" add:

<?xml version="1.0" encoding="utf-8"?>
<extension version="3.2" type="plugin" group="system" method="upgrade" >
<name>System - ZOO Event Slack</name>
<author>Ray Lawlor - ZOOMOodsPlus</author>
<creationDate>November 2018</creationDate>
<copyright>Copyright (C)2018 Ray Lawlor - ZOOMOodsPlus</copyright>
<license>http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 only</license>
<authorEmail>zoomodsplus@gmail.com<;/authorEmail>
<authorUrl>https://www.zoomodsplus.com</authorUrl>
<version>1.0.0</version>
<description></description>
<files>
<filename plugin="zooeventslack">zooeventslack.php</filename>
</files>
</extension>

Now over to our PHP file, let’s bootstrap a typical Joomla System plugin, like this:

<?php
/**
* @package System - ZOO Event Slack
* @author Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @copyright Copyright (C) Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 only
*/

// no direct access
defined('_JEXEC') or die('Restricted access');

jimport('joomla.plugin.plugin');

class plgSystemZooeventslack extends JPlugin
{
}

Step 3 - Loading ZOO into the plugin

Our code is going to run on every Joomla request cycle and this is done in the “onAfterInitialise” method.

This method will fire after Joomla is initialised on every page request. So edit the PHP file to:

<?php
/**
* @package System - ZOO Event Slack
* @author Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @copyright Copyright (C) Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 only
*/

// no direct access
defined('_JEXEC') or die('Restricted access');

jimport('joomla.plugin.plugin');

class plgSystemZooeventslack extends JPlugin
{

public function onAfterInitialise()
{


}
}

Now we need to call in the ZOO system. First we check that ZOO exists on this Joomla install. Next we load in the Joomla config file after we check the file exists.

Then we can load the entire ZOO system in the $zoo object variable by calling the static function getInstance. 

So edit the PHP file to this:

<?php
/**
* @package System - ZOO Event Slack
* @author Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @copyright Copyright (C) Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 only
*/

// no direct access
defined('_JEXEC') or die('Restricted access');

jimport('joomla.plugin.plugin');

class plgSystemZooeventslack extends JPlugin
{

public function onAfterInitialise()
{

if (!JComponentHelper::getComponent('com_zoo', true)->enabled) {
return;
}

jimport('joomla.filesystem.file');
if (!JFile::exists(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php')) {
return;
}
require_once(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php');

if (!class_exists('App')) {
return;
}

$zoo = App::getInstance('zoo');


}
}
NOTE:  This code is how we load ZOO into any plugin, module or script we develop in Joomla.

Now we can begin building the hook required to run our code. To do this we need to connect to the event dispatcher on the $zoo object variable we created earlier. So change the PHP file to:

<?php
/**
* @package System - ZOO Event Slack
* @author Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @copyright Copyright (C) Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 only
*/

// no direct access
defined('_JEXEC') or die('Restricted access');

jimport('joomla.plugin.plugin');

class plgSystemZooeventslack extends JPlugin
{

public function onAfterInitialise()
{

if (!JComponentHelper::getComponent('com_zoo', true)->enabled) {
return;
}

jimport('joomla.filesystem.file');
if (!JFile::exists(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php')) {
return;
}
require_once(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php');

if (!class_exists('App')) {
return;
}

$zoo = App::getInstance('zoo');

$zoo->event->dispatcher->connect('item:saved', array($this, 'sendMessage'));

}
}

This CONNECT method takes 2 arguments, the first is the type of event we want to hook into. In our case this is ITEM:SAVED. This event will fire when a ZOO item is saved.

The second argument takes an array of the class and method to run.

Here we send in $this to use this plugin class and then the function we want to run, in this case lets call it sendMessage.

So now we need to create the sendMessage function.

Step 4 - Creating the Event function

Firstly, the thing to know here is that any function called as a ZOO event function takes a parameter called $event and this contains the event object which holds the item data as well as other event metadata.

To get the item data we use $item = $event->getSubject();

We don’t want to bombard our Slack every time an item is saved, we need only send the message when a new item is created. Luckily the $event object contains a boolean property called NEW that we can use.

So change the PHP file to:

<?php
/**
* @package System - ZOO Event Slack
* @author Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @copyright Copyright (C) Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 only
*/

// no direct access
defined('_JEXEC') or die('Restricted access');

jimport('joomla.plugin.plugin');

class plgSystemZooeventslack extends JPlugin
{

public function onAfterInitialise()
{

if (!JComponentHelper::getComponent('com_zoo', true)->enabled) {
return;
}

jimport('joomla.filesystem.file');
if (!JFile::exists(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php')) {
return;
}
require_once(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php');

if (!class_exists('App')) {
return;
}

$zoo = App::getInstance('zoo');

$zoo->event->dispatcher->connect('item:saved', array($this, 'sendMessage'));

}


public function sendMessage($event)
{
$item = $event->getSubject();
$new = $event['new'];

}

}

Now that we have the boolean variable $new, we can wrap everything in an IF block that tests if we have a NEW item.

Since we need to link back to the edit view of the item, we need to build our admin link. So change the PHP file to:

<?php
/**
* @package System - ZOO Event Slack
* @author Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @copyright Copyright (C) Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 only
*/

// no direct access
defined('_JEXEC') or die('Restricted access');

jimport('joomla.plugin.plugin');

class plgSystemZooeventslack extends JPlugin
{

public function onAfterInitialise()
{

if (!JComponentHelper::getComponent('com_zoo', true)->enabled) {
return;
}

jimport('joomla.filesystem.file');
if (!JFile::exists(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php')) {
return;
}
require_once(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php');

if (!class_exists('App')) {
return;
}

$zoo = App::getInstance('zoo');

$zoo->event->dispatcher->connect('item:saved', array($this, 'sendMessage'));

}


public function sendMessage($event)
{
$item = $event->getSubject();
$new = $event['new'];


if ($new) {

$item_link = JURI::root() . 'administrator/index.php?' . http_build_query(array(
'option' => "com_zoo",
'controller' => 'item',
'changeapp' => $item->application_id,
'task' => 'edit',
'cid[]' => $item->id,
), '', '&');

}

}

}
NOTE: I won't go into how Joomla URLs work in this tutorial

This new code simply builds an admin URL to the item and places it into the $item_link variable.

Now let’s set up the $message variable. We’re going to send the message as an attachment to allow us to send a URL link as well as other item details. This needs to be a JSON object with a main property of ATTACHMENTS.

So change the PHP file to:

<?php
/**
* @package System - ZOO Event Slack
* @author Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @copyright Copyright (C) Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 only
*/

// no direct access
defined('_JEXEC') or die('Restricted access');

jimport('joomla.plugin.plugin');

class plgSystemZooeventslack extends JPlugin
{

public function onAfterInitialise()
{

if (!JComponentHelper::getComponent('com_zoo', true)->enabled) {
return;
}

jimport('joomla.filesystem.file');
if (!JFile::exists(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php')) {
return;
}
require_once(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php');

if (!class_exists('App')) {
return;
}

$zoo = App::getInstance('zoo');

$zoo->event->dispatcher->connect('item:saved', array($this, 'sendMessage'));

}


public function sendMessage($event)
{
$item = $event->getSubject();
$new = $event['new'];


if ($new) {

$item_link = JURI::root() . 'administrator/index.php?' . http_build_query(array(
'option' => "com_zoo",
'controller' => 'item',
'changeapp' => $item->application_id,
'task' => 'edit',
'cid[]' => $item->id,
), '', '&');

$message = '{
"attachments": [{
"color": "good",
"title": "' . $item->name . '",
"title_link": "' . $item_link . '",
"text": "A new item named: ' . $item->name . ' has been added to your ZOO app.",
"ts": ' . time() . '
}]
}';

}

}

}

NOTE:  All these JSON properties are explained in the Slack docs.

Next we add the final CURL script.

Firstly we initialise CURL with the HOOK URL that Slack supplied when setting up the web hook.

So change the PHP file to:

<?php
/**
* @package System - ZOO Event Slack
* @author Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @copyright Copyright (C) Ray Lawlor - ZOOModsPlus https://www.zoomodsplus.com
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 only
*/

// no direct access
defined('_JEXEC') or die('Restricted access');

jimport('joomla.plugin.plugin');

class plgSystemZooeventslack extends JPlugin
{

public function onAfterInitialise()
{

if (!JComponentHelper::getComponent('com_zoo', true)->enabled) {
return;
}

jimport('joomla.filesystem.file');
if (!JFile::exists(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php')) {
return;
}
require_once(JPATH_ADMINISTRATOR . '/components/com_zoo/config.php');

if (!class_exists('App')) {
return;
}

$zoo = App::getInstance('zoo');

$zoo->event->dispatcher->connect('item:saved', array($this, 'sendMessage'));

}


public function sendMessage($event)
{
$item = $event->getSubject();
$new = $event['new'];


if ($new) {

$item_link = JURI::root() . 'administrator/index.php?' . http_build_query(array(
'option' => "com_zoo",
'controller' => 'item',
'changeapp' => $item->application_id,
'task' => 'edit',
'cid[]' => $item->id,
), '', '&');

$message = '{
"attachments": [{
"color": "good",
"title": "' . $item->name . '",
"title_link": "' . $item_link . '",
"text": "A new item named: ' . $item->name . ' has been added to your ZOO app.",
"ts": ' . time() . '
}]
}';


$c = curl_init('https://hooks.slack.com/services/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');
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($c, CURLOPT_POST, true);
curl_setopt($c, CURLOPT_POSTFIELDS, $message);
curl_exec($c);
curl_close($c);

}

}

}

Ok now we can save everything and go to the backend of Joomla. We need to go to Extensions >> Discover, then instal the new plugin and then enable it.

Now when we save a new item in ZOO, the Slack webhook will fire, and the message we created will be sent to our Slack channel.

That's it!

I hope this tutorial has been useful. If you have any feedback please leave a comment or contact me here.

Leave a comment

You are commenting as guest.

Get updates in your inbox:

Copyright © 2018 ZooModsPlus.
ALL RIGHTS RESERVED.