| Version 7 (modified by tobias382, 5 years ago) |
|---|
Introduction
If you're interested in developing new plugins for Phergie, you've come to the right place. This guide is a work in progress to aid prospective plugin developers in getting started with Phergie's plugin API.
Getting Started
First, check out a copy of the trunk from the Subversion repository. If you're inexperienced with Subversion, check out Version Control with Subversion, a free online book and excellent reference. If you're a Windows user, TortoiseSVN is also recommended.
Second, if you aren't already fairly familiar with the PHP 5 object model, the Classes and Objects (PHP 5) section of the PHP manual is highly suggested reading, as a lot of this material will come into play while developing plugins for Phergie.
Basics
Plugins are stored within the Phergie/Plugin? folder. Each instantiable plugin should have its own file in that folder and, if needed, a directory by the same name (minus the extension, of course) to include any other files it requires. Each abstract plugin that may be required must have its own file(s) in Phergie/Plugin/Abstract?.
Within its main file, a plugin should contain a single class definition. This class should extend Phergie_Plugin_Abstract_Base and should prefix its name with Phergie_Plugin_. See the boilerplate code below.
<?php require_once 'Phergie/Plugin/Abstract/Base.php'; // Replace Pluginname here with the actual plugin name class Phergie_Plugin_Pluginname extends Phergie_Plugin_Abstract_Base { // Plugin code goes here }
IRC is a protocol centered around events. As such, plugins are designed to intercept these events and act on them in some way. The best reference for what events are available for interception by plugins is the base plugin class.
- The checkDependencies method is called within Bot.php, before plugins are instantiated. It should be used in cases when a plugin depends on a specific version of PHP, one or more PHP extensions, or another plugin in order to function properly.
- The init method is called when plugins are instantiated within Bot.php, before a connection to the server is made. It should be used in the same manner as (i. e. in place of) a constructor.
- Methods whose names are prefixed with on, such as onPrivmsg, intercept specific events while the client is connected to the server. See the docblock above each in the base plugin class for a description of its associated event.
- The shutdown method is called before the client terminates its connection to the server. It should be used in the same manner as a destructor.
All plugins are implicitly passed an event instance before event handler methods are called. This can be accessed within event handler methods via $this->event. Most events include arguments of some sort, such as the nick of the user that sent them or some sort of message content. These can be accessed either by calling $this->event->getArguments() which returns an array, $this->event->getArgument(#) where # is the position of the argument beginning from 0 or an argument name from the table below, or $this->event->getArgname() where Argname is an argument name from the table below.
| Event Type | Position | Name |
| QUIT | 0 | message |
| JOIN | 0 | channel |
| KICK | 0 | channel |
| 1 | user | |
| 2 | comment | |
| PART | 0 | channel |
| MODE | 0 | target |
| 1 | mode | |
| 2 | limit | |
| 3 | user | |
| 4 | banmask | |
| TOPIC | 0 | channel |
| 1 | topic | |
| PRIVMSG | 0 | receiver |
| 1 | text | |
| NOTICE | 0 | nickname |
| 1 | text | |
| ACTION | 0 | target |
| 1 | action |
More information on the arguments passed for each type of event can be found in Chapter 4 of the RFC for the IRC protocol. For more information on the capabilities of the event instance, check out the request (passed to most event handler methods) and response (passed to the onResponse method) classes.
Tip: Private messages are an oddity because, when intercepted as an event, the first parameter can be either a channel name or the bot's name (the latter not being particularly useful). In order to make this easier to deal with, the request class has a getSource method that returns either the channel name or the nick of the user who sent the message.
Often, a plugin's features will rely upon its ability to interact with the server beyond its ability to receive intercepted events. Specifically, it requires the ability to initiate events. Through some method overloading magic, methods defined in the underlying driver used by Bot.php are exposed to plugin instances. The base driver class is a good reference for these methods.
- Methods whose names are prefixed with do, such as doPrivmsg, execute specifics commands to interact with the server. See the docblock above each in the base driver class for a description of its associated command.
- getIni, setIni, getPluginIni, and setPluginIni are used to access and manipulate values obtained from the configuration file.
- parseHostmask is used to parse hostmasks in cases where they may be used for authenticating user identities.
- debug is used for sending debugging output to stdout while testing plugins.
The best way to get started with plugins is simply to jump in and start toying with code. The existing plugins provide good working examples.
Specialized Plugins
A few abstract plugin classes exist to provide functionality commonly needed by multiple plugins. These help in developing a plugin more rapidly by implementing generic logic to alleviate the need of reinventing the wheel within each plugin.
Command Plugin
Often, plugins deliver some on-demand functionality that is triggered by a user-issued command. The Command plugin encapsulates logic to parse messages containing commands and associated arguments and to pass that information to methods specifically meant to handle those commands while making the plugin implementation cleaner, more intuitive, and more easily maintainable. The Php and UrbanDictionary plugins are short, relatively simple examples of Command plugin implementations.
Essentially, rather than writing onPrivmsg handlers that manually parse the message text, the Command plugin handles this portion of the process and passes the arguments to a method named for the command being issued. So, for example, if the command was karma and it included a single argument, term, then its handler method would look like this.
<?php public function onDoKarma($term) { $source = $this->event->getSource(); // logic to handle the command }
AdminCommand Plugin
The AdminCommand plugin functions identically to the Command plugin except that it adds a simple access control layer on top of it. In order for it to respond to commands, the user must be either an op if the ops configuration setting is enabled or a pattern matching the user's hostmask must be included in the admins configuration setting. A subclass of AdminCommand can either have its own instances of these settings in the configuration file, or they can inherit the values set for the AdminCommand plugin in the configuration file.
Cron Plugin
The Cron plugin provides anacron-like functionality in that it limits how frequently actions are executed simply by ensuring that they aren't executed before a certain amount of time has elapsed. Checking for whether or not actions should be executed is currently limited to instances when a PING or PRIVMSG event is received from the server. To use this functionality, plugins can simply be made to extend this case and implement the abstract run method, and a delay setting (in seconds) for the plugin can be added to the configuration file.
Future Plans
If you find Phergie lacking a feature, feel free to submit a ticket. Before you do so, please check out our active ticket list to be sure that we don't already know about your request. There are a few plans for additions to the core that should make plugin development a bit easier.
Centralized Garbage Collection
At the moment, plugins are essentially having to roll their own garbage collection functionality for cases where data may not be needed after a certain point or may need to be purged from memory on a regular basis. This will likely be implemented using a driver-based approach where the initial concrete implementation will use PHP arrays and a later planned implementation will use memcached.