mirror of
https://github.com/OpenXE-org/OpenXE.git
synced 2024-11-16 13:07:14 +01:00
222 lines
6.8 KiB
PHP
222 lines
6.8 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Xentral\Widgets\DataTable\Service;
|
||
|
|
||
|
use Xentral\Components\Database\Database;
|
||
|
use Xentral\Widgets\DataTable\Column\ColumnCollection;
|
||
|
use Xentral\Widgets\DataTable\DataTableBuildConfig;
|
||
|
use Xentral\Widgets\DataTable\Exception\BuildFailedException;
|
||
|
use Xentral\Widgets\DataTable\Options\DataTableOptions;
|
||
|
use Xentral\Widgets\DataTable\DataTableInterface;
|
||
|
use Xentral\Widgets\DataTable\Feature\DataTableFeatureInterface;
|
||
|
use Xentral\Widgets\DataTable\Feature\FeatureCollection;
|
||
|
use Xentral\Widgets\DataTable\Filter\FilterCollection;
|
||
|
use Xentral\Widgets\DataTable\PreparedDataTable;
|
||
|
use Xentral\Widgets\DataTable\Type\DataTableTypeInterface;
|
||
|
|
||
|
final class DataTableBuilder
|
||
|
{
|
||
|
/** @var Database $database */
|
||
|
private $database;
|
||
|
|
||
|
/**
|
||
|
* @param Database $database
|
||
|
*/
|
||
|
public function __construct(Database $database)
|
||
|
{
|
||
|
$this->database = $database;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param DataTableBuildConfig $config
|
||
|
*
|
||
|
* @throws BuildFailedException
|
||
|
*
|
||
|
* @return DataTableInterface
|
||
|
*/
|
||
|
public function buildTable(DataTableBuildConfig $config)
|
||
|
{
|
||
|
if (empty(trim($config->getTableName()))) {
|
||
|
throw new BuildFailedException('Build config is incomplete. Table name is empty.');
|
||
|
}
|
||
|
if (empty(trim($config->getAjaxUrl()))) {
|
||
|
throw new BuildFailedException('Build config is incomplete. Property "ajaxUrl" is missing.');
|
||
|
}
|
||
|
if (!class_exists($config->getTableClass(), true)) {
|
||
|
throw new BuildFailedException(sprintf('DataTable class "%s" not found', $config->getTableClass()));
|
||
|
}
|
||
|
$interfaces = class_implements($config->getTableClass(), true);
|
||
|
if (!in_array(DataTableTypeInterface::class, $interfaces, true)) {
|
||
|
throw new BuildFailedException(
|
||
|
'Can not build data table. Class does not implement ' . DataTableTypeInterface::class
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/** @var DataTableTypeInterface $table */
|
||
|
$className = $config->getTableClass();
|
||
|
$table = new $className();
|
||
|
|
||
|
// @todo getParent() verarbeiten
|
||
|
|
||
|
$options = new DataTableOptions();
|
||
|
$table->configureOptions($options);
|
||
|
|
||
|
$columns = new ColumnCollection();
|
||
|
$table->configureColumns($columns);
|
||
|
|
||
|
$query = $this->database->select();
|
||
|
$table->configureQuery($query);
|
||
|
|
||
|
if ($query->hasOrderBy()) {
|
||
|
throw new BuildFailedException(
|
||
|
'Sorting in "configureQuery" will be overwritten. ' .
|
||
|
'Use "setDefaultSorting" in "configureOptions" instead.'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
$features = new FeatureCollection();
|
||
|
$table->configureFeatures($features);
|
||
|
|
||
|
$filters = new FilterCollection();
|
||
|
$table->configureFilters($filters);
|
||
|
|
||
|
$preparedTable = new PreparedDataTable($config, $options, $query, $columns, $features, $filters);
|
||
|
$this->prepareTable($preparedTable);
|
||
|
|
||
|
return $preparedTable;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param DataTableInterface $table
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
private function prepareTable(DataTableInterface $table)
|
||
|
{
|
||
|
$this->prepareColumns($table);
|
||
|
$this->applyFeatures($table);
|
||
|
$this->prepareSorting($table);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param DataTableInterface $table
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
private function applyFeatures(DataTableInterface $table)
|
||
|
{
|
||
|
/** @var DataTableFeatureInterface $feature */
|
||
|
foreach ($table->getFeatures() as $feature) {
|
||
|
$feature->modifyTable($table);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param DataTableInterface $table
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
private function prepareColumns(DataTableInterface $table)
|
||
|
{
|
||
|
// Spalten aus dem SQL-Query holen
|
||
|
$query = $table->getBaseQuery();
|
||
|
$columnNames = $query->getCols();
|
||
|
|
||
|
foreach ($columnNames as $alias => $fullColumnName) {
|
||
|
// Spalten mit Spaltenaliasen zuerst behandeln (easy)
|
||
|
$column = $table->getColumns()->getByName($alias);
|
||
|
if ($column !== null) {
|
||
|
$column->setDbColumn($fullColumnName);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Tabellenalias aus Spaltenname entfernen
|
||
|
$shortColumnName = $this->extractNameFromColumn($fullColumnName);
|
||
|
$column = $table->getColumns()->getByName($shortColumnName);
|
||
|
if ($column !== null) {
|
||
|
$column->setDbColumn($fullColumnName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param DataTableInterface $table
|
||
|
*
|
||
|
* @return void
|
||
|
*/
|
||
|
private function prepareSorting(DataTableInterface $table)
|
||
|
{
|
||
|
$columnNames = array_column($table->getColumns()->toArray(), 'data');
|
||
|
$defaultSorting = $table->getOptions()->getDefaultSorting();
|
||
|
$postSorting = $table->getOptions()->getPostSorting();
|
||
|
$preSorting = $table->getOptions()->getPreSorting();
|
||
|
|
||
|
$defaultSorting = $this->translateSortingValues($columnNames, $defaultSorting);
|
||
|
$postSorting = $this->translateSortingValues($columnNames, $postSorting);
|
||
|
$preSorting = $this->translateSortingValues($columnNames, $preSorting);
|
||
|
|
||
|
/**
|
||
|
* Sortierung, wenn nichts gesetzt ist; Benutzer-Sortierung überschreibt diesen Wert
|
||
|
*
|
||
|
* @see https://datatables.net/reference/option/order
|
||
|
*/
|
||
|
if (empty($defaultSorting)) {
|
||
|
$defaultSorting = [[0, 'asc']];
|
||
|
}
|
||
|
$table->getOptions()->setOption('order', $defaultSorting);
|
||
|
|
||
|
/**
|
||
|
* Vor- und Nach-Sortierung; Kann vom Benutzer nicht geändert werden
|
||
|
*
|
||
|
* @see https://datatables.net/reference/option/orderFixed
|
||
|
*/
|
||
|
if (!empty($preSorting)) {
|
||
|
$orderFixed['pre'] = $preSorting;
|
||
|
}
|
||
|
if (!empty($postSorting)) {
|
||
|
$orderFixed['post'] = $postSorting;
|
||
|
}
|
||
|
if (!empty($orderFixed)) {
|
||
|
$table->getOptions()->setOption('orderFixed', $orderFixed);
|
||
|
} else {
|
||
|
$table->getOptions()->removeOption('orderFixed');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @example ['lagerbestand' => 'DESC', 'bezeichnung' => 'ASC'] wird zu [[3, 'desc'], [1, 'asc']]
|
||
|
*
|
||
|
* @param array $columnNames
|
||
|
* @param array $sortingValues
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
private function translateSortingValues($columnNames, $sortingValues)
|
||
|
{
|
||
|
$result = [];
|
||
|
|
||
|
foreach ($sortingValues as $columnName => $sortOrder) {
|
||
|
$columnIndex = array_search($columnName, $columnNames, true);
|
||
|
if ($columnIndex !== false) {
|
||
|
$result[] = [$columnIndex, strtolower($sortOrder)];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $column
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
private function extractNameFromColumn($column)
|
||
|
{
|
||
|
if ($pos = strrpos($column, '.')) {
|
||
|
return substr($column, $pos + 1);
|
||
|
}
|
||
|
|
||
|
return $column;
|
||
|
}
|
||
|
}
|