What John has said is a very good explanation for the core of the Java implementation -- unfortunately for you, what he covered isn't going to help you write PHP code at all, because all of that fancy parallel processing (with the exception of the dependency graph, which I'll get to) simply won't work in the PHP world.
In a nutshell, this is how you process gadgets: Step 1: Fetch the gadget spec XML. This *should* consult a cache first, to minimize load on the gadget author's HTTP server. The spec does not say how long to cache for (suggest 24 hours or less), but we do require that you support bypassing / clearing the cache on your server somehow. The PHP implementation should support the "nocache=1" query parameter to be compatible with Java. Relevant Java classes: GadgetServer, RemoteContentFetcher, GadgetDataCache Step 2: Process the gadget spec. This is hard, especially since the spec hasn't been published yet (it will be later this week, I'm told). I would strongly recommend using SimpleXML and follow the same processing pattern as you'll see in GadgetSpecParser. SimpleXML should make this pretty easy, and you won't have to go through the pain of all that DOM nastiness that our Java implementation had to deal with. Relevant Java classes: GadgetSpecParser, GadgetSpec Step 3: Fetch message bundles. These are fetched by inspecting the <Locale> tags in the spec and making http requests for the bundle files. You should get your locale from the "lang" and "country" query parameters. Processing rules for locales have a few caveats, so examine MessageBundleSubstituter carefully and emulate that behavior. The actual messagebundle spec is extremely simple. Message bundles should be cached using the same caching policy as Step #1. Relevant classes: MessageBundle, MessageBundleParser, MessageBundleSubstituter Step 4: Perform hangman variable substitutions. This is done by replacing __UP, __MSG, __MODULE, and other placeholders with other values. You should perform these substitutions in the following order: __MSG __BIDI __MODULE __UP MSG and UP need to be html escaped to prevent XSS attacks. BIDI is a set of constants (see BidiSubstituter or the spec, whenever it gets published, for details). __MODULE only has one possible value right now: __MODULE_ID__, which is the "mid" query parameter (an UNSIGNED integer). Only do a single pass for each substitution type (you can use either a regex, or implement a basic parser like we did), and do not revist types already processed (i.e. don't substitute __MSG after you've already done __UP). Relevant classes: Substitutions, MessageBundleSubstituter, BidiSubstituter, ModuleSubstituter, UserPrefsSubstituter Step 5: Process <Require> / <Optional> features. This is going to be hard to do right now without the spec. We will be publishing this shortly, but what you see in shindig right now is, for the most part, the complete set of what will be in the initial "mandatory" support list. The good news is that most of this work is already done for you. You need to implement support for feature.xml loading and proper handling of <dependency>. See trunk/features/README for details on the file format, and look at JsFeatureLoader for an implementation. Combine this with the dependency graph resolution in GagdetFeatureRegistry.getIncludedFeatures and you should be good to go. Relevant classes: GadgetFeatureRegistry, JsFeature, JsFeatureLoader Step 6: Output gadget content. The order is as follows: - standard html header (an ugly inline version can be seen in GadgetRenderingServlet. This will be a lot cleaner in a PHP template). Replicate this exactly for now (even the lack of a DOCTYPE). - feature libraries (separate scripts, or ideally rolled up into a single file or script block like we do in GadgetRenderingServlet) - Initialization of feature libraries (currently only gadgets.ifpc_, gadgets.Prefs, and gadgets.io need this) - processed gadget code from step 4. - a single call to gadgets.util.runOnLoadHandlers - close your html Ideally, all of the output from step 6 (except the html body wrapper) should be passed through Caja, but right now that's going to be difficult to do in PHP. Don't worry about it for now, I'll have a solution for you shortly. This implements what we have on gmodules.com. Ideally, everything up to and including step 5 should be able to be done directly from some library similar to GadgetProcessor, and the wrapper of Step 6 should happen in the code that specifically handles outputting iframe content. I *strongly* recommend using curl_multi in implementing containers to fetch all of the gadget data in parallel, then caching that so that when the iframes load, they will be loading entirely from cache (which will be fast). This is really the only part of the whole pipeline that needs to be run in parallel, due to the fact that http fetching is slow. I expect that the steps I have just described will more or less become the companion document to the XML schema for the gadget spec when it gets published later this week. John is responsible for making that happen, so please send him feedback if you feel that there is any ambiguity in the processing rules. Let me know if I left anything out. ~Kevin

