Using Zend Framework with Drupal

I have been using ExpressionEngine and Zend Framework on my current project. We recently migrated the cms to Drupal (see migration), but we wanted to keep the Zend Framework apps. Most of the content of the website is handled by Drupal 7 (link), but certain urls on the website are handled by Zend Framework. On the Zend pages, I removed all layout information so that it is controlled by the Drupal theme.

Setup

I placed Zend’s application folder under Drupal’s root folder. We also have Zend’s application files located under Zend’s Library folder (so the application path is /application/Zend/application.php). This is not a requirement – Zend’s files can be located anywhere.

Note: Although our Zend apps are controlling the content for certain url’s, these urls must exist within Drupal or you will receive a 404 error. For instance, one of our Zend apps is located in the following url:

“/provisioning/basic-template”

Prior to viewing the page, I created a basic page in Drupal (title only, no content) and set the url alias to “/provisioning/basic-template”.

Drupal Theme

So the first step to having Zend Framework and Drupal work together is to let Drupal know which urls will be controlled by Zend. I do this in the template.php file of my Drupal theme. To do this, I use the preprocess_page hook.

function mris_preprocess_page(&$vars) {  
  if (isset($_SERVER['REQUEST_URI'])) 
  { 
  ///********   CUSTOM CODE FOR APPLICATION *****////
    $path_info = $_SERVER['REQUEST_URI'];
    $path_info = strtolower(rtrim($path_info, '/'));
    $path_zend_apps = array(
      "/mris-customers/public-records/public-records-data-status",
      "/mris-customers/public-records/tax-rates",
      "/mris-customers/public-records/zoning-codes",
      "/mris-customers/compliance/listing-contingencyexpiration-report",
      "/mris-customers/compliance/listing-compliance-report",
      "/mris-customers/agent-search",
      "/mris-customers/broker-search",
      "/mris-customers/text-alerts"
    );
 
    $isProvisioning = preg_match('/^\/provisioning/', $path_info);	
 
    // if on of the urls exist, allow zend framework to control the page   
    if (in_array($path_info, $path_zend_apps) || $isProvisioning)
    {
      // Load Zend application with right path
 
      define('APPLICATION_PATH', DRUPAL_ROOT . '/application');
      set_include_path(implode(PATH_SEPARATOR, array(
        realpath(APPLICATION_PATH . '/library'),
        realpath(APPLICATION_PATH),
        get_include_path(),
      )));
 
      /** Zend_Application */
      require_once APPLICATION_PATH . '/library/Zend/Application.php';
 
      // load the generic view
      require_once APPLICATION_PATH . '/views/View.php';
      $vars["zend_view"] = new views_View($vars);
 
      //load js and css files that are used with the zend apps
      drupal_add_css(drupal_get_path('theme', 'mris') . '/css/custom-theme/jquery-ui-1.8.5.custom.css', array('group' => JS_THEME));
      drupal_add_css(drupal_get_path('theme', 'mris') . '/css/zend_styles.css', array('group' => JS_THEME));
      drupal_add_css(drupal_get_path('theme', 'mris') . '/css/ui.jqgrid.css', array('group' => JS_THEME));			
      drupal_add_js(drupal_get_path('theme', 'mris') . '/js/grid.locale-en.js', array('group' => JS_THEME));
      drupal_add_js(drupal_get_path('theme', 'mris') . '/js/jquery-ui-1.8.5.custom.min.js', array('group' => JS_THEME));
      drupal_add_js(drupal_get_path('theme', 'mris') . '/js/jquery.jqGrid.min.js', array('group' => JS_THEME));
      ...		
 
      // if the apps are related to provisioning, load additional js files
      if ($isProvisioning) {
        drupal_add_js('/ckeditor/ckeditor.js', array('group' => JS_THEME));	
	drupal_add_js(drupal_get_path('theme', 'mris') . '/js/provisioning.js', array('group' => JS_THEME));
	drupal_add_js(drupal_get_path('theme', 'mris') . '/js/provisioning_validate.js', array('group' => JS_THEME));
      }
   }
}

The script checks whether the current url exists in the zend_apps array or begins with ‘/provisioning’, and if it does, it loads Zend’s application.php file. I make two different path checks because I want certain Javascript files to be added to the page if the urls begin with ‘/provisioning’.

Note the lines:

require_once APPLICATION_PATH . '/views/View.php';
$vars["zend_view"] = new views_View($vars);

These lines are key to having Zend interact with Drupal. I created a generic view based upon a Drupal MVC article that I found here. The generic view is located in /application/views/View.php. The view is loaded into Drupal’s $var. More on this later.

class views_View {
 
    private $_vars;
 
    /**
     *
     * @param array $vars
     */
    public function  __construct($vars)
    {
        $this->_vars = $vars;
    }
 
    /**
     * Dispath and render requested application
     * 
     * @param string $request
     */
    public function dispatch()
    {
        // Local namespace
        $view = $this;
       $application = new Zend_Application(
	    APPLICATION_ENV,
	    APPLICATION_PATH . '/configs/application.ini'
       );
       $application->bootstrap()->run();
    }
}

When the dispatch method is called, Zend’s Bootstrap is called.

In the _initRouter method of our Bootstrap, we create all of the routes used by our Zend apps.

public function _initRouter()
    {
        $front = Zend_Controller_Front::getInstance();
        $router = $front->getRouter();
 
        $router->addRoute('public-records',
                           new Zend_Controller_Router_Route(
                            'mris-customers/public-records/:action',
                            array('controller' => 'public-records', 'action' => 'action')));
 
        $router->addRoute('compliance',
                          new Zend_Controller_Router_Route(
                           'mris-customers/compliance/:action',
                           array('controller' => 'compliance', 'action' => 'action')));
 
        $router->addRoute('agent-search',
                          new Zend_Controller_Router_Route(
                           'mris-customers/agent-search',
                           array('controller' => 'agent', 'action' => 'search')));
 
	$router->addRoute('provisioning-basic-template',
                           new Zend_Controller_Router_Route(
                            'provisioning/basic-template',
                            array('controller' => 'provisioning', 'action' => 'basictemplate')));
 
        ...		
 
        // Returns the router resource to bootstrap resource registry
        return $router;
    }

Calling the View

We are just about done. Now we need to call the generic view. We make this call in Drupal’s theme template file (page.tpl.php).

In this file, look for:

print render($page['content']);

and replace it with:

if (isset($zend_view)) {
      $zend_view->dispatch();		
} else {
      print render($page['content']);
}

That’s it. Now you can use Zend Framework with Drupal. Drupal is great as an Content Management System, but Zend Framework is the better choice when it comes to application development. Using this process, you don’t have to choose one or the other. Enjoy.

Be Sociable, Share!

Checkout My New Site - T-shirts For Geeks