Cartalyst LLC.
Data-grid by Cartalyst
4
115
0
14
0

This package requires a valid subscription. Subscribe for access.

Introduction

Cartalyst's Data Grid package makes it easy for you to filter data sources. Data Grid shifts the focus from pagination to data filtration. Pass any data source through a data handler and the package will take care of the rest so you can use the filtered result set to create your applications.

We emphasize filtering first, sorting second, and lastly, paginating those results.

Features

  • Easily filter large data sources
  • Create JSON responses to use in your API
  • Build paginated result sets

Installation

The best and easiest way to install the Data Grid package is with Composer.

Preparation

Open your composer.json file and add the following to the require array:

"cartalyst/data-grid": "1.0.*"

Add the following lines after the require array on your composer.json file:

"repositories": [
    {
        "type": "composer",
        "url": "https://packages.cartalyst.com"
    }
]

Note: Make sure your composer.json file is in a valid JSON format after applying the required changes.
You can use the JSONLint online tool to validate your composer.json file.

Install the dependencies

Run Composer to install or update the new requirement.

php composer install

or

php composer update

Now you are able to require the vendor/autoload.php file to autoload the package.

Integration

Laravel 4

The Data Grid package has optional support for Laravel 4 and it comes bundled with a Service Provider and a Facade for easy integration.

After installing the package, open your Laravel config file located at app/config/app.php and add the following lines.

In the $providers array add the following service provider for this package.

'Cartalyst\DataGrid\DataGridServiceProvider',

In the $aliases array add the following facade for this package.

'DataGrid' => 'Cartalyst\DataGrid\Facades\DataGrid',

Configuration

After installing, you can publish the package configuration file into your application by running the following command on your terminal:

php artisan config:publish cartalyst/data-grid

This will publish the config file to app/config/packages/cartalyst/data-grid/config.php where you can modify the package configuration.

Collection Handlers

By default, the package will register two built-in data handlers with Laravel, the Cartalyst\DataGrid\DataHandlers\CollectionHandler and the Cartalyst\DataGrid\DataHandlers\DatabaseHandler.

With these two data handlers you can use the follow types of data.

CollectionHandler

  • Illuminate Collection objects
  • Arrays with data objects which could be:
    • An array
    • An object which is an instance of or extends the stdClass object
    • An object which implements the Illuminate\Support\ArrayableInterface interface

DatabaseHandler

  • Queries
  • Query results
  • Eloquent Models & Relationships

Note: You can register more data handlers by publishing and editing the config file. Read more about publishing the config file here.

Creating a Data Grid object

Creating a Data Grid object in Laravel 4 can be done in the same way as you do in native PHP except that you make use of the DataGrid alias.

$dataGrid = DataGrid::make($data, $columns);

Working With The Query Builder

Thanks to the default built-in database data handler, Cartalyst's Data Grid package can work with instances of many different database objects. One of them is Illuminate\Database\Query\Builder. You can pass along an instance of this class as a data source for your Data Grid and the data handler will extract the data from the query and prepares it as a result set.

For instance, if you'd like to use the data from the users table as a data source for your Data Grid.

$query = DB::table('users')->where('age', '>', 20);

$dataGrid = DataGrid::make($query, array(
    'name',
    'email',
    'address',
));

This will create a Data Grid object with all of the users and the selected columns in the result set.

You can also pass along a query result set.

$users = DB::table('users')->get();

$dataGrid = DataGrid::make($users, array(
    'name',
    'email',
    'address',
));

Working With Eloquent

The built-in database data handler also enables you to pass along Eloquent objects as a data source.

Eloquent Models

You can pass along an Eloquent model as a data source.

$user = new User;

$dataGrid = DataGrid::make($user, array(
    'name',
    'email',
    'address',
));

This would retrieve all of the users and create a result set with them in the DataGrid object.

Eloquent Query Builder

You can also pass along an instance of the Eloquent query builder:

$query = with(new User)->newQuery();

$dataGrid = DataGrid::make($query, array(
    'name',
    'email',
    'address',
));
Eloquent Results

Besides models and the query builder, the DatabaseHandler data handler also accepts Eloquent results.

$users = User::where('age', '>', 20)->get();

$dataGrid = DataGrid::make($users, array(
    'name',
    'email',
    'address',
));
Eloquent Relationships

Eloquent relationships are also supported. Don't forget to call the relationship method instead of the property.

$roles = User::find(1)->roles();

$dataGrid = DataGrid::make($roles, array(
    'title',
    'level',
    'created_at',
));

Joining Tables

Because we can pass along database query objects, we can also join tables together and get a combined result set from multiple tables. If you have duplicate column names after joining the tables you can create aliases for them in the columns array.

$query = DB::query('cars')
    ->join('manufacturers', 'cars.manufacturer_id', '=', 'manufacturers.id')
    ->select('cars.*', 'manufacturers.name');

$dataGrid = DataGrid::make($query, array(
    'manufacturers.name' => 'manufacturer_name',
    'name' => 'car_name',
    'year',
    'price',
));

Using Data Grid With Routes

Because the Data Grid object will render the result set as a JSON response, you can use it to make API routes in your application.

Route::get('users', function()
{
    $query = DB::table('users');

    return DataGrid::make($query, array(
        'name',
        'email',
        'address',
    ));
});

You can see at how a Data Grid result set looks like here.

Using Data Grid In Views

Besides outputting the Data Grid object as JSON responses to work with APIs, you can also use them to build tabular data views for your application. Let's look at an extensive example.

First we'll register the route.

Route::get('posts', function()
{
    // Get all the posts from the database.
    $posts = Post::all();

    // Create a data grid object to list all posts
    // with their id, title and creation date.
    $dataGrid = DataGrid::make($posts, array('id', 'title', 'created_at'));

    // Get the data handler.
    $dataHandler = $dataGrid->getDataHandler();

    // If there are results, let's build the tabular data view.
    if ($results = $dataHandler->getResults())
    {
        // Get the amount of pages.
        $pagesCount = $dataHandler->getPagesCount();

        // Calculate the per page.
        $perPage = floor(count($posts) / $pagesCount);

        // Manually create pagination.
        $paginator = Paginator::make($results, count($posts), $perPage);

        // Build and output the view.
        return View::make('posts', compact('results', 'paginator'));
    }

    return 'No posts found.';
});

Now let's create the posts view.

<table>
    <thead>
        <tr>
            <th>#</th>
            <th>Title</th>
            <th>Created at</th>
        </tr>
    </thead>
    <tbody>
        @foreach ($results as $result)
        <tr>
            @foreach ($result as $value)
            <td>{{ $value }}</td>
            @endforeach
        </tr>
        @endforeach
    </tbody>
</table>

{{ $paginator->links() }}

This will build you a nice overview table with your tabular data. Notice that we've manually created an instance of the Paginator class with the data from our data handler. If you change the pages on the paginator, the table should page through the list of records automatically because your request provider will catch the page request parameter.

Using With The Javascript Plugin

Before you can use the Javascript plugin you have to publish the package's assets first.

php artisan asset:publish cartalyst/data-grid

This will publish Data Grid's assets into public/packages/cartalyst/data-grid so you can link to them in your views.

You can read more about installing and using the Javascript plugin here.

Native

Coming Soon.

Usage

Cartalyst's Data Grid package provides a couple of ways to interact with. The most basic way is to instantiate a new environment with the Cartalyst\DataGrid\Environment class and use Cartalyst's default built-in Cartalyst\DataGrid\DataHandlers\CollectionHandler for data handling.

After creating a Data Grid object you can use the registered data handler to interact with your result set.

Loading An Environment

Before you can use the Data Grid package you need to load a new environment first. This environment will determine which request provider it needs to instantiate for you to interact with. Natively it will load an instance of Cartalyst\DataGrid\RequestProviders\NativeProvider.

$environment = new Cartalyst\DataGrid\Environment;

From here on out you can start working with the Data Grid package.

You can register your custom request provider by sending it along when instantiating a new environment.

$provider = new CustomProvider;

$environment = new Cartalyst\DataGrid\Environment($provider);

Note: Make sure that your request provider implements Cartalyst\DataGrid\RequestProviders\ProviderInterface.

Registering Data Handlers

Data handlers are essentially drivers which manipulate a data source and return the required data. You can register data handlers with your environment by using the addDataHandlerMapping function.

$environment->addDataHandlerMapping('FooDataHandler', function($data)
{
    return ($data instanceof FooData);
});

Now whenever you pass along data which is an instance of FooData when instantiating the Data Grid, the package will know to use the FooDataHandler to handle the data.

Alternatively you can register your data handlers when loading an environment.

$handlers => array(

    'FooDataHandler' => function($data)
    {
        return ($data instanceof FooData);
    },

    'BarDataHandler' => function($data)
    {
        return ($data instanceof BarData);
    },

);

$environment = new Cartalyst\DataGrid\Environment(null, $handlers);

Default Data Handlers

Cartalyst's Data Grid package provides two data handlers by default. One of them is the Cartalyst\DataGrid\DataHandlers\CollectionHandler which provides support for arrays and Illuminate\Support\Collection objects.

If you'd like to use the CollectionHandler data handler you need to register it to your Data Grid environment.

$environment->addDataHandlerMapping('Cartalyst\DataGrid\DataHandlers\CollectionHandler', function($data)
{
    return(
        $data instanceof Illuminate\Support\Collection or
        is_array($data)
    );
});

Now whenever you pass along an array of data or an Illuminate\Support\Collection object when instantiating the Data Grid, the package will know to use the CollectionHandler to handle the data.

Note: When we're using examples in the documentation for Data Grid, we're going to assume you have registered the CollectionHandler data handler.

Creating Custom Data Handlers

In addition to register the default data handlers provided by the package, you can create your own custom data handlers as well. All data handlers need to extend the abstract Cartalyst\DataGrid\DataHandlers\BaseHandler class.

use Cartalyst\DataGrid\DataHandlers\BaseHandler;
use Cartalyst\DataGrid\DataHandlers\HandlerInterface;

class CustomHandler extends BaseHandler implements HandlerInterface {

}

Specific handlers can be created to handle specific sets of data like framework specific result sets or a certain service's API result responses.

Creating a Data-Grid Object

Creating a Data Grid object can be done by calling the make function on the Data Grid environment.

$dataGrid = $environment->make($data, $columns);

Calling the make function will send back an instance of Cartalyst\DataGrid\DataGrid. The $data variable must contain all of the data you want to filter. This can be any sort of data type as long as it can be handled by your data handlers. The $columns variable must contain an array of all the columns for each data object to include in the result set.

The data provided can hold data objects of the following types:

  • An array
  • An object which is an instance of or extends the stdClass object
  • An object which implements the Illuminate\Support\ArrayableInterface interface

A basic example of creating a Data Grid object could be:

$object = new StdClass;
$object->title = 'foo';
$object->age = 20;

$data = array(
    array(
        'title' => 'bar',
        'age'   => 34,
    ),
    $object,
);

$dataGrid = $environment->make($data, array(
    'title',
    'age',
));

Because we send in the data wrapped in an array, the Data Grid object will handle the data with the registered CollectionHandler Data Handler.

Note: If a data object in the $data set doesn't has a column set in the $columns array, it will return null in the result set for that column.

You can also rename columns by defining them as a key/value pair with the originial name being the key and the new name being the value.

$dataGrid = $environment->make($data, array(
    'title' => 'new_title_column_name',
    'age'   => 'new_age_column_name',
));

Catching Unsupported Data Types

When the Data Grid package can't find a Data Handler for the provided data, it will throw a RuntimeException[^1]. You can catch it by doing the following:

try
{
    $dataGrid = $environment->make($data, $columns);
}
catch (\RuntimeException $exception)
{
    echo $exception->getMessage();
}

[^1]: PHP manual on the RuntimeException class

Data Handler

Introduction

The data handler is the class that handles and filters the data you passed along. In the examples below we'll go over the basic functionality for a data handler.

Accessing the registered data handler can be done by calling the getDataHandler method on the Data Grid object.

$handler = $dataGrid->getDataHandler();

Retrieving Results

You can retrieve the result set by calling the getResults method on the data handler.

$results = $handler->getResults();

This will return an array with the result set after all the request parameters have been applied.

Other Methods

Get the total amount of results.

$totalCount = $handler->getTotalCount();

Get the total amount of filtered results.

$filteredCount = $handler->getFilteredCount();

Get the current page.

$page = $handler->getPage();

Get the number of pages.

$pagesCount = $handler->getPagesCount();

Get the previous page.

$previousPage = $handler->getPreviousPage();

Get the next page.

$nextPage = $handler->getNextPage();

Get the number of results per page.

$perPage = $handler->getPerPage();

Javascript Plugin

Introduction

One of our goals with Data Grid was to leave the front end HTML up to you, and avoid what most plugins do by keeping you within a container. We built a Javascript plugin (data-grid.js) that works together with the Tempo rendering engine to allow you to easily built flexible data grids.

You can see a working demo of the plugin at the demo page.

Requirements

Using data-grid.js requires the following:

Installing

Add jQuery, Tempo and data-grid.js to the <head> section of your page.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="//raw.github.com/twigkit/tempo/master/tempo.min.js"></script>
<script src="/vendor/cartalyst{url}/src/public/js/data-grid.js"></script>

The HTML

Data Grid requires three elements for instantiation: a results container, pagination container and finally an applied filters container. Each of these containers will contain either one or many Tempo templates.

Results Container

<table class="results" data-grid="main" data-source="http://example.com/api/v1/foo">
    <thead>
        <tr>
            <td>City</td>
            <td>Population</td>
        </tr>
    </thead>
    <tbody>
        <tr data-template>
            <td>[[ city ]]</td>
            <td>[[ population ]]</td>
        </tr>
    </tbody>
</table>

The required data-grid attribute will allow you to create multiple Data Grids on a single page and the results class will mark it as the results container. The data-source attribute contains the API endpoint URI.

You might notice that the [[ ... ]] is different from the default Tempo brace syntax. This is needed to allow the use of [? ... ?]. You can always change this behaviour by changing the plugin's options.

Pagination Container

<ul class="pagination" data-grid="main">
    <li data-template data-if-infinite data-page="[[ page ]]">Load More</li>
    <li data-template data-if-throttle data-throttle>[[ label ]]</li>
    <li data-template data-page="[[ page ]]">[[ pageStart ]] - [[ pageLimit ]]</li>
</ul>

Because we're setting the same data-grid attribute, the plugin will know to group it with your results container. We use the pagination class to indicate it as the pagination container.

There are three templates that are used inside the pagination container. The data-if-infinite template will render only when the pagination type is set to infinite. The data-if-throttle template will render if a throttle is set and reached. The last template is the template used for the multiple pagination type.

As for the other attributes, the data-page attribute is where we store the current page. The data-throttle attribute is our selector for events to increase the throttle. By default we will use pageStart and pageLimit in our pagination template to indicate which results are displayed on each page. This would output to 1 - 10, 11 - 20, ...

Filters Container

<ul class="applied" data-grid="main">
    <li data-template>
        [? if column == undefined ?]
            [[ valueLabel ]]
        [? else ?]
            [[ valueLabel ]] in [[ columnLabel ]]
        [? endif ?]
    </li>
</ul>

We use our custom itteration of Tempo's brace syntax to build if else statements. We check for columns so you can display your filters in a readable manner. If your filter isn't filtering within a column it will just display the filter. If your filtering within a column we show both the filter and column.

The Javascript

Now that you have all of your templates setup, let's instantiate Data Grid. The first argument within the instantiation is the grid, this is the value of the data-grid attribute. This allows us you to have a flexible layout, and multiple Data Grids on a page. Next is the results container for the response, followed by the pagination container and finally the applied filters container.

<script>
    $(function()
    {
        $.datagrid('main', '.results', '.pagination', '.applied');
    });
</script>

Should you have placed the data-source attribute on the results container, the plugin will automatically know which URI to make it API calls to. You can also set the URI through the plugin's options.

After applying the plugin, you should get a nicely filled table with all of your data and pagination.

Applying Filters & Sorting

Lets go over how to set filters and sorts now that you have your Data Grid returning results. We use two attributes for setting filters and sorts, data-filter and data-sort. Both are done in key/value pairs separated by ,. Note the space after the comma, this is needed. Filters and Sorts can be set on any element within site.

Some filter examples:

<a href="#" data-filter="all:USA" data-grid="main">Filter USA</a>

This will filter the Data Grid of main, for anything matching USA.

<a href="#" data-filter="state:Washington" data-grid="main">Filter Washington</a>

This will filter the Data Grid of main, for anything with a state of Washington

<a href="#" data-filter="all:USA, state:Washington" data-grid="main">Filter USA by Washington State</a>

This will filter the Data Grid of main, for anything within the USA, and with a state of Washington.

Some sort examples:

<a href="#" data-sort="city:asc" data-grid="main">Sort By City ASC</a>

This will sort the Data Grid of 'main', by City ASC.

<a href="#" data-sort="city:desc" data-grid="main">Sort By City DESC</a>

This will sort the Data Grid of 'main', by City DESC.

From time to time, when using filters and sorts you will run into issues when your column names have underscores or something of that nature. Because of this we've created the data-label attribute to help you rewrite this for the user. The data-label works just like filters and sorts as in its a key/value pair, separated by ,. Again, note the whitespace after the comma.

Heres a filter with a label fix.

<a href="#" data-filter="country_code:USA" data-label="country_code:Country Code">Filter by Country Code</a>

Adding Search

Data Grid ships with a few other things to help developers get off the ground faster. If you are looking to search within your data set, all you need to do is create a form and set the data-grid attribute and set data-search. Make sure the input name is set to filter.

<form method="post" action="" accept-charset="utf-8" data-search data-grid="main">
    <input name="filter" type="text" placeholder="Filter All">
    <button>Add Filter</button>
</form>

Now if you are looking for to let users filter within defined columns all you need to do is add a select menu within the form. The select name should be set to 'column' and the value of options set to the column name.

<form method="post" action="" accept-charset="utf-8" data-search data-grid="main">
    <select name="column" class="input-medium">
        <option value="all">All</option>
        <option value="city">city</option>
        <option value="population">Population</option>
    </select>
    <input name="filter" type="text" placeholder="Filter All">
    <button>Add Filter</button>
</form>

Resetting

If you want to give your users a simple way to reset Data Grid, just create a button, set the attributes data-grid and data-reset and your done.

<button data-reset data-grid="main">Reset</button>

Options

You can add plugin options by adding a fifth object parameter to your plugin instantiation.

<script>
    $(function()
    {
        $.datagrid('main', '.results', '.pagination', '.applied',
        {
            source: 'http://example.com/api/v1{url}',
            sort: {
                column: 'city',
                direction: 'desc'
            },
            ...
        });
    });
</script>

Below is a list with all of the available options.

Option Type Description
source string The API endpoint URI.
sort object Set a default column and direction for sorting.
threshold integer Minimum amount of results before pagination is applied.
dividend integer The maximum amount of pages you wish to have.
throttle integer The maxmim amount of results on a single page. Overrides dividend.
type string The type of pagination to use. Options are: "single", "multiple" and "infinite".
tempoOptions object Changes the surrounding braces. Data Grid's default is set to [[ ... ]].
loader string class of id of a loading element to be shown while the ajax request is made.
callback function This parameter you can pass a function that will run every time a filter is added, or a sort is applied. This function recives one argument, and gives you access to anyting set within the plugin.

Result Sets

Introduction

After instantiating a Data Grid object you have a couple of options to work with the data result sets. Depending on the request provider which you registered with your environment, the implementation of these methods can differ. In the examples below we're going to assume you're using the default Cartalyst\DataGrid\RequestProviders\NativeProvider request provider.

You can filter results by sending specific request parameters along with your HTTP request. Your request provider will catch these so your data handler can filter the data based on these request parameters.

Generating Results

You can convert the result set from the Data Grid object to an array or JSON response by calling the toArray or toJson functions.

$environment = new Cartalyst\DataGrid\Environment;
$dataGrid = $environment->make($data, $columns);

// Retrieve the result set as an array.
$array = $dataGrid->toArray();

// Retrieve the result set as a JSON response.
$json = $dataGrid->toJson();

The returned response would look something like this:

{
    "total_count": 3,
    "filtered_count": 3,
    "page": 1,
    "pages_count": 1,
    "previous_page": null,
    "next_page": null,
    "per_page": 3,
    "results": [
        {
            "name": "John Doe",
            "age": 22,
            "location": "New York"
        },
        ...
    ]
}

The response contains some useful information like the total number of results, the amount of filtered results, the current, previous and next page and a list with all of the results for the current page.

Note: When sending the Data Grid object to the browser, it will be automatically converted to a JSON response. This is very useful, for example, when building APIs.

Sorting Results

You can sort the result set by sending a request parameter with the sort key.

http://example.com/search?sort=name

This will sort the results by name.

Reverting the sorted results can be done by sending a request parameter with the direction key.

http://example.com/search?sort=name&direction=desc

Now the results will be sorted descended by name.

Switching Pages

Changing the page in a result set can be done by sending a request parameter with the page key.

http://example.com/search?page=2

This would show the results on the second page of the result set.

Filter Results

You can filter results by sending a request parameter with the filters key. The filters request parameter must provide filters based as a key (column) and value (column value) array.

For example:

http://testing.loc/search?filters[0][name]=foo&filters[1][age]=24

This would show only results which have a foo name and an age of 24.

Paginating Results

There are three request parameters you can use to paginate a result set: threshold, dividend and throttle.

threshold is the number of results before pagination is applied to the result set. For example: if you set this to 5 then only when there are more than 5 results, pagination would be applied. The default for this parameter is 100.

dividend is the ideal number of pages you want to have for your result set. If you set this, for example, to 5 and the number of results is greater then the threshold the data handler will try to create a paginated result set with a maximum of 5 pages. The amount of results / page is calculated by dividing the total results with the dividend. the default value for this parameter is 10.

throttle is the maximum amount of results you wish to display on a single page. Should the amount of results for each page be greater than this number, a new amount of results / page will be calculated by diving the threshold with the dividend. This means that the amount of pages can be greater than set by dividend. The default value for this parameter is 100.

An example of these request parameters can be:

http://example.com/search?threshold=5&dividend=10&throttle=100

In this example, the data handler will start paginating the results when there are more than 5 results. When there are less than 100 results, pagination will be created with 10 pages containing a number of results for each page based on dividing the total number of results by 10 (dividend). Should there be more than 100 results, the amount of results would be limited by 100 and the amount of results for each page would be calculated by dividing the throttle with the dividend.

You wont find fancy lifestyle graphics and marketing bravado here. Just cold... hard... code...

Code Well, Rock On!
Processing Payment...