revaycolizer / data-display
The DataDisplay class is a dynamic PHP data table renderer built with Sweet Alert and Bootstrap. It supports adding, editing, deleting, searching, joining tables, and pagination โ all from a fluent interface.
This package is auto-updated.
Last update: 2025-04-25 20:21:58 UTC
README
๐ DataDisplay Component
The DataDisplay class is a dynamic PHP data table renderer built with Sweet Alert and Bootstrap. It supports adding, editing, deleting, searching, joining tables, and pagination โ all from a fluent interface.
Required Packages For The Magic To Work
- Sweet Alert 2
- DataTable
- BootStrap 5
- Doctrine (optional)
โจ Features
๐ Dynamic table rendering with Bootstrap
๐ Searchable columns with support for input/select types
๐ CRUD Operations With Permissions
๐ Editable records with modals
โ Add new records using modals
โ Delete functionality with confirmation
๐ Supports JOINs
๐ Pagination support
๐ CSRF protection
To get Started Run This on Terminal
composer require revaycolizer/data-display
Instantiate the Component Using Doctrine For Data Fetching
use Revaycolizer\Crud\DataDisplay; $dataTable = DataDisplay::create($entityManager, User::class);
Instantiate the Component Using Classes For Data fetching
$dataDisplay = DataDisplay::create(null, Category::class,DataSourceType::CLASSES);
Provide The Method Which Will be Used in Fetching Data When Using Classes
$dataDisplay ->setClassFetchDataFunction("all")
Provide The Method With It's Parameters Which Will be Used in Fetching Data When Using Classes
$dataDisplay->setClassFetchDataFunction("all:param1,param2")
DataDisplay Modes
Mode 1: Default
By Default the mode is Default There is no Need to Set Mode
->setMode("default")
Mode 2: Report
If mode is set to report it will remove the CRUD Buttons(Add,Edit & Delete)
->setMode("report")
๐ง Configuration
Set Columns to Add
$dataTable->columnToBeAdded([ 'username' => ['type' => 'input', 'input_type' => 'text', 'label' => 'Username'], 'role' => ['type' => 'select', 'label' => 'Role', 'options' => $roles, 'value_field' => 'id', 'label_field' => 'name'] ]);
Set Columns to Edit
$dataTable->columnsToBeEdited([ 'username' => ['type' => 'input', 'input_type' => 'text'], 'role' => ['type' => 'select', 'options' => $roles, 'value_field' => 'id', 'label_field' => 'name'] ]);
Set Add Permission
It takes a boolean value
$dataTable->setAddPermission(true);
set Datatable Buttons
$dataTable->setDataTableButtons([ 'copy' => true, 'csv' => ['title' => 'Exported CSV'], 'excel' => ['title' => 'Excel Export'], 'pdf' => [ 'title' => 'PDF Export', 'orientation' => 'landscape', 'pageSize' => 'A4', ], 'print' => ['title' => 'Printable View'], 'colvis' => ['text' => 'Toggle Columns'], ]);
Select Fields and JOINs
$dataTable->valuesToSelect([ 'e.id', 'e.username', 'r.name AS role_name' ])->tablesToJoin([ ['table' => 'e.role', 'alias' => 'r', 'on' => 'e.role = r.id'] ]);
Values to Render
If there are no Values to Render, it uses the Values to Select as a Fallback to render the items
->valuesToRender([ "name", "price", "category_name" ])
Edit Button Conditions
You can decide to not specify the group operator which by default it will use AND operator as a fallback
->setEditButtonConditions([ 'conditions' => [ ['field' => 'name', 'operator' => '=', 'value' => 'rrrooo'], ['field' => 'price', 'operator' => '=', 'value' => '566'], ], ])
Specifying Group Operator
->setEditButtonConditions([ 'conditions' => [ ['field' => 'name', 'operator' => '=', 'value' => 'rrrooo'], ['field' => 'price', 'operator' => '=', 'value' => '566'], ], 'group_operator' => 'OR', ])
How to Set Conditions:
Case 1: Simple OR condition (Conditions connected by OR):
->setEditButtonConditions([ 'conditions' => [ ['field' => 'name', 'operator' => '=', 'value' => 'rrrooo'], ['field' => 'price', 'operator' => '=', 'value' => '566'], ], 'group_operator' => 'OR', ])
This will return true if either name is equal to 'rrrooo' OR price is equal to 566.
Case 2: Simple AND condition (Conditions connected by AND):
->setEditButtonConditions([ 'conditions' => [ ['field' => 'name', 'operator' => '=', 'value' => 'rrrooo'], ['field' => 'price', 'operator' => '=', 'value' => '566'], ], 'group_operator' => 'AND', ])
This will return true if both name is equal to 'rrrooo' AND price is equal to 566.
Case 3: Mixed AND and OR (More complex logic with groups):
->setEditButtonConditions([ 'groups' => [ [ 'conditions' => [ ['field' => 'name', 'operator' => '=', 'value' => 'rrrooo'], ['field' => 'price', 'operator' => '=', 'value' => '566'], ], 'group_operator' => 'AND', // Conditions within this group are ANDed ], [ 'conditions' => [ ['field' => 'stock', 'operator' => '>', 'value' => '100'], ['field' => 'category', 'operator' => '=', 'value' => 'Electronics'], ], 'group_operator' => 'OR', // Conditions within this group are ORed ], ], 'group_operator' => 'AND', // Groups themselves are ANDed together ])
This will evaluate like:
(name = 'rrrooo' AND price = '566')
OR
(stock > 100 OR category = 'Electronics')
The overall result will be true if either the AND group (name and price) is true AND the OR group (stock or category) is true.
Edit Callback Function
Instead of using setEditButtonCondition You can opt to use setEditButtonConditionCallback to provide your own callback
->setEditButtonConditionCallback(function ($row) { return $row['price'] > 500; })
Custom Add Form
->setCustomAddFormRenderer(function () { echo '<div class="mb-3"><label>Custom Field</label><input name="name" class="form-control" /></div>'; })
Custom Add Form Header/Title
->setCustomAddFormHeader("Add New Category")
Custom Edit Form
THe id Of Inputs Should have the datatable id passed eg dataTable_editModalprice
Where dataTable is the id of datatable
->setCustomEditFormRenderer(function () { echo '<div class="mb-3"><label>Custom Field</label><input id="dataTable_editModalprice" name="name" class="form-control" /></div>'; })
Custom Edit Form With Select
->setCustomEditFormRenderer(function () use ($categories) { echo '<div class="mb-3"> <label for="dataTable_editModalname">Product Name</label> <input id="dataTable_editModalname" name="name" class="form-control" /> </div>'; echo '<div class="mb-3"> <label for="dataTable_editModalprice">Price ($)</label> <input id="dataTable_editModalprice" name="price" class="form-control" /> </div>'; echo '<div class="mb-3"> <label for="dataTable_editModalcategory_id">Category</label> <select id="dataTable_editModalcategory_id" name="category_id" class="form-control"> <option value="">-- Select Category --</option>'; foreach ($categories as $cat) { echo '<option value="' . htmlspecialchars($cat['id']) . '">' . htmlspecialchars($cat['name']) . '</option>'; } echo ' </select> </div>'; })
Custom Edit Form Header/Title
->setCustomEditFormHeader("Edit Category")
Dialog Size
Add Dialog Size
->setAddDialogSize("modal-fullscreen")
Edit Dialog Size
->setEditDialogSize("modal-fullscreen")
Enable Search
$dataTable->searchable([ 'e.username' => ['type' => 'input', 'label' => 'Username', 'column' => 'username'], 'r.id' => ['type' => 'select', 'label' => 'Role', 'column' => 'id', 'options' => $roles, 'value_field' => 'id', 'label_field' => 'name'] ]);
Custom Columns Before Actions Columns
->addColumnBeforeActions('Status Icon', fn($row) => $row['active'] ? '๐ข' : '๐ด')
Custom Columns Before Actions Columns Without Being Escaped
->addColumnBeforeActions('Role', fn($row) => "<b>{$row['role']}</b>", raw: true)
Custom Columns Before Actions Columns With Callback Visibility
->addColumnBeforeActions( 'Secret', fn($row) => '๐ Secret!', raw: true, visibleWhen: fn($row) => $row['price'] > 1 && $row['name']==='RRR' )
Custom Columns Before Actions Columns With Boolean Visibility
->addColumnAfterActions( 'Secret Info', fn($row) => '๐ Secret!', raw: true, visibleWhen: fn($row) => true )
Custom Columns After Actions Columns
->addColumnAfterActions('Status Icon', fn($row) => $row['active'] ? '๐ข' : '๐ด')
Custom Columns After Actions Columns Without Being Escaped
->addColumnAfterActions('Role', fn($row) => "<b>{$row['role']}</b>", raw: true)
Custom Columns After Actions Columns With Callback Visibility
->addColumnAfterActions( 'Secret', fn($row) => '๐ Secret!', raw: true, visibleWhen: fn($row) => $row['price'] > 1 && $row['name']==='RRR' )
Custom Columns After Actions Columns With Boolean Visibility
->addColumnAfterActions( 'Secret Info', fn($row) => '๐ Secret!', raw: true, visibleWhen: fn($row) => true )
Data Transformation
->setRowDataTransformer(function($row) { if (!empty($row['id'])) { $row['name'] = strtoupper($row['name']); $row['role'] = strtoupper($row['name']); } if($row['price']>600){ $row['active'] =true; } $row['total_price'] = $row['price'] +1; return $row; })
Enable Pagination
$dataTable->enablePagination(10, ['username', 'role']);
๐ฅ Rendering the Table
$dataTable->renderDataTable($_GET['page'] ?? 1);
๐งผ Handling Form Submissions
$dataTable->handleRequest($_POST ?? []);
โ Example a Simple Workflow Without Joins
Columns to add and Columns to Edit support using both associative and indexed array
$dataDisplay = DataDisplay::create($entityManager, User::class); $dataDisplay ->valuesToSelect(["e.id", "e.name"]) ->columnToBeAdded([ "name" ]) ->columnsToBeEdited([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]); $dataDisplay->handleRequest($_POST ?? []); $dataDisplay->renderDataTable();
โ Example a Simple Workflow With Add Permission
$dataDisplay = DataDisplay::create($entityManager, User::class); $dataDisplay ->valuesToSelect(["e.id", "e.name"]) ->columnToBeAdded([ "name" ]) ->columnsToBeEdited([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ->setAddPermission(true) ->setDataTableButtons([ 'copy' => true, 'csv' => true, 'excel' => ['title' => 'Excel Export'], 'pdf' => [ 'title' => 'PDF Export', 'orientation' => 'landscape', 'pageSize' => 'A4', ], 'print' => ['title' => 'Printable View'], 'colvis' => ['text' => 'Toggle Columns'], ]);
โ Example a Simple Workflow With Datatable Buttons
$dataDisplay = DataDisplay::create($entityManager, User::class); $dataDisplay ->valuesToSelect(["e.id", "e.name"]) ->columnToBeAdded([ "name" ]) ->columnsToBeEdited([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ->setDataTableButtons([ 'copy' => true, 'csv' => true, 'excel' => ['title' => 'Excel Export'], 'pdf' => [ 'title' => 'PDF Export', 'orientation' => 'landscape', 'pageSize' => 'A4', ], 'print' => ['title' => 'Printable View'], 'colvis' => ['text' => 'Toggle Columns'], ]);
โ Example a Simple Workflow With Custom Add and Edit Form
$dataDisplay = DataDisplay::create($entityManager, User::class); $dataDisplay ->valuesToSelect(["e.id", "e.name"]) ->columnToBeAdded([ "name" ]) ->columnsToBeEdited([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ->setAddPermission(true) ->setCustomAddFormRenderer(function () { echo '<div class="mb-3"><label>Custom Field</label><input name="name" class="form-control" /></div>'; }) ->setCustomEditFormRenderer(function () { echo '<div class="mb-3"><label>Custom Field</label><input id="name" name="name" class="form-control" /></div>'; }) ->setDataTableButtons([ 'copy' => true, 'csv' => true, 'excel' => ['title' => 'Excel Export'], 'pdf' => [ 'title' => 'PDF Export', 'orientation' => 'landscape', 'pageSize' => 'A4', ], 'print' => ['title' => 'Printable View'], 'colvis' => ['text' => 'Toggle Columns'], ]); $dataDisplay->handleRequest($_POST ?? []); $dataDisplay->renderDataTable();
โ Example a Simple Workflow With Joins and Search Functionality
$categories = Category::getAllCategories($entityManager) ?? []; $dataDisplay = DataDisplay::create($entityManager, Product::class); $dataDisplay ->valuesToSelect(["e.id", "e.name", "e.price", "c.name AS category_name"]) ->columnToBeAdded([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Product Name", ], "price" => [ "type" => "input", "input_type" => "number", "label" => 'Price ($)', ], "category_id" => [ "type" => "select", "label" => "Category", "options" => $categories, "value_field" => "id", "label_field" => "name", ], ]) ->columnsToBeEdited([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], "price" => [ "type" => "input", "input_type" => "number", "label" => "Price", ], "category_id" => [ "type" => "select", "label" => "Category", "options" => $categories, "value_field" => "id", "label_field" => "name", ], ]) ->enablePagination(10, ["e.name", "e.id"]) ->searchable([ "category_id" => [ "type" => "select", "label" => "Category", "operator" => "=", "table" => "e", "column" => "category_id", "options" => $categories, "value_field" => "id", "label_field" => "name", ], ]) ->setAddButtonLabel("Create New Product") ->setTableId("dataTable") ->tablesToJoin([ [ "table" => "Category::class", "alias" => "c", "on" => "e.category_id = c.id", ], ]); $dataDisplay->handleRequest($_POST ?? []); $dataDisplay->renderDataTable();
โ Example a Simple Workflow With Custom Add and Edit Form
$categories = Category::getAllCategories($entityManager) ?? []; $dataDisplay = DataDisplay::create($entityManager, Product::class); $dataDisplay ->valuesToSelect(["e.id", "e.name", "e.price","e.category_id", "c.name AS category_name"]) ->columnToBeAdded([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Product Name", ], "price" => [ "type" => "input", "input_type" => "number", "label" => 'Price ($)', ], "category_id" => [ "type" => "select", "label" => "Category", "options" => $categories, "value_field" => "id", "label_field" => "name", ], ]) ->columnsToBeEdited([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], "price" => [ "type" => "input", "input_type" => "number", "label" => "Price", ], "category_id" => [ "type" => "select", "label" => "Category 1", "options" => $categories, "value_field" => "id", "label_field" => "name", ], ]) ->valuesToRender([ "id", "name", "price", "category_name" ]) ->setCustomAddFormHeader("Add New Category") ->setCustomEditFormHeader("Edit Category") ->setCustomEditFormRenderer(function () use ($categories) { echo '<div class="mb-3"> <label for="dataTable_editModalname">Product Name</label> <input id="dataTable_editModalname" name="name" class="form-control" /> </div>'; echo '<div class="mb-3"> <label for="dataTable_editModalprice">Price ($)</label> <input id="dataTable_editModalprice" name="price" class="form-control" /> </div>'; echo '<div class="mb-3"> <label for="dataTable_editModalcategory_id">Category</label> <select id="dataTable_editModalcategory_id" name="category_id" class="form-control"> <option value="">-- Select Category --</option>'; foreach ($categories as $cat) { echo '<option value="' . htmlspecialchars($cat['id']) . '">' . htmlspecialchars($cat['name']) . '</option>'; } echo ' </select> </div>'; }) ->setEditButtonConditionCallback(function ($row) { return $row['price'] > 100; }) ->searchable([ "category" => [ "type" => "select", "label" => "Category", "operator" => "=", "table" => "e", "column" => "category_id", "options" => $categories, "value_field" => "id", "label_field" => "name", ], ]) ->setAddButtonLabel("Create New Product") ->setTableId("dataTable") ->tablesToJoin([ [ "table" => Category::class, "alias" => "c", "on" => "e.category_id = c.id", ], ]) ->setDataTableButtons([ 'copy' => true, 'csv' => ['title' => 'Exported CSV'], 'excel' => ['title' => 'Excel Export'], 'pdf' => [ 'title' => 'PDF Export', 'orientation' => 'landscape', 'pageSize' => 'A4', ], 'print' => ['title' => 'Printable View'], 'colvis' => ['text' => 'Toggle Columns'], ]); $dataDisplay->handleRequest($_POST ?? []); $dataDisplay->renderDataTable();
โ Example a Simple Workflow With Data Transformation,Joins and Custom Columns
$categories = Category::getAllCategories($entityManager) ?? []; $dataDisplay = DataDisplay::create($entityManager, Product::class); $dataDisplay ->valuesToSelect(["e.id", "e.name", "e.price","e.category_id", "c.name AS category_name"]) ->columnToBeAdded([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Product Name", ], "price" => [ "type" => "input", "input_type" => "number", "label" => 'Price ($)', ], "category_id" => [ "type" => "select", "label" => "Category", "options" => $categories, "value_field" => "id", "label_field" => "name", ], ]) ->columnsToBeEdited([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], "price" => [ "type" => "input", "input_type" => "number", "label" => "Price", ], "category_id" => [ "type" => "select", "label" => "Category 1", "options" => $categories, "value_field" => "id", "label_field" => "name", ], ]) ->valuesToRender([ "id", "name", "price", "category_name" ]) ->setRowDataTransformer(function($row) { if (!empty($row['id'])) { $row['name'] = strtoupper($row['name']); $row['role'] = strtoupper($row['name']); } if($row['price']>600){ $row['active'] =true; } $row['total_price'] = $row['price'] +1; return $row; }) ->addColumnAfterActions('Status Icon', fn($row) => $row['active'] ? '๐ข' : '๐ด') ->addColumnBeforeActions('Role', fn($row) => "<b>{$row['role']}</b>", raw: true) ->addColumnAfterActions( 'Secret Info', fn($row) => '๐ Secret!', raw: true, visibleWhen: fn($row) => true ) ->addColumnAfterActions( 'Secret', fn($row) => '๐ Secret!', raw: true, visibleWhen: fn($row) => $row['price'] > 1 && $row['name']==='RRR' ) ->tablesToJoin([ [ "table" => Category::class, "alias" => "c", "on" => "e.category_id = c.id", ], ]);
โ Example a Simple Workflow With Classes For Data Fetching
$dataDisplay = DataDisplay::create(null, Category::class,DataSourceType::CLASSES); $dataDisplay ->setClassFetchDataFunction("all") ->columnToBeAdded([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ->columnsToBeEdited([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ->valuesToRender(["id", "name"]) ->searchable([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ; $dataDisplay->handleRequest($_POST ?? []); $dataDisplay->renderDataTable();
โ Example a Simple Workflow With Report Mode
$dataDisplay = DataDisplay::create(null, Category::class,DataSourceType::CLASSES); $dataDisplay ->setClassFetchDataFunction("all") ->setMode("report") ->columnToBeAdded([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ->columnsToBeEdited([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ->valuesToRender(["id", "name"]) ->searchable([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ->setCustomAddAction("/test") ->setCustomEditAction("/admin") ; $dataDisplay->handleRequest($_POST ?? []); $dataDisplay->renderDataTable();
โ Example a Simple Workflow With Dialog Size
$dataDisplay = DataDisplay::create(null, Category::class,DataSourceType::CLASSES); $dataDisplay ->setClassFetchDataFunction("all") ->setAddDialogSize("modal-fullscreen") ->setEditDialogSize("modal-fullscreen") ->columnToBeAdded([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ->columnsToBeEdited([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ->valuesToRender(["id", "name"]) ->searchable([ "name" => [ "type" => "input", "input_type" => "text", "label" => "Name", ], ]) ->setCustomAddAction("/test") ->setCustomEditAction("/admin") ; $dataDisplay->handleRequest($_POST ?? []); $dataDisplay->renderDataTable();
UPDATING DATABASE schema
php bin/doctrine orm:schema-tool:update --force --dump-sql