Jump to content

Plugins theory, how can I allow people to add plugins to my script?


Recommended Posts

Hello everyone,

 

I'm in the process of creating a PHP script (will be open-source), I just need to know how to make it easy for people to add plugins?

Like I don't really know much about the concept of plugins (how they should work), all I know is that there should be a function to activate / deactivate the plugin, but how can I make it possible for people to run their "code" wherever they want?

 

I've heard about "hooks" but I don't really understand how this should work, anyone can explain please?

 

Thank you very much in advance ;)

This is probably not something that can be easily explained within a simple forum reply. But recently I have been working on an 'Event Manager' for php which implements something similar to "hooks".

 

I blogged about it here http://thorpesystems.com/2011/11/very-simple-events-in-php/

 

Using a system similar to this you can have your application trigger events at specific locations and your plugins would listen for these events and act upon them.

A plugin system is a simple theory, although it can be more complicated to actually write it.

 

There are two general approaches: hooks and modifications. The differences are very important to understand. Modifications make actual edits to file(s) and therefore can be more buggy, because actual code has to be modified; while hooks are a more clean approach because you can modify arrays dynamically therefore circumventing potentially buggy hacks/modifications.

 

Both approaches can be found in SMF itself (this forum software), it allows mod authors to utilize hooks, yet still allows actual modification to its' files.

Hello,

 

Thank you very much for replying, I've read a little bit about hooks and I want you please to correct me if I'm wrong :

 

- there should be a function "add_hook()" that allows plugin developers to add another function to a placement in the script

- there should be multiple hook placements in the script to allow plugin developers add their code where they need.

 

Can I know where exactly I am supposed to add those "hook placements" in the code? (for example, before every HTML output, before SQL calls etc..?) or it's something I can decide based on how & where I want the plugins to work ?

 

Thanks :)

I'd be very intrigued to hear your thoughts on it's clumsiness.

 

LOL I think the entire mod/admin team has quite some stories to tell you ;) They hanged the pictures of the SMF dev team on their wall for a regular darts game!

I am part of the SMF Team...

 

Can you please send me a poster size picture of yourself then? :)

 

My main gripe with SMF's plugin solution is that you generally need to hack the core or at least a theme to get things working. Searching for specific strings of code and replacing them with other strings of code. If it did you "hooks" (I know you say it does but I haven't seen or used any) it would be much cleaner.

 

The entire code bass is a bit of a mess in my opinion, but then again, I work in a completely OOP environment generally and most things are separated properly into the appropriate layer.

 

Your not alone here however. IMO there aren't too many open source apps around in PHP that are that well designed. I think it's just what happens when projects get a larger code base and don't have enough "bigger picture" design applied to them.

My avatar is me ;)

 

Oh, I would definitely agree with that, although as of SMF 2.0 RC4 (I do believe) quite a few hooks were added, and now we're in SMF 2.0.2, and there are many more hooks available for use.

 

Hooks are not required, by any means, but we definitely suggest that mod authors utilize hooks to broaden the use range of their modification.

 

SMF 2.1 will have more extensibility for hooks, as of now most majour arrays have hooks, and definitely by the next release more useful ones will be included as well.

Your not alone here however. IMO there aren't too many open source apps around in PHP that are that well designed. I think it's just what happens when projects get a larger code base and don't have enough "bigger picture" design applied to them.

 

Yeah, pretty much all of the most popular PHP applications are utter spaghetti code.

 

That's both a great and a terrible feature of PHP.

make a folder called plugins

each plugin has to have a class in it and have code to function with your code

 

here i sm y example system we now use in wowroster

 

simple mode

class guild_rep
{
var $members_list_select;
var $members_list_table;
var $members_list_where = array();
var $members_list_fields = array();

/*
*	__construct
*	this is there the veriables for the addons are 
*	set in the plugin these are unique to each addon 
*
*	contact the addon author is you have a sugestion 
*	as to where plugin code should occure or use there descression
*/

public function __construct()
{
	global $roster;
	$this->members_list_select = '`rep`.`curr_rep`, `rep`.`max_rep`, `rep`.`AtWar`, `rep`.`Standing`, `rep`.`name` AS \'repname\', IF( `rep`.`Standing` IS NULL OR `rep`.`Standing` = \'\', 1, 0 ) AS `repisnull`, ';

	$this->members_list_table = 'LEFT JOIN `'.$roster->db->table('reputation').'` AS rep ON `members`.`member_id` = `rep`.`member_id` ';

	$this->members_list_where['guild_rep'] = "`rep`.`name` = '".$roster->data['guild_name']."' OR `rep`.`name` IS NULL";

	$this->members_list_fields['guild_rep'] = array (
			'lang_field' => 'reputation',
			'value'      => 'guild_rep_function::guild_rep',
			'order'      => array( '`rep`.`max_rep` ASC','`rep`.`curr_rep` ASC' ),
			'order_d'    => array( '`rep`.`max_rep` DESC','`rep`.`curr_rep` DESC' ),
			'filter'     => false,
			'display'    => 5
		);
}
}

and to call said files

 

function _initPlugins()
{
	global $roster, $addon;
	$addons = $roster->addon_data;
	if( !empty($addons) )
	{
		foreach( $addons as $addon_name => $addonx )
		{
			$dirx = ROSTER_ADDONS . $addonx['basename'] . DIR_SEP . 'inc' . DIR_SEP . 'plugins' . DIR_SEP;
			if (is_dir($dirx))
			{
				$dir = opendir ($dirx);
				while (($file = readdir($dir)) !== false)
				{
					if (strpos($file, '.php',1))
					{
						$info = pathinfo($file);
						$file_name =  basename($file,'.'.$info['extension']);
						list($reqaddon, $scope, $name) = explode('-',$file_name);
						if (isset($roster->plugin_data[$name]) && $roster->plugin_data[$name]['active'] == '1')
						{
							if ($scope == $roster->scope && $reqaddon == $addon['basename'])
							{
								require($dirx . $file);
								$addonstuff = new $name;
								$this->members_list_select .= $addonstuff->members_list_select;
								$this->members_list_table .= $addonstuff->members_list_table;
								if (isset($addonstuff->members_list_where))
								{
									$this->members_list_where[] = $addonstuff->members_list_where;
								}
								$this->members_list_fields[] = $addonstuff->members_list_fields;

								unset($addonstuff);
							}
						}
					}
				}
			}

		}
	}

	return true;

}

 

this loops the dir for each file in this case plugins for an addon but can be changed to just incluse any plugin happy coding

yes our frame work uses reg global so addons can use our fw not there oen makes them smaller lol but thats the basic idea

 

There's never a need to use 'global'.  Argument lists exist for a reason.  It's especially egregious to use 'global' in an OOP setting, as it creates a hidden link to an outside context, thereby coupling the object to its environment.  Simply put, if you're using 'global', you're doing it wrong.

this is getten slightly off topic .... but as a final point if im so wrong wht does phpbba nd smf use the global command in there functions in there class files...

 

@MrGary

some things i have found placing hooks at the start mid and end of a script gives more options for a user also look into event hooks but thats a larger can of worms..

this is getten slightly off topic .... but as a final point if im so wrong wht does phpbba nd smf use the global command in there functions in there class files...

 

Because they're poorly engineered POS?  WordPress is immensely popular, too.  Doesn't stop it from being a complete war zone under the hood.

 

Do yourself a favor and get the following books:

 

PHP Object, Patterns, and Practice by Matt Zandstra

 

Design Patterns: Elements of Reusable Object-Oriented Software by the Gang of Four

 

And look up the term 'Dependency Injection'.

this is getten slightly off topic .... but as a final point if im so wrong wht does phpbba nd smf use the global command in there functions in there class files...

 

Because of this:

Yeah, pretty much all of the most popular PHP applications are utter spaghetti code.

yes our frame work uses reg global so addons can use our fw not there oen makes them smaller lol but thats the basic idea

 

There's never a need to use 'global'.  Argument lists exist for a reason.  It's especially egregious to use 'global' in an OOP setting, as it creates a hidden link to an outside context, thereby coupling the object to its environment.  Simply put, if you're using 'global', you're doing it wrong.

 

I'm sorry to bring this topic back again but, do you really mean that "global" shouldn't be used in OOP methods?

Sometimes I need a lot of global variables, if I pass them as arguments it would make my class look ugly, (20+ arguments for one method)...

 

Usually I need the $database, $template, $language, $settings variables which are elementary for many classes...

 

"global" makes it a lot easier, can you please tell me why it's not a good thing to use "global" in OOP methods?

 

Because even in PHP documentation, they use that : http://php.net/manual/en/language.variables.scope.php

 

Thank you :)

yes our frame work uses reg global so addons can use our fw not there oen makes them smaller lol but thats the basic idea

 

There's never a need to use 'global'.  Argument lists exist for a reason.  It's especially egregious to use 'global' in an OOP setting, as it creates a hidden link to an outside context, thereby coupling the object to its environment.  Simply put, if you're using 'global', you're doing it wrong.

 

I'm sorry to bring this topic back again but, do you really mean that "global" shouldn't be used in OOP methods?

Sometimes I need a lot of global variables, if I pass them as arguments it would make my class look ugly, (20+ arguments for one method)...

 

Usually I need the $database, $template, $language, $settings variables which are elementary for many classes...

 

"global" makes it a lot easier, can you please tell me why it's not a good thing to use "global" in OOP methods?

 

Because even in PHP documentation, they use that : http://php.net/manual/en/language.variables.scope.php

 

Thank you :)

 

'global' ties a particular function/method to a particular context.  That's the antithesis of modularity.  How?  By creating a hidden requirement for that function/method.

 

One of the core tenants of OOP is 'code to an interface'.  All objects have an interface - their publicly accessible methods.  Moreover, every method has a signature: their name, argument list, and return value.  This allows methods to behave as black boxes, whereby certain things (what's in the argument list) are passed into the box (the method itself), and something comes out the other side (return value).  How the internals of the box work are immaterial so long as the signature is known.

 

'global' throws a monkey wrench into the whole thing because it's not part of a method's signature.  This creates an implicit requirement, known primarily only by the method itself.  That, in turn, requires whatever code is trying to invoke that method to have to know about the innards of the method.  That creates a tight bond between the method and its calling environment.

 

Then there's the issue of scope.  Objects are supposed to be encapsulated - distinct entities with clear boundaries, where the only thing the public knows about them are their interfaces.  'global' kills encapsulation in two ways:

 

1. As I said above, it makes it necessary for external code to know something about the guts of the object in order to use it.

2. Since global variables are always available, the object's boundaries crumble.  Anything can enter an object from anywhere, at any time.

 

Keep in mind, the same arguments can be made for using 'global' with regular old functions.  If you're looking to write modular, reusable code, 'global' is the wrong way to go.

 

Yes, using 'global' is easy.  It's a crutch, and all it does is introduce bad habits that lead to spaghetti code.  And, if you'll note, the link you provided merely illustrates how scope works in PHP.  It's not endorsing the use of 'global'.  The vast majority of code examples on the PHP site do NOT use 'global'.

 

Finally, if you have 20+ parameters for a method, that's a sign that your design is critically flawed.  Can you show an example?

The Class "Comment" creates an object, than checks that all what the user has typed is SQL injection free / Javascript injection free etc (needs the variable $database to "escape" SQL injection"... Checks that it respects the maximum number of characters defined by the administrator (needs the variable $settings that contains all the admin settings that have been extracted from the database to avoid multiple calls to the db)... And gets the author's IP address's ID (ID in the database to avoid storing IP Addresses everywhere), so it needs the object $ip...

 

It also verifies that the page we're willing to add a comment on accepts new comments (need the object $page to check that)

 

The same class (Comment) has a method to display the comment (display_comment()) that needs the $template variable to do that...

 

All this avoids multiple callings to database...

 

Well for arguments we need all what contributes to building a comment, "subject" "message" "author's website" "author's email" "author's username" "date of creation" etc...

 

Am I doing anything wrong?

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.