Search

Is it possible for an Event to hook into the page lifecycle and get access to the generated HTML for a frontend page?

I have modified symphony/toolkit/class.frontendpage.php where $output is set (from a generate() method), however it would be great if I could achieve the same by using an Event. I am adding some functionality that requires the full HTML output. I don't need to modify it, just parse it and execute code elsewhere.

Without modification to the core, can an Event do this?

If so, I'd love to be able to wrap my implementation up into an Extension that installs the event and supporting assets and configuration.

I come from an ASP.NET background, where there's a plethora of events that can be hooked in to throughout the page lifecycle (from initial HTTP request through to HTML rendering).

I have modified symphony/toolkit/class.frontendpage.php where $output is set (from a generate() method), however it would be great if I could achieve the same by using an Event.

There are no delegates that you can hook into on the front end. However, since you're not manipulating the front end and just need the HTML, delegates wouldn't be necessary anyways. Modifying symphony/toolkit/class.frontendpage.php is definitely not a good idea since your changes will be overwritten by an upgrade.

You probably want to create a class that extends symphony/toolkit/class.frontendpage.php with your changes and include that in an event that does your required manipulation.

For your extension, you must create an extension.driver.php which will allow you to install/uninstall your supporting assets and configurations. Take a look at symphony/toolkit/class.extension.php for the methods you can use in your extension.driver.php.

Probably the easiest way is to put a delegate into the frontend class (/lib/core/class.frontend.php). Really there should have been one there all along. Try putting this at line 63, just after the output generation line, before the return statement:

$this->ExtensionManager->notifyMembers('FrontendPostGenerate', '/frontend/', array('output' => &$output));

You can then subscribe using an Extension.

Thanks both. Alistair, this sounds like a sensible way forward. Can I assume that line now becomes part of the core and won't be removed (in r5 at least) by updates?

I haven't created an extension before, so I think I'm missing a trick. Have created my driver and enabled the extension. Should this simply work out of the box?

Class extension_extendedtype extends Extension{

    public function about(){
        return array('name' => 'ET',
                     'name' => 'Extended Type: Generate images',
                     'author' => array('name' => 'Nick Dunn',
                                       'website' => 'http://airlock.com',
                                       'email' => 'nick.dunn@airlock.com'),
                     'version' => '1.0',
                     'release-date' => '2008-07-15',
                    );
    }

    public function getSubscribedDelegates(){
        return array(
                    array(
                        'page' => '/frontend/',
                        'delegate' => 'FrontendPostGenerate',
                        'callback' => 'frontendPostGenerate'
                    )                       
        );
    }

    public function frontendPostGenerate($context) {
        echo("frontendPostGenerate");
    }

}

I have then created an event in the extension's /events/ sub folder which I can successfully add to a page and have its load() function called. Question is, how do I link these together, by subscribing to the delegate in the Extension/Event and getting the $output?

I'm nabbing code from other extensions/events without really knowing what they do or where they're used ;-)

Can I assume that line now becomes part of the core and won't be removed (in r5 at least) by updates?

There will be a delegate available for manipulating the page output in RC1.

Have created my driver and enabled the extension. Should this simply work out of the box?

Don't see why that would not work. Try enabling it again just to make sure the delegate has been registered.

Question is, how do I link these together, by subscribing to the delegate in the Extension/Event and getting the $output?

Not quite sure what you are trying to achieve. Events are primarily for performing actions and putting details into the XML. This delegate you've added is specifically for manipulating the HTML output, but that comes long after all the Events are triggered. Perhaps you can explain a little more about how you need this to work for you.

Ok I'll explain exactly what I'm trying to do :-)

At Airlock we have developed what we think is an sIFR killer for using rich typography. You specify your niche font in the font stack of a CSS selector, and a clever mix of JavaScript and PHP finds the font on the server and outputs a correctly formatted PNG. This is fine when we can run PHP on the production environment. But when we can't (and create a static HTML export of Symphony) we also need to create the PNGs for all headings.

I've done the hard work and written the code that does this. It takes the generated HTML, parses it to find the headings and calls various scripts to generate the PNGs and generate the CSS to replace the text with the images. I have achieved this by including the code in class.frontendpage and executing on every page load. However I want the following functionality (eventually):

  1. Ability to turn this functionality on and off globally (hence an extension, enable/disable it)
  2. Ability to apply this functionality only to specific pages (hence an event, to include on certain pages)

Does that help?

All is clear now. Well, the delegate is the best bet since that is really the only place you get access to the page output. The unfortunate thing about delegates on the front-end is that they cannot be specific to any page since that would severely limit their usefulness. A developer has no idea what pages a user has on their site, so it would be impossible to define the getSubscribedDelegates() function.

Using an Event would give you the ability to perform actions that influence the output, but via XML, and that doesn't sound like it would work for you.

In Rev5 your best option is to use the delegate, and perhaps use types on your page to denote which should have this process applied. In your delegate function you can look up the page, check if a certain type exists and decide if you wish to proceed or not.

Thanks Alistair, this is making more sense. I can now subscribe to the delegate in the extension and it executes on every page load.

Inside this delegate is there a way for $context to contain information about the page? I'm looking to get at the page parameters ($current-page etc.)

I'm looking to get at the page parameters ($current-page etc.)

You would need to modify the delegate to include more information. I would suggest instead of putting the delegate in class.frontend.php, it is instead placed on line 77 of /toolkit/class.frontendpage.php which would give you access to what you're after. Try this as a replacement to the delegate in class.frontend.php:

$this->_Parent->ExtensionManager->notifyMembers('FrontendPostGenerate', '/frontend/', array('output' => &$output, 'env' => &$this->_env));

Then, you should be able to use print_r($context['env']); to see what's in there.

Perfect, thanks :-)

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details