Skip to content

Instantly share code, notes, and snippets.

@junaidpv
Created August 27, 2011 19:58
Show Gist options
  • Save junaidpv/1175799 to your computer and use it in GitHub Desktop.
Save junaidpv/1175799 to your computer and use it in GitHub Desktop.
Class that helps to load resources with dependencies easily, such as JavaScripts, CSSs
<?php
/**
* @author Junaid P V (http://junaidpv.in)
* @license GPLv3
*/
/**
* Class that helps to load resource easily, such as JavaScripts, CSSs
*
* @version 1.0
*/
class Resource_loader {
private $libraryResources = array();
private $resources = array();
/**
* Add resources that reside on disk.
*
* @param array $resources
*/
public function add($resources) {
foreach ($resources as $name => $resource) {
// It is always resource links added with this method
$tmpArray = array('type' => 'link');
// Add scripts if given
if (isset($resource['scripts'])) {
$tmpArray['scripts'] = $this->alwaysArray($resource['scripts']);
}
// Add styles if given
if (isset($resource['styles'])) {
$tmpArray['styles'] = $this->alwaysArray($resource['styles']);
}
if (isset($resource['dependencies'])) {
$tmpArray['dependencies'] = $this->alwaysArray(
$resource['dependencies']
);
}
$this->resources[$name] = $tmpArray;
}
}
/**
* Add library resources.
* Resource added by this method will be loaded
* when there is at leat one dependance for it
*
* @param array $resources
*/
public function addLibrary($resources) {
foreach ($resources as $name => $resource) {
// It is always resource links added with this method
$tmpArray = array('type' => 'link');
// Add scripts if given
if (isset($resource['scripts'])) {
$tmpArray['scripts'] = $this->alwaysArray($resource['scripts']);
}
// Add styles if given
if (isset($resource['styles'])) {
$tmpArray['styles'] = $this->alwaysArray($resource['styles']);
}
if (isset($resource['dependencies'])) {
$tmpArray['dependencies'] = $this->alwaysArray(
$resource['dependencies']
);
}
$this->libraryResources[$name] = $tmpArray;
}
}
/**
* Add resouces (JS and CSS) as raw string.
*
* @param array $resources
*/
public function addRaw($resources) {
foreach ($resources as $name => $resource) {
// It is always raw resources added by this method
$tmpArray = array('type' => 'raw');
if (isset($resource['scripts'])) {
$tmpArray['scripts'] = $this->alwaysArray($resource['scripts']);
}
if (isset($resource['styles'])) {
$tmpArray['styles'] = $this->alwaysArray($resource['styles']);
}
if (isset($resource['dependencies'])) {
$tmpArray['dependencies'] = $this->alwaysArray(
$resource['dependencies']
);
}
$this->resources[$name] = $tmpArray;
}
}
/**
* Add raw library resources.
* Resource added by this method will be loaded
* when there is at leat one dependance for it
*
* @param array $resources
*/
public function addRawLibrary($resources) {
foreach ($resources as $name => $resource) {
// It is always raw resources added by this method
$tmpArray = array('type' => 'raw');
if (isset($resource['scripts'])) {
$tmpArray['scripts'] = $this->alwaysArray($resource['scripts']);
}
if (isset($resource['styles'])) {
$tmpArray['styles'] = $this->alwaysArray($resource['styles']);
}
if (isset($resource['dependencies'])) {
$tmpArray['dependencies'] =
$this->alwaysArray($resource['dependencies']);
}
$this->libraryResources[$name] = $tmpArray;
}
}
/**
* Returns HTML snippet that can be inserted on web pages
* to be send to client.
* Caution: This funtion must not be called more than once.
*
* @return string
*/
public function render() {
// Get all resources in correct order.
$ordered = $this->getOrdered();
// Start with a blank html snippet.
$html = '';
foreach ($ordered as $res) {
if ($res['type'] == 'raw') {
// It is a raw resouce, we need to add the source code.
if (isset($res['scripts'])) {
$html .= "\n".'<script type="text/javascript">';
foreach ($res['scripts'] as $script) {
$html .= "\n" . $script;
}
$html .= '</script>';
}
if (isset($res['styles'])) {
$html .= "\n".'<style type="text/css">';
foreach ($res['styles'] as $style) {
$html .= "\n" . $style;
}
$html .= '</style>';
}
} elseif ($res['type'] == 'link') {
if (isset($res['scripts'])) {
foreach ($res['scripts'] as $script) {
$html .= "\n" . '<script type="text/javascript" src="'
. $script . '"></script>';
}
}
if (isset($res['styles'])) {
foreach ($res['styles'] as $style) {
$html .= "\n"
. '<link rel="stylesheet" type="text/css" href="'
. $style . '" />';
}
}
}
}
return $html;
}
/**
* Get resource array having all resources in correct order.
*/
private function getOrdered() {
// Get the unordered resource array.
$source = $this->resources;
// Create a blank ordered array to start with.
$ordered = array();
// Itereate over all items in unordered resource array to put every
// item in correct order.
while (true) {
if (count($source) == 0) {
// No more item in $source, let's stop it
break;
}
// Get frist item in $source
$pair = $this->array_kshift($source);
// and put that item in correct order at $ordered.
// putItemAtCorrectPosition will manage dependent items.
$this->putItemAtCorrectPosition($pair[0], $pair[1], $ordered);
}
return $ordered;
}
/**
* Put the specified item at correct position in $ordered.
* If depended item(s) are in $source they will be put before the item.
*
* @param array $item
* @param array $ordered
* @param array $source
*/
private function putItemAtCorrectPosition($resourceName, $resource, &$ordered) {
// Let's check about dependecies before putting item in $ordered.
if (isset($resource['dependencies'])) {
// Check whether any depended resource in $source
// since all depended items should be in $ordered before
// the current item put in.
foreach ($resource['dependencies'] as $subject) {
if (array_key_exists($subject, $ordered)) {
// Depended is already included
continue;
}
else {
$source = null;
if (array_key_exists($subject, $this->libraryResources)) {
// Dependency is on library
$source = $this->libraryResources;
}
elseif (array_key_exists($subject, $this->resources)) {
// Dependency is on normal resource
$source = $this->resources;
}
else {
// Depended resource is not available at all.
// It is mistake and let us throw and
// exception informing about it.
throw new Exception(
"Depended item '$subject' could not be found"
);
}
// Take a copy of it from source
$depended = $source[$subject];
// Remove it from source
unset($source[$subject]);
// And put the depended item in $ordered
// at correct position
$this->putItemAtCorrectPosition(
$subject,
$depended,
$ordered
);
}
}
}
// We have already put every depended items in correct position,
// so put current item at the end of $ordered.
$ordered[$resourceName] = $resource;
}
private function alwaysArray($value) {
return (is_array($value) ? $value : array($value));
}
/**
* Array shift with key
*
* @param array $arr
* @return array
*/
private function array_kshift(&$arr) {
list($k) = array_keys($arr);
$r = array($k, $arr[$k]);
unset($arr[$k]);
return $r;
}
/**
* Sometimes some libraries needs to be loaded even some other script has
* no dependency on them, like posabsolute jquery validation.
*
* @param string $name
*/
public function alwaysLoadLibrary($name) {
if (!array_key_exists($name, $this->resources)) {
// No need to add if the library is already as normal resource
if(array_key_exists($name, $this->libraryResources)) {
// Move resource from library to normal
// so it will be loaded always
$this->resources[$name] = $this->libraryResources[$name];
// then remove from library
unset ($this->libraryResources[$name]);
}
else {
// Resource is not on both library and normal resources
throw new Exception(
"Library '$name' not yet added!"
);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment