views:

58

answers:

2

In my Zend Framework modules, I have views that require specific javascript, CSS and images.

Is that possible to include them in the module in a way that I don't have to copy them in each project that uses the module ? (because the "public/" folder is not part of the module, but specific to each application)

If not, how can I do ?

Thanks !

A: 

"Install Directions" that include linking/alaising "public_html/mymodule/" to a sub directory in your module folder is about the simplest it gets.

I have written a controller/action/route that serves up scripts/css/images in the past. It wasn't terribly complicated, but it was kind of a pain to handle caching properly. I'm not saying this is a great way to do it, I mean, you really shouldn't want to spend all the time setting up zend framework and dispatching an action to give someone a static javascript file... However, you could do this AND tell them to link the directory too.

In case you decide to use it, here's the Abstract I wrote that can serve up some static content:

<?php

class MW_Script_Controller_Abstract extends Zend_Controller_Action
{
  protected $_basepath;

  public function publicAction()
  {
    // not initialized
    if (!$this->_basepath) throw new Exception("base path not set");


    if (!($filename = $this->_request->getParam("filename")))
      $filename = $this->_request->getParam(1);

    if (!$filename) throw new Exception("Unknown Filename");

    $fn = realpath($this->_basepath."/".$filename);

    if (!$fn || !is_file($fn)) throw new MW_Controller_404Exception("File not found");

    // determine extension to determine mime-type
    preg_match("#\.([^.]+)$#", $filename, $matches);
    if (!empty($matches[1]) switch (strtolower($matches[1]))
    {
      case "js": 
        $this->getResponse()->setHeader('Content-Type', 'text/javascript'); 
        ini_set('html_errors', 0);
        break;
      case "css": 
        $this->getResponse()->setHeader('Content-Type', 'text/css'); 
        ini_set('html_errors', 0);
        break;
      case "html":
        $this->getResponse()->setHeader('Content-Type', 'text/html');
        break;
      default:
        $this->getResponse()->setHeader('Content-Type', 'text/plain'); 
        ini_set('html_errors', 0);
        break;
    }

    // Disable Layout
    $this->_helper->viewRenderer->setNoRender(true);     
    $this->_helper->layout->disableLayout();

    $mtime = filemtime($fn);

    if ($modsince = $this->getRequest()->getServer('HTTP_IF_MODIFIED_SINCE'))
    {
      $modsince = new Zend_Date($modsince);
      $modsince = $modsince->getTimestamp();

      if ($mtime <= $modsince) {
        $this->getResponse()->setHttpResponseCode(304); 
        return;
      }
    }

    $this->getResponse()->setHeader('Last-Modified', gmdate("D, d M Y H:i:s",$mtime). " GMT");
    readfile($fn);
    // All Done
  }
}

And the Route:

<?php
class MW_Script_Route extends Zend_Controller_Router_Route_Abstract
{
  /**
   * The Root Path for this "MW_Script_Controller" area
   *
   * @var string a root "path" for this route
   **/
  protected $_rootpath;

  /**
   * Holds user submitted default values for route's variables. Name and value pairs.
   * @var array
   */
  protected $_defaults = array();

  /**
   * Instantiates route based on passed Zend_Config structure
   *
   * @param Zend_Config $config Configuration object
   */
  public static function getInstance(Zend_Config $config)
  {
      $defs = ($config->defaults instanceof Zend_Config) ? $config->defaults->toArray() : array();
      return new self($config->route, $defs);
  }
  /**
   * Stores the basepath for later matching, also stores defaults.  If no "module" is passed in to 
   * the $defaults array,  the "basepath" will be used as a module name, "index" will be used as a 
   * controller, and "public" will be used as a action.
   *
   * @param string $route Map used to match with later submitted URL path
   * @param array $defaults Defaults for map variables with keys as variable names
   * @param array $reqs Regular expression requirements for variables (keys as variable names)
   */
  public function __construct($route, $defaults = array())
  {

      $route = trim($route, '/');
      $this->_defaults = (array) $defaults;
      if (!isset($this->_defaults["module"])) $this->_defaults["module"] = $route;
      if (!isset($this->_defaults["controller"])) $this->_defaults["controller"] = "index";
      if (!isset($this->_defaults["action"])) $this->_defaults["action"] = "public";

      $this->_rootpath = $route;

  }

  public function match($request)
  {
    $path = trim($request->getPathInfo(), '/');
    if (substr($path, 0, strlen($this->_rootpath)) == $this->_rootpath)
    {
      $values = $this->_defaults;
      $values["filename"] = substr($path,strlen($this->_rootpath)+1);
      return $values;
    }
  }

  public function assemble($data = array(), $reset = false, $encode = false)
  {
    if (isset($data["filename"])) $filename = $data["filename"];
    if (isset($data["1"])) $filename = $data["1"];
    return $this->_rootpath . "/" .$filename;
  }

} // END class MW_Script_Controller_Route extends Zend_Controller_Router_Route_Abstract
gnarf
Linking/aliasing : we (a team) work on Mac, Linux and Windows, and synchronise through SVN. I think this will be a real mess (and linking is not possible on windows). As fos the controller that serves the images, the theory is interesting, but I don't want to build up a whole Zend Application in memory just for a static image.
Matthieu
A: 

The simplest way is to put assets in public directory and use baseUrl() helper.

However, the best way is to move all scripts to /public directory. Then you will swapable 'skins'. Of course, you'll have to add additional rules to .htaccess protect the .phtml's

To do this, you will have to customize standard application structure to suit you needs.
For further explanation see my answer in this post.

takeshin
I'm not sure I'm following you : I have my module X that uses the image X1.jpg (this image is only used by X). If in another application, I use the X module, I don't want to copy the images (I want the images of module X inside the module). I don't see how your answer can help me.
Matthieu
Mmmh I have a doubt : when I talk about a script, I mean Javascript. You talk about ".phtml", this means views.
Matthieu