Documentation v8.1.5

Preview Downloads Purchase

Server Side

With server-side processing enabled, all paging, searching, ordering actions that DataTables performs are handed off to a server where an SQL engine (or similar) can perform these actions on the large data set. For more information please check the official documentation.
Selected
<!--begin::Wrapper-->
<div class="d-flex flex-stack mb-5">
    <!--begin::Search-->
    <div class="d-flex align-items-center position-relative my-1">
        <span class="svg-icon svg-icon-2">...</span>
        <input type="text" data-kt-docs-table-filter="search" class="form-control form-control-solid w-250px ps-15" placeholder="Search Customers"/>
    </div>
    <!--end::Search-->

    <!--begin::Toolbar-->
    <div class="d-flex justify-content-end" data-kt-docs-table-toolbar="base">
        <!--begin::Filter-->
        <button type="button" class="btn btn-light-primary me-3" data-bs-toggle="tooltip" title="Coming Soon">
            <span class="svg-icon svg-icon-2">...</span>
            Filter
        </button>
        <!--end::Filter-->

        <!--begin::Add customer-->
        <button type="button" class="btn btn-primary" data-bs-toggle="tooltip" title="Coming Soon">
            <span class="svg-icon svg-icon-2">...</span>
            Add Customer
        </button>
        <!--end::Add customer-->
    </div>
    <!--end::Toolbar-->

    <!--begin::Group actions-->
    <div class="d-flex justify-content-end align-items-center d-none" data-kt-docs-table-toolbar="selected">
        <div class="fw-bold me-5">
            <span class="me-2" data-kt-docs-table-select="selected_count"></span> Selected
        </div>

        <button type="button" class="btn btn-danger" data-bs-toggle="tooltip" title="Coming Soon">
            Selection Action
        </button>
    </div>
    <!--end::Group actions-->
</div>
<!--end::Wrapper-->

<!--begin::Datatable-->
<table id="kt_datatable_example_1" class="table align-middle table-row-dashed fs-6 gy-5">
    <thead>
    <tr class="text-start text-gray-400 fw-bold fs-7 text-uppercase gs-0">
        <th class="w-10px pe-2">
            <div class="form-check form-check-sm form-check-custom form-check-solid me-3">
                <input class="form-check-input" type="checkbox" data-kt-check="true" data-kt-check-target="#kt_datatable_example_1 .form-check-input" value="1"/>
            </div>
        </th>
        <th>Customer Name</th>
        <th>Email</th>
        <th>Company</th>
        <th>Payment Method</th>
        <th>Created Date</th>
        <th class="text-end min-w-100px">Actions</th>
    </tr>
    </thead>
    <tbody class="text-gray-600 fw-semibold">
    </tbody>
</table>
<!--end::Datatable-->
"use strict";

// Class definition
var KTDatatablesServerSide = function () {
    // Shared variables
    var table;
    var dt;
    var filterPayment;

    // Private functions
    var initDatatable = function () {
        dt = $("#kt_datatable_example_1").DataTable({
            searchDelay: 500,
            processing: true,
            serverSide: true,
            order: [[5, 'desc']],
            stateSave: true,
            select: {
                style: 'multi',
                selector: 'td:first-child input[type="checkbox"]',
                className: 'row-selected'
            },
            ajax: {
                url: "https://preview.keenthemes.com/api/datatables.php",
            },
            columns: [
                { data: 'RecordID' },
                { data: 'Name' },
                { data: 'Email' },
                { data: 'Company' },
                { data: 'CreditCardNumber' },
                { data: 'Datetime' },
                { data: null },
            ],
            columnDefs: [
                {
                    targets: 0,
                    orderable: false,
                    render: function (data) {
                        return `
                            <div class="form-check form-check-sm form-check-custom form-check-solid">
                                <input class="form-check-input" type="checkbox" value="${data}" />
                            </div>`;
                    }
                },
                {
                    targets: 4,
                    render: function (data, type, row) {
                        return `<img src="${hostUrl}media/svg/card-logos/${row.CreditCardType}.svg" class="w-35px me-3" alt="${row.CreditCardType}">` + data;
                    }
                },
                {
                    targets: -1,
                    data: null,
                    orderable: false,
                    className: 'text-end',
                    render: function (data, type, row) {
                        return `
                            <a href="#" class="btn btn-light btn-active-light-primary btn-sm" data-kt-menu-trigger="click" data-kt-menu-placement="bottom-end" data-kt-menu-flip="top-end">
                                Actions
                                <span class="svg-icon svg-icon-5 m-0">
                                    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1">
                                        <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
                                            <polygon points="0 0 24 0 24 24 0 24"></polygon>
                                            <path d="M6.70710678,15.7071068 C6.31658249,16.0976311 5.68341751,16.0976311 5.29289322,15.7071068 C4.90236893,15.3165825 4.90236893,14.6834175 5.29289322,14.2928932 L11.2928932,8.29289322 C11.6714722,7.91431428 12.2810586,7.90106866 12.6757246,8.26284586 L18.6757246,13.7628459 C19.0828436,14.1360383 19.1103465,14.7686056 18.7371541,15.1757246 C18.3639617,15.5828436 17.7313944,15.6103465 17.3242754,15.2371541 L12.0300757,10.3841378 L6.70710678,15.7071068 Z" fill="currentColor" fill-rule="nonzero" transform="translate(12.000003, 11.999999) rotate(-180.000000) translate(-12.000003, -11.999999)"></path>
                                        </g>
                                    </svg>
                                </span>
                            </a>
                            <!--begin::Menu-->
                            <div class="menu menu-sub menu-sub-dropdown menu-column menu-rounded menu-gray-600 menu-state-bg-light-primary fw-bold fs-7 w-125px py-4" data-kt-menu="true">
                                <!--begin::Menu item-->
                                <div class="menu-item px-3">
                                    <a href="#" class="menu-link px-3" data-kt-docs-table-filter="edit_row">
                                        Edit
                                    </a>
                                </div>
                                <!--end::Menu item-->

                                <!--begin::Menu item-->
                                <div class="menu-item px-3">
                                    <a href="#" class="menu-link px-3" data-kt-docs-table-filter="delete_row">
                                        Delete
                                    </a>
                                </div>
                                <!--end::Menu item-->
                            </div>
                            <!--end::Menu-->
                        `;
                    },
                },
            ],
            // Add data-filter attribute
            createdRow: function (row, data, dataIndex) {
                $(row).find('td:eq(4)').attr('data-filter', data.CreditCardType);
            }
        });

        table = dt.$;

        // Re-init functions on every table re-draw -- more info: https://datatables.net/reference/event/draw
        dt.on('draw', function () {
            initToggleToolbar();
            toggleToolbars();
            handleDeleteRows();
            KTMenu.createInstances();
        });
    }

    // Search Datatable --- official docs reference: https://datatables.net/reference/api/search()
    var handleSearchDatatable = function () {
        const filterSearch = document.querySelector('[data-kt-docs-table-filter="search"]');
        filterSearch.addEventListener('keyup', function (e) {
            dt.search(e.target.value).draw();
        });
    }

    // Filter Datatable
    var handleFilterDatatable = () => {
        // Select filter options
        filterPayment = document.querySelectorAll('[data-kt-docs-table-filter="payment_type"] [name="payment_type"]');
        const filterButton = document.querySelector('[data-kt-docs-table-filter="filter"]');

        // Filter datatable on submit
        filterButton.addEventListener('click', function () {
            // Get filter values
            let paymentValue = '';

            // Get payment value
            filterPayment.forEach(r => {
                if (r.checked) {
                    paymentValue = r.value;
                }

                // Reset payment value if "All" is selected
                if (paymentValue === 'all') {
                    paymentValue = '';
                }
            });

            // Filter datatable --- official docs reference: https://datatables.net/reference/api/search()
            dt.search(paymentValue).draw();
        });
    }

    // Delete customer
    var handleDeleteRows = () => {
        // Select all delete buttons
        const deleteButtons = document.querySelectorAll('[data-kt-docs-table-filter="delete_row"]');

        deleteButtons.forEach(d => {
            // Delete button on click
            d.addEventListener('click', function (e) {
                e.preventDefault();

                // Select parent row
                const parent = e.target.closest('tr');

                // Get customer name
                const customerName = parent.querySelectorAll('td')[1].innerText;

                // SweetAlert2 pop up --- official docs reference: https://sweetalert2.github.io/
                Swal.fire({
                    text: "Are you sure you want to delete " + customerName + "?",
                    icon: "warning",
                    showCancelButton: true,
                    buttonsStyling: false,
                    confirmButtonText: "Yes, delete!",
                    cancelButtonText: "No, cancel",
                    customClass: {
                        confirmButton: "btn fw-bold btn-danger",
                        cancelButton: "btn fw-bold btn-active-light-primary"
                    }
                }).then(function (result) {
                    if (result.value) {
                        // Simulate delete request -- for demo purpose only
                        Swal.fire({
                            text: "Deleting " + customerName,
                            icon: "info",
                            buttonsStyling: false,
                            showConfirmButton: false,
                            timer: 2000
                        }).then(function () {
                            Swal.fire({
                                text: "You have deleted " + customerName + "!.",
                                icon: "success",
                                buttonsStyling: false,
                                confirmButtonText: "Ok, got it!",
                                customClass: {
                                    confirmButton: "btn fw-bold btn-primary",
                                }
                            }).then(function () {
                                // delete row data from server and re-draw datatable
                                dt.draw();
                            });
                        });
                    } else if (result.dismiss === 'cancel') {
                        Swal.fire({
                            text: customerName + " was not deleted.",
                            icon: "error",
                            buttonsStyling: false,
                            confirmButtonText: "Ok, got it!",
                            customClass: {
                                confirmButton: "btn fw-bold btn-primary",
                            }
                        });
                    }
                });
            })
        });
    }

    // Reset Filter
    var handleResetForm = () => {
        // Select reset button
        const resetButton = document.querySelector('[data-kt-docs-table-filter="reset"]');

        // Reset datatable
        resetButton.addEventListener('click', function () {
            // Reset payment type
            filterPayment[0].checked = true;

            // Reset datatable --- official docs reference: https://datatables.net/reference/api/search()
            dt.search('').draw();
        });
    }

    // Init toggle toolbar
    var initToggleToolbar = function () {
        // Toggle selected action toolbar
        // Select all checkboxes
        const container = document.querySelector('#kt_datatable_example_1');
        const checkboxes = container.querySelectorAll('[type="checkbox"]');

        // Select elements
        const deleteSelected = document.querySelector('[data-kt-docs-table-select="delete_selected"]');

        // Toggle delete selected toolbar
        checkboxes.forEach(c => {
            // Checkbox on click event
            c.addEventListener('click', function () {
                setTimeout(function () {
                    toggleToolbars();
                }, 50);
            });
        });

        // Deleted selected rows
        deleteSelected.addEventListener('click', function () {
            // SweetAlert2 pop up --- official docs reference: https://sweetalert2.github.io/
            Swal.fire({
                text: "Are you sure you want to delete selected customers?",
                icon: "warning",
                showCancelButton: true,
                buttonsStyling: false,
                showLoaderOnConfirm: true,
                confirmButtonText: "Yes, delete!",
                cancelButtonText: "No, cancel",
                customClass: {
                    confirmButton: "btn fw-bold btn-danger",
                    cancelButton: "btn fw-bold btn-active-light-primary"
                },
            }).then(function (result) {
                if (result.value) {
                    // Simulate delete request -- for demo purpose only
                    Swal.fire({
                        text: "Deleting selected customers",
                        icon: "info",
                        buttonsStyling: false,
                        showConfirmButton: false,
                        timer: 2000
                    }).then(function () {
                        Swal.fire({
                            text: "You have deleted all selected customers!.",
                            icon: "success",
                            buttonsStyling: false,
                            confirmButtonText: "Ok, got it!",
                            customClass: {
                                confirmButton: "btn fw-bold btn-primary",
                            }
                        }).then(function () {
                            // delete row data from server and re-draw datatable
                            dt.draw();
                        });

                        // Remove header checked box
                        const headerCheckbox = container.querySelectorAll('[type="checkbox"]')[0];
                        headerCheckbox.checked = false;
                    });
                } else if (result.dismiss === 'cancel') {
                    Swal.fire({
                        text: "Selected customers was not deleted.",
                        icon: "error",
                        buttonsStyling: false,
                        confirmButtonText: "Ok, got it!",
                        customClass: {
                            confirmButton: "btn fw-bold btn-primary",
                        }
                    });
                }
            });
        });
    }

    // Toggle toolbars
    var toggleToolbars = function () {
        // Define variables
        const container = document.querySelector('#kt_datatable_example_1');
        const toolbarBase = document.querySelector('[data-kt-docs-table-toolbar="base"]');
        const toolbarSelected = document.querySelector('[data-kt-docs-table-toolbar="selected"]');
        const selectedCount = document.querySelector('[data-kt-docs-table-select="selected_count"]');

        // Select refreshed checkbox DOM elements
        const allCheckboxes = container.querySelectorAll('tbody [type="checkbox"]');

        // Detect checkboxes state & count
        let checkedState = false;
        let count = 0;

        // Count checked boxes
        allCheckboxes.forEach(c => {
            if (c.checked) {
                checkedState = true;
                count++;
            }
        });

        // Toggle toolbars
        if (checkedState) {
            selectedCount.innerHTML = count;
            toolbarBase.classList.add('d-none');
            toolbarSelected.classList.remove('d-none');
        } else {
            toolbarBase.classList.remove('d-none');
            toolbarSelected.classList.add('d-none');
        }
    }

    // Public methods
    return {
        init: function () {
            initDatatable();
            handleSearchDatatable();
            initToggleToolbar();
            handleFilterDatatable();
            handleDeleteRows();
            handleResetForm();
        }
    }
}();

// On document ready
KTUtil.onDOMContentLoaded(function () {
    KTDatatablesServerSide.init();
});
[
    {
        "RecordID": 1,
        "OrderID": "49349-387",
        "Name": "Dugald Beastall",
        "Email": "dbeastall0@ezinearticles.com",
        "Address": "88 Scott Crossing",
        "City": "Daze",
        "Country": "China",
        "CountryCode": "CN",
        "Company": "Hammes-Mitchell",
        "Currency": "CNY",
        "Notes": "mus vivamus vestibulum sagittis sapien cum sociis natoque penatibus et magnis dis parturient montes nascetur ridiculus mus etiam vel augue",
        "Department": "Human Resources",
        "Website": "amazon.com",
        "Latitude": 20.0429063,
        "Longitude": 110.354037,
        "Datetime": "2020-04-10 05:48:26",
        "TimeZone": "Asia\/Chongqing",
        "Money": "$178460.50",
        "Gender": "M",
        "CreditCardNumber": "4682474206308",
        "CreditCardType": "visa"
    },
    {
        "RecordID": 2,
        "OrderID": "51808-213",
        "Name": "Aristotle Aicken",
        "Email": "aaicken1@friendfeed.com",
        "Address": "4 Merrick Court",
        "City": "Hobo",
        "Country": "Philippines",
        "CountryCode": "PH",
        "Company": "Schimmel, Towne and Torp",
        "Currency": "PHP",
        "Notes": "sed sagittis nam congue risus semper porta volutpat quam pede",
        "Department": "Sales",
        "Website": "answers.com",
        "Latitude": 13.5085076,
        "Longitude": 123.1804731,
        "Datetime": "2020-10-02 05:40:48",
        "TimeZone": "Asia\/Manila",
        "Money": "$1150804.73",
        "Gender": "M",
        "CreditCardNumber": "372301415416298",
        "CreditCardType": "americanexpress"
    },
    {
        "RecordID": 3,
        "OrderID": "58443-0015",
        "Name": "Yvonne Comiam",
        "Email": "ycomiam2@oracle.com",
        "Address": "5284 Fieldstone Parkway",
        "City": "Damu",
        "Country": "China",
        "CountryCode": "CN",
        "Company": "Padberg Group",
        "Currency": "CNY",
        "Notes": "luctus et ultrices posuere cubilia curae nulla dapibus dolor vel est donec odio justo sollicitudin ut suscipit a feugiat et",
        "Department": "Engineering",
        "Website": "ox.ac.uk",
        "Latitude": 24.134518,
        "Longitude": 111.485304,
        "Datetime": "2020-07-08 23:05:11",
        "TimeZone": "Asia\/Shanghai",
        "Money": "$54341.33",
        "Gender": "F",
        "CreditCardNumber": "4017956514996",
        "CreditCardType": "visa"
    },
    {
        "RecordID": 4,
        "OrderID": "49288-0189",
        "Name": "Benton Reynalds",
        "Email": "breynalds3@studiopress.com",
        "Address": "65026 Ruskin Lane",
        "City": "Gelap",
        "Country": "Indonesia",
        "CountryCode": "ID",
        "Company": "Koss and Sons",
        "Currency": "IDR",
        "Notes": "volutpat quam pede lobortis ligula sit amet eleifend pede libero quis orci nullam molestie nibh in",
        "Department": "Business Development",
        "Website": "dot.gov",
        "Latitude": -6.9654201,
        "Longitude": 112.2443628,
        "Datetime": "2020-11-24 22:01:00",
        "TimeZone": "Asia\/Jakarta",
        "Money": "$77709.51",
        "Gender": "M",
        "CreditCardNumber": "337941293027131",
        "CreditCardType": "americanexpress"
    },
    {
        "RecordID": 5,
        "OrderID": "10675-002",
        "Name": "Cody Drysdell",
        "Email": "cdrysdell4@youku.com",
        "Address": "80916 Dottie Hill",
        "City": "Ne\u1e96alim",
        "Country": "Israel",
        "CountryCode": "IL",
        "Company": "Boyer Group",
        "Currency": "ILS",
        "Notes": "maecenas ut massa quis augue luctus tincidunt nulla mollis molestie lorem quisque ut erat curabitur gravida nisi at nibh",
        "Department": "Training",
        "Website": "huffingtonpost.com",
        "Latitude": 32.058597,
        "Longitude": 34.9136,
        "Datetime": "2020-12-03 20:02:41",
        "TimeZone": "Asia\/Jerusalem",
        "Money": "$1045848.44",
        "Gender": "F",
        "CreditCardNumber": "372301498885559",
        "CreditCardType": "americanexpress"
    },
    {
        "RecordID": 6,
        "OrderID": "35356-028",
        "Name": "Sebastiano Mingard",
        "Email": "smingard5@wsj.com",
        "Address": "6121 Armistice Road",
        "City": "Starcevica",
        "Country": "Bosnia and Herzegovina",
        "CountryCode": "BA",
        "Company": "Kiehn-Runte",
        "Currency": "BAM",
        "Notes": "a odio in hac habitasse platea dictumst maecenas ut massa quis augue luctus tincidunt nulla mollis molestie lorem quisque ut",
        "Department": "Business Development",
        "Website": "cbsnews.com",
        "Latitude": 44.7607693,
        "Longitude": 17.2038547,
        "Datetime": "2020-07-05 07:12:56",
        "TimeZone": "Europe\/Sarajevo",
        "Money": "$703053.38",
        "Gender": "M",
        "CreditCardNumber": "4017956322929",
        "CreditCardType": "visa"
    },
    {
        "RecordID": 7,
        "OrderID": "54868-5792",
        "Name": "Nickie Debill",
        "Email": "ndebill6@weebly.com",
        "Address": "92202 Rutledge Avenue",
        "City": "Greenwood",
        "Country": "Canada",
        "CountryCode": "CA",
        "Company": "Wiza-Blanda",
        "Currency": "CAD",
        "Notes": "eros vestibulum ac est lacinia nisi venenatis tristique fusce congue diam",
        "Department": "Business Development",
        "Website": "printfriendly.com",
        "Latitude": 44.98345,
        "Longitude": -64.89879,
        "Datetime": "2020-01-29 04:28:02",
        "TimeZone": "America\/Moncton",
        "Money": "$564744.00",
        "Gender": "F",
        "CreditCardNumber": "337941218508546",
        "CreditCardType": "americanexpress"
    },
    {
        "RecordID": 8,
        "OrderID": "11822-0656",
        "Name": "Anstice Ygoe",
        "Email": "aygoe7@japanpost.jp",
        "Address": "6 Hollow Ridge Junction",
        "City": "Wushi",
        "Country": "China",
        "CountryCode": "CN",
        "Company": "Goodwin LLC",
        "Currency": "CNY",
        "Notes": "sit amet nunc viverra dapibus nulla suscipit ligula in lacus curabitur",
        "Department": "Legal",
        "Website": "netlog.com",
        "Latitude": 31.491169,
        "Longitude": 120.31191,
        "Datetime": "2020-01-21 06:16:04",
        "TimeZone": "Asia\/Chongqing",
        "Money": "$1099551.54",
        "Gender": "F",
        "CreditCardNumber": "5438780052553151",
        "CreditCardType": "mastercard"
    },
    {
        "RecordID": 9,
        "OrderID": "60681-3006",
        "Name": "Iseabal Bottomley",
        "Email": "ibottomley8@reverbnation.com",
        "Address": "225 Birchwood Junction",
        "City": "Timbuktu",
        "Country": "Mali",
        "CountryCode": "ML",
        "Company": "Stark-Mills",
        "Currency": "XOF",
        "Notes": "varius ut blandit non interdum in ante vestibulum ante ipsum primis in faucibus orci luctus et",
        "Department": "Human Resources",
        "Website": "themeforest.net",
        "Latitude": 16.7665887,
        "Longitude": -3.0025615,
        "Datetime": "2020-07-02 19:36:35",
        "TimeZone": "Africa\/Bamako",
        "Money": "$137510.03",
        "Gender": "F",
        "CreditCardNumber": "5358043968138476",
        "CreditCardType": "mastercard"
    },
    {
        "RecordID": 10,
        "OrderID": "75847-1501",
        "Name": "Cobby McWhirter",
        "Email": "cmcwhirter9@goo.ne.jp",
        "Address": "50557 Hudson Court",
        "City": "Villa Gesell",
        "Country": "Argentina",
        "CountryCode": "AR",
        "Company": "Bruen, Kutch and Bartell",
        "Currency": "ARS",
        "Notes": "suscipit nulla elit ac nulla sed vel enim sit amet",
        "Department": "Engineering",
        "Website": "vimeo.com",
        "Latitude": -34.7368519,
        "Longitude": -58.5019467,
        "Datetime": "2020-11-18 00:32:20",
        "TimeZone": "America\/Argentina\/Buenos_Aires",
        "Money": "$189903.13",
        "Gender": "M",
        "CreditCardNumber": "5339559580646442",
        "CreditCardType": "mastercard"
    }
]
<?php
include 'class-list-util.php';

class DataTableApi
{
    public $columnsDefault = [
        'RecordID'         => true,
        'OrderID'          => true,
        'Name'             => true,
        'Country'          => true,
        'CountryCode'      => true,
        'City'             => true,
        'Company'          => true,
        'Address'          => true,
        'Email'            => true,
        'Currency'         => true,
        'Notes'            => true,
        'Department'       => true,
        'Website'          => true,
        'Latitude'         => true,
        'Longitude'        => true,
        'Datetime'         => true,
        'TimeZone'         => true,
        'Money'            => true,
        'Gender'           => true,
        'CreditCardNumber' => true,
        'CreditCardType'   => true,
    ];

    public function __construct()
    {
        header('Content-Type: application/json');
        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
        header('Access-Control-Allow-Headers: *');
    }

    public function init()
    {
        if (isset($_REQUEST['columnsDef']) && is_array($_REQUEST['columnsDef'])) {
            foreach ($_REQUEST['columnsDef'] as $field) {
                $columnsDefault[$field] = true;
            }
        }

        // get all raw data
        $alldata = $this->getJsonDecode();

        $data = [];
        // internal use; filter selected columns only from raw data
        foreach ($alldata as $d) {
            $data[] = $this->filterArray($d, $this->columnsDefault);
        }

        // filter by general search keyword
        if (isset($_REQUEST['search']['value']) && $_REQUEST['search']['value']) {
            $data = $this->arraySearch($data, $_REQUEST['search']['value']);
        }

        // count data
        $totalRecords = $totalDisplay = count($data);

        // sort
        if (isset($_REQUEST['order'][0]['column']) && $_REQUEST['order'][0]['dir']) {
            $column = $_REQUEST['order'][0]['column'];
            $dir    = $_REQUEST['order'][0]['dir'];
            usort($data, function ($a, $b) use ($column, $dir) {
                $a = array_slice($a, $column, 1);
                $b = array_slice($b, $column, 1);
                $a = array_pop($a);
                $b = array_pop($b);

                if ($dir === 'asc') {
                    return $a > $b ? 1 : -1;
                }

                return $a < $b ? 1 : -1;
            });
        }

        // pagination length
        if (isset($_REQUEST['length'])) {
            $data = array_splice($data, $_REQUEST['start'], $_REQUEST['length']);
        }

        $data = $this->reformat($data);

        $result = [
            'recordsTotal'    => $totalRecords,
            'recordsFiltered' => $totalDisplay,
            'data'            => $data,
        ];

        echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    }

    public function filterArray($array, $allowed = [])
    {
        return array_filter(
            $array,
            function ($val, $key) use ($allowed) { // N.b. $val, $key not $key, $val
                return isset($allowed[$key]) && ($allowed[$key] === true || $allowed[$key] === $val);
            },
            ARRAY_FILTER_USE_BOTH
        );
    }

    public function filterKeyword($data, $search, $field = '')
    {
        $filter = '';
        if (isset($search['value'])) {
            $filter = $search['value'];
        }
        if (!empty($filter)) {
            if (!empty($field)) {
                if (strpos(strtolower($field), 'date') !== false) {
                    // filter by date range
                    $data = $this->filterByDateRange($data, $filter, $field);
                } else {
                    // filter by column
                    $data = array_filter($data, function ($a) use ($field, $filter) {
                        return (boolean) preg_match("/$filter/i", $a[$field]);
                    });
                }

            } else {
                // general filter
                $data = array_filter($data, function ($a) use ($filter) {
                    return (boolean) preg_grep("/$filter/i", (array) $a);
                });
            }
        }

        return $data;
    }

    public function filterByDateRange($data, $filter, $field)
    {
        // filter by range
        if (!empty($range = array_filter(explode('|', $filter)))) {
            $filter = $range;
        }

        if (is_array($filter)) {
            foreach ($filter as &$date) {
                // hardcoded date format
                $date = date_create_from_format('m/d/Y', stripcslashes($date));
            }
            // filter by date range
            $data = array_filter($data, function ($a) use ($field, $filter) {
                // hardcoded date format
                $current = date_create_from_format('m/d/Y', $a[$field]);
                $from    = $filter[0];
                $to      = $filter[1];
                if ($from <= $current && $to >= $current) {
                    return true;
                }

                return false;
            });
        }

        return $data;
    }

    public function getJsonDecode(): mixed
    {
        return json_decode(file_get_contents('customers.json'), true);
    }

    /**
     * @param  array  $data
     *
     * @return array
     */
    public function reformat($data): array
    {
        return array_map(function ($item) {
            // hide credit card number
            $item['CreditCardNumber'] = '**** '.substr($item['CreditCardNumber'], -4);

            $item['CreditCardType'] = $item['CreditCardType'] === 'americanexpress' ? 'american-express' : $item['CreditCardType'];

            // reformat datetime
            $item['Datetime'] = date('d M Y, g:i a', strtotime($item['Datetime']));

            return $item;
        }, $data);
    }

    public function arraySearch($array, $keyword)
    {
        return array_filter($array, function ($a) use ($keyword) {
            return (boolean) preg_grep("/$keyword/i", (array) $a);
        });
    }

}

$api = new DataTableApi;
$api->init();
<?php
/**
 * class-list-util.php
 *
 * List utility class
 */

/**
 * List utility.
 *
 * Utility class to handle operations on an array of objects.
 */
class List_Util
{
    /**
     * The input array.
     *
     * @access private
     * @var array
     */
    private $input = array();

    /**
     * The output array.
     *
     * @access private
     * @var array
     */
    private $output = array();

    /**
     * Temporary arguments for sorting.
     *
     * @access private
     * @var array
     */
    private $orderby = array();

    /**
     * Constructor.
     *
     * Sets the input array.
     *
     *
     * @param  array  $input  Array to perform operations on.
     */
    public function __construct($input)
    {
        $this->output = $this->input = $input;
    }

    /**
     * Returns the original input array.
     *
     * @access public
     *
     * @return array The input array.
     */
    public function get_input()
    {
        return $this->input;
    }

    /**
     * Returns the output array.
     *
     * @access public
     *
     * @return array The output array.
     */
    public function get_output()
    {
        return $this->output;
    }

    /**
     * Filters the list, based on a set of key => value arguments.
     *
     *
     * @param  array  $args  Optional. An array of key => value arguments to match
     *                         against each object. Default empty array.
     * @param  string  $operator  Optional. The logical operation to perform. 'AND' means
     *                         all elements from the array must match. 'OR' means only
     *                         one element needs to match. 'NOT' means no elements may
     *                         match. Default 'AND'.
     *
     * @return array Array of found values.
     */
    public function filter($args = array(), $operator = 'AND')
    {
        if (empty($args)) {
            return $this->output;
        }

        $operator = strtoupper($operator);

        if (!in_array($operator, array('AND', 'OR', 'NOT'), true)) {
            return array();
        }

        $count    = count($args);
        $filtered = array();

        foreach ($this->output as $key => $obj) {
            $to_match = (array) $obj;

            $matched = 0;
            foreach ($args as $m_key => $m_value) {
                if (array_key_exists($m_key, $to_match) && $m_value == $to_match[$m_key]) {
                    $matched++;
                }
            }

            if (
                ('AND' == $operator && $matched == $count) ||
                ('OR' == $operator && $matched > 0) ||
                ('NOT' == $operator && 0 == $matched)
            ) {
                $filtered[$key] = $obj;
            }
        }

        $this->output = $filtered;

        return $this->output;
    }

    /**
     * Plucks a certain field out of each object in the list.
     *
     * This has the same functionality and prototype of
     * array_column() (PHP 5.5) but also supports objects.
     *
     *
     * @param  int|string  $field  Field from the object to place instead of the entire object
     * @param  int|string  $index_key  Optional. Field from the object to use as keys for the new array.
     *                              Default null.
     *
     * @return array Array of found values. If `$index_key` is set, an array of found values with keys
     *               corresponding to `$index_key`. If `$index_key` is null, array keys from the original
     *               `$list` will be preserved in the results.
     */
    public function pluck($field, $index_key = null)
    {
        if (!$index_key) {
            /*
             * This is simple. Could at some point wrap array_column()
             * if we knew we had an array of arrays.
             */
            foreach ($this->output as $key => $value) {
                if (is_object($value)) {
                    $this->output[$key] = $value->$field;
                } else {
                    $this->output[$key] = $value[$field];
                }
            }

            return $this->output;
        }

        /*
         * When index_key is not set for a particular item, push the value
         * to the end of the stack. This is how array_column() behaves.
         */
        $newlist = array();
        foreach ($this->output as $value) {
            if (is_object($value)) {
                if (isset($value->$index_key)) {
                    $newlist[$value->$index_key] = $value->$field;
                } else {
                    $newlist[] = $value->$field;
                }
            } else {
                if (isset($value[$index_key])) {
                    $newlist[$value[$index_key]] = $value[$field];
                } else {
                    $newlist[] = $value[$field];
                }
            }
        }

        $this->output = $newlist;

        return $this->output;
    }

    /**
     * Sorts the list, based on one or more orderby arguments.
     *
     *
     * @param  string|array  $orderby  Optional. Either the field name to order by or an array
     *                                    of multiple orderby fields as $orderby => $order.
     * @param  string  $order  Optional. Either 'ASC' or 'DESC'. Only used if $orderby
     *                                    is a string.
     * @param  bool  $preserve_keys  Optional. Whether to preserve keys. Default false.
     *
     * @return array The sorted array.
     */
    public function sort($orderby = array(), $order = 'ASC', $preserve_keys = false)
    {
        if (empty($orderby)) {
            return $this->output;
        }

        if (is_string($orderby)) {
            $orderby = array($orderby => $order);
        }

        foreach ($orderby as $field => $direction) {
            $orderby[$field] = 'DESC' === strtoupper($direction) ? 'DESC' : 'ASC';
        }

        $this->orderby = $orderby;

        if ($preserve_keys) {
            uasort($this->output, array($this, 'sort_callback'));
        } else {
            usort($this->output, array($this, 'sort_callback'));
        }

        $this->orderby = array();

        return $this->output;
    }

    /**
     * Callback to sort the list by specific fields.
     *
     * @access private
     *
     * @param  object|array  $a  One object to compare.
     * @param  object|array  $b  The other object to compare.
     *
     * @return int 0 if both objects equal. -1 if second object should come first, 1 otherwise.
     * @see    List_Util::sort()
     *
     */
    private function sort_callback($a, $b)
    {
        if (empty($this->orderby)) {
            return 0;
        }

        $a = (array) $a;
        $b = (array) $b;

        foreach ($this->orderby as $field => $direction) {
            if (!isset($a[$field]) || !isset($b[$field])) {
                continue;
            }

            if ($a[$field] == $b[$field]) {
                continue;
            }

            $results = 'DESC' === $direction ? array(1, -1) : array(-1, 1);

            if (is_numeric($a[$field]) && is_numeric($b[$field])) {
                return ($a[$field] < $b[$field]) ? $results[0] : $results[1];
            }

            return 0 > strcmp($a[$field], $b[$field]) ? $results[0] : $results[1];
        }

        return 0;
    }
}

function list_filter($list, $args = array(), $operator = 'AND')
{
    if (!is_array($list)) {
        return array();
    }

    $util = new List_Util($list);

    return $util->filter($args, $operator);
}
Learn & Get Inspired

Support at devs.keenthemes.com

Join our developers community to find answer to your question and help others. FAQs
Get Support
Video Tutorials
From guides and how-tos, to live demos and code examples to get started right away.
Metronic Downloads
Download your prefered framework and demo with one click.
What's New ?
Latest features and improvements added with our users feedback in mind.
Buy now