Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

...

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_Plugin Component Proposal

Proposed Component Name Zend_Plugin
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Plugin
Proposers Keith Pope Shaun Mitchell
Revision 0.1 - 07 July 2006: Initial Submission
0.5 - 21 July 2006: First Draft
0.6 - 02 September: Added Listeners
0.7 - 12 September: Updated Use-case (wiki revision: 21)

Table of Contents

1. Overview

Zend_Plugin provides a simple way for developers to add a plugin architecture to their application.

2. References

  • PHP|Architect Magazine Article - Developing a plugin architecture by Titus Barik

3. Component Requirements, Constraints, and Acceptance Criteria

  • Implement a plugin contract that all plugins will abide by.
  • Have a plugin loader / Manager.
  • Enable developers to add hooks and filters into their application.
  • Allow plugins to send notifications and optional data

4. Dependencies on Other Framework Components

  • Zend_Exception

5. Theory of Operation

Developers should be able to load a plugin or set of plugins and then add hooks/filters to these plugins anywhere in their application.
Secondly plugins can be send notifications of their state and send optional data with the notification.

6. Milestones / Tasks

7. Class Index

  • Zend_Plugin_Exception
  • Zend_Plugin
  • Zend_Plugin_Interface
  • Zend_Plugin_Event

8. Use Cases

UC-01 Simple Use
  • Creating plugins
  • Sending events
UC-02 Use with notifications
  • Creating plugins
  • Sending events
UC-03 Use with serialization

Coming Soon...

9. Class Skeletons

  • Zend_Plugin_Exception
  • Zend_Plugin_Event
  • Zend_Plugin_Interface
  • Zend_Plugin

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
zend_plugin zend_plugin Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Aug 29, 2006

    <p>The problem with this, priority is setup per class.. So if you take a CMS as an example, each module for the CMS has a plugin class, The problem you have is they can't set priority within that class only per plugin.</p>

    <p>To make this workable you really need to be able to set priority on a call basis, There are also times where you might want to ensure a plugin is "final".</p>

  2. Aug 30, 2006

    <p>I see your point with the priority, maybe I could add in priority for register() aswell?</p>

    <p>I am currently working on adding in listeners so that plugins can notify for errors etc.</p>

    <p>Hopefully I will have time to update the proposal soon, just got to finish my exams first <ac:emoticon ac:name="smile" /></p>

    <p>Not sure what you mean by final?</p>

    <p>Thx for the comments </p>

    <p>Keith Pope</p>

  3. Aug 30, 2006

    <p>The reasoning behind the plugin classes only having priority is that we didn't want to allow plugin developers to choose the priority that their plugin was loaded into the application, we wanted that decision left to the application developer.</p>

    <p>I do see your point; I think we should allow priorities within plugins so that the plugin developer can set the priority on their own calls.</p>

    <p>Thanks for the comments. As Keith mentioned the listeners will also add a lot of functionality.</p>

    <p>Cheers,</p>

    <p>Shaun Mitchell</p>

    1. Aug 31, 2006

      <p>Your right the plugin developer should not be able to force priority, instead it should be set on load for each hook, This allows the application developer to rearrange priority as they need, For example drupals control panel allows you to change the priority of its input text filters.</p>

      <p>Say you have an abuse module that inclues spam and word filtering, The work filtering priority would depend on what your doing, you might want to run it before your bbcode filter or after depending on the setup, where the spam check could be run ay any time.</p>

      <p>AS it is now the only way to have fine grained control over order of EACH hook is to have a seperate class for every little hook.</p>

  4. Sep 01, 2006

    <p>With the current implementation you can order the way the events are registered as they are fired in the order you register them.</p>

    <p>So if you do </p>

    <p>Zend_Plugin::register('action', 'add_user', array($this, 'checkUserName'), 1);<br />
    Zend_Plugin::register('action', 'add_user', array($this, 'sendEmail'), 1);</p>

    <p>it will do </p>

    <p>checkUserName then sendEmail</p>

    <p>Developers then can implement their own ordering system if they want inside the introspect() method, say if they wanted to load the order from config or db.</p>

    <p>This way we can avoid the extra complexity of having 2 priorities.</p>

    <p>Hope this makes sense</p>

    <p>Thx Keith</p>

  5. Sep 06, 2006

    <p>Im still not understanding, In your example the developer of myPlugin defines the priority for his functions.</p>

    <p>What if the developer of the application in general says that the internal call to intCheckUserName HAS to be run before myPlugin CheckUserName no matter what priority myPlugin sets?</p>

    <p>If you assume hooks will be called across multiple plugins you need to be able to set priority outside of those plugins.</p>

    <p>Here is an example of what I want to control, 2 plugins are submitted to my CMS </p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    class plugin1()

    Unknown macro: { function filterHTML() function spamCheck() }

    class plugin2() {
    function filterHTML()
    function spamCheck()
    }
    ]]></ac:plain-text-body></ac:macro>
    <p>2 plugins both wanting to perform some sort of spam check and filtering html.. What If I want to run in this order</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    plugin1->spamCheck()
    plugin2->filterHTML()
    plugin2->spamCheck()
    plugin1->filterHTML()
    ]]></ac:plain-text-body></ac:macro>
    <p>From what I am seeing in your code/example there is no way to control this outside of the plugin code itself. For the order to be right in this case Develper of Plugin 1 would have to confer with the Developer of Plugin 2 and then say they do confer, what if developer of the CMS decides they are wrong and wants to override that?</p>

    1. Sep 06, 2006

      <p>You are correct in that the above order can not be fired. The plugins are loaded and given a priority. For example:</p>

      <p>As the application developer I've loaded all my plugins:</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      Zend_Plugin::addPluginGroup(array('plugin1', 'plugin2'), array(1, 2)); // I have set the priorites that these plugins will be executed, plugin1 first then plugin2.
      ]]></ac:plain-text-body></ac:macro>
      <p>Now I've added a hook like "echoComment" (for a blog):</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      Zend_Plugin::applyFilters('echoComment', $comment); //$comment is the comment text from the DB
      ]]></ac:plain-text-body></ac:macro>
      <p>The applyFilters method will now loop through the plugin array; key'd and sorted by the plugins priorities. Then the plugins introspect method will load the callbacks and the order that the plugin developer registered the callbacks is the order they are fired.</p>

      <p>Zend_Plugin::doAction and Zend_Plugin::applyFilters doesn't navigate around the plugins array and fire callbacks. It basically loops through the plugin array and fires the callback in the order they were loaded.</p>

      <p>As the application developer I only have control over loading plugins in a certain order and not the order that their callbacks are fired. Also I can't tell doAction or applyFilters to fire different plugins callbacks in different orders / times.</p>

      <p>I hope this helps to explain what we are thinking of right now, we tried to keep every thing as simple as we could.</p>

      1. Sep 09, 2006

        <p>At this point then I think its to simple, here is an idea</p>

        <p>Adjust register to use class name instead of having to pass a class instance</p>

        <p>Now depending on the use you can use if as you have it explained, or the developer can handle the registering himself, this way he can control load order 100%</p>

        <p>The other problem with your current method is it now requires loading of every single plugin class ahead of time so it can "register" its hooks into the system.</p>

        1. Sep 19, 2006

          <p>Hey Richard,</p>

          <p> I think I understand what you are getting at with the passing of a class instance. Keith and I are looking at it now. We have just added your namespace idea (thank you for that one) into our development code and will update the proposal as soon as we have tested it.</p>

          <p>Lastly, you have a good point about having to load all plugins to load their hooks. It would be a good idea to get all the plugins hooks and only load the plugins that are required when a hook is actually fired.</p>

          <p>Thanks again.</p>

          1. Oct 07, 2006

            <p>Any progress on this <ac:emoticon ac:name="wink" /> I have a project that would find this usefull..</p>

            <p>I have my own system worked out but would like to stick to zend modules when I can <ac:emoticon ac:name="wink" /></p>

  6. Oct 09, 2006

    <p>Hi Richard,</p>

    <p>I am currently moving jobs so I have no time to do much at the moment.</p>

    <p>I can send you a copy of our latest svn branch if you want, I was going to make some major changes when I get chance. We were looking at moving to a singleton class (maybe) and removing some of the un-needed bits and some general code cleaning.</p>

    <p>Email me if I can help in any way.</p>

    <p>Thx</p>

    <p>Keith</p>

    1. Oct 10, 2006

      <p>I would be more then happy to take a look, If your thinking of a major overhaul I can also send you some example code that I threw together to see if it gives you any ideas</p>

      1. Oct 10, 2006

        <p>Thanks Richard,</p>

        <p> Please send any coded ideas you have to myself or Keith and we would love to take a look. Not sure if Keith has already sent you our current development version but I look forward to hearing your thoughts on what we have so far.</p>

        <p>Cheers,</p>

        <p>Shaun M</p>

  7. Oct 12, 2006

    <p>Hi Richard,</p>

    <p>I have emailed you the SVN details for the component, did you get the email?</p>

    <p>thx</p>

    <p>Keith</p>

    1. Nov 08, 2006

      <p>Yes I got it, sorry have been busy myself</p>

  8. Nov 08, 2006

    <p>I did manage to take a look at this a while back,</p>

    <p>Basically if the developer wanted to registered things himself to have full control of the order a few changes need to be made so the developer could call register instead of the plugins having to do it themselves.</p>

    <p>In the register portion it requires a reference format in the callback, if it could be adjusted so you can do the following</p>

    <p>Zend_Plugin::register('action', 'add_user', array('classname', 'checkUserName'), 1);</p>

    <p>Then the developer can manage registering.</p>

    <p>Also there is no checking to make sure when a plugin is registered that you can't overrwrite another plugin of the same priority.</p>

    <p>Then due to the nature of how things are setup all plugins/filters are loaded regardless of if they are used or not, Since the intent is the class registers itself this is required, however in a developer controlled enviroment where your only passing names and not full objects this could be avoided, and objects would only need to be loaded if called.</p>

    <p>Otherwise the overall code looks great <ac:emoticon ac:name="wink" /></p>

    1. Nov 08, 2006

      <p>One more note, the way you have it setup the listeners are really just sort of a plugin tree allowing you to "cascade" the calling of plugins, Would it make sense to "track" what listeners have been called and do some sort of checking to prevent a endless loop?</p>

  9. Nov 14, 2006

    <ac:macro ac:name="note"><ac:parameter ac:name="title">Proposal not being considered</ac:parameter><ac:rich-text-body>
    <p>We have reviewed this proposal. We are not considering it at this time for inclusion in Zend Framework.</p>

    <p>An architectural pattern like plugins is a means to a goal, not a goal itself. The problem with a generic component for plugins is the same problem with generic treatment of factories, or interfaces, or any other design pattern. Trying to create a one-size-fits-all approach to architecture is too likely to result in a solution that is inappropriate for any given case. </p></ac:rich-text-body></ac:macro>

  10. Nov 15, 2006

    <p>Ok I was sort of coming to that conclusion anyway.</p>

    <p>However from going through the process I do see the need for a good event dispatcher (ie Zend_Event). Probably a bit similar to the pear event dispatcher. I think a good way to dispatch events would probably negate the need for a plugin system altogether, or a least make it very easy to create a tailored plugin system to the users needs.</p>

    <p>I have been thinking about doing this for a while now, hopefully I will get some time to actually start doing some work on it. </p>

    <p>Would this be something of interest for the framework?</p>

    <p>Thanks for the review </p>

    <p>Keith</p>

    1. Nov 23, 2006

      <p>We would be glad to review such a proposal. But my first thought is that it is another example of a design pattern-like solution, looking for a use case to justify it.</p>

      <p>Why would you want an event dispatcher? Are application objects in great need to receive events? What would they do with an event if they received one?</p>

      <p>Keep in mind that I don't consider it a valid requirements statement to say we need a component solely because we don't have that component.</p>

      <p>I'm not saying that Zend Framework can't provide generic implementations of design patterns (like MVC), or that it can't provide infrastructure components that serve as a carrier for information (like Db). But I caution against creating technology without having a clear, concrete purpose and use case in mind for it. </p>

      <p>Zend Framework is trying to solve the most common real world problems that people are having with their web applications, and to provide greater value than other solutions available, by being simpler and easier to use.</p>

      <p>Is it so common for web applications to have internal event-driven mechanisms that we need a Zend Framework component to do that? It seems to me that web apps <strong>are</strong> event-driven, but the events are provided by the client, or by controller redirects.</p>

  11. Jun 14, 2007

    <p>I agree with Keith. Having an Event Dispatcher like the PEAR one for Zend Framework would be a really good thing. I can already see good interactions between this component and the existing Zend modules  :</p>

    <p>- Event Dispatcher + Mail => Mail Notifcation</p>

    <p>- Event Dispatcher + Feed => RSS Driven Events</p>

    <p>- Event Dispatcher + Date ( and Calendar Proposal) => User's defined scheduled notification</p>

    <p> Of course those combination are use cases and not proposals for the framework.</p>