├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── composer.json ├── jqGrid.png ├── phpunit.xml ├── public └── .gitkeep ├── src ├── Mgallegos │ └── LaravelJqgrid │ │ ├── Encoders │ │ ├── JqGridJsonEncoder.php │ │ └── RequestedDataInterface.php │ │ ├── Exceptions │ │ ├── JsonEncodingMaxDepthException.php │ │ ├── JsonEncodingStateMismatchException.php │ │ ├── JsonEncodingSyntaxErrorException.php │ │ ├── JsonEncodingUnexpectedControlCharException.php │ │ └── JsonEncodingUnknownException.php │ │ ├── Facades │ │ ├── GridEncoder.php │ │ └── GridRender.php │ │ ├── LaravelJqgridServiceProvider.php │ │ ├── Renders │ │ ├── JqGridRender.php │ │ ├── RenderInterface.php │ │ └── Validations │ │ │ ├── ColModel │ │ │ └── NameValidation.php │ │ │ ├── FilterToolbar │ │ │ └── .gitkeep │ │ │ ├── GridOptions │ │ │ └── .gitkeep │ │ │ ├── Navigator │ │ │ └── .gitkeep │ │ │ └── PropertyValidatorInterface.php │ │ └── Repositories │ │ ├── EloquentRepositoryAbstract.php │ │ └── RepositoryInterface.php ├── config │ ├── .gitkeep │ └── config.php ├── lang │ └── .gitkeep ├── migrations │ └── .gitkeep └── views │ └── .gitkeep └── tests └── .gitkeep /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | .project 3 | .buildpath 4 | .settings 5 | composer.phar 6 | composer.lock 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | 8 | before_script: 9 | - curl -s http://getcomposer.org/installer | php 10 | - php composer.phar install --dev 11 | 12 | script: phpunit -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | All LaravelJqGrid code is Copyright (c) 2013 by the original authors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel jqGrid package 2 | 3 | [![Latest Stable Version](https://poser.pugx.org/mgallegos/laravel-jqgrid/v/stable.png)](https://packagist.org/packages/mgallegos/laravel-jqgrid) [![Total Downloads](https://poser.pugx.org/mgallegos/laravel-jqgrid/downloads.png)](https://packagist.org/packages/mgallegos/laravel-jqgrid) 4 | 5 | Laravel jqGrid package allows you to easily integrate the popular jQuery Grid Plugin (jqGrid) into your Laravel application. 6 | 7 | ![Image](https://raw.github.com/mgallegos/laravel-jqgrid/master/jqGrid.png) 8 | 9 | ## Requirements 10 | 11 | * [Laravel 4, 5, 6, 7 or 8 Framework](http://laravel.com/docs/installation) 12 | * [jQuery v2.0.0 or later](http://jquery.com/) 13 | * [Your choice of a jQuery UI theme](http://jqueryui.com/themeroller/#themeGallery) 14 | * [Free JGrid Plugin](https://github.com/free-jqgrid/jqGrid) or [jQuery Grid Plugin](http://www.trirand.com/blog/) 15 | 16 | ## Features 17 | 18 | * Spreadsheet Exporter. 19 | * CSV Exporter. 20 | * Config file with global properties to use in all grids of your application. 21 | * PHP Render to handle the jqGrid HTML and Javascript code. 22 | * JSON Data Enconder to send the data to the grid in the correct format. 23 | * Datasource independent (you are able to create your own datasource implementation). 24 | 25 | ## Documentation 26 | 27 | The complete documentation can be found at: [mariogallegos.com](http://goo.gl/Krn7o7) 28 | 29 | ## Live Demos 30 | 31 | There are three demos available: 32 | 33 | * Pivot Grid(Not available) 34 | * CRUD Web App with jqGrid forms(Not available) 35 | * [CRUD Web App with a custom form](http://www.mariogallegos.com/cms/open-source-development/laravel-jqgrid/demo3) 36 | 37 | ## Tutorials 38 | 39 | There are three tutorials available: 40 | 41 | * Building a Pivot Grid and handling jqGrid events using Laravel jqGrid package(Not available) 42 | * Building a CRUD Web App with jqGrid forms using Laravel jqGrid package(Not available) 43 | * [Building a CRUD Web App with a custom form using Laravel jqGrid package](http://www.mariogallegos.com/cms/tutorials) 44 | 45 | ## Aditional information 46 | 47 | Any questions, problems or feature request feel free to open an [issue](https://github.com/mgallegos/laravel-jqgrid/issues). 48 | 49 | 50 | ## License 51 | 52 | Laravel jqGrid package is open source software licensed under the MIT License. 53 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mgallegos/laravel-jqgrid", 3 | "description": "Laravel jqGrid package allows you to easily integrate the popular jQuery Grid Plugin (jqGrid) into your Laravel application.", 4 | "keywords": ["laravel", "jquery", "jqgrid", "grid"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Mario Gallegos", 9 | "email": "freelance@mariogallegos.com" 10 | } 11 | ], 12 | "require": { 13 | "php": ">=5.3.0", 14 | "illuminate/support": "4.*|5.*|6.*|7.*|8.*|9.*|10.*|11.*|12.*", 15 | "phpoffice/phpspreadsheet": "^1.8" 16 | }, 17 | "autoload": { 18 | "classmap": [ 19 | "src/migrations" 20 | ], 21 | "psr-0": { 22 | "Mgallegos\\LaravelJqgrid": "src/" 23 | } 24 | }, 25 | "minimum-stability": "dev" 26 | } 27 | -------------------------------------------------------------------------------- /jqGrid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgallegos/laravel-jqgrid/afcb0331512926a22fdc4308a9d3b242d193c807/jqGrid.png -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgallegos/laravel-jqgrid/afcb0331512926a22fdc4308a9d3b242d193c807/public/.gitkeep -------------------------------------------------------------------------------- /src/Mgallegos/LaravelJqgrid/Encoders/JqGridJsonEncoder.php: -------------------------------------------------------------------------------- 1 | '; 175 | break; 176 | case 'ge': //greater or equal 177 | $filter['op'] = '>='; 178 | break; 179 | case 'bw': //begins with 180 | $filter['op'] = 'like'; 181 | $filter['data'] = $filter['data'] . '%'; 182 | break; 183 | case 'bn': //does not begin with 184 | $filter['op'] = 'not like'; 185 | $filter['data'] = $filter['data'] . '%'; 186 | break; 187 | case 'in': //is in 188 | $filter['op'] = 'is in'; 189 | break; 190 | case 'ni': //is not in 191 | $filter['op'] = 'is not in'; 192 | break; 193 | case 'ew': //ends with 194 | $filter['op'] = 'like'; 195 | $filter['data'] = '%' . $filter['data']; 196 | break; 197 | case 'en': //does not end with 198 | $filter['op'] = 'not like'; 199 | $filter['data'] = '%' . $filter['data']; 200 | break; 201 | case 'cn': //contains 202 | $filter['op'] = 'like'; 203 | $filter['data'] = '%' . str_replace(' ', '%', $filter['data']) . '%'; 204 | break; 205 | case 'cnpg': //contains PostgreSQL 206 | $filter['op'] = 'ilike'; 207 | $filter['data'] = '%' . str_replace(' ', '%', $filter['data']) . '%'; 208 | break; 209 | case 'nc': //does not contains 210 | $filter['op'] = 'not like'; 211 | $filter['data'] = '%' . $filter['data'] . '%'; 212 | break; 213 | case 'nu': //is null 214 | $filter['op'] = 'is null'; 215 | $filter['data'] = ''; 216 | break; 217 | case 'nn': //is not null 218 | $filter['op'] = 'is not null'; 219 | $filter['data'] = ''; 220 | break; 221 | case 'btw': //between 222 | $filter['op'] = 'between'; 223 | break; 224 | } 225 | } 226 | } 227 | else 228 | { 229 | $filters['rules'] = array(); 230 | } 231 | 232 | $Repository->beforeProcessing(); 233 | 234 | $count = $Repository->getTotalNumberOfRows($filters['rules']); 235 | 236 | if(empty($limit)) 237 | { 238 | $limit = $count; 239 | } 240 | 241 | if(!is_int($count)) 242 | { 243 | throw new Exception('The method getTotalNumberOfRows must return an integer'); 244 | } 245 | 246 | if( $count > 0 ) 247 | { 248 | $totalPages = ceil($count/$limit); 249 | } 250 | else 251 | { 252 | $totalPages = 0; 253 | } 254 | 255 | if ($page > $totalPages) 256 | { 257 | $page = $totalPages; 258 | } 259 | 260 | if ($limit < 0 ) 261 | { 262 | $limit = 0; 263 | } 264 | 265 | $start = $limit * $page - $limit; 266 | 267 | if ($start < 0) 268 | { 269 | $start = 0; 270 | } 271 | 272 | $limit = $limit * $page; 273 | 274 | if(empty($postedData['pivotRows'])) 275 | { 276 | $rows = $Repository->getRows($limit, $start, $sidx, $sord, $filters['rules'], $nodeId, $nodeLevel, $exporting); 277 | 278 | if($encodeRowsToUtf8) 279 | { 280 | $rows = $this->utf8ize($rows); 281 | } 282 | 283 | if($count < count($rows)) 284 | { 285 | $count = count($rows); 286 | } 287 | } 288 | else 289 | { 290 | $rows = json_decode($postedData['pivotRows'], true); 291 | } 292 | 293 | if(!is_array($rows) || (isset($rows[0]) && !is_array($rows[0]))) 294 | { 295 | throw new Exception('The method getRows must return an array of arrays, example: array(array("column1" => "1-1", "column2" => "1-2"), array("column1" => "2-1", "column2" => "2-2"))'); 296 | } 297 | 298 | if($exporting) 299 | { 300 | $method_name = 'export_to_'.$postedData['exportFormat']; 301 | 302 | if(method_exists($Repository, $method_name) ) 303 | { 304 | return $Repository->$method_name( 305 | array_merge( 306 | ['rows'=> $rows], 307 | ['postedData'=> $postedData] 308 | ) 309 | ); 310 | } 311 | 312 | $this->setSpreadsheetStyles(); 313 | 314 | $StreamedResponse = new StreamedResponse(); 315 | $StreamedResponse->setCallback(function () use (&$rows, $postedData) 316 | { 317 | 318 | // foreach (json_decode($postedData['fileProperties'], true) as $key => $value) 319 | // { 320 | // $method = 'set' . ucfirst($key); 321 | 322 | // $Excel->$method($value); 323 | // } 324 | 325 | $groupingView = json_decode($postedData['groupingView'], true); 326 | $groupHeaders = json_decode($postedData['groupHeaders'], true); 327 | $columnsPositions = $summaryTypes = $modelLabels = $modelSelectFormattersValues = $modelNumberFormatters = $modelDateFormatters = $numericColumns = $textColumns = array(); 328 | $groupFieldName = ''; 329 | $columnCounter = 0; 330 | $Spreadsheet = new Spreadsheet(); 331 | $Worksheet = $Spreadsheet->getActiveSheet(); 332 | 333 | foreach (json_decode($postedData['model'], true) as $a => $model) 334 | { 335 | $styles = array(); 336 | $formatCode = ''; 337 | $isVisible = false; 338 | 339 | if(!empty($groupingView) && $groupingView['groupField'][0] == $model['name']) 340 | { 341 | if(isset($model['hidden']) && $model['hidden'] === true) 342 | { 343 | $groupFieldHidden = true; 344 | } 345 | else 346 | { 347 | $groupFieldHidden = false; 348 | } 349 | 350 | $groupFieldName = $model['name']; 351 | 352 | if(isset($model['label'])) 353 | { 354 | $groupFieldLabel = $model['label']; 355 | } 356 | else 357 | { 358 | $groupFieldLabel = $model['name']; 359 | } 360 | } 361 | 362 | if(isset($model['hidden']) && $model['hidden'] !== true) 363 | { 364 | $columnCounter++; 365 | 366 | $isVisible = true; 367 | $columnsPositions[$model['name']] = $columnCounter; 368 | } 369 | 370 | if(isset($model['hidedlg']) && $model['hidedlg'] === true) 371 | { 372 | continue; 373 | } 374 | 375 | if(isset($model['summaryType'])) 376 | { 377 | $summaryTypes[isset($model['label']) ? $model['label'] : $model['name']] = $model['summaryType']; 378 | } 379 | 380 | if($model['hidden'] === false || $model['name'] == $groupFieldName) 381 | { 382 | if(isset($model['label'])) 383 | { 384 | $modelLabels[$model['name']] = $model['label']; 385 | } 386 | else 387 | { 388 | $modelLabels[$model['name']] = $model['name']; 389 | } 390 | } 391 | 392 | if(isset($model['formatter'])) 393 | { 394 | switch ($model['formatter']) 395 | { 396 | case 'select': 397 | if(isset($model['editoptions']['value'])) 398 | { 399 | foreach (explode(';', $model['editoptions']['value']) as $index => $value) 400 | { 401 | $temp = explode(':', $value); 402 | 403 | $modelSelectFormattersValues[isset($model['label']) ? $model['label'] : $model['name']][$temp[0]] = $temp[1]; 404 | } 405 | } 406 | 407 | break; 408 | case 'integer': 409 | $formatCode = '0'; 410 | // $modelNumberFormatters[$model['name']] = '0'; 411 | 412 | array_push($numericColumns, isset($model['label']) ? $model['label'] : $model['name']); 413 | 414 | break; 415 | case 'number': 416 | case 'currency': 417 | if(isset($model['formatoptions']['prefix'])) 418 | { 419 | // $prefix = $model['formatoptions']['prefix']; 420 | 421 | $formatCode = '"' . $model['formatoptions']['prefix'] . '"#,##0.00'; 422 | } 423 | else 424 | { 425 | // $prefix = ''; 426 | $formatCode = '#,##0.00'; 427 | } 428 | 429 | // $formatCode = '"' . $prefix . '"#,##0.00'; 430 | // $modelNumberFormatters[$model['name']] = '"' . $prefix . '"#,##0.00'; 431 | 432 | array_push($numericColumns, isset($model['label']) ? $model['label'] : $model['name']); 433 | 434 | break; 435 | case 'date': 436 | if((isset($model['formatoptions']['srcformat']) || $postedData['srcDateFormat']) && (isset($model['formatoptions']['newformat']) || $postedData['newDateFormat'])) 437 | { 438 | if(isset($model['formatoptions']['srcformat'])) 439 | { 440 | $srcformat = $model['formatoptions']['srcformat']; 441 | } 442 | else 443 | { 444 | $srcformat = $postedData['srcDateFormat']; 445 | } 446 | 447 | if(isset($model['formatoptions']['newformat'])) 448 | { 449 | $newformat = $model['formatoptions']['newformat']; 450 | } 451 | else 452 | { 453 | $newformat = $postedData['newDateFormat']; 454 | } 455 | 456 | // $modelDateFormatters[$model['name']] = array('srcformat' => $srcformat, 'newformat' => $newformat); 457 | $modelDateFormatters[isset($model['label']) ? $model['label'] : $model['name']] = array('srcformat' => $srcformat, 'newformat' => $newformat); 458 | } 459 | 460 | break; 461 | } 462 | } 463 | 464 | if (isset($model['align']) && isset($model['hidden']) && $model['hidden'] !== true) 465 | { 466 | switch ($model['align']) { 467 | case 'left': 468 | $styles = array_merge($styles, $this->styleAlignmentLeft); 469 | break; 470 | case 'right': 471 | $styles = array_merge($styles, $this->styleAlignmentRight); 472 | break; 473 | case 'center': 474 | $styles = array_merge($styles, $this->styleAlignmentCenter); 475 | break; 476 | default: 477 | # code... 478 | break; 479 | } 480 | } 481 | 482 | if($isVisible) 483 | { 484 | $letter = $this->numToLetter($columnCounter, true); 485 | 486 | if(!empty($styles)) 487 | { 488 | $Worksheet->getStyle($letter . ':' . $letter)->applyFromArray($styles); 489 | } 490 | 491 | if(!empty($formatCode)) 492 | { 493 | $Worksheet->getStyle($letter . ':' . $letter) 494 | ->getNumberFormat() 495 | ->applyFromArray( 496 | [ 497 | 'formatCode' => $formatCode 498 | ] 499 | ); 500 | } 501 | else 502 | { 503 | $Worksheet->getStyle($letter . ':' . $letter) 504 | ->getNumberFormat() 505 | ->setFormatCode( \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_TEXT ); 506 | 507 | array_push($textColumns, isset($model['label']) ? $model['label'] : $model['name']); 508 | } 509 | 510 | 511 | if(!empty($model['width'])) 512 | { 513 | // $Worksheet->getColumnDimension($letter)->setAutoSize(true); 514 | // $Worksheet->getColumnDimension($letter)->setWidth($model['width'], 'px'); 515 | } 516 | } 517 | } 518 | 519 | $copyRows = $rows; 520 | $rows = array(); 521 | 522 | if(empty($postedData['pivot'])) 523 | { 524 | foreach ($copyRows as $index => $row) 525 | { 526 | $currentRow = array(); 527 | 528 | foreach ($modelLabels as $columnName => $value) 529 | { 530 | $currentRow[$value] = isset($row[$columnName]) ? $row[$columnName] : ''; 531 | } 532 | 533 | foreach ($modelSelectFormattersValues as $label => $modelSelectFormatterValue) 534 | { 535 | if(isset($currentRow[$label])) 536 | { 537 | $currentRow[$label] = isset($modelSelectFormatterValue[$currentRow[$label]])?$modelSelectFormatterValue[$currentRow[$label]]:$currentRow[$label]; 538 | } 539 | } 540 | 541 | foreach ($modelDateFormatters as $label => $modelDateFormatter) 542 | { 543 | if(isset($currentRow[$label]) && !empty($currentRow[$label])) 544 | { 545 | $currentRow[$label] = Carbon::createFromFormat($modelDateFormatter['srcformat'], $currentRow[$label])->format($modelDateFormatter['newformat']); 546 | } 547 | } 548 | 549 | foreach ($numericColumns as $index => $label) 550 | { 551 | if(isset($currentRow[$label])) 552 | { 553 | $currentRow[$label] = (float) $currentRow[$label]; 554 | } 555 | } 556 | 557 | $rows[] = $currentRow; 558 | // $row = $currentRow; 559 | } 560 | } 561 | 562 | // foreach (json_decode($postedData['sheetProperties'], true) as $key => $value) 563 | // { 564 | // $method = 'set' . ucfirst($key); 565 | 566 | // $Sheet->$method($value); 567 | // } 568 | 569 | $subTotalGroupedRowsNumber = array(); 570 | 571 | if(!empty($groupingView)) 572 | { 573 | $groupedRows = $groupedRowsNumbers = $subTotalGroupedRow = $currentSubTotalGroupedRow = array(); 574 | $rowCounter = 0; 575 | 576 | foreach ($rows as $index => $row) 577 | { 578 | if($rowCounter == 0) 579 | { 580 | $currentgroupFieldValue = $row[$groupFieldLabel]; 581 | 582 | if($groupFieldHidden) 583 | { 584 | unset($row[$groupFieldLabel]); 585 | } 586 | 587 | $firstColumnName = key($row); 588 | 589 | $groupedRow = $row; 590 | 591 | foreach ($groupedRow as $label => &$cell) 592 | { 593 | if($firstColumnName == $label) 594 | { 595 | $cell = $currentgroupFieldValue; 596 | } 597 | else 598 | { 599 | $cell = ''; 600 | } 601 | 602 | $subTotalGroupedRow[$label] = ''; 603 | } 604 | 605 | $currentSubTotalGroupedRow = $subTotalGroupedRow; 606 | 607 | $rowCounter = 2; 608 | 609 | if(!empty($groupHeaders)) 610 | { 611 | $rowCounter++; 612 | } 613 | 614 | array_push($groupedRows, $groupedRow); 615 | array_push($groupedRowsNumbers, $rowCounter); 616 | } 617 | else 618 | { 619 | if($row[$groupFieldLabel] != $currentgroupFieldValue) 620 | { 621 | $currentgroupFieldValue = $groupedRow[$firstColumnName] = $row[$groupFieldLabel]; 622 | 623 | $rowCounter++; 624 | 625 | if(!empty($summaryTypes)) 626 | { 627 | foreach ($summaryTypes as $column => $summaryType) 628 | { 629 | switch ($summaryType) { 630 | case 'count': 631 | $currentSubTotalGroupedRow[$column] = "($currentSubTotalGroupedRow[$column]) total"; 632 | break; 633 | } 634 | } 635 | 636 | array_push($groupedRows, $currentSubTotalGroupedRow); 637 | array_push($subTotalGroupedRowsNumber, $rowCounter); 638 | 639 | $currentSubTotalGroupedRow = $subTotalGroupedRow; 640 | 641 | $rowCounter++; 642 | } 643 | 644 | array_push($groupedRows, $groupedRow); 645 | array_push($groupedRowsNumbers, $rowCounter); 646 | } 647 | 648 | if($groupFieldHidden) 649 | { 650 | unset($row[$groupFieldLabel]); 651 | } 652 | } 653 | 654 | if(!empty($summaryTypes)) 655 | { 656 | foreach ($summaryTypes as $label => $summaryType) 657 | { 658 | switch ($summaryType) { 659 | case 'sum': 660 | if(empty($currentSubTotalGroupedRow[$label])) 661 | { 662 | $currentSubTotalGroupedRow[$label] = $row[$label] + 0; 663 | } 664 | else 665 | { 666 | $currentSubTotalGroupedRow[$label] += $row[$label]; 667 | } 668 | 669 | break; 670 | case 'count': 671 | if($currentSubTotalGroupedRow[$label] != 0 && empty($currentSubTotalGroupedRow[$label])) 672 | { 673 | $currentSubTotalGroupedRow[$label] = 0; 674 | } 675 | else 676 | { 677 | $currentSubTotalGroupedRow[$label] ++; 678 | } 679 | 680 | break; 681 | } 682 | } 683 | } 684 | 685 | array_push($groupedRows, $row); 686 | 687 | $rowCounter++; 688 | } 689 | 690 | if(!empty($summaryTypes)) 691 | { 692 | foreach ($summaryTypes as $column => $summaryType) 693 | { 694 | switch ($summaryType) { 695 | case 'count': 696 | $currentSubTotalGroupedRow[$column] = "($currentSubTotalGroupedRow[$column]) total"; 697 | break; 698 | } 699 | } 700 | 701 | array_push($groupedRows, $currentSubTotalGroupedRow); 702 | array_push($subTotalGroupedRowsNumber, ++$rowCounter); 703 | } 704 | 705 | $lastCellLetter = $this->numToLetter($columnCounter, true); 706 | 707 | foreach ($groupedRowsNumbers as $index => $groupedRowsNumber) 708 | { 709 | $Worksheet->mergeCells("A$groupedRowsNumber:$lastCellLetter$groupedRowsNumber"); 710 | } 711 | 712 | $rows = $groupedRows; 713 | } 714 | 715 | // $columnFormats = array(); 716 | 717 | // foreach ($modelNumberFormatters as $columnName => $format) 718 | // { 719 | // if(isset($columnsPositions[$columnName])) 720 | // { 721 | // $columnFormats[$this->numToLetter($columnsPositions[$columnName], true)] = $format; 722 | // } 723 | // } 724 | 725 | // $Sheet->setColumnFormat($columnFormats); 726 | 727 | $footerRow = json_decode($postedData['fotterRow'], true); 728 | 729 | if(!empty($footerRow)) 730 | { 731 | array_push($rows, $footerRow); 732 | } 733 | 734 | $headers = $firstHeader = array(); 735 | 736 | if(!empty($groupHeaders)) 737 | { 738 | foreach ($groupHeaders as $index => $groupHeader) 739 | { 740 | $firstHeader[$columnsPositions[$groupHeader['startColumnName']] - 1] = $groupHeader['titleText']; 741 | 742 | $Worksheet->mergeCells( 743 | $this->numToLetter( 744 | $columnsPositions[$groupHeader['startColumnName']], 745 | true 746 | ) . 747 | '1:' . 748 | $this->numToLetter( 749 | // $columnsPositions[$groupHeader['startColumnName']] + $groupHeader['numberOfColumns'] - 1, 750 | $columnsPositions[$groupHeader['startColumnName']] + $groupHeader['numberOfColumns'], 751 | true 752 | ) . 753 | '1' 754 | ); 755 | } 756 | 757 | array_push($headers, $firstHeader); 758 | array_push($headers, array_keys($rows[0])); 759 | 760 | $Worksheet->fromArray($headers, null, 'A1'); 761 | $Worksheet->getStyle('A1:' . $this->numToLetter($columnCounter, true) . '1') 762 | ->applyFromArray($this->styleBold); 763 | $Worksheet->getStyle('A1:' . $this->numToLetter($columnCounter, true) . '1') 764 | ->getAlignment() 765 | ->setWrapText(true); 766 | $Worksheet->getStyle('A2:' . $this->numToLetter($columnCounter, true) . '2') 767 | ->applyFromArray($this->styleBold); 768 | 769 | $counterRow = 3; 770 | } 771 | else 772 | { 773 | array_push($headers, array_keys($rows[0])); 774 | 775 | $Worksheet->fromArray($headers, null, 'A1'); 776 | 777 | $Worksheet->getStyle('A1:' . $this->numToLetter($columnCounter, true) . '1') 778 | ->applyFromArray($this->styleBold); 779 | $Worksheet->getStyle('A1:' . $this->numToLetter($columnCounter, true) . '1') 780 | ->getAlignment() 781 | ->setWrapText(true); 782 | 783 | $counterRow = 2; 784 | } 785 | 786 | $columns = array_keys($rows[0]); 787 | 788 | foreach ($rows as $key => $row) 789 | { 790 | $counterColumn = 'A'; 791 | 792 | foreach ($columns as $column) 793 | { 794 | if(in_array($column, $textColumns)) 795 | { 796 | $Worksheet->setCellValueExplicit( 797 | "$counterColumn$counterRow", $row[$column], 798 | \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING 799 | ); 800 | } 801 | else 802 | { 803 | $Worksheet->setCellValue("$counterColumn$counterRow", $row[$column]); 804 | } 805 | 806 | $counterColumn++; 807 | } 808 | 809 | $counterRow++; 810 | } 811 | 812 | foreach ($subTotalGroupedRowsNumber as $index => $number) 813 | { 814 | $Worksheet->getStyle('A' . $number . ':' . $this->numToLetter($columnCounter, true) . $number) 815 | ->applyFromArray($this->styleBold); 816 | } 817 | 818 | if(!empty($footerRow)) 819 | { 820 | if(!empty($headers)) 821 | { 822 | $footerRowNumber = count($rows) + count($headers); 823 | } 824 | else 825 | { 826 | $footerRowNumber = count($rows) + 1; 827 | } 828 | 829 | $Worksheet->getStyle('A' . $footerRowNumber . ':' . $this->numToLetter($columnCounter, true) . $footerRowNumber) 830 | ->applyFromArray($this->styleBold); 831 | 832 | // $Worksheet->row($footerRowNumber, function($Row) 833 | // { 834 | // $Row->setFontWeight('bold'); 835 | // }); 836 | } 837 | 838 | $Writer = new Xlsx($Spreadsheet); 839 | $Writer->save('php://output'); 840 | }); 841 | 842 | $contentDisposition = 'attachment; filename=' . $postedData['name'] . '.xlsx'; 843 | $StreamedResponse->setStatusCode(Response::HTTP_OK); 844 | $StreamedResponse->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); 845 | $StreamedResponse->headers->set('Content-Disposition', $contentDisposition); 846 | 847 | return $StreamedResponse->send(); 848 | } 849 | else 850 | { 851 | echo $this->safe_json_encode( 852 | array( 853 | 'page' => $page, 854 | 'total' => $totalPages, 855 | 'records' => $count, 856 | 'rows' => $rows 857 | ) 858 | ); 859 | } 860 | } 861 | 862 | /** 863 | * Takes a number and converts it to a-z,aa-zz,aaa-zzz, etc with uppercase option 864 | * 865 | * @access protected 866 | * @param int number to convert 867 | * @param bool upper case the letter on return? 868 | * @return string letters from number input 869 | */ 870 | protected function numToLetter($c, $uppercase = FALSE) 871 | { 872 | $c = intval($c); 873 | if ($c <= 0) return ''; 874 | 875 | $letter = ''; 876 | 877 | while($c != 0){ 878 | $p = ($c - 1) % 26; 879 | $c = intval(($c - $p) / 26); 880 | $letter = chr(65 + $p) . $letter; 881 | } 882 | 883 | return ($uppercase ? strtoupper($letter) : $letter); 884 | } 885 | 886 | /** 887 | * Safe JSON_ENCODE function that tries to deal with UTF8 chars or throws a valid exception. 888 | * 889 | * Lifted from http://stackoverflow.com/questions/10199017/how-to-solve-json-error-utf8-error-in-php-json-decode 890 | * Based on: http://php.net/manual/en/function.json-last-error.php#115980 891 | * @param $value 892 | * @return string 893 | */ 894 | protected function safe_json_encode($value) 895 | { 896 | if (version_compare(PHP_VERSION, '5.4.0') >= 0) 897 | { 898 | $encoded = json_encode($value, JSON_PRETTY_PRINT); 899 | } 900 | else 901 | { 902 | $encoded = json_encode($value); 903 | } 904 | switch (json_last_error()) 905 | { 906 | case JSON_ERROR_NONE: 907 | return $encoded; 908 | case JSON_ERROR_DEPTH: 909 | throw new JsonEncodingMaxDepthException('Maximum stack depth exceeded.'); 910 | case JSON_ERROR_STATE_MISMATCH: 911 | throw new JsonEncodingStateMismatchException('Underflow or the modes mismatch.'); 912 | case JSON_ERROR_CTRL_CHAR: 913 | throw new JsonEncodingUnexpectedControlCharException('Unexpected control character found.'); 914 | case JSON_ERROR_SYNTAX: 915 | throw new JsonEncodingSyntaxErrorException('Syntax , malformed JSON.'); 916 | case JSON_ERROR_UTF8: 917 | $clean = $this->utf8ize($value); 918 | return $this->safe_json_encode($clean); 919 | default: 920 | throw new JsonEncodingUnknownException('Unknown error'); 921 | } 922 | } 923 | 924 | /** 925 | * Clean the array passed in from UTF8 chars. 926 | * 927 | * Lifted from http://stackoverflow.com/questions/10199017/how-to-solve-json-error-utf8-error-in-php-json-decode 928 | * Based on: http://php.net/manual/en/function.json-last-error.php#115980 929 | * 930 | * @param $mixed 931 | * @return array|string 932 | */ 933 | protected function utf8ize($mixed) 934 | { 935 | if (is_array($mixed)) 936 | { 937 | foreach ($mixed as $key => $value) 938 | { 939 | $mixed[$key] = $this->utf8ize($value); 940 | } 941 | } else if (is_string ($mixed)) 942 | { 943 | return utf8_encode($mixed); 944 | } 945 | 946 | return $mixed; 947 | } 948 | 949 | /** 950 | * Set Spreadsheet styles 951 | * 952 | * @return void 953 | */ 954 | protected function setSpreadsheetStyles() 955 | { 956 | $this->styleBold = [ 957 | 'font' => [ 958 | 'bold' => 'true' 959 | ] 960 | ]; 961 | 962 | $this->styleAlignmentLeft = [ 963 | 'alignment' => [ 964 | 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT, 965 | ] 966 | ]; 967 | 968 | $this->styleAlignmentRight = [ 969 | 'alignment' => [ 970 | 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_RIGHT, 971 | ] 972 | ]; 973 | 974 | $this->styleAlignmentCenter = [ 975 | 'alignment' => [ 976 | 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, 977 | ] 978 | ]; 979 | } 980 | } 981 | -------------------------------------------------------------------------------- /src/Mgallegos/LaravelJqgrid/Encoders/RequestedDataInterface.php: -------------------------------------------------------------------------------- 1 | isLaravelVersion('4')) 34 | { 35 | $this->package('mgallegos/laravel-jqgrid'); 36 | } 37 | // elseif ($this->isLaravelVersion('5')) 38 | else 39 | { 40 | $this->publishes([ 41 | __DIR__ . '/../../config/config.php' => config_path('laravel-jqgrid.php'), 42 | ]); 43 | 44 | $this->mergeConfigFrom( 45 | __DIR__ . '/../../config/config.php', 'laravel-jqgrid' 46 | ); 47 | } 48 | } 49 | 50 | /** 51 | * Register the service provider. 52 | * 53 | * @return void 54 | */ 55 | public function register() 56 | { 57 | if ($this->isLaravelVersion('5')) 58 | { 59 | $this->app->register('Maatwebsite\Excel\ExcelServiceProvider'); 60 | } 61 | $this->registerRender(); 62 | $this->registerEncoder(); 63 | } 64 | 65 | /** 66 | * Register render service provider. 67 | * 68 | * @return void 69 | */ 70 | public function registerRender() 71 | { 72 | if ($this->isLaravelVersion('4')) 73 | { 74 | $prefix = 'laravel-jqgrid::'; 75 | } 76 | // elseif ($this->isLaravelVersion('5')) 77 | else 78 | { 79 | $prefix = 'laravel-jqgrid.'; 80 | } 81 | 82 | $this->app->bind('gridrender', function($app) use ($prefix) 83 | { 84 | return new Renders\JqGridRender( 85 | array(), 86 | array(new NameValidation()), 87 | array(), 88 | array(), 89 | $app['config']->get($prefix . 'default_grid_options'), 90 | $app['config']->get($prefix . 'default_pivot_grid_options'), 91 | $app['config']->get($prefix . 'default_group_header_options'), 92 | $app['config']->get($prefix . 'default_col_model_properties'), 93 | $app['config']->get($prefix . 'default_navigator_options'), 94 | $app['config']->get($prefix . 'default_filter_toolbar_options'), 95 | $app['config']->get($prefix . 'default_filter_toolbar_buttons_options'), 96 | $app['config']->get($prefix . 'default_export_buttons_options'), 97 | $app['config']->get($prefix . 'default_file_properties'), 98 | $app['config']->get($prefix . 'default_sheet_properties'), 99 | $app['config']->get($prefix . 'function_type_properties'), 100 | $app['config']->get($prefix . 'pivot_options'), 101 | $app['config']->get($prefix . 'group_header_options'), 102 | $app['session']->token() 103 | ); 104 | }); 105 | } 106 | 107 | /** 108 | * Register encoder service provider. 109 | * 110 | * @return void 111 | */ 112 | public function registerEncoder() 113 | { 114 | $this->app->bind('Mgallegos\LaravelJqgrid\Encoders\RequestedDataInterface', function($app) 115 | { 116 | return new Encoders\JqGridJsonEncoder(); 117 | }); 118 | } 119 | 120 | /** 121 | * Determine if laravel starts with any of the given version strings 122 | * 123 | * @param string|array $startsWith 124 | * @return boolean 125 | */ 126 | protected function isLaravelVersion($startsWith) 127 | { 128 | return Str::startsWith(Application::VERSION, $startsWith); 129 | } 130 | 131 | 132 | /** 133 | * Get the services provided by the provider. 134 | * 135 | * @return array 136 | */ 137 | public function provides() 138 | { 139 | return array('gridrender', 'Mgallegos\LaravelJqgrid\Encoders\RequestedDataInterface'); 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /src/Mgallegos/LaravelJqgrid/Renders/JqGridRender.php: -------------------------------------------------------------------------------- 1 | gridId = str_random(10); 350 | $this->jqPivot = false; 351 | $this->frozenColumn = false; 352 | $this->colModelValidators = $colModelValidators; 353 | $this->optionValidators = $optionValidators; 354 | $this->navigatorValidators = $navigatorValidators; 355 | $this->filterToolbarValidators = $filterToolbarValidators; 356 | $this->colModel = array(); 357 | $this->options = $defaultGridOptions; 358 | $this->pivotOptions = $defaultPivotGridOptions; 359 | $this->pivotOptionsNames = $pivotOptionsNames; 360 | $this->groupHeaderOptions = $defaultGroupHeaderOptions; 361 | $this->groupHeaderOptionsNames = $groupHeaderOptionsNames; 362 | $this->navigatorOptions = $defaultNavigatorOptions; 363 | $this->navigatorEditOptions = array(); 364 | $this->navigatorAddOptions = array(); 365 | $this->navigatorDeleteOptions = array(); 366 | $this->navigatorSearchOptions = array(); 367 | $this->navigatorViewOptions = array(); 368 | $this->filterToolbarOptions = $defaultfilterToolbarOptions; 369 | $this->filterToolbarButtonsOptions = $defaultFilterToolbarButtonsOptions; 370 | $this->exportButtonsOptions = $defaultExportButtonsOptions; 371 | $this->fileProperties = $defaultFileProperties; 372 | $this->sheetProperties = $defaultSheetProperties; 373 | $this->defaultColModelProperties = $defaultColModelProperties; 374 | $this->defaultGridOptions = $defaultGridOptions; 375 | $this->defaultPivotGridOptions = $defaultPivotGridOptions; 376 | $this->defaultGroupHeaderOptions = $defaultGroupHeaderOptions; 377 | $this->defaultNavigatorOptions = $defaultNavigatorOptions; 378 | $this->defaultfilterToolbarOptions = $defaultfilterToolbarOptions; 379 | $this->defaultFilterToolbarButtonsOptions = $defaultFilterToolbarButtonsOptions; 380 | $this->defaultExportButtonsOptions = $defaultExportButtonsOptions; 381 | $this->defaultFileProperties = $defaultFileProperties; 382 | $this->defaultSheetProperties = $defaultSheetProperties; 383 | $this->functionTypeProperties = $functionTypeProperties; 384 | $this->token = $token; 385 | } 386 | 387 | /** 388 | * Add a column at the last position in the columns model. 389 | * 390 | * @param string $id 391 | * 392 | * @return $this 393 | * Returns an object, allowing the calls to be chained together in a single statement 394 | */ 395 | public function setGridId($id=null) 396 | { 397 | $this->gridId = $id; 398 | 399 | return $this; 400 | } 401 | 402 | /** 403 | * Add a column at the last position in the columns model. 404 | * 405 | * @param array $properties 406 | * An array of valid jqGrid column model property, the index key of the array must correspond to a column model property. 407 | * Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:colmodel_options 408 | * @return $this 409 | * Returns an object, allowing the calls to be chained together in a single statement 410 | */ 411 | public function addColumn(array $properties = array()) 412 | { 413 | foreach ($this->colModelValidators as $validator) 414 | { 415 | $validator->validate($properties); 416 | } 417 | 418 | if (in_array('frozen', $properties)) 419 | { 420 | $this->frozenColumn = true; 421 | } 422 | 423 | if (!isset($properties['name']) && !isset($properties['index'])) 424 | { 425 | $properties = array_add($properties, 'name', 'Col. ' . (count($this->colModel) + 1)); 426 | $properties = array_add($properties, 'index', 'Col. ' . (count($this->colModel) + 1)); 427 | } 428 | 429 | if (!isset($properties['name']) && isset($properties['index'])) 430 | { 431 | $properties = array_add($properties, 'name', $properties['index']); 432 | } 433 | 434 | if (isset($properties['name']) && !isset($properties['index'])) 435 | { 436 | $properties = array_add($properties, 'index', $properties['name']); 437 | } 438 | 439 | $this->markFunctionTypeProperty($properties); 440 | 441 | array_push($this->colModel, array_merge($this->defaultColModelProperties, $properties)); 442 | 443 | return $this; 444 | } 445 | 446 | /** 447 | * Add a group header. This are columns that can be added above the normal grid columns. 448 | * This method has no effect when working with pivot grid. 449 | * 450 | * @param array $properties 451 | * An array of valid group header options. 452 | * Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:groupingheadar 453 | * @return $this 454 | * Returns an object, allowing the calls to be chained together in a single statement 455 | */ 456 | public function addGroupHeader(array $properties = array()) 457 | { 458 | foreach ($this->optionValidators as $validator) 459 | { 460 | $validator->validate(array_add(array(), $option, $value)); 461 | } 462 | 463 | $this->markFunctionTypeProperty($properties); 464 | 465 | if(!isset($this->groupHeaderOptions['groupHeaders'])) 466 | { 467 | $this->groupHeaderOptions['groupHeaders'] = array(); 468 | } 469 | 470 | array_push($this->groupHeaderOptions['groupHeaders'], $properties); 471 | 472 | return $this; 473 | } 474 | 475 | /** 476 | * Add a X dimension. Use this method only when working with pivot grids. 477 | * 478 | * @param array $properties 479 | * An array of valid xDimension options. 480 | * Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:pivotsettings 481 | * @return $this 482 | * Returns an object, allowing the calls to be chained together in a single statement 483 | */ 484 | public function addXDimension(array $properties = array()) 485 | { 486 | foreach ($this->colModelValidators as $validator) 487 | { 488 | $validator->validate($properties); 489 | } 490 | 491 | $this->markFunctionTypeProperty($properties); 492 | 493 | if(!isset($this->pivotOptions['xDimension'])) 494 | { 495 | $this->pivotOptions['xDimension'] = array(); 496 | } 497 | 498 | array_push($this->pivotOptions['xDimension'], array_merge($this->defaultColModelProperties, $properties)); 499 | 500 | return $this; 501 | } 502 | 503 | /** 504 | * Add a Y dimension. Use this method only when working with pivot grids. 505 | * 506 | * @param array $properties 507 | * An array of valid yDimension options. 508 | * Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:pivotsettings 509 | * @return $this 510 | * Returns an object, allowing the calls to be chained together in a single statement 511 | */ 512 | public function addYDimension(array $properties = array()) 513 | { 514 | foreach ($this->colModelValidators as $validator) 515 | { 516 | $validator->validate($properties); 517 | } 518 | 519 | $this->markFunctionTypeProperty($properties); 520 | 521 | if(!isset($this->pivotOptions['yDimension'])) 522 | { 523 | $this->pivotOptions['yDimension'] = array(); 524 | } 525 | 526 | array_push($this->pivotOptions['yDimension'], array_merge($this->defaultColModelProperties, $properties)); 527 | 528 | return $this; 529 | } 530 | 531 | /** 532 | * Add an aggregate. Use this method only when working with pivot grids. 533 | * 534 | * @param array $properties 535 | * An array of valid aggregate options (all jqGrid column model property can be used). 536 | * Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:pivotsettings 537 | * @return $this 538 | * Returns an object, allowing the calls to be chained together in a single statement 539 | */ 540 | public function addAggregate(array $properties = array()) 541 | { 542 | foreach ($this->colModelValidators as $validator) 543 | { 544 | $validator->validate($properties); 545 | } 546 | 547 | $this->markFunctionTypeProperty($properties); 548 | 549 | if(!isset($this->pivotOptions['aggregates'])) 550 | { 551 | $this->pivotOptions['aggregates'] = array(); 552 | } 553 | 554 | array_push($this->pivotOptions['aggregates'], array_merge($this->defaultColModelProperties, $properties)); 555 | 556 | return $this; 557 | } 558 | 559 | /** 560 | * Set a jqGrid option. 561 | * 562 | * @param string $option 563 | * A valid jqGrid option, online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options or 564 | * a valid pivot grid option, online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:pivotsettings 565 | * a valid group header option, online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:groupingheadar 566 | * @param mixed $option 567 | * A value of an option can be a string, boolean or array. 568 | * @return $this 569 | * Returns an object, allowing the calls to be chained together in a single statement 570 | */ 571 | public function setGridOption($option, $value) 572 | { 573 | foreach ($this->optionValidators as $validator) 574 | { 575 | $validator->validate(array_add(array(), $option, $value)); 576 | } 577 | 578 | if (in_array($option, array('xDimension', 'yDimension', 'aggregates'))) 579 | { 580 | foreach ($value as &$v) 581 | { 582 | $v = array_merge($this->defaultColModelProperties, $v); 583 | $this->markFunctionTypeProperty($v); 584 | } 585 | } 586 | 587 | $property = array_add(array(), $option, $value); 588 | 589 | $this->markFunctionTypeProperty($property); 590 | 591 | if (in_array($option, $this->pivotOptionsNames)) 592 | { 593 | if(isset($this->pivotOptions[$option])) 594 | { 595 | $this->pivotOptions[$option] = $property[$option]; 596 | } 597 | else 598 | { 599 | $this->pivotOptions = array_add($this->pivotOptions, $option, $property[$option]); 600 | } 601 | } 602 | else if (in_array($option, $this->groupHeaderOptionsNames)) 603 | { 604 | if(isset($this->groupHeaderOptions[$option])) 605 | { 606 | $this->groupHeaderOptions[$option] = $property[$option]; 607 | } 608 | else 609 | { 610 | $this->groupHeaderOptions = array_add($this->groupHeaderOptions, $option, $property[$option]); 611 | } 612 | } 613 | else 614 | { 615 | if(isset($this->options[$option])) 616 | { 617 | $this->options[$option] = $property[$option]; 618 | } 619 | else 620 | { 621 | $this->options = array_add($this->options, $option, $property[$option]); 622 | } 623 | } 624 | 625 | return $this; 626 | } 627 | 628 | /** 629 | * Set a jqGrid event. 630 | * 631 | * @param string $event 632 | * Valid grid event, online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:events&s[]=event 633 | * @param string $code 634 | * Javascript code which will be executed when the event raises 635 | * @return $this 636 | * Returns an object, allowing the calls to be chained together in a single statement 637 | */ 638 | public function setGridEvent($event, $code) 639 | { 640 | foreach ($this->optionValidators as $validator) 641 | { 642 | $validator->validate(array_add(array(), $event, $code)); 643 | } 644 | 645 | $this->options = array_add($this->options, $event, '###' . $code . '###'); 646 | 647 | return $this; 648 | } 649 | 650 | /** 651 | * Set options in the navigator or in any of the following modules add,edit,del,view, search. Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:navigator 652 | * 653 | * @param string $module 654 | * Can be navigator, add, edit, del, view, search. 655 | * @param array $options 656 | * Options that are applicable to this module The key correspond to the options in jqGrid 657 | * @return $this 658 | * Returns an object, allowing the calls to be chained together in a single statement 659 | */ 660 | public function setNavigatorOptions($module, array $options) 661 | { 662 | foreach ($this->navigatorValidators as $validator) 663 | { 664 | $validator->validate(array_add(array(), $module, $options)); 665 | } 666 | 667 | $this->markFunctionTypeProperty($options); 668 | 669 | switch ($module) 670 | { 671 | case 'navigator': 672 | $this->navigatorOptions = array_merge($this->navigatorOptions, $options); 673 | break; 674 | case 'edit': 675 | $this->navigatorEditOptions = $options; 676 | break; 677 | case 'add': 678 | $this->navigatorAddOptions = $options; 679 | break; 680 | case 'del': 681 | $this->navigatorDeleteOptions = $options; 682 | break; 683 | case 'search': 684 | $this->navigatorSearchOptions = $options; 685 | break; 686 | case 'view': 687 | $this->navigatorViewOptions = $options; 688 | break; 689 | } 690 | 691 | return $this; 692 | } 693 | 694 | /** 695 | * Set an event in the navigator or in the diffrent modules add,edit,del,view, search. Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:navigator 696 | * 697 | * @param string $module 698 | * Can be navigator, edit, add, del, search, view. 699 | * @param string $event 700 | * Valid event for the particular module 701 | * @param string $code 702 | * Javascript code which will be executed when the event raises 703 | * @return $this 704 | * Returns an object, allowing the calls to be chained together in a single statement 705 | */ 706 | public function setNavigatorEvent($module, $event, $code) 707 | { 708 | foreach ($this->navigatorValidators as $validator) 709 | { 710 | //$validator->validate(array_add(array(), $module, $options)); 711 | } 712 | 713 | switch ($module) 714 | { 715 | case 'navigator': 716 | $this->navigatorOptions = array_add($this->navigatorOptions, $event, '###' . $code . '###'); 717 | break; 718 | case 'edit': 719 | $this->navigatorEditOptions = array_add($this->navigatorEditOptions, $event, '###' . $code . '###'); 720 | break; 721 | case 'add': 722 | $this->navigatorAddOptions = array_add($this->navigatorAddOptions, $event, '###' . $code . '###'); 723 | break; 724 | case 'del': 725 | $this->navigatorDeleteOptions = array_add($this->navigatorDeleteOptions, $event, '###' . $code . '###'); 726 | break; 727 | case 'search': 728 | $this->navigatorSearchOptions = array_add($this->navigatorSearchOptions, $event, '###' . $code . '###'); 729 | break; 730 | case 'view': 731 | $this->navigatorViewOptions = array_add($this->navigatorViewOptions, $event, '###' . $code . '###'); 732 | break; 733 | } 734 | 735 | return $this; 736 | } 737 | 738 | /** 739 | * Set options for the toolbar filter when enabled. Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:toolbar_searching 740 | * 741 | * @param array $options 742 | * Options that are applicable to the filter toolbar 743 | * @return $this 744 | * Returns an object, allowing the calls to be chained together in a single statement 745 | */ 746 | public function setFilterToolbarOptions(array $options) 747 | { 748 | foreach ($this->filterToolbarValidators as $validator) 749 | { 750 | $validator->validate($options); 751 | } 752 | 753 | $this->markFunctionTypeProperty($options); 754 | 755 | $this->filterToolbarOptions = array_merge($this->filterToolbarOptions, $options); 756 | 757 | return $this; 758 | } 759 | 760 | /** 761 | * Set a export button option 762 | * 763 | * @param string $option 764 | * A valid export button option: xlsButtonVisible, xlsButtonText, xlsIcon, csvButtonVisible, csvButtonText, csvIcon, srcDateFormat, newDateFormat 765 | * @param mixed $option 766 | * A value of an option can be a string or boolean. 767 | * @return $this 768 | * Returns an object, allowing the calls to be chained together in a single statement 769 | */ 770 | public function setExportButtonsOption($option, $value) 771 | { 772 | if(isset($this->exportButtonsOptions[$option])) 773 | { 774 | $this->exportButtonsOptions[$option] = $value; 775 | } 776 | else 777 | { 778 | $this->exportButtonsOptions = array_add($this->exportButtonsOptions, $option, $value); 779 | } 780 | 781 | return $this; 782 | } 783 | 784 | /** 785 | * Set a Spreadsheet file property. 786 | * 787 | * @param string $option 788 | * A valid Spreadsheet file property, online documentation available at https://phpspreadsheet.readthedocs.io/ 789 | * @param mixed $option 790 | * A value of an option can be a string, boolean or array. 791 | * @return $this 792 | * Returns an object, allowing the calls to be chained together in a single statement 793 | */ 794 | public function setFileProperty($option, $value) 795 | { 796 | if(isset($this->fileProperties[$option])) 797 | { 798 | $this->fileProperties[$option] = $value; 799 | } 800 | else 801 | { 802 | $this->fileProperties = array_add($this->fileProperties, $option, $value); 803 | } 804 | 805 | return $this; 806 | } 807 | 808 | /** 809 | * Set a toolbar event. 810 | * 811 | * @param string $event 812 | * Valid toolbar grid event, online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:toolbar_searching 813 | * @param string $code 814 | * Javascript code which will be executed when the event raises 815 | * @return $this 816 | * Returns an object, allowing the calls to be chained together in a single statement 817 | */ 818 | public function setFilterToolbarEvent($event, $code) 819 | { 820 | foreach ($this->filterToolbarValidators as $validator) 821 | { 822 | $validator->validate(array_add(array(), $event, $code)); 823 | } 824 | 825 | $this->filterToolbarOptions = array_merge($this->filterToolbarOptions, array_add(array(), $event, '###' . $code . '###')); 826 | 827 | return $this; 828 | } 829 | 830 | /** 831 | * When this method is called the grid will be treated as Pivot Grid (differents javascript methods are used to generate the grid) according to the official documentation. Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:pivotdescription. 832 | * 833 | * @return $this 834 | * Returns an object, allowing the calls to be chained together in a single statement 835 | */ 836 | public function setGridAsPivot() 837 | { 838 | $this->jqPivot = true; 839 | 840 | return $this; 841 | } 842 | 843 | /** 844 | * Hide XLS Navigator button. 845 | * 846 | * @return $this 847 | * Returns an object, allowing the calls to be chained together in a single statement 848 | */ 849 | public function hideXlsExporter() 850 | { 851 | $this->exportButtonsOptions['xlsButtonVisible'] = false; 852 | 853 | return $this; 854 | } 855 | 856 | /** 857 | * Hide csv Navigator button. 858 | * 859 | * @return $this 860 | * Returns an object, allowing the calls to be chained together in a single statement 861 | */ 862 | public function hideCsvExporter() 863 | { 864 | $this->exportButtonsOptions['csvButtonVisible'] = false; 865 | 866 | return $this; 867 | } 868 | 869 | /** 870 | * Set a Spreadsheet sheet property. 871 | * 872 | * @param string $option 873 | * A valid Spreadsheet sheet property, online documentation available at https://phpspreadsheet.readthedocs.io/ 874 | * @param mixed $option 875 | * A value of an option can be a string, boolean or array. 876 | * @return $this 877 | * Returns an object, allowing the calls to be chained together in a single statement 878 | */ 879 | public function setSheetProperty($option, $value) 880 | { 881 | if(isset($this->sheetProperties[$option])) 882 | { 883 | $this->sheetProperties[$option] = $value; 884 | } 885 | else 886 | { 887 | $this->sheetProperties = array_add($this->sheetProperties, $option, $value); 888 | } 889 | 890 | return $this; 891 | } 892 | 893 | /** 894 | * Enable filter toolbar. 895 | * 896 | * @param boolean $createToggleButton 897 | * If true a toggle button will be created in the navigator. Default is null 898 | * @param boolean $createClearButton 899 | * If true a clear button will be created in the navigator. Default is null 900 | * @return $this 901 | * Returns an object, allowing the calls to be chained together in a single statement 902 | */ 903 | public function enableFilterToolbar($createToggleButton = null, $createClearButton = null) 904 | { 905 | $this->filterToolbarButtonsOptions['filterToolbar'] = true; 906 | 907 | if(!is_null($createToggleButton)) 908 | { 909 | $this->filterToolbarButtonsOptions['toggleButton'] = $createToggleButton; 910 | } 911 | 912 | if(!is_null($createClearButton)) 913 | { 914 | $this->filterToolbarButtonsOptions['clearButton'] = $createClearButton; 915 | } 916 | 917 | return $this; 918 | } 919 | 920 | /** 921 | * Main method that construct the html and javascript code of the grid. 922 | * 923 | * @param boolean $script 924 | * If true javascript tags will be included within the output. Default is true 925 | * @param boolean $createTableElement 926 | * If true the table element is created automatically from this method. Default is true 927 | * @param boolean $createPagerElement 928 | * If true the pager element is created automatically from this method. Default is true 929 | * @param boolean $echo 930 | * If false the function return the string representing the grid. Default is true 931 | * @return mixed 932 | * String if $echo is set to false, void in any other case 933 | */ 934 | public function renderGrid($script = true, $createTableElement = true, $createPagerElement = true, $echo = true) 935 | { 936 | $this->options = array_add($this->options, 'colModel', $this->colModel); 937 | 938 | if (!isset($this->options['pager'])) 939 | { 940 | $this->options = array_add($this->options, 'pager', $this->gridId . 'Pager'); 941 | } 942 | 943 | if(isset($this->options['filename'])) 944 | { 945 | $fileName = mb_substr($this->options['filename'],0,31); 946 | } 947 | else 948 | { 949 | $fileName = $this->gridId; 950 | } 951 | 952 | if(isset($this->options['groupingView'])) 953 | { 954 | $groupingView = $this->options['groupingView']; 955 | } 956 | else 957 | { 958 | $groupingView = array(); 959 | } 960 | 961 | if(isset($this->groupHeaderOptions['groupHeaders'])) 962 | { 963 | $groupHeaders = $this->groupHeaderOptions['groupHeaders']; 964 | } 965 | else 966 | { 967 | $groupHeaders = array(); 968 | } 969 | 970 | $html = ''; 971 | $html .= ' 972 |
973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | fileProperties) . '\'> 986 | sheetProperties) . '\'> 987 | 988 | 989 |
'; 990 | 991 | if($createTableElement) 992 | { 993 | $html .= '
'; 994 | } 995 | 996 | if($createTableElement) 997 | { 998 | $html .= '
'; 999 | } 1000 | 1001 | if($this->jqPivot) 1002 | { 1003 | $mtype = $this->options['mtype']; 1004 | unset($this->options['colModel'], $this->options['mtype'], $this->options['datatype']); 1005 | $script = 'jQuery("#' . $this->gridId . '").jqGrid("jqPivot", "'. $this->options['url'] . '", ' . json_encode($this->pivotOptions) . ', ' . json_encode($this->options) . ', {async : false, type: "' . $mtype .'"});'; 1006 | $script .= 'jQuery("#' . $this->gridId . '").navGrid("#'. $this->options['pager'] .'", '. json_encode($this->navigatorOptions, JSON_FORCE_OBJECT) .', '. json_encode($this->navigatorEditOptions, JSON_FORCE_OBJECT) .', '. json_encode($this->navigatorAddOptions, JSON_FORCE_OBJECT) .', '. json_encode($this->navigatorDeleteOptions, JSON_FORCE_OBJECT) .', '. json_encode($this->navigatorSearchOptions, JSON_FORCE_OBJECT) .', '. json_encode($this->navigatorViewOptions, JSON_FORCE_OBJECT) .' );'; 1007 | } 1008 | else 1009 | { 1010 | $script = 'jQuery("#' . $this->gridId . '").jqGrid(' . json_encode($this->options) . ')'; 1011 | $script .= '.navGrid("#'. $this->options['pager'] .'", '. json_encode($this->navigatorOptions, JSON_FORCE_OBJECT) .', '. json_encode($this->navigatorEditOptions, JSON_FORCE_OBJECT) .', '. json_encode($this->navigatorAddOptions, JSON_FORCE_OBJECT) .', '. json_encode($this->navigatorDeleteOptions, JSON_FORCE_OBJECT) .', '. json_encode($this->navigatorSearchOptions, JSON_FORCE_OBJECT) .', '. json_encode($this->navigatorViewOptions, JSON_FORCE_OBJECT) .' );'; 1012 | } 1013 | /* 1014 | $script .= 'jQuery("#' . $this->gridId . '").jqGrid("navButtonAdd", "#' . $this->options['pager'] . '",{"id": "' . $this->gridId . 'XlsButton", "caption":"' . $this->exportButtonsOptions['xlsButtonText'] . '", "buttonicon":"' . $this->exportButtonsOptions['xlsIcon'] . '", "onClickButton":function(){ ' . $this->getJavascriptExportFunctionCode() . ' jQuery("#' . $this->gridId . 'ExportFormat").val("xls"); jQuery("#' . $this->gridId . 'ExportForm").submit();} });'; 1015 | $script .= 'jQuery("#' . $this->gridId . '").jqGrid("navButtonAdd", "#' . $this->options['pager'] . '",{"id": "' . $this->gridId . 'CsvButton", "caption":"' . $this->exportButtonsOptions['csvButtonText'] . '", "buttonicon":"' . $this->exportButtonsOptions['csvIcon'] . '", "onClickButton":function(){ ' . $this->getJavascriptExportFunctionCode() . ' jQuery("#' . $this->gridId . 'ExportFormat").val("csv"); jQuery("#' . $this->gridId . 'ExportForm").submit();} });'; 1016 | 1017 | if($this->exportButtonsOptions['xlsButtonVisible'] || $this->exportButtonsOptions['csvButtonVisible']) 1018 | { 1019 | $script .= 'jQuery("#' . $this->gridId . '").jqGrid("navSeparatorAdd", "#' . $this->options['pager'] . '");'; 1020 | } 1021 | 1022 | if(!$this->exportButtonsOptions['xlsButtonVisible']) 1023 | { 1024 | $script .= 'jQuery("#' . $this->gridId . 'XlsButton").hide();'; 1025 | } 1026 | 1027 | if(!$this->exportButtonsOptions['csvButtonVisible']) 1028 | { 1029 | $script .= 'jQuery("#' . $this->gridId . 'CsvButton").hide();'; 1030 | } 1031 | */ 1032 | foreach ($this->exportButtonsOptions as $key => $value) 1033 | { 1034 | if( preg_match('/ButtonVisible$/', $key) && gettype($value) == 'boolean' ) 1035 | { 1036 | $script .= "\n\n\t// Add button and hendler for ". strtoupper(substr($key, 0, -1*strlen('ButtonVisible'))) . "-export : \n"; 1037 | $script .= $this->getJavascriptExportFunctionCode( substr($key, 0, -1*strlen('ButtonVisible') ) ); 1038 | } 1039 | } 1040 | 1041 | if($this->exportButtonsVisible) 1042 | { 1043 | $script .= 'jQuery("#' . $this->gridId . '").jqGrid("navSeparatorAdd", "#' . $this->options['pager'] . '");'; 1044 | } 1045 | 1046 | if($this->filterToolbarButtonsOptions['filterToolbar']) 1047 | { 1048 | $script .= 'jQuery("#' . $this->gridId . '").jqGrid("filterToolbar", ' . json_encode($this->filterToolbarOptions, JSON_FORCE_OBJECT) . ');'; 1049 | 1050 | if($this->filterToolbarButtonsOptions['toggleButton']) 1051 | { 1052 | $script .= 'jQuery("#' . $this->gridId . '").jqGrid("navButtonAdd", "#' . $this->options['pager'] . '",{"caption":"'. $this->filterToolbarButtonsOptions['toggleButtonText'] .'", "buttonicon":"ui-icon-pin-s", "onClickButton":function(){ jQuery("#' . $this->gridId . '")[0].toggleToolbar();} });'; 1053 | } 1054 | 1055 | if($this->filterToolbarButtonsOptions['clearButton']) 1056 | { 1057 | $script .= 'jQuery("#' . $this->gridId . '").jqGrid("navButtonAdd", "#' . $this->options['pager'] . '",{"caption":"'. $this->filterToolbarButtonsOptions['clearButtonText'] .'", "buttonicon":"ui-icon-refresh", "onClickButton":function(){ jQuery("#' . $this->gridId . '")[0].clearToolbar();} });'; 1058 | } 1059 | 1060 | $script .= 'jQuery("#' . $this->gridId . '").jqGrid("navSeparatorAdd", "#' . $this->options['pager'] . '");'; 1061 | } 1062 | 1063 | if(!empty($this->groupHeaderOptions)) 1064 | { 1065 | $script .= 'setTimeout(function () {jQuery("#' . $this->gridId . '").jqGrid("setGroupHeaders", ' . json_encode($this->groupHeaderOptions) . ');}, 500);'; 1066 | } 1067 | 1068 | if($this->frozenColumn) 1069 | { 1070 | $script .= 'jQuery("#' . $this->gridId . '").jqGrid("setFrozenColumns");'; 1071 | } 1072 | 1073 | $script = str_replace(array('"###','###"','\"', '"JS>>>', '<<reset(); 1076 | 1077 | if($script) 1078 | { 1079 | $script = ''; 1080 | } 1081 | 1082 | if($echo) 1083 | { 1084 | echo $html . $script; 1085 | } 1086 | else 1087 | { 1088 | return $html.$script; 1089 | } 1090 | } 1091 | 1092 | /** 1093 | * Reset variables to their original state. 1094 | * 1095 | * @return void 1096 | */ 1097 | protected function reset() 1098 | { 1099 | $this->gridId = str_random(10); 1100 | $this->jqPivot = false; 1101 | $this->frozenColumn = false; 1102 | $this->options = $this->defaultGridOptions; 1103 | $this->pivotOptions = $this->defaultPivotGridOptions; 1104 | $this->groupHeaderOptions = $this->defaultGroupHeaderOptions; 1105 | $this->colModel = array(); 1106 | $this->navigatorOptions = $this->defaultNavigatorOptions; 1107 | $this->navigatorEditOptions = array(); 1108 | $this->navigatorAddOptions = array(); 1109 | $this->navigatorDeleteOptions = array(); 1110 | $this->navigatorSearchOptions = array(); 1111 | $this->navigatorViewOptions = array(); 1112 | $this->filterToolbarOptions = $this->defaultfilterToolbarOptions; 1113 | $this->filterToolbarButtonsOptions = $this->defaultFilterToolbarButtonsOptions; 1114 | $this->exportButtonsOptions = $this->defaultExportButtonsOptions; 1115 | $this->fileProperties = $this->defaultFileProperties; 1116 | $this->sheetProperties = $this->defaultSheetProperties; 1117 | } 1118 | 1119 | /** 1120 | * Mark function type properties. 1121 | * First and last quotes will be removed from the javascript code to all properties marked by this method 1122 | * 1123 | * @param array $properties 1124 | * An array of valid jqGrid column model property, the key of the array must correspond to a column model property. 1125 | * 1126 | * @return void 1127 | */ 1128 | protected function markFunctionTypeProperty(array &$properties) 1129 | { 1130 | foreach ($properties as $key => &$value) 1131 | { 1132 | if (in_array($key, array_keys($this->functionTypeProperties))) 1133 | { 1134 | if (!in_array($value, $this->functionTypeProperties[$key])) 1135 | { 1136 | $value = '###' . $value . '###'; 1137 | } 1138 | } 1139 | else 1140 | { 1141 | if(is_array($value) && array_values($value) != $value) 1142 | { 1143 | $this->markFunctionTypeProperty($value); 1144 | } 1145 | } 1146 | 1147 | } 1148 | } 1149 | 1150 | /** 1151 | * Get exporter's javascript code. 1152 | * 1153 | * @param string $exportFormat 1154 | * @return void 1155 | */ 1156 | protected function getJavascriptExportFunctionCode($exportFormat) 1157 | { 1158 | $code = 'jQuery("#' . $this->gridId . '").jqGrid("navButtonAdd", "#' . $this->options['pager']; 1159 | $code .= '",{"id": "' . $this->gridId . ucfirst($exportFormat) . 'Button", "caption":"' . $this->exportButtonsOptions[$exportFormat . 'ButtonText']; 1160 | $code .= '", "buttonicon":"' . $this->exportButtonsOptions[$exportFormat . 'Icon']; 1161 | $code .= '", "onClickButton":function(){ '; 1162 | 1163 | $code .= ' 1164 | var headers = [], rows = [], row, cellCounter, postData, groupingView, sidx, sord; 1165 | jQuery("#' . $this->gridId . 'Model").val(JSON.stringify(jQuery("#' . $this->gridId . '").getGridParam("colModel"))); 1166 | postData = jQuery("#' . $this->gridId . '").getGridParam("postData"); 1167 | if(postData["filters"] != undefined) 1168 | { 1169 | jQuery("#' . $this->gridId . 'Filters").val(postData["filters"]); 1170 | } 1171 | '; 1172 | 1173 | $code .= ' 1174 | groupingView = jQuery("#' . $this->gridId . '").getGridParam("groupingView"); 1175 | sidx = jQuery("#' . $this->gridId . '").getGridParam("sortname"); 1176 | if(sidx == null) sidx = ""; 1177 | sord = jQuery("#' . $this->gridId . '").getGridParam("sortorder"); 1178 | if(sord == null) sord = ""; 1179 | if(groupingView.groupField.length > 0) 1180 | { 1181 | jQuery("#' . $this->gridId . 'Sidx").val(groupingView.groupField[0] + " " + groupingView.groupOrder[0] + "," + " " + sidx); 1182 | } 1183 | else 1184 | { 1185 | jQuery("#' . $this->gridId . 'Sidx").val(sidx); 1186 | } 1187 | jQuery("#' . $this->gridId . 'Sord").val(sord); 1188 | '; 1189 | 1190 | if($this->jqPivot) 1191 | { 1192 | $code .= ' 1193 | jQuery.each($("#gbox_' . $this->gridId . '").find(".ui-jqgrid-sortable"), function( index, header ) 1194 | { 1195 | headers.push(jQuery(header).text()); 1196 | }); 1197 | jQuery.each($("#gview_' . $this->gridId . '").find(".ui-widget-content"), function( index, gridRows ) 1198 | { 1199 | row = {}, cellCounter = 0; 1200 | jQuery.each($(gridRows).find("td"), function( index, cell) 1201 | { 1202 | row[headers[cellCounter++]] = $(cell).text(); 1203 | }); 1204 | for (i = cellCounter; i < headers.length; i++) { 1205 | row[headers[i]] = ""; 1206 | } 1207 | rows.push(row); 1208 | }); 1209 | jQuery("#' . $this->gridId . 'Rows").val(JSON.stringify(rows)); 1210 | '; 1211 | } 1212 | else 1213 | { 1214 | //Include footer row if exists 1215 | $code .= ' 1216 | jQuery.each($("#gbox_' . $this->gridId . '").find(".ui-jqgrid-sortable").filter(":visible"), function( index, header ) 1217 | { 1218 | headers.push(jQuery(header).text()); 1219 | }); 1220 | row = {}, cellCounter = 0; 1221 | jQuery.each($("#gview_' . $this->gridId . '").find(".footrow").find("td").filter(":visible"), function( index, cell) 1222 | { 1223 | row[headers[cellCounter++]] = $(cell).text(); 1224 | }); 1225 | jQuery("#' . $this->gridId . 'FotterRow").val(JSON.stringify(row)); 1226 | '; 1227 | } 1228 | 1229 | if(isset($this->exportButtonsOptions['srcDateFormat'])) 1230 | { 1231 | $code .= ' jQuery("#' . $this->gridId . 'SrcDateFormat").val("' . $this->exportButtonsOptions['srcDateFormat'] . '");'; 1232 | } 1233 | 1234 | if(isset($this->exportButtonsOptions['newDateFormat'])) 1235 | { 1236 | $code .= ' jQuery("#' . $this->gridId . 'NewDateFormat").val("' . $this->exportButtonsOptions['newDateFormat'] . '");'; 1237 | } 1238 | 1239 | $code .= ' jQuery("#' . $this->gridId . 'ExportFormat").val("' . $exportFormat . '");'; 1240 | $code .= 'jQuery("#' . $this->gridId . 'ExportForm").submit();} });'; 1241 | 1242 | if(!$this->exportButtonsOptions[$exportFormat . 'ButtonVisible']) 1243 | { 1244 | $code .= 'jQuery("#' . $this->gridId . ucfirst($exportFormat) . 'Button").hide();'; 1245 | }else 1246 | { 1247 | $this->exportButtonsVisible = TRUE; 1248 | } 1249 | 1250 | return $code; 1251 | } 1252 | 1253 | 1254 | public function addExport(array $properties = array()) 1255 | { 1256 | $export_type = ''; 1257 | foreach ($properties as $key => $value) 1258 | { 1259 | if( preg_match('/ButtonVisible$/', $key) && gettype($value) == 'boolean' ) 1260 | { 1261 | $export_type = substr($key, 0, -1*strlen('ButtonVisible') ); 1262 | } 1263 | } 1264 | if ( $export_type == '' ) 1265 | { 1266 | throw new \Exception('addExport-method does not set the required parameter ...ButtonVisible or can not determine the type of the method by prefix of this parameter'); 1267 | } 1268 | 1269 | $notFoundKeys = array_diff( [$export_type.'ButtonVisible', $export_type.'ButtonText', $export_type.'Icon'], array_keys($properties)); 1270 | if ( count($notFoundKeys) > 0 ) 1271 | { 1272 | throw new \Exception('addExport-method does not set the required parameters: '.implode(', ', $notFoundKeys)); 1273 | } 1274 | 1275 | $this->exportButtonsOptions = array_merge($this->exportButtonsOptions, $properties); 1276 | 1277 | return $this; 1278 | } 1279 | } 1280 | -------------------------------------------------------------------------------- /src/Mgallegos/LaravelJqgrid/Renders/RenderInterface.php: -------------------------------------------------------------------------------- 1 | 'column index/name 1','op'=>'operator','data'=>'searched string column 1'), array('field'=>'column index/name 2','op'=>'operator','data'=>'searched string column 2')) 80 | * The 'field' key will contain the 'index' column property if is set, otherwise the 'name' column property. 81 | * The 'op' key will contain one of the following operators: '=', '<', '>', '<=', '>=', '<>', '!=','like', 'not like', 'is in', 'is not in'. 82 | * when the 'operator' is 'like' the 'data' already contains the '%' character in the appropiate position. 83 | * The 'data' key will contain the string searched by the user. 84 | * @return integer 85 | * Total number of rows 86 | */ 87 | public function getTotalNumberOfRows(array $filters = array()) 88 | { 89 | return intval($this->Database->whereNested(function($query) use ($filters) 90 | { 91 | foreach ($filters as $filter) 92 | { 93 | if($filter['op'] == 'is in') 94 | { 95 | $query->whereIn($filter['field'], explode(',',$filter['data'])); 96 | continue; 97 | } 98 | 99 | if($filter['op'] == 'is not in') 100 | { 101 | $query->whereNotIn($filter['field'], explode(',',$filter['data'])); 102 | continue; 103 | } 104 | 105 | if($filter['op'] == 'is null') 106 | { 107 | $query->whereNull($filter['field']); 108 | continue; 109 | } 110 | 111 | if($filter['op'] == 'is not null') 112 | { 113 | $query->whereNotNull($filter['field']); 114 | continue; 115 | } 116 | 117 | if($filter['op'] == 'between') 118 | { 119 | if(strpos($filter['data'], ' - ') !== false) 120 | { 121 | list($from, $to) = explode(' - ', $filter['data'], 2); 122 | 123 | if(!$from or !$to) 124 | { 125 | throw new \Exception('Invalid between format'); 126 | } 127 | } 128 | else 129 | { 130 | throw new \Exception('Invalid between format'); 131 | } 132 | 133 | if( $from == $to) 134 | { 135 | $query->where($filter['field'], $from); 136 | }else 137 | { 138 | //$query->whereBetween($filter['field'], array($from, $to)); 139 | $query->where($filter['field'], '>=', $from); 140 | $query->where($filter['field'], '<=', $to); 141 | } 142 | 143 | continue; 144 | } 145 | 146 | $query->where($filter['field'], $filter['op'], $filter['data']); 147 | } 148 | }) 149 | ->count()); 150 | } 151 | 152 | 153 | /** 154 | * Get the rows data to be shown in the grid. 155 | * 156 | * @param integer $limit 157 | * Number of rows to be shown into the grid 158 | * @param integer $offset 159 | * Start position 160 | * @param string $orderBy 161 | * Column name to order by. 162 | * @param string $sord 163 | * Sorting order 164 | * @param array $filters 165 | * An array of filters, example: array(array('field'=>'column index/name 1','op'=>'operator','data'=>'searched string column 1'), array('field'=>'column index/name 2','op'=>'operator','data'=>'searched string column 2')) 166 | * The 'field' key will contain the 'index' column property if is set, otherwise the 'name' column property. 167 | * The 'op' key will contain one of the following operators: '=', '<', '>', '<=', '>=', '<>', '!=','like', 'not like', 'is in', 'is not in'. 168 | * when the 'operator' is 'like' the 'data' already contains the '%' character in the appropiate position. 169 | * The 'data' key will contain the string searched by the user. 170 | * @param string $nodeId 171 | * Node id (used only when the treeGrid option is set to true) 172 | * @param string $nodeLevel 173 | * Node level (used only when the treeGrid option is set to true) 174 | * @param boolean $exporting 175 | * Flag that determines if the data will be exported (used only when the treeGrid option is set to true) 176 | * @return array 177 | * An array of array, each array will have the data of a row. 178 | * Example: array(array("column1" => "1-1", "column2" => "1-2"), array("column1" => "2-1", "column2" => "2-2")) 179 | */ 180 | public function getRows($limit, $offset, $orderBy = null, $sord = null, array $filters = array(), $nodeId = null, $nodeLevel = null, $exporting = false) 181 | { 182 | $orderByRaw = null; 183 | 184 | if(!is_null($orderBy) || !is_null($sord)) 185 | { 186 | $found = false; 187 | $pos = strpos($orderBy, 'desc'); 188 | 189 | if ($pos !== false) 190 | { 191 | $found = true; 192 | } 193 | else 194 | { 195 | $pos = strpos($orderBy, 'asc'); 196 | 197 | if ($pos !== false) 198 | { 199 | $found = true; 200 | } 201 | } 202 | 203 | if($found) 204 | { 205 | $orderBy = rtrim($orderBy); 206 | 207 | if(substr($orderBy, -1) == ',') 208 | { 209 | $orderBy = substr($orderBy, 0, -1); 210 | } 211 | else 212 | { 213 | $orderBy .= " $sord"; 214 | } 215 | 216 | $orderByRaw = $orderBy; 217 | } 218 | else 219 | { 220 | $this->orderBy = array(array($orderBy, $sord)); 221 | } 222 | } 223 | 224 | if($limit == 0) 225 | { 226 | $limit = 1; 227 | } 228 | 229 | if(empty($orderByRaw)) 230 | { 231 | $orderByRaw = array(); 232 | 233 | foreach ($this->orderBy as $orderBy) 234 | { 235 | array_push($orderByRaw, implode(' ',$orderBy)); 236 | } 237 | 238 | $orderByRaw = implode(',',$orderByRaw); 239 | } 240 | 241 | $rows = $this->Database->whereNested(function($query) use ($filters, $nodeId, $exporting) 242 | { 243 | foreach ($filters as $filter) 244 | { 245 | if($filter['op'] == 'is in') 246 | { 247 | $query->whereIn($filter['field'], explode(',',$filter['data'])); 248 | continue; 249 | } 250 | 251 | if($filter['op'] == 'is not in') 252 | { 253 | $query->whereNotIn($filter['field'], explode(',',$filter['data'])); 254 | continue; 255 | } 256 | 257 | if($filter['op'] == 'is null') 258 | { 259 | $query->whereNull($filter['field']); 260 | continue; 261 | } 262 | 263 | if($filter['op'] == 'is not null') 264 | { 265 | $query->whereNotNull($filter['field']); 266 | continue; 267 | } 268 | 269 | if($filter['op'] == 'between') 270 | { 271 | if(strpos($filter['data'], ' - ') !== false) 272 | { 273 | list($from, $to) = explode(' - ', $filter['data'], 2); 274 | 275 | if(!$from or !$to) 276 | { 277 | throw new \Exception('Invalid between format'); 278 | } 279 | } 280 | else 281 | { 282 | throw new \Exception('Invalid between format'); 283 | } 284 | 285 | if( $from == $to) 286 | { 287 | $query->where($filter['field'], $from); 288 | }else 289 | { 290 | //$query->whereBetween($filter['field'], array($from, $to)); 291 | $query->where($filter['field'], '>=', $from); 292 | $query->where($filter['field'], '<=', $to); 293 | } 294 | continue; 295 | } 296 | 297 | $query->where($filter['field'], $filter['op'], $filter['data']); 298 | } 299 | 300 | if($this->treeGrid && !$exporting) 301 | { 302 | if(empty($nodeId)) 303 | { 304 | $query->whereNull($this->parentColumn); 305 | } 306 | else 307 | { 308 | $query->where($this->parentColumn, '=', $nodeId); 309 | } 310 | } 311 | }) 312 | ->take($limit) 313 | ->skip($offset) 314 | ->orderByRaw($orderByRaw) 315 | ->get($this->visibleColumns); 316 | 317 | if(!is_array($rows)) 318 | { 319 | $rows = $rows->toArray(); 320 | } 321 | 322 | foreach ($rows as &$row) 323 | { 324 | $row = (array) $row; 325 | 326 | if($this->treeGrid && !$exporting) 327 | { 328 | if(is_null($nodeLevel)) 329 | { 330 | $row['level'] = 0; 331 | } 332 | else 333 | { 334 | $row['level'] = (int)$nodeLevel + 1; 335 | } 336 | 337 | if($row[$this->leafColumn] == 0) 338 | { 339 | $row[$this->leafColumn] = false; 340 | } 341 | else 342 | { 343 | $row[$this->leafColumn] = true; 344 | } 345 | } 346 | } 347 | 348 | return $rows; 349 | } 350 | 351 | } 352 | -------------------------------------------------------------------------------- /src/Mgallegos/LaravelJqgrid/Repositories/RepositoryInterface.php: -------------------------------------------------------------------------------- 1 | 'column index/name 1','op'=>'operator','data'=>'searched string column 1'), array('field'=>'column index/name 2','op'=>'operator','data'=>'searched string column 2')) 28 | * The 'field' key will contain the 'index' column property if is set, otherwise the 'name' column property. 29 | * The 'op' key will contain one of the following operators: '=', '<', '>', '<=', '>=', '<>', '!=','like', 'not like', 'is in', 'is not in'. 30 | * when the 'operator' is 'like' the 'data' already contains the '%' character in the appropiate position. 31 | * The 'data' key will contain the string searched by the user. 32 | * @return integer 33 | * Total number of rows 34 | */ 35 | public function getTotalNumberOfRows(array $filters = array()); 36 | 37 | 38 | /** 39 | * Get the rows data to be shown in the grid. 40 | * 41 | * @param integer $limit 42 | * Number of rows to be shown into the grid 43 | * @param integer $offset 44 | * Start position 45 | * @param string $orderBy 46 | * Column name to order by. 47 | * @param string $sord 48 | * Sorting order 49 | * @param array $filters 50 | * An array of filters, example: array(array('field'=>'column index/name 1','op'=>'operator','data'=>'searched string column 1'), array('field'=>'column index/name 2','op'=>'operator','data'=>'searched string column 2')) 51 | * The 'field' key will contain the 'index' column property if is set, otherwise the 'name' column property. 52 | * The 'op' key will contain one of the following operators: '=', '<', '>', '<=', '>=', '<>', '!=','like', 'not like', 'is in', 'is not in'. 53 | * when the 'operator' is 'like' the 'data' already contains the '%' character in the appropiate position. 54 | * The 'data' key will contain the string searched by the user. 55 | * @param string $nodeId 56 | * Node id (used only when the treeGrid option is set to true) 57 | * @param string $nodeLevel 58 | * Node level (used only when the treeGrid option is set to true) 59 | * @param boolean $exporting 60 | * Flag that determines if the data will be exported (used only when the treeGrid option is set to true) 61 | * @return array 62 | * An array of array, each array will have the data of a row. 63 | * Example: array(array("column1" => "1-1", "column2" => "1-2"), array("column1" => "2-1", "column2" => "2-2")) 64 | */ 65 | public function getRows($limit, $offset, $orderBy = null, $sord = null, array $filters = array(), $nodeId = null, $nodeLevel = null, $exporting); 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/config/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgallegos/laravel-jqgrid/afcb0331512926a22fdc4308a9d3b242d193c807/src/config/.gitkeep -------------------------------------------------------------------------------- /src/config/config.php: -------------------------------------------------------------------------------- 1 | array('datatype' => 'json', 'mtype' => 'POST', 'treeGridModel' => 'adjacency'), 25 | 26 | /* 27 | |-------------------------------------------------------------------------- 28 | | Default Pivot Grid Options 29 | |-------------------------------------------------------------------------- 30 | | 31 | | An array of pivot grid options that will be set to all grids of your applications, 32 | | the key of the array must correspond to a valid pivot grid option. 33 | | These options can override by setting a different value in a specific grid. 34 | | Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:pivotsettings 35 | | 36 | */ 37 | 38 | 'default_pivot_grid_options' => array('yDimension' => array()), 39 | 40 | /* 41 | |-------------------------------------------------------------------------- 42 | | Default Group Header Options 43 | |-------------------------------------------------------------------------- 44 | | 45 | | An array of group header options that will be set to all grids of your applications, 46 | | the key of the array must correspond to a valid pivot grid option. 47 | | These options can override by setting a different value in a specific grid. 48 | | Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:groupingheadar 49 | | 50 | */ 51 | 52 | 'default_group_header_options' => array('useColSpanStyle' => true), 53 | 54 | /* 55 | |-------------------------------------------------------------------------- 56 | | Default column model properties 57 | |-------------------------------------------------------------------------- 58 | | 59 | | An array of column model properties that will be set to all columns grid of your applications, 60 | | the key of the array must correspond to a valid column model property. 61 | | These column model properties can override by setting a different value in a specific grid. 62 | | Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:colmodel_options 63 | | 64 | */ 65 | 66 | 'default_col_model_properties' => array('searchoptions' => array('sopt'=>array('cn'))), 67 | 68 | /* 69 | |-------------------------------------------------------------------------- 70 | | Default navigator options 71 | |-------------------------------------------------------------------------- 72 | | 73 | | Default navigators options that will be set to all grid of your applications, 74 | | the key of the array must correspond to a valid navigator option. 75 | | These options can override by setting a different value in a specific grid. 76 | | Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:navigator 77 | | 78 | */ 79 | 80 | 'default_navigator_options' => array('add' => false, 'edit' => false, 'del' => false, 'search' => false, 'view' => true, 'refresh' => false), 81 | 82 | /* 83 | |-------------------------------------------------------------------------- 84 | | Default filter toolbar options 85 | |-------------------------------------------------------------------------- 86 | | 87 | | Default navigators options that will be set to all grid of your applications, 88 | | the key of the array must correspond to a valid filter toolbar option. 89 | | These options can override by setting a different value in a specific grid. 90 | | Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:toolbar_searching 91 | | 92 | */ 93 | 94 | 'default_filter_toolbar_options' => array('stringResult' => true), 95 | 96 | /* 97 | |-------------------------------------------------------------------------- 98 | | Default Filter Toolbar Buttons Options 99 | |-------------------------------------------------------------------------- 100 | | 101 | | An array of toolbar button options that will be set to all grids of your applications. 102 | | filterToolbar: enable o disabled the filter toolbar 103 | | toggleButton: add a button to toggle the filter toolbar 104 | | clearButton: add a button to clear the filter toolbar 105 | | toggleButtonText: text of the toggle button 106 | | clearButtonText: text of the clear button 107 | | 108 | */ 109 | 110 | 'default_filter_toolbar_buttons_options' => array('filterToolbar' => false, 'toggleButton' => true, 'clearButton' => true, 'toggleButtonText' => '', 'clearButtonText' => ''), 111 | 112 | /* 113 | |-------------------------------------------------------------------------- 114 | | Default Export Buttons Options 115 | |-------------------------------------------------------------------------- 116 | | 117 | | An array of toolbar button options that will be set to all grids of your applications. 118 | | xlsButtonVisible: show or hide the xls export button 119 | | xlsButtonText: text of the xls export button 120 | | xlsIcon: xls icon (jquery ui icon) 121 | | csvButtonVisible: show or hide the csv export button 122 | | csvButtonText: text of the csv export button 123 | | csvIcon: csv icon (jquery ui icon) 124 | | srcDateFormat: source (database) date format (php available formats: http://php.net/manual/en/datetime.formats.date.php) 125 | | newDateFormat: new date format (php available formats: http://php.net/manual/en/datetime.formats.date.php) 126 | | 127 | */ 128 | 129 | 'default_export_buttons_options' => array('xlsButtonVisible' => true, 'xlsButtonText' => 'xls', 'xlsIcon' => 'ui-icon-arrowthickstop-1-s', 'csvButtonVisible' => true, 'csvButtonText' => 'csv', 'csvIcon' => 'ui-icon-arrowthickstop-1-s', 'srcDateFormat' => 'Y-m-d', 'newDateFormat' => 'm/d/Y'), 130 | 131 | /* 132 | |-------------------------------------------------------------------------- 133 | | Default Spreadsheet File Properties 134 | |-------------------------------------------------------------------------- 135 | | 136 | | Default Spreadsheet File Properties that will be set to all grid of your applications, 137 | | the key of the array must correspond to a Spreadsheet File Property. 138 | | These properties can override by setting a different value in a specific grid. 139 | | Online documentation available at https://phpspreadsheet.readthedocs.io/ 140 | | 141 | */ 142 | 143 | 'default_file_properties' => array(), 144 | 145 | /* 146 | |-------------------------------------------------------------------------- 147 | | Default Spreadsheet Sheet Properties 148 | |-------------------------------------------------------------------------- 149 | | 150 | | Default Spreadsheet Sheet Properties that will be set to all grid of your applications, 151 | | the key of the array must correspond to a Spreadsheet Sheet Property. 152 | | These properties can override by setting a different value in a specific grid. 153 | | Online documentation available at https://phpspreadsheet.readthedocs.io/ 154 | | 155 | */ 156 | 157 | 'default_sheet_properties' => array(), 158 | 159 | /* 160 | |-------------------------------------------------------------------------- 161 | | Pivot options 162 | |-------------------------------------------------------------------------- 163 | | 164 | | Pivots options defined by the jqGrid documentation. 165 | | Warning: This options are vital when using the grid as a pivot grid, do not modify them unless you know what you are doing. 166 | | Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:pivotsettings 167 | | 168 | */ 169 | 170 | 'pivot_options' => array('aggregates', 'colTotals', 'frozenStaticCols', 'groupSummary', 'groupSummaryPos', 'rowTotals', 'rowTotalsText', 'xDimension', 'yDimension'), 171 | 172 | /* 173 | |-------------------------------------------------------------------------- 174 | | Group header options 175 | |-------------------------------------------------------------------------- 176 | | 177 | | Group header options options defined by the jqGrid documentation. 178 | | Warning: This options are vital when grouping header columns, do not modify them unless you know what you are doing. 179 | | Online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:groupingheadar 180 | | 181 | */ 182 | 183 | 'group_header_options' => array('useColSpanStyle', 'groupHeaders'), 184 | 185 | /* 186 | |-------------------------------------------------------------------------- 187 | | Function type Grid options and column properties 188 | |-------------------------------------------------------------------------- 189 | | 190 | | These options and properties can be set as a string by the programmer, but first and last quotes will be removed from the javascript code. 191 | | In some cases there are predefined values that are exceptions, these can be included as an array. 192 | | "JqGrid options" online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:colmodel_options 193 | | "JqGrid column properties" online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:colmodel_options 194 | | "JqGrid predefined format types" online documentation available at http://www.trirand.com/jqgridwiki/doku.php?id=wiki:predefined_formatter 195 | | Warning: This options are vital for the functionaty of the package, do not modify them unless you know what you are doing. 196 | | 197 | */ 198 | 199 | 'function_type_properties' => array( 200 | 'datatype' => array('xml', 'xmlstring', 'json', 'jsonstring', 'local', 'javascript', 'clientSide'), 201 | 'cellattr' => array(), 202 | 'formatter' => array('integer', 'number', 'currency', 'date', 'email', 'link', 'showlink', 'checkbox', 'select', 'actions'), 203 | 'unformat' => array(), 204 | 'sorttype' => array('int','integer', 'float','number', 'currency', 'date', 'text'), 205 | 'dataInit' => array(), 206 | 'fn' => array(), 207 | 'custom_element' => array(), 208 | 'custom_value' => array(), 209 | 'custom_func' => array(), 210 | 'buildSelect' => array(), 211 | 'summaryType' => array('sum','count','avg','min','max'), 212 | 'rowattr' => array(), 213 | 'converter' => array(), 214 | ), 215 | ); 216 | -------------------------------------------------------------------------------- /src/lang/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgallegos/laravel-jqgrid/afcb0331512926a22fdc4308a9d3b242d193c807/src/lang/.gitkeep -------------------------------------------------------------------------------- /src/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgallegos/laravel-jqgrid/afcb0331512926a22fdc4308a9d3b242d193c807/src/migrations/.gitkeep -------------------------------------------------------------------------------- /src/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgallegos/laravel-jqgrid/afcb0331512926a22fdc4308a9d3b242d193c807/src/views/.gitkeep -------------------------------------------------------------------------------- /tests/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgallegos/laravel-jqgrid/afcb0331512926a22fdc4308a9d3b242d193c807/tests/.gitkeep --------------------------------------------------------------------------------