OpenXE/classes/Widgets/DataTable/Service/DataTableBuilder.php

222 lines
6.8 KiB
PHP
Raw Normal View History

2021-05-21 08:49:41 +02:00
<?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;
}
}