Build Status

Cabinet is a PHP 5.3+ library providing a simple file storage layer.

It provides a unified API for storing and retrieving files as well as getting basic informations like size and content type of a file.

This is useful if

  • you want to write reusable components with a configurable file storage backend
  • you want to ensure scalability for your file storage (You can for example start storing your files on your servers filesystem and switch later to Amazon S3)

Cabinet offers adapters for PHP streams and Amazon S3 out of the box. But you can easily write your own adapters by implementing DotsUnited\Cabinet\Adapter\AdapterInterface.

Installation

Cabinet can be installed using the Composer tool. You can either add dotsunited/cabinet to the dependencies in your composer.json, or if you want to install Cabinet as standalone, go to the main directory and run:

$ wget http://getcomposer.org/composer.phar
$ php composer.phar install

You can then use the composer-generated autoloader to access the Cabinet classes:

<?php
require 'vendor/autoload.php';
?>

Usage

Instances of Cabinet adapters can be either created directly or using the static DotsUnited\Cabinet\Cabinet::factory() method.

Using a Cabinet Adapter constructor

You can create an instance of an adapter using its constructor. An adapter constructor takes one argument, which is an array of configuration parameters.

<?php
$adapter = new \DotsUnited\Cabinet\Adapter\StreamAdapter(array(
    'base_path' => '/my/base/path',
    'base_uri'  => 'http://static.example.com'
));
?>

Using the Cabinet factory

As an alternative to using an adapter constructor directly, you can create an instance of an adapter using the static method DotsUnited\Cabinet\Cabinet::factory().

The first argument is a string that names the adapter class (for example '\DotsUnited\Cabinet\Adapter\StreamAdapter'). The second argument is the same array of parameters you would have given to the adapter constructor.

<?php
$adapter = \DotsUnited\Cabinet\Cabinet::factory('\DotsUnited\Cabinet\Adapter\StreamAdapter', array(
    'base_path' => '/my/base/path',
    'base_uri'  => 'http://static.example.com'
));
?>

Alternatively, the first argument can be an associative array. The adapter class is then read from the 'adapter' key. Optionally, it can contain a 'config' key holding the configuration parameters. In this case, the second argument will be ignored.

<?php
$adapter = \DotsUnited\Cabinet\Cabinet::factory(array(
    'adapter' => '\DotsUnited\Cabinet\Adapter\StreamAdapter',
    'config' => array(
        'base_path' => '/my/base/path',
        'base_uri'  => 'http://static.example.com'
    )
));
?>

Managing files

Once you created the adapter, you can store, retrieve and get informations about files with the following methods:

Import a external local file:

<?php
$adapter->import($external, $file);
?>

Write data to a file:

<?php
$adapter->write($file, $data);
?>

Read data from a file:

<?php
$adapter->read($file);
?>

Get a read-only stream resource for a file:

<?php
$adapter->stream($file);
?>

Copy a file internally:

<?php
$adapter->copy($src, $dest);
?>

Rename a file internally:

<?php
$adapter->rename($src, $dest);
?>

Delete a file:

<?php
$adapter->unlink($file);
?>

Check whether a file exists:

<?php
$adapter->exists($file);
?>

Get a files size:

<?php
$adapter->size($file);
?>

Get a files MIME content type:

<?php
$adapter->type($file);
?>

Get the web-accessible uri for the given file:

<?php
$adapter->uri($file);
?>

Adapters

Cabinet offers two adapters:

  • DotsUnited\Cabinet\Adapter\StreamAdapter for PHP streams
  • DotsUnited\Cabinet\Adapter\AmazonS3Adapter for Amazon S3

Each adapter accepts its own set of configuration parameters which can be passed as an associative array to the constructor.

DotsUnited\Cabinet\Adapter\StreamAdapter

Configuration parameters for DotsUnited\Cabinet\Adapter\StreamAdapter:

  • base_path: Path where to store the files.
  • base_uri: Uri where your files are publicly accessible.
  • directory_umask: The umask for directories created by the adapter (default is 0700).
  • file_umask: The umask for files created by the adapter (default is 0600).
  • stream_context: The stream context to use with filesystem functions. This can be either a resource created with stream_context_create() or an array with context options.
  • mime_type_detector: An instance of DotsUnited\Cabinet\MimeType\Detector\DetectorInterface used to detect mime content types. This is optional, default is DotsUnited\Cabinet\MimeType\Detector\Fileinfo.
  • filename_filter: An instance of DotsUnited\Cabinet\Filter\FilterInterface. Filename filters are explained in the next section.

DotsUnited\Cabinet\Adapter\AmazonS3Adapter

Configuration parameters for DotsUnited\Cabinet\Adapter\AmazonS3Adapter:

  • s3_client: A Aws\S3\S3Client instance (See the AWS SDK docs).
  • bucket: Bucket where to store the files.
  • storage_class: The storage class setting for files. Allowed values: STANDARD, REDUCED_REDUNDANCY. The default value is STANDARD.
  • acl: The ACL settings for files. Allowed values: private, public-read, public-read-write, authenticated-read, bucket-owner-read, bucket-owner-full-control. The default value is private.
  • uri_expiration_time: The expiration time for web-accessible URIs if you store private files. This can bei either a timestamp or a string parsable by strtotime().
  • throw_exceptions: A boolean indicating whether to throw exceptions (Exceptions from the Aws\S3\S3Client are catched and rethrown as \RuntimeException).
  • mime_type_detector: An instance of DotsUnited\Cabinet\MimeType\Detector\DetectorInterface used to detect mime content types. This is optional, default is DotsUnited\Cabinet\MimeType\Detector\Fileinfo.
  • filename_filter: An instance of DotsUnited\Cabinet\Filter\FilterInterface. Filename filters are explained in the next section.

Filename filters

You can manipulate the filename you pass to each method of an adapter with filters. Filters are classes which implement DotsUnited\Cabinet\Filter\FilterInterface.

You can add filters like this:

<?php
$adapter->setFilenameFilter(new MyFilenameFilter());
?>

If you need multiple filters, you can use DotsUnited\Cabinet\Filter\FilterChain like this:

<?php
$filterChain = new \DotsUnited\Cabinet\Filter\FilterChain();

$filterChain->addFilter(new MyFilenameFilter1());
$filterChain->addFilter(new MyFilenameFilter2());

$adapter->setFilenameFilter($filterChain);
?>

Examples

Cabinet provides a filter to prepend a hashed subpath to the filename and is intended to be used with the DotsUnited\Cabinet\Adapter\StreamAdapter adapter.

This spreads the files over subdirectories to ensure performance by avoiding to many files in one directory. This is done by using a configurable number of characters of the filename's MD5 as a directory name. That pretty much guarantees an even spread.

Simply register the DotsUnited\Cabinet\Filter\HashedSubpathFilter filter with the adapter:

<?php
$config = array(
    'level' => 4
);

$adapter->setFilenameFilter(new \DotsUnited\Cabinet\Filter\HashedSubpathFilter($config);
?>

License

Cabinet is released under the New BSD License.

Build Status

BundleFu is a PHP 5.3+ library which bundles multiple css/javascript files into a big package and sends it out at once.

It is highly inspired by the Ruby on Rails plugin bundle-fu.

In short, it turns this:

<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/jquery.myplugin.js"></script>
<script type="text/javascript" src="/js/app.js"></script>
<script type="text/javascript" src="/js/app.module.js"></script>
<link media="screen" type="text/css" href="/css/reset.css">
<link media="screen" type="text/css" href="/css/jquery.myplugin.css">
<link media="screen" type="text/css" href="/css/app.css">
<link media="screen" type="text/css" href="/css/app.module.css">

Into this:

<link href="/css/cache/bundle_3f84da97fc873ca8371a8203fcdd8a82.css?1234567890" rel="stylesheet" type="text/css">
<script src="/js/cache/bundle_3f84da97fc873ca8371a8203fcdd8a82.js?1234567890" type="text/javascript"></script>

Features

  • Automatically detects modifications to your css and javascript files and regenerates the bundles automatically.
  • Bundle contents can be modified by filters for css url rewriting to avoid broken images, code minification and compression etc. (A Google Closure Compiler filter using the Service API comes with the library).

Installation

BundleFu can be installed using the Composer tool. You can either add dotsunited/bundlefu to the dependencies in your composer.json, or if you want to install BundleFu as standalone, go to the main directory and run:

$ wget http://getcomposer.org/composer.phar
$ php composer.phar install

You can then use the composer-generated autoloader to access the BundleFu classes:

<?php
require 'vendor/autoload.php';
?>

Usage

Configure a Bundle instance:

<?php
$bundle = new \DotsUnited\BundleFu\Bundle();

$bundle
    // Set the document root
    ->setDocRoot('/path/to/your/document_root')

    // Set the css cache path (relative to the document root)
    ->setCssCachePath('css/cache')

    // Set the javascript cache path (relative to the document root)
    ->setJsCachePath('js/cache');
?>

Alternatively, you can pass an options array to the constructor (or use the method setOptions later):

<?php
$options = array(
    'doc_root' => '/path/to/your/document_root',
    'css_cache_path' => 'css/cache',
    'js_cache_path' => 'js/cache',
);

$bundle = new \DotsUnited\BundleFu\Bundle($options);
?>

Use the instance to bundle your files in your templates:

<?php $bundle->start(); ?>
<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/jquery.myplugin.js"></script>
<script type="text/javascript" src="/js/app.js"></script>
<script type="text/javascript" src="/js/app.module.js"></script>
<link media="screen" type="text/css" href="/css/reset.css">
<link media="screen" type="text/css" href="/css/jquery.myplugin.css">
<link media="screen" type="text/css" href="/css/app.css">
<link media="screen" type="text/css" href="/css/app.module.css">
<?php $bundle->end(); ?>

Output the bundle <script> and <link> tags wherever you want:

<?php
// Renders both <script> and <link> tags
echo $bundle->render();

// Renders the <link> tag only
echo $bundle->renderCss();

// Renders the <script> tag only
echo $bundle->renderJs();
?>

Using the Factory

You can also use a factory to create bundle instances. The advantage is, that the factory can hold global options (like bypass and doc_root) which are shared across all created bundles:

<?php
$options = array(
    'doc_root' => '/path/to/your/document_root',
    'css_cache_path' => 'css/cache',
    'js_cache_path' => 'js/cache',
);

$factory = new \DotsUnited\BundleFu\Factory($options);

// $bundle1 and $bundle2 use the same doc_root, css_cache_path and js_cache_path options
$bundle1 = $factory->createBundle();
$bundle2 = $factory->createBundle();
?>

You can pass specific options to the createBundle method (global factory options will be overwritten):

<?php
$bundle1 = $factory->createBundle(array('name' => 'bundle1', 'doc_root' => '/path/to/another/document_root'));
$bundle2 = $factory->createBundle(array('name' => 'bundle2'));
?>

The factory also lets you define name aliases for filters. You can then define the string alias for the css_filter and js_filter options instead of passing a filter instance:

<?php
$filters = array(
    'js_closure_compiler' => new \DotsUnited\BundleFu\Filter\ClosureCompilerServiceFilter()
);

$factory = new \DotsUnited\BundleFu\Factory(array(), $filters);

$bundle1 = $factory->createBundle(array('js_filter' => 'js_closure_compiler'));
?>

Filters

You can manipulate the loaded css/javascript files and the bundled css/javascript code with filters. Filters are classes which implement DotsUnited\BundleFu\Filter\FilterInterface.

You can add filters like this:

<?php
$bundle->setCssFilter(new MyCssFilter());
$bundle->setJsFilter(my MyJsFilter());
?>

If you need multiple filters, you can use DotsUnited\BundleFu\Filter\FilterChain like this:

<?php
$filterChain = new \DotsUnited\BundleFu\Filter\FilterChain();

$filterChain->addFilter(new MyCssFilter1());
$filterChain->addFilter(new MyCssFilter2());

$bundle->setCssFilter($filterChain);
?>

Default filters

BundleFu provides the following filters out of the box.

CssUrlRewriteFilter

The DotsUnited\BundleFu\Filter\CssUrlRewriteFilter rewrites relative URLs in your CSS file to avoid broken image references:

<?php
$bundle->setCssFilter(new \DotsUnited\BundleFu\Filter\CssUrlRewriteFilter());
?>

ClosureCompilerServiceFilter

This filter compiles javascript code with the Google Closure Compiler using the Service API.

Simply add the DotsUnited\BundleFu\Filter\ClosureCompilerServiceFilter filter and your javascript bundles will be automatically compiled:

<?php
$bundle->setJsFilter(new \DotsUnited\BundleFu\Filter\ClosureCompilerServiceFilter());
?>

CallbackFilter

The DotsUnited\BundleFu\Filter\CallbackFilter can filter by using any PHP callback. If you want to compress your CSS using YUI Compressor you can either write a custom filter or use the following code leveraging the Callback filter:

<?php
$filter = new \DotsUnited\BundleFu\Filter\CallbackFilter(function($content) {
    $descriptorspec = array(
         0 => array('pipe', 'r'),  // STDIN
         1 => array('pipe', 'w'),  // STDOUT
         2 => array('pipe', 'a')   // STDERR
    );

    $handle = proc_open('java -jar /path/to/yuicompressor.jar --type css' , $descriptorspec, $pipes);

    if (is_resource($handle)) {
        fwrite($pipes[0], $content);
        fclose($pipes[0]);

        $compressed = stream_get_contents($pipes[1]);
        fclose($pipes[1]);

        proc_close($handle);

        if ($compressed) {
            return $compressed;
        }
    }

    return $content;
});

$bundle->setCssFilter($filter);
?>

Notes

  • All content inside of $bundle->start() and $bundle->end() will be lost. Be sure to only put css/javascript includes inside of the block.
  • Scripts/stylesheets are detected by parsing the output and looking for include files. HTML comments are ignored, so if you comment out a script like this:

    <!-- <script src="/js/script.js" type="text/javascript"></script> -->
    

    the comment will be ignored and the file will be bundled anyways. Be sure to comment out via PHP:

    <?php /* <script src="/js/script.js" type="text/javascript"></script> */ ?>
    
  • External dependencies via querystring loading will not work:

    <script src="/js/scriptaculous.js?load=effects,controls" type="text/javascript"></script>
    

    Instead, you'll need to include each javascript file as normal.

License

BundleFu is released under the MIT License.

Build Status

The BundleFuTwigExtension integrates BundleFu into the Twig template engine.

Installation

BundleFuTwigExtension can be installed using the Composer tool. You can either add dotsunited/bundlefu-twig-extension to the dependencies in your composer.json, or if you want to install BundleFuTwigExtension as standalone, go to the main directory and run:

$ wget http://getcomposer.org/composer.phar 
$ php composer.phar install

You can then use the composer-generated autoloader to access the BundleFuTwigExtension classes:

<?php
require 'vendor/autoload.php';
?>

Usage

Register the BundleFuExtension to your Twig environment:

<?php
$factory = new \DotsUnited\BundleFu\Factory();
$extension = \DotsUnited\BundleFu\Twig\BundleFuExtension($factory);

$twig = new \Twig_Environment($loader);
$twig->addExtension($extension);
?>

The extension uses the factory to create bundle instances. See the BundleFu documentation about how to configure the factory.

The extension exposes a new bundle tag with the following syntax:

{% bundle name='test_bundle'
          doc_root = '/my/docroot'
          bypass=false
          render_as_xhtml=true
          css_filter='css_filter'
          js_filter='js_filter'
          css_cache_path='cache'
          js_cache_path='cache'
          css_cache_url='/cache'
          js_cache_url='/cache'
%}
<link href="/css_1.css" media="screen" rel="stylesheet" type="text/css"/>
<script src="/js_1.js" type="text/javascript"></script>
{% endbundle %}

License

BundleFuTwigExtension is released under the MIT License.

Build Status

The BundleFuSilexServiceProvider integrates BundleFu into the Silex micro-framework.

Installation

BundleFuSilexServiceProvider can be installed using the Composer tool. You can either add dotsunited/bundlefu-silex-service-provider to the dependencies in your composer.json, or if you want to install BundleFuSilexServiceProvider as standalone, go to the main directory and run:

$ wget http://getcomposer.org/composer.phar 
$ php composer.phar install

You can then use the composer-generated autoloader to access the BundleFuSilexServiceProvider classes:

<?php
require 'vendor/autoload.php';
?>

Usage

Register the BundleFuServiceProvider to your Silex application:

<?php
$app = new \Silex\Application();

$app->register(new DotsUnited\BundleFu\Silex\BundleFuServiceProvider());
?>

You can now use the bundlefu.factory service to create bundles in your application:

<?php
$bundle = $app['bundlefu.factory']->createBundle();
?>

To configure the factory, you can pass the bundlefu.options and bundlefu.filters parameters:

<?php
$app->register(new DotsUnited\BundleFu\Silex\BundleFuServiceProvider(), array(
    'bundlefu.options' => array(
        'bypass' => true
    ),
    'bundlefu.filters' => array(
        'js_closure_compiler' => new \DotsUnited\BundleFu\Filter\ClosureCompilerService()
    )
));
?>

Twig

The service provider automatically registers the BundleFu twig extension if Twig is available (ensure that you register the BundleFuServiceProvider after the TwigServiceProvider in your application).

If do not want the extension to be registered, set bundlefu.twig.extension with the value false as a parameter:

<?php
$app->register(new DotsUnited\BundleFu\Silex\BundleFuServiceProvider(), array(
    'bundlefu.twig.extension' => false
));
?>

License

BundleFuSilexServiceProvider is released under the MIT License.

A jQuery plugin to display a lavalamp style navigation.

Basic usage

To use the lavalamp plugin you have to include the latest jQuery build and the plugin source in your HTML document:

<script type="text/javascript" 
        src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script type="text/javascript" 
        src="/path/to/jquery.twitterTimeline.js"></script>

The second step is to add this simple markup:

<ul class="lavalamp">
    <li><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Blog</a></li>
    <li><a href="#">Contact</a></li>
</ul>

Finally you have to initialize the plugin with your desired parameters:

<script type="text/javascript">
    $(function() {
        $('.lavalamp').lavalamp({
            // Your configuration goes here
        });
    });
</script>

Checkout the examples for sample implementations.

License

Copyright (c) 2012 Dots United GmbH. Licensed under the MIT license.

twitterTimeline is a jQuery plugin to display the recent tweets of a twitter user that comes with a lot of configuration options. Instead of the twitter search API this plugin uses the GET statuses/user_timeline from the API as the search does not return tweets older than a week.

If localStorage is supported by the client, the fetched tweets will be cached within the localStorage to ensure, that tweets are displayed as soon as possible.

Basic usage

To use twitterTimeline you have to include the latest jQuery build and the twitterTimeline source inside the head tag of your HTML document:

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="/path/to/jquery.twitterTimeline.js"></script>

The second step is to add a container element to your HTML where you want the tweets to appear, e.g. div:

<div id="tweetContainer"></div>

Finally you have to initialize the plugin with your desired parameters:

<script type="text/javascript">
    $(function() {
        $('#tweetContainer').twitterTimeline({
            //your configuration goes here
        });
    });
</script>

Configuration options

You can pass a set of these options to the initialize function to set a custom behaviour for the plugin.

Property (Type) Default Description
ajax (object)
{
    url: 'http://api.twitter.com/1/statuses/user_timeline.json',
    data: {
        screen_name     : 'twitter',
        since_id        : null,
        max_id          : null,
        page            : 1,
        trim_user       : true,
        include_rts     : false,
        exclude_replies : true
    },
    dataType: 'jsonp'
}
Options passed to $.ajax(). For the data part, you can find a complete list of valid parameters here: https://dev.twitter.com/docs/api/1/get/statuses/user_timeline
count (integer) 5 Specifies the number of tweets that are displayed by the plugin.
refresh (boolean|integer) false If set to a numeric value, the timeline will be refreshed every x milliseconds. New tweets will be prepended to the list, and old tweets will be deleted to maintain the maximum number specified with the count option.
tweetTemplate (object)
function(item) {
    return '

' + TwitterTimeline.parseTweet(item.text) + '

'; }
Function to render each tweet. The tweet data is passed as an argument, and the plugin is accessible via the this variable.
animateAdd (object)
function(el) { return el; }
Animate method to add elements. This method has to return the new element. If not, the element will not be added to the DOM.
animateRemove (object)
function(el) { el.remove(); }
Animate method to remove elements. This method has to remove the element from the DOM!

Methods

The tweetTimeline plugin provieds the following public methods:

Method name Parameter Description
fetch(options) (optional) ajax options Fetch new Tweets from the API and add them to the containert. The optional ajax parameter extends the plugins ajax options.
update(items) array items Manually add tweets to the container.

If you want to manually refresh the tweet list for example, you can use the following line to fetch new tweets:

$('#tweetContainer').twitterTimeline('fetch');

Example settings

The following example is used for the tweet box you can find on our website.

<script type="text/javascript">
    $(function() {
        $('#tweetContainer').twitterTimeline({
            ajax: {
                data: {
                    screen_name: 'dotsunited',
                    count: 1
                }
            },
            count: 1,
            tweetTemplate: function(item) {
                var dateRegEx = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) \+([0-9]{4}) ([0-9]{4})$/;
                var date = dateRegEx.exec(item.created_at);
                var tweet = '<p><div class="date">' + date[3] + ' '  + date[2] + ' '  + date[8] + '</div><p>' + $.twitterTimeline.parseTweet() + '</p></p>';
                return tweet;
            },
            animateAdd: function(el) {
                return el.hide().delay(300).slideDown(500);
            },
            animateRemove: function(el) {
                el.slideUp(300, function() {
                    el.remove();
                });
            }
        });
    });
</script>

License

Copyright (c) 2012 Dots United GmbH. Licensed under the MIT license.

Dots United - Agentur für neue Medien