mirror of
https://github.com/mrclay/minify.git
synced 2025-08-06 22:26:28 +02:00
Controllers now supply all options and are easier to write! serve() returns more useful info and needs only one option array for both controller/minify options.
This commit is contained in:
30
README
30
README
@@ -42,33 +42,25 @@ Sources with known "last modified" timestamps allow Minify to implement
|
|||||||
conditional GETs.
|
conditional GETs.
|
||||||
|
|
||||||
You configure Minify via a Minify_Controller object. The controller
|
You configure Minify via a Minify_Controller object. The controller
|
||||||
supplies the sources and some other information about a request,
|
supplies the sources and default options to serve a request,
|
||||||
determining how it's to be responded to. Several controllers are
|
determining how it's to be responded to. Several controllers are
|
||||||
supplied with Minify, but it's also fairly easy to write your own. E.g.
|
supplied with Minify, but it's also fairly easy to write your own. E.g.
|
||||||
a controller could emulate v1.x of minify.php.
|
a controller could emulate v1.x of minify.php.
|
||||||
|
|
||||||
To use an existing controller, you call Minify::serve(), passing it the
|
To use an existing controller, you call Minify::serve(), passing it:
|
||||||
name of your controller of choice (without the "Minify_Controller"
|
1. the name of your controller of choice (without the "Minify_Controller"
|
||||||
prefix), an array of options for the controller, and an array of general
|
prefix) or a custom controller object subclassed from Minify_Controller_Base.
|
||||||
Minify options (optional). Eg.:
|
2. a combined array of controller and Minify options. Eg.:
|
||||||
|
|
||||||
// serve a minified javascript file and tell clients to cache it for a
|
// serve a minified javascript file and tell clients to cache it for a
|
||||||
// year
|
// year
|
||||||
Minify::serve(
|
Minify::serve('Files', array(
|
||||||
'Files'
|
'files' => array('/path/to/file1.js', '/path/to/file2.js')
|
||||||
,array('/path/to/file1.js', '/path/to/file2.js')
|
,'setExpires' => (time() + 86400 * 365)
|
||||||
,array('setExpires' => (time() + 86400 * 365))
|
));
|
||||||
);
|
|
||||||
|
|
||||||
The above creates an instance of Minify_Controller_Files, passing the
|
The above creates an instance of Minify_Controller_Files, which creates
|
||||||
two arrays to its constructor.
|
source objects from the 'files' option, and supplies other default options.
|
||||||
|
|
||||||
The first array depends on the controller. In this case,
|
|
||||||
Minify_Controller_Files needs a list of file paths.
|
|
||||||
|
|
||||||
The second array (optional) has options for Minify. (Since this is
|
|
||||||
passed through the controller, some controllers may use/alter this
|
|
||||||
data).
|
|
||||||
|
|
||||||
MINIFY USAGE
|
MINIFY USAGE
|
||||||
|
|
||||||
|
139
lib/Minify.php
139
lib/Minify.php
@@ -26,6 +26,10 @@ require_once 'Minify/Source.php';
|
|||||||
|
|
||||||
class Minify {
|
class Minify {
|
||||||
|
|
||||||
|
const TYPE_CSS = 'text/css';
|
||||||
|
const TYPE_JS = 'application/x-javascript';
|
||||||
|
const TYPE_HTML = 'text/html';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool Should the un-encoded version be cached?
|
* @var bool Should the un-encoded version be cached?
|
||||||
*
|
*
|
||||||
@@ -63,7 +67,7 @@ class Minify {
|
|||||||
*
|
*
|
||||||
* @return mixed false on failure or array of content and headers sent
|
* @return mixed false on failure or array of content and headers sent
|
||||||
*/
|
*/
|
||||||
public static function serve($type, $ctrlOptions = array(), $minOptions = array()) {
|
public static function serveold($type, $ctrlOptions = array(), $minOptions = array()) {
|
||||||
$class = 'Minify_Controller_' . $type;
|
$class = 'Minify_Controller_' . $type;
|
||||||
if (! class_exists($class, false)) {
|
if (! class_exists($class, false)) {
|
||||||
require_once "Minify/Controller/{$type}.php";
|
require_once "Minify/Controller/{$type}.php";
|
||||||
@@ -80,22 +84,82 @@ class Minify {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a request for a minified file.
|
* Serve a request for a minified file.
|
||||||
*
|
*
|
||||||
* You must supply a controller object which has the same public API
|
* @param mixed instance of subclass of Minify_Controller_Base or string name of controller. E.g. 'Files'
|
||||||
* as Minify_Controller.
|
|
||||||
*
|
*
|
||||||
* @param Minify_Controller $controller
|
* @param array $options controller/serve options
|
||||||
|
*
|
||||||
|
* @return array success, statusCode, content, and headers generated
|
||||||
|
*
|
||||||
|
* Here are the available options and defaults in the base controller:
|
||||||
|
*
|
||||||
|
* 'isPublic' : send "public" instead of "private" in Cache-Control
|
||||||
|
* headers, allowing shared caches to cache the output. (default true)
|
||||||
|
*
|
||||||
|
* 'quiet' : set to true to have no content/headers sent (default false)
|
||||||
|
*
|
||||||
|
* 'encodeOutput' : to disable content encoding, set this to false (default true)
|
||||||
|
*
|
||||||
|
* 'encodeMethod' : generally you should let this be determined by
|
||||||
|
* HTTP_Encoder (leave null), but you can force a particular encoding
|
||||||
|
* to be returned, by setting this to 'gzip', 'deflate', 'compress', or ''
|
||||||
|
* (no encoding)
|
||||||
|
*
|
||||||
|
* 'encodeLevel' : level of encoding compression (0 to 9, default 9)
|
||||||
|
*
|
||||||
|
* 'contentTypeCharset' : if given, this will be appended to the Content-Type
|
||||||
|
* header sent (needed mainly for HTML docs)
|
||||||
|
*
|
||||||
|
* 'setExpires' : set this to a timestamp or GMT date to have Minify send
|
||||||
|
* an HTTP Expires header instead of checking for conditional GET (default null).
|
||||||
|
* E.g. (time() + 86400 * 365) for 1yr
|
||||||
|
* Note this has nothing to do with server-side caching.
|
||||||
|
*
|
||||||
|
* 'perType' : this is an array of options to send to a particular minifier
|
||||||
|
* function using the content-type as key. E.g. To send the CSS minifier an
|
||||||
|
* option:
|
||||||
|
* <code>
|
||||||
|
* $options['perType'][Minify::TYPE_CSS]['optionName'] = 'optionValue';
|
||||||
|
* </code>
|
||||||
|
* When the CSS minifier is called, the 2nd argument will be
|
||||||
|
* array('optionName' => 'optionValue').
|
||||||
|
*
|
||||||
|
* Any controller options are documented in that controller's setupSources() method.
|
||||||
*
|
*
|
||||||
* @return mixed false on failure or array of content and headers sent
|
|
||||||
*/
|
*/
|
||||||
public static function handleRequest($controller) {
|
public static function serve($controller, $options = array()) {
|
||||||
if (! $controller->requestIsValid) {
|
if (is_string($controller)) {
|
||||||
return false;
|
// make $controller into object
|
||||||
|
$class = 'Minify_Controller_' . $controller;
|
||||||
|
if (! class_exists($class, false)) {
|
||||||
|
require_once "Minify/Controller/{$controller}.php";
|
||||||
|
}
|
||||||
|
$controller = new $class();
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up controller sources and mix remaining options with
|
||||||
|
// controller defaults
|
||||||
|
$options = $controller->setupSources($options);
|
||||||
|
$options = $controller->analyzeSources($options);
|
||||||
|
self::$_options = $controller->mixInDefaultOptions($options);
|
||||||
|
|
||||||
|
if (! $controller->sources) {
|
||||||
|
// invalid request!
|
||||||
|
if (! self::$_options['quiet']) {
|
||||||
|
header(self::$_options['badRequestHeader']);
|
||||||
|
echo self::$_options['badRequestHeader'];
|
||||||
|
}
|
||||||
|
list(,$statusCode) = explode(' ', self::$_options['badRequestHeader']);
|
||||||
|
return array(
|
||||||
|
'success' => false
|
||||||
|
,'statusCode' => (int)$statusCode
|
||||||
|
,'content' => ''
|
||||||
|
,'headers' => array()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self::$_controller = $controller;
|
self::$_controller = $controller;
|
||||||
self::_resolveOptions($controller->minOptions);
|
|
||||||
|
|
||||||
$cgOptions = array(
|
$cgOptions = array(
|
||||||
'lastModifiedTime' => self::$_options['lastModifiedTime']
|
'lastModifiedTime' => self::$_options['lastModifiedTime']
|
||||||
@@ -112,11 +176,13 @@ class Minify {
|
|||||||
// client's cache is valid
|
// client's cache is valid
|
||||||
if (self::$_options['quiet']) {
|
if (self::$_options['quiet']) {
|
||||||
return array(
|
return array(
|
||||||
'content' => ''
|
'success' => true
|
||||||
,'headers' => $cg->getHeaders()
|
,'statusCode' => 304
|
||||||
|
,'content' => ''
|
||||||
|
,'headers' => array()
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$cg->sendHeaders();
|
$cg->sendHeaders();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// client will need output
|
// client will need output
|
||||||
@@ -165,10 +231,12 @@ class Minify {
|
|||||||
foreach ($headers as $name => $val) {
|
foreach ($headers as $name => $val) {
|
||||||
header($name . ': ' . $val);
|
header($name . ': ' . $val);
|
||||||
}
|
}
|
||||||
echo $content;
|
echo $content;
|
||||||
}
|
}
|
||||||
return array(
|
return array(
|
||||||
'content' => $content
|
'success' => true
|
||||||
|
,'statusCode' => 200
|
||||||
|
,'content' => $content
|
||||||
,'headers' => $headers
|
,'headers' => $headers
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -193,34 +261,7 @@ class Minify {
|
|||||||
*/
|
*/
|
||||||
private static $_cache = null;
|
private static $_cache = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve Minify options based on those passed from controller and Minify's defaults
|
|
||||||
*
|
|
||||||
* @return null
|
|
||||||
*/
|
|
||||||
private static function _resolveOptions($ctrlOptions)
|
|
||||||
{
|
|
||||||
self::$_options = array_merge(array(
|
|
||||||
// default options
|
|
||||||
'isPublic' => true
|
|
||||||
,'encodeOutput' => true
|
|
||||||
,'encodeMethod' => null // determine later
|
|
||||||
,'encodeLevel' => 9
|
|
||||||
,'perType' => array() // per-type minifier options
|
|
||||||
,'contentTypeCharset' => null // leave out of Content-Type header
|
|
||||||
,'setExpires' => null // send Expires header
|
|
||||||
,'quiet' => false
|
|
||||||
), $ctrlOptions);
|
|
||||||
$defaultMinifiers = array(
|
|
||||||
'text/css' => array('Minify_CSS', 'minify')
|
|
||||||
,'application/x-javascript' => array('Minify_Javascript', 'minify')
|
|
||||||
,'text/html' => array('Minify_HTML', 'minify')
|
|
||||||
);
|
|
||||||
if (! isset($ctrlOptions['minifiers'])) {
|
|
||||||
$ctrlOptions['minifiers'] = array();
|
|
||||||
}
|
|
||||||
self::$_options['minifiers'] = array_merge($defaultMinifiers, $ctrlOptions['minifiers']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch encoded content from cache (or generate and store it).
|
* Fetch encoded content from cache (or generate and store it).
|
||||||
@@ -288,21 +329,25 @@ class Minify {
|
|||||||
$type = self::$_options['contentType']; // ease readability
|
$type = self::$_options['contentType']; // ease readability
|
||||||
|
|
||||||
// when combining scripts, make sure all statements separated
|
// when combining scripts, make sure all statements separated
|
||||||
$implodeSeparator = ($type === 'application/x-javascript')
|
$implodeSeparator = ($type === self::TYPE_JS)
|
||||||
? ';'
|
? ';'
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
// default options and minifier function for all sources
|
// allow the user to pass a particular array of options to each
|
||||||
|
// minifier (designated by type). source objects may still override
|
||||||
|
// these
|
||||||
$defaultOptions = isset(self::$_options['perType'][$type])
|
$defaultOptions = isset(self::$_options['perType'][$type])
|
||||||
? self::$_options['perType'][$type]
|
? self::$_options['perType'][$type]
|
||||||
: array();
|
: array();
|
||||||
// if minifier not set, default is no minification
|
// if minifier not set, default is no minification. source objects
|
||||||
|
// may still override this
|
||||||
$defaultMinifier = isset(self::$_options['minifiers'][$type])
|
$defaultMinifier = isset(self::$_options['minifiers'][$type])
|
||||||
? self::$_options['minifiers'][$type]
|
? self::$_options['minifiers'][$type]
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
if (Minify_Source::haveNoMinifyPrefs(self::$_controller->sources)) {
|
if (Minify_Source::haveNoMinifyPrefs(self::$_controller->sources)) {
|
||||||
// all source have same options/minifier, better performance
|
// all source have same options/minifier, better performance
|
||||||
|
// to combine, then minify once
|
||||||
foreach (self::$_controller->sources as $source) {
|
foreach (self::$_controller->sources as $source) {
|
||||||
$pieces[] = $source->getContent();
|
$pieces[] = $source->getContent();
|
||||||
}
|
}
|
||||||
@@ -312,7 +357,7 @@ class Minify {
|
|||||||
$content = call_user_func($defaultMinifier, $content, $defaultOptions);
|
$content = call_user_func($defaultMinifier, $content, $defaultOptions);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// minify each source with its own options and minifier
|
// minify each source with its own options and minifier, then combine
|
||||||
foreach (self::$_controller->sources as $source) {
|
foreach (self::$_controller->sources as $source) {
|
||||||
// allow the source to override our minifier and options
|
// allow the source to override our minifier and options
|
||||||
$minifier = (null !== $source->minifier)
|
$minifier = (null !== $source->minifier)
|
||||||
|
@@ -7,111 +7,58 @@
|
|||||||
* for minification and set options like contentType. It's also responsible
|
* for minification and set options like contentType. It's also responsible
|
||||||
* for loading minifier code upon request.
|
* for loading minifier code upon request.
|
||||||
*/
|
*/
|
||||||
class Minify_Controller_Base {
|
abstract class Minify_Controller_Base {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array instances of Minify_Source, which provide content and
|
* Setup controller sources
|
||||||
* any individual minification needs.
|
|
||||||
*
|
*
|
||||||
* @see Minify_Source
|
* You must override this method in your subclass controller to set
|
||||||
|
* $this->sources. If the request is NOT valid, make sure $this->sources
|
||||||
|
* is left an empty array. Then strip any controller-specific options from
|
||||||
|
* $options and return it.
|
||||||
|
*
|
||||||
|
* @param array $options controller and Minify options
|
||||||
|
*
|
||||||
|
* @param array $options Minify options
|
||||||
*/
|
*/
|
||||||
public $sources = array();
|
abstract public function setupSources($options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array options to be read by Minify
|
* Get default Minify options for this controller.
|
||||||
*
|
*
|
||||||
* Any unspecified options will use the default values.
|
* Override in subclass to change defaults
|
||||||
*
|
|
||||||
* 'minifiers': this is an array with content-types as keys and callbacks as
|
|
||||||
* values. Specify a custom minifier by setting this option. E.g.:
|
|
||||||
*
|
|
||||||
* <code>
|
|
||||||
* $this->options['minifiers']['application/x-javascript'] =
|
|
||||||
* array('Minify_Packer', 'minify'); // callback
|
|
||||||
* </code>
|
|
||||||
*
|
|
||||||
* Note that, when providing your own minifier, the controller must be able
|
|
||||||
* to load its code on demand. @see loadMinifier()
|
|
||||||
*
|
|
||||||
* 'perType' : this is an array of options to send to a particular content
|
|
||||||
* type minifier by using the content-type as key. E.g. To send the CSS
|
|
||||||
* minifier an option: $options['perType']['text/css']['foo'] = 'bar';
|
|
||||||
* When the CSS minifier is called, the 2nd argument will be
|
|
||||||
* array('foo' => 'bar').
|
|
||||||
*
|
|
||||||
* 'isPublic' : send "public" instead of "private" in Cache-Control headers,
|
|
||||||
* allowing shared caches to cache the output. (default true)
|
|
||||||
*
|
|
||||||
* 'encodeOutput' : to disable content encoding, set this to false
|
|
||||||
*
|
|
||||||
* 'encodeMethod' : generally you should let this be determined by
|
|
||||||
* HTTP_Encoder (the default null), but you can force a particular encoding
|
|
||||||
* to be returned, by setting this to 'gzip', 'deflate', 'compress', or ''
|
|
||||||
* (no encoding)
|
|
||||||
*
|
|
||||||
* 'encodeLevel' : level of encoding compression (0 to 9, default 9)
|
|
||||||
*
|
|
||||||
* 'contentTypeCharset' : if given, this will be appended to the Content-Type
|
|
||||||
* header sent, useful mainly for HTML docs.
|
|
||||||
*
|
|
||||||
* 'setExpires' : set this to a timestamp or GMT date to have Minify send
|
|
||||||
* an HTTP Expires header instead of checking for conditional GET.
|
|
||||||
* E.g. (time() + 86400 * 365) for 1yr (default null)
|
|
||||||
* This has nothing to do with server-side caching.
|
|
||||||
*
|
|
||||||
* 'quiet' : set to true to have Minify not output any content/headers
|
|
||||||
* (bool, default = false)
|
|
||||||
*
|
*
|
||||||
|
* @return array options for Minify
|
||||||
*/
|
*/
|
||||||
public $minOptions = array();
|
public function getDefaultMinifyOptions() {
|
||||||
|
return array(
|
||||||
|
'isPublic' => true
|
||||||
|
,'encodeOutput' => true
|
||||||
|
,'encodeMethod' => null // determine later
|
||||||
|
,'encodeLevel' => 9
|
||||||
|
,'perType' => array() // no per-type minifier options
|
||||||
|
,'contentTypeCharset' => null // leave out of Content-Type header
|
||||||
|
,'setExpires' => null // use conditional GET
|
||||||
|
,'quiet' => false // serve() will send headers and output
|
||||||
|
|
||||||
|
// if you override this, the response code MUST be directly after
|
||||||
|
// the first space.
|
||||||
|
,'badRequestHeader' => 'HTTP/1.0 400 Bad Request'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var bool was the user request valid
|
* Get default minifiers for this controller.
|
||||||
*
|
*
|
||||||
* This must be explicity be set to true to process the request. This should
|
* Override in subclass to change defaults
|
||||||
* be done by the child class constructor.
|
*
|
||||||
|
* @return array minifier callbacks for common types
|
||||||
*/
|
*/
|
||||||
public $requestIsValid = false;
|
public function getDefaultMinifers() {
|
||||||
|
$ret[Minify::TYPE_JS] = array('Minify_Javascript', 'minify');
|
||||||
/**
|
$ret[Minify::TYPE_CSS] = array('Minify_CSS', 'minify');
|
||||||
* Parent constructor for a controller class
|
$ret[Minify::TYPE_HTML] = array('Minify_HTML', 'minify');
|
||||||
*
|
return $ret;
|
||||||
* If your subclass controller is not happy with the request, it can simply return
|
|
||||||
* without setting $this->requestIsValid. Minify will not check any other member.
|
|
||||||
*
|
|
||||||
* If the request is valid, you must set $this->requestIsValid = true and also call
|
|
||||||
* the parent constructor, passing along an array of source objects and any Minify
|
|
||||||
* options:
|
|
||||||
* <code>
|
|
||||||
* parent::__construct($sources, $options);
|
|
||||||
* </code>
|
|
||||||
*
|
|
||||||
* This function sets $this->sources and determines $this->options 'contentType' and
|
|
||||||
* 'lastModifiedTime'.
|
|
||||||
*
|
|
||||||
* @param array $sources array of Minify_Source instances
|
|
||||||
*
|
|
||||||
* @param array $options options for Minify
|
|
||||||
*
|
|
||||||
* @return null
|
|
||||||
*/
|
|
||||||
public function __construct($sources, $options = array()) {
|
|
||||||
if (empty($sources)) {
|
|
||||||
$this->requestIsValid = false;
|
|
||||||
}
|
|
||||||
$this->sources = $sources;
|
|
||||||
if (! isset($options['contentType'])) {
|
|
||||||
$options['contentType'] = Minify_Source::getContentType($this->sources);
|
|
||||||
}
|
|
||||||
// last modified is needed for caching, even if setExpires is set
|
|
||||||
if (! isset($options['lastModifiedTime'])) {
|
|
||||||
$max = 0;
|
|
||||||
foreach ($sources as $source) {
|
|
||||||
$max = max($source->lastModified, $max);
|
|
||||||
}
|
|
||||||
$options['lastModifiedTime'] = $max;
|
|
||||||
}
|
|
||||||
$this->minOptions = $options;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -124,7 +71,10 @@ class Minify_Controller_Base {
|
|||||||
* function will include 'Jimmy/Minifier.php'
|
* function will include 'Jimmy/Minifier.php'
|
||||||
*
|
*
|
||||||
* If you need code loaded on demand and this doesn't suit you, you'll need
|
* If you need code loaded on demand and this doesn't suit you, you'll need
|
||||||
* to override this function by extending the class.
|
* to override this function in your subclass.
|
||||||
|
* @see Minify_Controller_Page::loadMinifier()
|
||||||
|
*
|
||||||
|
* @param callback $minifierCallback callback of minifier function
|
||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
@@ -137,4 +87,58 @@ class Minify_Controller_Base {
|
|||||||
require str_replace('_', '/', $minifierCallback[0]) . '.php';
|
require str_replace('_', '/', $minifierCallback[0]) . '.php';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array instances of Minify_Source, which provide content and
|
||||||
|
* any individual minification needs.
|
||||||
|
*
|
||||||
|
* @see Minify_Source
|
||||||
|
*/
|
||||||
|
public $sources = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mix in default controller options with user-given options
|
||||||
|
*
|
||||||
|
* @param array $options user options
|
||||||
|
*
|
||||||
|
* @return array mixed options
|
||||||
|
*/
|
||||||
|
public final function mixInDefaultOptions($options)
|
||||||
|
{
|
||||||
|
$ret = array_merge(
|
||||||
|
$this->getDefaultMinifyOptions(), $options
|
||||||
|
);
|
||||||
|
if (! isset($options['minifiers'])) {
|
||||||
|
$options['minifiers'] = array();
|
||||||
|
}
|
||||||
|
$ret['minifiers'] = array_merge(
|
||||||
|
$this->getDefaultMinifers(), $options['minifiers']
|
||||||
|
);
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyze sources (if there are any) and set $options 'contentType'
|
||||||
|
* and 'lastModifiedTime' if they already aren't.
|
||||||
|
*
|
||||||
|
* @param array $options options for Minify
|
||||||
|
*
|
||||||
|
* @return array options for Minify
|
||||||
|
*/
|
||||||
|
public final function analyzeSources($options = array()) {
|
||||||
|
if ($this->sources) {
|
||||||
|
if (! isset($options['contentType'])) {
|
||||||
|
$options['contentType'] = Minify_Source::getContentType($this->sources);
|
||||||
|
}
|
||||||
|
// last modified is needed for caching, even if setExpires is set
|
||||||
|
if (! isset($options['lastModifiedTime'])) {
|
||||||
|
$max = 0;
|
||||||
|
foreach ($this->sources as $source) {
|
||||||
|
$max = max($source->lastModified, $max);
|
||||||
|
}
|
||||||
|
$options['lastModifiedTime'] = $max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,9 +9,11 @@ require_once 'Minify/Controller/Base.php';
|
|||||||
* <code>
|
* <code>
|
||||||
* $dr = $_SERVER['DOCUMENT_ROOT'];
|
* $dr = $_SERVER['DOCUMENT_ROOT'];
|
||||||
* Minify::serve('Files', array(
|
* Minify::serve('Files', array(
|
||||||
* $dr . '/js/jquery.js'
|
* 'files' => array(
|
||||||
* ,$dr . '/js/plugins.js'
|
* $dr . '/js/jquery.js'
|
||||||
* ,$dr . '/js/site.js'
|
* ,$dr . '/js/plugins.js'
|
||||||
|
* ,$dr . '/js/site.js'
|
||||||
|
* )
|
||||||
* ));
|
* ));
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
@@ -19,28 +21,36 @@ require_once 'Minify/Controller/Base.php';
|
|||||||
class Minify_Controller_Files extends Minify_Controller_Base {
|
class Minify_Controller_Files extends Minify_Controller_Base {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $spec array of full paths of files to be minified
|
* Set up file sources
|
||||||
*
|
*
|
||||||
* @param array $options options to pass to Minify
|
* @param array $options controller and Minify options
|
||||||
|
* @return array Minify options
|
||||||
*
|
*
|
||||||
* @return null
|
* Controller options:
|
||||||
|
*
|
||||||
|
* 'files': (required) array of complete file paths
|
||||||
*/
|
*/
|
||||||
public function __construct($spec, $options = array()) {
|
public function setupSources($options) {
|
||||||
|
// strip controller options
|
||||||
|
$files = $options['files'];
|
||||||
|
unset($options['files']);
|
||||||
|
|
||||||
$sources = array();
|
$sources = array();
|
||||||
foreach ($spec as $file) {
|
foreach ($files as $file) {
|
||||||
$file = realpath($file);
|
$file = realpath($file);
|
||||||
if (file_exists($file)) {
|
if (file_exists($file)) {
|
||||||
$sources[] = new Minify_Source(array(
|
$sources[] = new Minify_Source(array(
|
||||||
'filepath' => $file
|
'filepath' => $file
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
return;
|
// file not found
|
||||||
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($sources) {
|
if ($sources) {
|
||||||
$this->requestIsValid = true;
|
$this->sources = $sources;
|
||||||
}
|
}
|
||||||
parent::__construct($sources, $options);
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,16 +8,11 @@ require_once 'Minify/Controller/Base.php';
|
|||||||
*
|
*
|
||||||
* <code>
|
* <code>
|
||||||
* $dr = $_SERVER['DOCUMENT_ROOT'];
|
* $dr = $_SERVER['DOCUMENT_ROOT'];
|
||||||
* Minify::serve('Groups', array(
|
* Minify::serve('Groups', array(
|
||||||
* 'css' => array(
|
* 'groups' => array(
|
||||||
* $dr . '/css/type.css'
|
* 'css' => array($dr . '/css/type.css', $dr . '/css/layout.css')
|
||||||
* ,$dr . '/css/layout.css'
|
* ,'js' => array($dr . '/js/jquery.js', $dr . '/js/site.js')
|
||||||
* )
|
* )
|
||||||
* ,'js' => array(
|
|
||||||
* $dr . '/js/jquery.js'
|
|
||||||
* ,$dr . '/js/plugins.js'
|
|
||||||
* ,$dr . '/js/site.js'
|
|
||||||
* )
|
|
||||||
* ));
|
* ));
|
||||||
* </code>
|
* </code>
|
||||||
*
|
*
|
||||||
@@ -27,20 +22,28 @@ require_once 'Minify/Controller/Base.php';
|
|||||||
class Minify_Controller_Groups extends Minify_Controller_Base {
|
class Minify_Controller_Groups extends Minify_Controller_Base {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $spec associative array of keys to arrays of file paths.
|
* Set up groups of files as sources
|
||||||
*
|
*
|
||||||
* @param array $options optional options to pass to Minify
|
* @param array $options controller and Minify options
|
||||||
|
* @return array Minify options
|
||||||
*
|
*
|
||||||
* @return null
|
* Controller options:
|
||||||
|
*
|
||||||
|
* 'groups': (required) array mapping PATH_INFO strings to arrays
|
||||||
|
* of complete file paths. @see Minify_Controller_Groups
|
||||||
*/
|
*/
|
||||||
public function __construct($spec, $options = array()) {
|
public function setupSources($options) {
|
||||||
|
// strip controller options
|
||||||
|
$groups = $options['groups'];
|
||||||
|
unset($options['groups']);
|
||||||
|
|
||||||
$pi = substr($_SERVER['PATH_INFO'], 1);
|
$pi = substr($_SERVER['PATH_INFO'], 1);
|
||||||
if (! isset($spec[$pi])) {
|
if (! isset($groups[$pi])) {
|
||||||
// not a valid group
|
// not a valid group
|
||||||
return;
|
return $options;
|
||||||
}
|
}
|
||||||
$sources = array();
|
$sources = array();
|
||||||
foreach ($spec[$pi] as $file) {
|
foreach ($groups[$pi] as $file) {
|
||||||
$file = realpath($file);
|
$file = realpath($file);
|
||||||
if (file_exists($file)) {
|
if (file_exists($file)) {
|
||||||
$sources[] = new Minify_Source(array(
|
$sources[] = new Minify_Source(array(
|
||||||
@@ -48,13 +51,13 @@ class Minify_Controller_Groups extends Minify_Controller_Base {
|
|||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
// file doesn't exist
|
// file doesn't exist
|
||||||
return;
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($sources) {
|
if ($sources) {
|
||||||
$this->requestIsValid = true;
|
$this->sources = $sources;
|
||||||
}
|
}
|
||||||
parent::__construct($sources, $options);
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,37 +11,47 @@ require_once 'Minify/Controller/Base.php';
|
|||||||
class Minify_Controller_Page extends Minify_Controller_Base {
|
class Minify_Controller_Page extends Minify_Controller_Base {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $spec array of options. You *must* set 'content' and 'id',
|
* Set up source of HTML content
|
||||||
* but setting 'lastModifiedTime' is recommeded in order to allow server
|
|
||||||
* and client-side caching.
|
|
||||||
*
|
*
|
||||||
* If you set <code>'minifyAll' => 1</code>, all CSS and Javascript blocks
|
* @param array $options controller and Minify options
|
||||||
* will be individually minified.
|
* @return array Minify options
|
||||||
*
|
*
|
||||||
* @param array $options optional options to pass to Minify
|
* Controller options:
|
||||||
*
|
*
|
||||||
* @return null
|
* 'content': (required) HTML markup
|
||||||
|
*
|
||||||
|
* 'id': (required) id of page (string for use in server-side caching)
|
||||||
|
*
|
||||||
|
* 'lastModifiedTime': timestamp of when this content changed. This
|
||||||
|
* is recommended to allow both server and client-side caching.
|
||||||
|
*
|
||||||
|
* 'minifyAll': should all CSS and Javascript blocks be individually
|
||||||
|
* minified? (default false)
|
||||||
*/
|
*/
|
||||||
public function __construct($spec, $options = array()) {
|
public function setupSources($options) {
|
||||||
|
// strip controller options
|
||||||
$sourceSpec = array(
|
$sourceSpec = array(
|
||||||
'content' => $spec['content']
|
'content' => $options['content']
|
||||||
,'id' => $spec['id']
|
,'id' => $options['id']
|
||||||
,'minifier' => array('Minify_HTML', 'minify')
|
|
||||||
);
|
);
|
||||||
if (isset($spec['minifyAll'])) {
|
unset($options['content'], $options['id']);
|
||||||
|
|
||||||
|
if (isset($options['minifyAll'])) {
|
||||||
|
// this will be the 2nd argument passed to Minify_HTML::minify()
|
||||||
$sourceSpec['minifyOptions'] = array(
|
$sourceSpec['minifyOptions'] = array(
|
||||||
'cssMinifier' => array('Minify_CSS', 'minify')
|
'cssMinifier' => array('Minify_CSS', 'minify')
|
||||||
,'jsMinifier' => array('Minify_Javascript', 'minify')
|
,'jsMinifier' => array('Minify_Javascript', 'minify')
|
||||||
);
|
);
|
||||||
$this->_loadCssJsMinifiers = true;
|
$this->_loadCssJsMinifiers = true;
|
||||||
|
unset($options['minifyAll']);
|
||||||
}
|
}
|
||||||
$sources[] = new Minify_Source($sourceSpec);
|
$this->sources[] = new Minify_Source($sourceSpec);
|
||||||
if (isset($spec['lastModifiedTime'])) {
|
|
||||||
$options['lastModifiedTime'] = $spec['lastModifiedTime'];
|
// may not be needed
|
||||||
}
|
//$options['minifier'] = array('Minify_HTML', 'minify');
|
||||||
$options['contentType'] = 'text/html';
|
|
||||||
$this->requestIsValid = true;
|
$options['contentType'] = Minify::TYPE_HTML;
|
||||||
parent::__construct($sources, $options);
|
return $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
private $_loadCssJsMinifiers = false;
|
private $_loadCssJsMinifiers = false;
|
||||||
|
@@ -38,9 +38,8 @@ if (isset($_GET['f'])) {
|
|||||||
// The Files controller serves an array of files, but here we just
|
// The Files controller serves an array of files, but here we just
|
||||||
// need one.
|
// need one.
|
||||||
Minify::serve('Files', array(
|
Minify::serve('Files', array(
|
||||||
dirname(__FILE__) . '/' . $filename
|
'files' => array(dirname(__FILE__) . '/' . $filename)
|
||||||
), array(
|
,'setExpires' => $setExpires
|
||||||
'setExpires' => $setExpires
|
|
||||||
));
|
));
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
@@ -14,8 +14,10 @@ $lastModified = time() - 86400;
|
|||||||
// Test minifying JS and serving with Expires header
|
// Test minifying JS and serving with Expires header
|
||||||
|
|
||||||
$expected = array(
|
$expected = array(
|
||||||
|
'success' => true
|
||||||
|
,'statusCode' => 200
|
||||||
// Minify_Javascript always converts to \n line endings
|
// Minify_Javascript always converts to \n line endings
|
||||||
'content' => preg_replace('/\\r\\n?/', "\n", file_get_contents($thisDir . '/minify/minified.js'))
|
,'content' => preg_replace('/\\r\\n?/', "\n", file_get_contents($thisDir . '/minify/minified.js'))
|
||||||
,'headers' => array (
|
,'headers' => array (
|
||||||
'Cache-Control' => 'public',
|
'Cache-Control' => 'public',
|
||||||
'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $tomorrow),
|
'Expires' => gmdate('D, d M Y H:i:s \G\M\T', $tomorrow),
|
||||||
@@ -23,10 +25,11 @@ $expected = array(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
$output = Minify::serve('Files', array(
|
$output = Minify::serve('Files', array(
|
||||||
$thisDir . '/minify/email.js'
|
'files' => array(
|
||||||
,$thisDir . '/minify/QueryString.js'
|
$thisDir . '/minify/email.js'
|
||||||
), array(
|
,$thisDir . '/minify/QueryString.js'
|
||||||
'quiet' => true
|
)
|
||||||
|
,'quiet' => true
|
||||||
,'setExpires' => $tomorrow
|
,'setExpires' => $tomorrow
|
||||||
,'encodeOutput' => false
|
,'encodeOutput' => false
|
||||||
));
|
));
|
||||||
@@ -44,7 +47,9 @@ if (! $passed) {
|
|||||||
unset($_SERVER['HTTP_IF_NONE_MATCH'], $_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
unset($_SERVER['HTTP_IF_NONE_MATCH'], $_SERVER['HTTP_IF_MODIFIED_SINCE']);
|
||||||
|
|
||||||
$expected = array(
|
$expected = array(
|
||||||
'content' => file_get_contents($thisDir . '/minify/minified.css')
|
'success' => true
|
||||||
|
,'statusCode' => 200
|
||||||
|
,'content' => file_get_contents($thisDir . '/minify/minified.css')
|
||||||
,'headers' => array (
|
,'headers' => array (
|
||||||
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
'Last-Modified' => gmdate('D, d M Y H:i:s \G\M\T', $lastModified),
|
||||||
'ETag' => "\"{$lastModified}pub\"",
|
'ETag' => "\"{$lastModified}pub\"",
|
||||||
@@ -53,13 +58,14 @@ $expected = array(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
$output = Minify::serve('Files', array(
|
$output = Minify::serve('Files', array(
|
||||||
$thisDir . '/css/styles.css'
|
'files' => array(
|
||||||
,$thisDir . '/css/subsilver.css'
|
$thisDir . '/css/styles.css'
|
||||||
), array(
|
,$thisDir . '/css/subsilver.css'
|
||||||
'quiet' => true
|
)
|
||||||
|
,'quiet' => true
|
||||||
,'lastModifiedTime' => $lastModified
|
,'lastModifiedTime' => $lastModified
|
||||||
,'encodeOutput' => false
|
,'encodeOutput' => false
|
||||||
));
|
));
|
||||||
$passed = assertTrue($expected === $output, 'Minify - CSS and Etag/Last-Modified');
|
$passed = assertTrue($expected === $output, 'Minify - CSS and Etag/Last-Modified');
|
||||||
echo "\nOutput: " .var_export($output, 1). "\n\n";
|
echo "\nOutput: " .var_export($output, 1). "\n\n";
|
||||||
if (! $passed) {
|
if (! $passed) {
|
||||||
@@ -74,15 +80,16 @@ $_SERVER['HTTP_IF_NONE_MATCH'] = "\"{$lastModified}pub\"";
|
|||||||
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = gmdate('D, d M Y H:i:s \G\M\T', $lastModified);
|
$_SERVER['HTTP_IF_MODIFIED_SINCE'] = gmdate('D, d M Y H:i:s \G\M\T', $lastModified);
|
||||||
|
|
||||||
$expected = array (
|
$expected = array (
|
||||||
'content' => '',
|
'success' => true
|
||||||
'headers' => array (
|
,'statusCode' => 304
|
||||||
'_responseCode' => 'HTTP/1.0 304 Not Modified',
|
,'content' => '',
|
||||||
),
|
'headers' => array()
|
||||||
);
|
);
|
||||||
$output = Minify::serve('Files', array(
|
$output = Minify::serve('Files', array(
|
||||||
$thisDir . '/css/styles.css'
|
'files' => array(
|
||||||
), array(
|
$thisDir . '/css/styles.css'
|
||||||
'quiet' => true
|
)
|
||||||
|
,'quiet' => true
|
||||||
,'lastModifiedTime' => $lastModified
|
,'lastModifiedTime' => $lastModified
|
||||||
,'encodeOutput' => false
|
,'encodeOutput' => false
|
||||||
));
|
));
|
||||||
|
Reference in New Issue
Block a user