This commit is contained in:
nikhil 2018-07-06 15:17:29 +05:30
parent c9c090ea2b
commit eb39d93241
13 changed files with 14883 additions and 2 deletions

View File

@ -211,7 +211,9 @@ return [
'Storage' => Illuminate\Support\Facades\Storage::class,
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class
'View' => Illuminate\Support\Facades\View::class,
'Datagrid' => Webkul\Ui\DataGrid\Facades\DataGrid::class
],
];

14082
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,77 @@
<?php
namespace Webkul\Admin\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use Webkul\Ui\DataGrid\Facades\DataGrid;
/**
* DataGrid controller
*
* @author Nikhil Malik <nikhil@webkul.com> @ysmnikhil
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class DataGridController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
DataGrid::make([
'name' => 'admin',
'select' => 'a.id',
'table' => 'admins as a',
'join' => [
[
'join' => 'leftjoin',
'table' => 'roles as r',
'primaryKey' => 'a.role_id',
'condition' => '=',
'secondryKey' => 'r.id',
]
],
'columns' => [
[
'name' => 'a.id as aila',
'type' => 'string',
'label' => 'Id',
'sortable' => true,
],
[
'name' => 'a.name',
'type' => 'string',
'label' => 'Name',
'sortable' => true,
'filterable' => false,
// will create on run time query
// 'filter' => [
// 'function' => 'where', // andwhere
// 'condition' => ['u.user_id', '=', '1'] // multiarray
// ],
'attributes' => [
'class' => 'class-a class-b',
'data-attr' => 'whatever you want',
'onclick' => "window.alert('alert from datagrid column')"
],
'wrapper' => function($value, $object){
return '<a href="'.$value.'">' . $object->name . '</a>';
},
]
],
// 'css' => []
]);
$result = DataGrid::render();
// dump($result);
// dd('datagrid');
return $result;
}
}

View File

@ -18,6 +18,8 @@ Route::group(['middleware' => ['web']], function () {
Route::get('/dashboard', 'Webkul\Admin\Http\Controllers\DashboardController@index')->name('admin.dashboard.index');
Route::get('/datagrid', 'Webkul\Admin\Http\Controllers\DataGridController@index')->name('admin.datagrid.index');
Route::get('/users', 'Webkul\User\Http\Controllers\UserController@index')->defaults('_config', [
'view' => 'admin::users.index'
])->name('admin.users.index');

View File

@ -0,0 +1,369 @@
<?php
namespace Webkul\Ui\DataGrid;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\DB;
use Webkul\Ui\DataGrid\Helpers\Column;
use Webkul\Ui\DataGrid\Helpers\Pagination;
use Webkul\Ui\DataGrid\Helpers\Css;
class DataGrid
{
/**
* Name of DataGrid
*
* @var string
*/
protected $name;
/**
* select from table(s)
*
* @var string
*/
protected $select;
/**
* Table
*
* @var String Classs name $table
*/
protected $table;
/**
* Join
*
* @var Array name $join
*
* [
* 'join' => 'left',
* 'table' => 'posts',
* 'primaryKey' => 'user.id',
* 'condition' => '=',
* 'secondryKey' => 'posts.user_id',
* 'callback' => 'not supported yet'
* ]
*/
protected $join;
/**
* Collection Object of Column $columns
*
* @var Collection
*/
protected $columns;
/**
* Pagination $pagination
*
* @var Pagination
*/
protected $pagination;
/**
* Css $css
*
* @var Css
*/
protected $css;
/*
public function __construct(
$name = null ,
$table = null ,
array $join = [],
Collection $columns = null,
Pagination $pagination = null
){
$this->make(
$name,
$table,
$join,
$columns,
$pagination
);
return $this;
}
*/
public function make($args){
// list($name, $select, $table, $join, $columns) = array_values($args);
$name = $select = $table = false;
$join = $columns = $css = [];
extract($args);
return $this->build($name, $select, $table, $join, $columns, $css);
}
public function build(
$name = null,
$select = false,
$table = null,
array $join = [],
array $columns = null,
array $css = [],
Pagination $pagination = null
){
$this->request = Request::capture();
$this->setName($name);
$this->setSelect($select);
$this->setTable($table);
$this->setJoin($join);
$this->addColumns($columns, true);
$this->setCss($css);
// $this->addPagination($pagination);
return $this;
}
/**
* Set Name.
*
* @return $this
*/
public function setName(string $name)
{
$this->name = $name ?: 'Default' . time();
return $this;
}
/**
* Set Select.
*
* @return $this
*/
public function setSelect($select)
{
$this->select = $select ?: false;
return $this;
}
/**
* Add Columns.
*
* @return $this
*/
public function setTable(string $table)
{
$this->table = $table ?: false;
return $this;
}
/**
* Add Columns.
*
* @return $this
*/
public function setJoin(array $join)
{
$this->join = $join ?: [];
return $this;
}
private function setCss($css = [])
{
$this->css = new Css($css);
return $this->css;
}
/**
* Add Columns.
*
* @return $this
*/
public function addColumns($columns = [], $reCreate = false)
{
if($reCreate) $this->columns = new Collection();
if($columns){
foreach($columns as $column){
$this->addColumn($column);
}
}
return $this;
}
/**
* Add Column.
*
* @return $this
*/
public function addColumn($column = [])
{
if($column instanceof Column){
$this->columns->push($column);
}elseif(gettype($column) == 'array' && $column){
$this->columns->push(new Column($column, $this->request));
}else{
throw new \Exception("DataGrid: Add Column argument is not valid!");
}
return $this;
}
/**
* Add ColumnMultiple.
*
* @return $this
*/
private function addColumnMultiple($column = [], $multiple = false)
{
if($column instanceof Column){
if($multiple){
if($this->columns->offsetExists($column->getName()))
$this->columns->offsetSet($column->getName(). time(), $column);
else
$this->columns->offsetSet($column->getName(), $column);
}else{
$this->columns->offsetSet($column->getName(), $column);
}
}elseif(gettype($column) == 'array' && $column){
$columnObj = new Column($column);
if($multiple){
if($this->columns->offsetExists($columnObj->getName()))
$this->columns->offsetSet($columnObj->getName(). time(), $columnObj);
else
$this->columns->offsetSet($columnObj->getName(), $columnObj);
}else{
$this->columns->offsetSet($columnObj->getName(), $columnObj);
}
}else{
throw new \Exception("DataGrid: Add Column argument is not valid!");
}
return $this;
}
/**
* Add Pagination.
*
* @return $this
*/
public function addPagination($pagination = [])
{
if($pagination instanceof Pagination){
$this->pagination = $pagination;
}elseif(gettype($pagination) == 'array' && $pagination){
$this->pagination = new Pagination($pagination);
}else{
throw new \Exception("DataGrid: Pagination argument is not valid!");
}
return $this;
}
private function getSelect()
{
$select = [];
foreach($this->columns as $column){
$select[] = $column->name;
}
$this->query->select(...$select);
if($this->select) $this->query->addselect($this->select);
}
/**
* ->join('contacts', 'users.id', '=', 'contacts.user_id')
*/
private function getQueryWithJoin()
{
foreach($this->join as $join){
$this->query->{$join['join']}($join['table'], $join['primaryKey'], $join['condition'], $join['secondryKey']);
}
}
private function getQueryWithColumnFilters()
{
foreach($this->columns as $column){
if($column->filter){
if (count($column->filter['condition']) == count($column->filter['condition'], COUNT_RECURSIVE)){
$this->query->{$column->filter['function']}(current($column->filter['condition']));
}else{
if(count($column->filter['condition']) == 3)
$this->query->{$column->filter['function']}(
extract(
array_combine(
// ['key', 'condition', 'value'],
array_fill( //will work with all kind of where conditions
0,
( count( $column->filter['condition']) - 1 ),
'array_fill_nikhil'.time()
),
$column->filter['condition']
)
)
);
}
}
}
}
private function getQueryWithFilters(){
foreach($this->columns as $column){
dd($this->request);
if($column->filterable){
if ($filter = $this->request->offsetGet($column->correct(false))){
if($condition = $this->request->offsetGet($column->correct(false).'.condition')){
$this->query->andwhere(
$this->correct(false),
$condition,
$filter
);
}
}
}
}
$query = ['sort' => $this->correct(false)];
if(($sort = $this->request->offsetGet('sort')) && $sort == $this->correct(false)){
if(!$order = $this->request->offsetGet('order')){
$query['order'] = self::ORDER_DESC;
}else{
$query['order'] = ($order == self::ORDER_DESC ? self::ORDER_ASC : self::ORDER_DESC);
}
}else{
$query['order'] = self::ORDER_DESC;
}
return '?'.http_build_query(array_merge($this->request->query->all(), $query));
}
private function getDbQueryResults()
{
$this->query = DB::table($this->table);
$this->getSelect();
$this->getQueryWithJoin();
$this->getQueryWithColumnFilters();
$this->getQueryWithFilters();
dd($this->query);
$this->results = $this->query->get();
return $this->results;
}
/**
* @return view
*/
public function render()
{
$this->getDbQueryResults();
dump($this->columns);
return view('ui::datagrid.index', [
'css' => $this->css,
'results' => $this->results,
'columns' => $this->columns,
]);
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Webkul\Ui\DataGrid\Facades;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Facade;
class DataGrid extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'datagrid';
}
}

View File

@ -0,0 +1,101 @@
<?php
namespace Webkul\Ui\DataGrid\Helpers;
abstract class AbstractFillable
{
const NO_RESULT = null;
protected $fillable = [];
abstract protected function setFillable();
public function __construct($args)
{
$error = false;
$this->setFillable();
foreach ($args as $key => $value){
$this->{$key} = $value;
// switch($value){
// case (in_array(gettype($value), ["array", "object", "function"])):
// $error = $this->fieldValidate(
// $key,
// $value,
// [$this->fillable[$key]['allowed']]
// );
// break;
// default:
// $error = $this->fieldValidate(
// $key,
// $value
// );
// }
// if($error) throw new \Exception($error);
}
// foreach($this->fillable as $fill){
// if(isset($args[$fill])){
// $this->{$fill} = [$args[$fill]];
// }
// }
}
private function fieldValidate($key, $value, $allowed = ['string', 'integer', 'float', "boolean"], $merge = false)
{
$error = false;
if( in_array($key, $this->fillable) ||
array_filter(
array_keys($this->fillable) , function($value){
return gettype($value) === "string";
}
)
){
if(in_array(gettype($value), $allowed)){
// if($merge){
// if(!$this->{$key}) $this->{$key} = [];
// $this->{$key}[] = $value;
// }else
// $this->{$key} = $value;
}else{
dump(gettype($value));
dump($value);
$error = 'Allowed params are not valid as per allowed condition! Key - ' . $key;
}
}else{
dump(in_array($key, $this->fillable));
dump($value);
$error = 'Not Allowed field! Key - ' . $key;
}
return $error ?: false;
}
public function __set($key, $value){
$error = false;
switch('$value'){ //no need to match this
case (in_array(gettype($value), ["array", "object", "function"])):
$error = $this->fieldValidate(
$key,
$value,
[$this->fillable[$key]['allowed']]
);
break;
default:
$error = $this->fieldValidate(
$key,
$value
);
break;
}
if($error) throw new \Exception($error);
$this->{$key} = $value;
}
public function __get($key){
if(in_array($key, $this->fillable)){
return property_exists($this, $key) ? $this->{$key} : false;
}else
return self::NO_RESULT;
}
}

View File

@ -0,0 +1,127 @@
<?php
namespace Webkul\Ui\DataGrid\Helpers;
use Illuminate\Http\Request;
class Column extends AbstractFillable
{
const SORT = 'sort';
const ORDER_DESC = 'DESC';
const ORDER_ASC = 'ASC';
private $request = null;
private $readableName = false;
private $value = false;
private $sortHtml = '<a href="%s">%s</a>';
// protected $name;
// protected $type;
// protected $label;
// protected $filterable;
// protected $sortable;
// protected $attributes;
// protected $wrapper;
// protected $callback;
/**
* Without Array it will treat it like string
*
* [
* 'name',
* 'Name',
* true,
* filter => [
* 'function' => 'where', // andwhere
* 'condition' => ['u.user_id', '=', '1'] // multiarray
* ],
* attributes => [
* 'class' => 'class-a, class-b',
* 'data-attr' => 'whatever you want',
* 'onlclick' => "window.alert('alert from datagrid column')"
* ],
* wrapper => function($value){
* return '<a href="'.$value.'">Nikhil</a>';
* },
* ]
*/
protected function setFillable(){
$this->fillable = [
'name',
'type',
'label',
'sortable',
'filterable',
'filter' => [
'allowed' => 'array',
],
'attributes' => [
'allowed' => 'array',
'validation' => 'FUTURE'
],
'wrapper' => [
// 'allowed' => 'function'
'allowed' => 'object'
],
'callback' => [
'allowed' => 'function'
]
];
}
public function __construct($args, $request = null){
parent::__construct($args);
$this->request = $request ?: Request::capture();
}
private function correct($tillDot = true){
$as = explode('as', $this->name);
if(count($as) > 1) return trim(end($as));
if(!$tillDot) return $this->name;
$dot = explode('.', $this->name);
if($dot) return trim(end($dot));
}
private function wrap($obj){
if($this->wrapper && is_callable($this->wrapper)){
$this->value = call_user_func($this->wrapper, $this->value, $obj);
}
}
private function sortingUrl(){
$query = ['sort' => $this->correct(false)];
if(($sort = $this->request->offsetGet('sort')) && $sort == $this->correct(false)){
if(!$order = $this->request->offsetGet('order')){
$query['order'] = self::ORDER_DESC;
}else{
$query['order'] = ($order == self::ORDER_DESC ? self::ORDER_ASC : self::ORDER_DESC);
}
}else{
$query['order'] = self::ORDER_DESC;
}
return '?'.http_build_query(array_merge($this->request->query->all(), $query));
}
/**
* need to process xss check on properties like label shouln't include <script>alert('Kaboom!')</script>
*/
public function sorting(){
if($this->sortable){
return vsprintf($this->sortHtml, [$this->sortingUrl(), $this->label]);
}else{
return $this->label;
}
}
public function render($obj){
if(property_exists($obj, ( $this->readableName = $this->correct()) ) ){
$this->value = $obj->{$this->readableName};
$this->wrap($obj);
}
return $this->value;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Webkul\Ui\DataGrid\Helpers;
class Css extends AbstractFillable
{
const NO_RESULT = 'no-class';
protected $datagrid = 'datagrid';
protected $table = 'table';
protected $thead = 'thead';
protected $thead_td = 'thead_td';
protected $tbody = 'tbody';
protected $tbody_td = 'tbody_td';
protected function setFillable(){
$this->fillable = [
'datagrid',
'table',
'thead',
'thead_td',
'tbody',
'tbody_td',
];
}
public function __construct($args){
parent::__construct($args);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Webkul\Ui\DataGrid\Helpers;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
class Pagination extends Paginator
{
const LIMIT = 20;
const OFFSET = 0;
const VIEW = '';
public function __construct(
int $limit = null,
int $offset = null,
int $view = null
){
$this->limit = $limit ?: self::LIMIT;
$this->offset = $offset ?: self::OFFSET;
$this->view = $view ?: self::VIEW;
parent::__construct([
], 20);
}
}

View File

@ -24,7 +24,6 @@ class UiServiceProvider extends ServiceProvider
Paginator::defaultView('ui::partials.pagination');
Paginator::defaultSimpleView('ui::partials.pagination');
}
/**
@ -34,5 +33,6 @@ class UiServiceProvider extends ServiceProvider
*/
public function register()
{
$this->app->bind('datagrid', 'Webkul\Ui\DataGrid\DataGrid');
}
}

View File

@ -0,0 +1,18 @@
<div class="{{ $css->datagrid }}">
<table class="{{ $css->table }}">
<thread class="{{ $css->thread }}">
<tr>
@foreach ($columns as $column)
<td class="{{ $css->thead_td }}">{{ $column->lable }}</td>
@endforeach
</tr>
</thread>
<tbody class="{{ $css->tbody }}">
<tr>
@foreach ($results as $result)
<td class="{{ $css->tbody_td }}">{{ $result->{$columns[$loop->index]->name} }}</td>
@endforeach
</tr>
</tbody>
</table>
</div>

View File

@ -0,0 +1,28 @@
<div class="{{ $css->datagrid }}">
<div class="{{ $css->filter }}">
Filtering Will be here
</div>
<table class="{{ $css->table }}">
<thead class="{{ $css->thead }}">
<tr>
@foreach ($columns as $column)
<td class="{{ $css->thead_td }}">{!! $column->sorting() !!}</td>
@endforeach
</tr>
</thead>
<tbody class="{{ $css->tbody }}">
<tr>
@foreach ($results as $result)
@foreach ($columns as $column)
<td class="{{ $css->tbody_td }}">{!! $column->render($result) !!}</td>
@endforeach
@endforeach
</tr>
</tbody>
</table>
<div class="{{ $css->pagination }}">
Pagination Will be here
</div>
</div>