Plugin Structure
Goals
- Provide a way to distribute additional functionality in a simple, standardized package, so that other developers can easily make use of it in their own applications.
- Allow a plugin to have *one or more* of the following component types - note that a single plugin can have both a new custom control, and a codegen template file, and maybe even a localization file.
- Allow for easy installation and un-installation of the plugins - if I don't like a plugin, I shouldn't have to manually clean my configuration files. Allow for both UI-based and completely unattended (script-based) installations of plugins.
- Create a platform that over the long-run will support things like
- Auto-notify the user that plugins are available
- Installing new plugins through the UI only (no downloads required)
- Supporting dependencies between plugins (i.e. plugin A can only be installed if plugin B is already installed)
- Set up a LOW BAR for writing plugins. Hey, I wrote this component for myself.. It's awesome, I want to share it. If it now takes me 2 hours to write an installation script for it, I'm very likely to not want to do it. I don't want to learn any new technology or anything like that to share my code. On the other hand, if it's just a couple of easy steps, I'll happily do it.
Components of Plugins
There may be zero, one, or more of the following plugin components in any given plugin.
Controls
Contains new contributed Control files. There may be .tpl files there, too.
Upon installation, all of these files will be placed in a directory that is NOT web-accessible.
Database Adapters
Contains new database adapter class files.
Upon installation, all of these files will be placed in a directory that is NOT web-accessible.
New Codegen Template Files
These are custom codegen templates. These would have gone into wwwroot\includes\qcodo\codegen\templates in the old directory structure.
Upon installation, all of these files will be placed in a directory that is NOT web-accessible.
New Assets: CSS/JS/Images
There may be zero or more of each of these in the plugin. Note that our API should support adding these files in bulk (i.e. I shouldn't have to include EVERY SINGLE .css file by hand... that'd suck).
Upon installation, all of these files will be placed in a directory that IS web-accessible.
Example Files
The plugin writer should be able to include one or more example files; these may be .php or .tpl files.
Each of the examples should have the following definable properties:
- friendly name
- list of files that go with that example
Internationalization files
These are custom translation files. There may be zero or more in a given plugin.
Upon installation, all of these files will be placed in a directory that is NOT web-accessible. NOTE: QCubed currently DOES NOT SUPPORT multiple translation files for the same language. Maybe exclude support for this from the initial release?
UNSUPPORTED: Core Template File Changes
We do not allow core template files to change, however overrides for templates are allowed in \includes\qcodo\codegen\templates\<same path as in core>
UNSUPPORTED: Customizations to Core Controls
We don't support these. Instead, of modifications have to be made in the core, we'll encourage our community to ask us to make those mods in the core.
Installation Script for Plugins
Setup is a big problem that every client (Win32) application out there has; it looks like we may have to deal with similar problems here. The issue, however, is that if we create a HIGH BAR for writing plugins, we will negatively affect the community (fewer folks will be writing plugins).
Example: I wrote QFilteredDatGrid for my own project, I didn't have to write any setup scripts! I just want to share my stuff, make it easy for me! Making me learn a brand new technology like MODX is, well, potentially a showstopper.
Manifest specified through PHP
Our developer community is extremely comfortable with PHP; if we provide for an easy way to specify what is to be included with a plugin through a PHP manifest file (example below), they'll likely be very comfortable there - simply because they already have IntelliSense-like code completion tools, etc.
The plugin writer will need to create a ZIP archive that includes all of their related files; that archive can have whatever content the user wants, but there must be one file, named plugin.php, that tells QCubed about the components of that script. Each of the plugin components (as specified above) are defined using PHP objects. '
$plugin = new QPlugin();
$plugin->Description = "My cool plugin";
$plugin->AutoLoad = true;
$example = QPluginExample();
$example->SetDescription("How to use this great plugin");
$example->AddFile("tutorial.php");
$example->AddFile("tutorial.tpl.php");
$plugin->AddComponent($example);
$cssFiles = new CssFileComponent();
$cssFiles->AddDirectory("/css/myCss");
$plugin->AddComponent($cssFiles);
Framework that supports this:
abstract class PluginComponent {
public function AddFile() {...}
public function AddDirectory() {...}
}
class ExampleFileComponent extends PluginComponent{
public function SetDescription();
}
class CssFileComponent extends PluginComponent{}
...
class Plugin{}
private $arrComponents;
public function AddComponent(PluginComponent $p) {...}
public function SetDescription($strDescription) {...}
}
QCubed Control Panel
The control panel is designed to be the central spot that allows the user to:
- View all installed plugins
- Add (=install) new plugins
- Uninstall existing plugins
To install a new plugin:
- The user navigates to the control panel and presses the "Install New Plugin" button.
- That brings up a modal QDialogBox that prompts the user to upload a .zip file with the plugin (a QFileAsset-type thing).
- The user uploads the zip file that they just downloaded from our plugin directory.
- The control panel unpacks the zip file, reads through the instructions in the plugin.php file (that has the format specified above), and based on that, does the following things:
- Copies all files from the unpacked zip to their appropriate folders (as defined by the 1.1 Proposed Directory Structure Directory Structure)
- modified plugin_config.xml
- modifies the plugin_classes.php file
- plugin_config.xml contains friendly information (name, description, version, author, install date) about all currently installed plugins. It is NOT loaded at run-time for every page.
- plugin_classes.php contains $ClassFile or $PreloadedClassFile definitions for all of the installed plugins.
Alex94040: Can you attach the HTML output of applying the XSLT to the MODX xml file, please, to save all of us time?
VexedPanda: I'm not sure how to convert xml/xsl to HTML. It renders nicely in the browser, but view source just shows me the XML.
Alex94040: My vote goes for implementing 1b right now, and adding mechanism 3 on top of it, as an advanced option, later.
VexedPanda: Hmm, I'd mostly be ok with that, but I have a feeling MODx (or at least our customized version) is simpler than you think. I've added what the code for 1b could look like to the page.
Really, the only extra stuff in there is stuff we really should have anyhow, like required QCubed version, plugin version, author, etc.
Alex94040: Vexed, I'm almost convinced that option 3 is on all accounts superior to option 1a. MODX is essentially a manifest file that is supported through better tools (as opposed to us trying to invent our own manifest). The one quesiton is, is MODX file format extensible enough for our needs? For example, if in the future we have dependencies between plugins (like Drupal has) - i.e. pluginA can only be installed if pluginB is already there - would we be able to specify that in the MODX manifest?
My other concern about MODX is the tools that exist to author these files. Looking up XML schemas is not a fun task; IntelliSense?-like technologies with code completion would make option 1b dramatically easier to use (i.e. you type "$plugin->Add" and see that you can add a Javascript file/folder, or a CSS file, etc).
VexedPanda: MODx is close to what we want, but is somewhat customized for phpBB. We would definitely need to modify it to meet our needs (for example, addExample isn't an action phpBB's version supports). It does currently support dependencies, though I'm unsure to what degree they're automated, since some important information such as dependency version number seems to be missing.
My only real concern about PHP is that it doesn't lend itself to modifying existing files, which is something we definitely want in the long run. If we're building a class to do things like register examples anyhow, I'm not sure how much extra work it would be to create support for modifying files in same manner that MODx would.
I guess what MODx brings us is really a pre-packaged system that's almost ready to go, whereas 1b would require us to write possibly beefy code behind it.
MikeHostetler:
My current concerns:
- MODX is too complicated and adds bloat, even as only an advanced option
- The assumption of something like 'automod' is that it patches existing core files, which is a bad idea in my mind. It's messy, and will break things.
The role of plugins has been discussed a little bit above, but I think warrents further discussion. Particularly, for those of us who have large QCubed installs to support, what role do we see plugins playing. For me, the purpose of a plugin is to extend core functionality beyond what is currently shipped with QCubed. That implies that things that belong in a plugin were intentially kept out of QCubed. Items such as database connectors would ideally be submitted and accepted to core. Most QControls will be checked into core, some will not. Localization files I wouldn't consider "plugins". Ideally, we'd provide localized versions of QCubed for download individually, so we'd handle this through our build process. So, the use case for plugins begins to narrow.
The use case for plugins I see as being two things:
- Custom QControls & associated Images, JS and CSS
- Custom codegen templates
Given that the purpose of these two use cases is very different, and the files are placed in very different places, we can almost ditch the label 'plugins' and come up with something else, ie. CodegenTemplate? and CustomQControl
CodegenTemplates? tend to be single application specific. In the future, these will be XML and PHP files. Right now, they're just PHP. That's fine. We should just leave them as PHP.
CustomQControls are a mix of PHP, Images, JS and CSS. For ease of creation, I believe these need to be in a single folder. Splitting them up would be very, very bad for many reasons, particularly ease of creation, ease of install and ease of distribution. Some sort of naming convention makes sense here, and we could easily design some sort of convention (no manifest files) that allows controls to override one another, handled through __autoload. It's OO PHP after all, we have all that capability available to us as well.
In the case that a CustomQControl needs to modify core to run, as a community, we encourage a patch to core directly, rather then leaving that responsibility to plugins.
Alex94040
As we've discussed in the IRC, using the naming convention for different components would make plugin-writing much more difficult. I think we're all leaning towards option 1b right now; let's pursue it. The thing to figure out, though, is the details.
I don't think we should be splitting up the notion of plugins into any categories. A plugin should allow you to package ANY number of JS files, CSS files, examples, etc. It should also allow you to add one or more QControls (think of the "custom dialog boxes" plugin - several different controls there). It should also allow you to add codegen customizations. This would be very easy to implement:
// usage:
$myPlugin = new Plugin();
$exampleFile = new ExampleFile();
$exampleFile->SetDescription("My Cool Example");
$myPlugin->addComponent($exampleFile);
The plugin (with all of its files) would be packaged up into a single .zip archive. There would be NO requirements around how things are named; only 1 file, index.php, should exist in that zip. That file would have the instantiation code similar to what's above ($myPlugin = new Plugin(), ...).
The user who wants to install the plugin would launch the "QCubed control panel", then pick a .zip file to upload. The uploaded zip would be deconstructed; based on the configuration settings in that zip, the files will get placed into the appropriate locations (examples - into the examples/plugins/pluginName folder, etc). That same control panel could be used to list all installed plugins and to uninstall them. (A nice automated way to install plugins would be good, too).
VexedPanda:
The purpose of automod is to allow easy patching of _existing_ files even if they've been customized. It should not be used for core files, but rather, included non-core files such as templates.
I like the idea of 1b the best, and it has my vote, but I would eventually like to see all the features of MODx being incorporated into it, as modification of existing files is something necessary for some common types of "plugins".
Basilieus:
Let's add a property to the plugin class so we can identify if the plugin needs to autoload or is preloaded. $blnAutoLoad = true; if set to false it is Preloaded.
VexedPanda:
Shouldn't the autoload setting be per plugin class file, not global to the plugin?
Alex94040:
Why would we want to allow pre-loading of class files for plugins at all? What are the scenarios when this is necessary? Can we just autoload (on demand) all the plugin classes?
Basilieus:
Because of naming conventions. If we use ClassFile? that file has to have 1 and only 1 class. If it contains two class or more, it would need preloaded. Edit: Unless it is setup in a way where the other classes are child classes of the parent class. But if we have more than 1 class that doesn't extend anything inside the file, it needs preloaded. Hope that makes sense.
Alex94040:
The core of the framework manages to overcome these issues; we should force a similar thing for the plugins. A major reason for slowness of PHP frameworks is that they preload a bunch of files, we can't afford to make that mistake. So I suggest we force all plugin files to be loaded on-demand. Thoughts?
Basilieus:
All the files that are Preloaded in the framework contain more than 1 class. We could simply create a line of code for each class in those files and assign them to ClassFile?ClassHere?.
VexedPanda:
Basilieus, the plugin_classes.php file addresses what you're concerned about. Each plugin must have one, the contents of which specify a list of class names and filenames containing them. Then during design time, we'll have a tool to generate a single global plugin_classes.php file which prepend will include, that basically fills in QApplication::$ClassFile?.
Attachments
-
install_mod.xml
(4.3 kB) - added by VexedPanda
15 months ago.
The modx example file
-
modx.prosilver.en.xsl
(66.4 kB) - added by VexedPanda
15 months ago.
the xsl to make the modx file human-readable.
