1201 lines
36 KiB
PHP
1201 lines
36 KiB
PHP
<?php
|
|
|
|
namespace KupShop\AdminBundle\AdminList;
|
|
|
|
use DatabaseCommunication;
|
|
use Frame;
|
|
use KupShop\AdminBundle\Util\ListColumns;
|
|
use KupShop\AdminBundle\Util\ListExporter;
|
|
use KupShop\KupShopBundle\Context\CurrencyContext;
|
|
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
|
use KupShop\KupShopBundle\Util\HtmlBuilder\HTML;
|
|
use KupShop\KupShopBundle\Util\StringUtil;
|
|
use KupShop\KupShopBundle\Util\System\UrlFinder;
|
|
use Pager;
|
|
use Query\Operator;
|
|
use Query\QueryBuilder;
|
|
|
|
#[\AllowDynamicProperties]
|
|
class BaseList extends Frame
|
|
{
|
|
use DatabaseCommunication;
|
|
use FiltersStorage;
|
|
|
|
protected $tableDef = ['fields' => []];
|
|
protected $pageDivide;
|
|
|
|
protected $template = 'list.tpl';
|
|
|
|
protected $showAddItem = false;
|
|
protected $showExport = true;
|
|
protected $showMassEdit = false;
|
|
|
|
private $massEditActive = false;
|
|
|
|
protected $tableName;
|
|
|
|
/**
|
|
* Must be set when $tableName is defined.
|
|
*/
|
|
protected ?string $tableAlias = null;
|
|
|
|
protected $orderParam = [];
|
|
|
|
protected $tableDefLoaded;
|
|
|
|
protected bool $useFilterQuery = false;
|
|
|
|
protected bool $useLazyNumberOfPages = false;
|
|
|
|
protected ?int $totalObjectsCount = null;
|
|
|
|
protected bool $useFiltersStorage = true;
|
|
|
|
protected bool $hasStringId = false;
|
|
|
|
// Column types
|
|
public const TYPE_STRING = 'string';
|
|
public const TYPE_DATE = 'date';
|
|
public const TYPE_DATETIME = 'datetime';
|
|
public const TYPE_FLOAT = 'float';
|
|
public const TYPE_INT = 'int';
|
|
public const TYPE_PRICE = 'price';
|
|
public const TYPE_PRICE_WITH_CURRENCY = 'priceWithCurrency';
|
|
public const TYPE_FLOAT_WITH_CURRENCY = 'floatWithCurrency';
|
|
public const TYPE_BOOL = 'bool';
|
|
public const TYPE_LIST = 'list';
|
|
public const TYPE_LIST_MULTISELECT = 'listMultiselect';
|
|
public const TYPE_LIST_AUTOCOMPLETE = 'autocomplete';
|
|
public const TYPE_LIST_ACTIONS = 'actions';
|
|
public const TYPE_LIST_MULTISELECT_AUTOCOMPLETE = 'multiselectAutocomplete';
|
|
public const TYPE_POSITION = 'position';
|
|
|
|
protected function getOrder($type)
|
|
{
|
|
$cookieName = 'adminList_'.$type;
|
|
|
|
if (!empty($_GET['window'])) {
|
|
$cookieName .= 'window';
|
|
}
|
|
|
|
if (!empty($_GET['order'])) {
|
|
// pokud ma starou formu
|
|
if (preg_match('/^([0-9]+)(a|d)$/i', $_GET['order'], $matches)) {
|
|
$orderParam = $this->createOrderParamFromOldStyle($matches);
|
|
} else {
|
|
$orderParam = [
|
|
'direction' => StringUtil::startsWith($_GET['order'], '-') ? 'DESC' : 'ASC',
|
|
'sort' => trim($_GET['order'], '-'),
|
|
];
|
|
}
|
|
} else {
|
|
$orderParam = $this->orderParam;
|
|
|
|
// fallback na cookie
|
|
if (!empty($_COOKIE[$cookieName])) {
|
|
// pokud je z cookie, tak musi mit starou formu
|
|
$orderParam = $this->createOrderParamFromOldStyle(unserialize($_COOKIE[$cookieName]));
|
|
}
|
|
|
|
if ($this->filterStorageReady()) {
|
|
if (isset($this->activeFilter)) {
|
|
$orderParam = json_decode($this->activeFilter['sort'] ?? '', true);
|
|
} else {
|
|
$defaultFilter = $this->getDefaultFilter();
|
|
if ($defaultFilter && !empty($defaultFilter['sort'])) {
|
|
$orderParam = $defaultFilter['sort'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// pokud je orderParam porad prazdny / neni nastaveny, tak pouzij default
|
|
if (empty($orderParam)) {
|
|
return $this->getDefaultOrder();
|
|
} else {
|
|
// fallback pokud se upravil key ve fields kvuli prekladum
|
|
if (!array_key_exists($orderParam['sort'], $this->getTableDef()['fields'])) {
|
|
foreach ($this->getTableDef()['fields'] as $key => $field) {
|
|
if ($field['title'] == $orderParam['sort']) {
|
|
$orderParam['sort'] = $key;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($this->getTableDef()['fields'][$orderParam['sort']]['visible'] == 'N') {
|
|
return $this->getDefaultOrder();
|
|
}
|
|
}
|
|
|
|
return $orderParam;
|
|
}
|
|
|
|
protected function getDefaultOrder()
|
|
{
|
|
if ($this->orderParam) {
|
|
return $this->orderParam;
|
|
}
|
|
|
|
$fields = array_keys($this->getTableDef()['fields']);
|
|
|
|
return [
|
|
'sort' => reset($fields),
|
|
'direction' => 'ASC',
|
|
];
|
|
}
|
|
|
|
private function createOrderParamFromOldStyle($old)
|
|
{
|
|
$tableDef = $this->getTableDef();
|
|
$fields = $tableDef['fields'];
|
|
$index = $old[1] ?? 0;
|
|
if ($index > 0) {
|
|
$index--;
|
|
}
|
|
$names = array_keys($fields);
|
|
|
|
return [
|
|
'sort' => $names[$index] ?? reset($names),
|
|
'direction' => ($old[2] ?? 'a') == 'a' ? 'ASC' : 'DESC',
|
|
];
|
|
}
|
|
|
|
public function &getTableDef()
|
|
{
|
|
// tableAlias can't be NULL when tableName is defined
|
|
assert(
|
|
!(!is_null($this->tableName) && is_null($this->tableAlias)),
|
|
'tableAlias can not be NULL when tableName is defined in '.static::class
|
|
);
|
|
|
|
if (!$this->tableDefLoaded) {
|
|
// customize
|
|
$this->tableDef = $this->customizeTableDef($this->tableDef);
|
|
if ($this->massEditActive) {
|
|
$this->tableDef = $this->customizeMassTableDef($this->tableDef);
|
|
}
|
|
$this->tableDef = $this->translateTableDef($this->tableDef);
|
|
|
|
/** @var ListColumns $listColumn */
|
|
$listColumn = ServiceContainer::getService(ListColumns::class);
|
|
$tableDef = $listColumn->orderTableDef($this->tableDef, getVal('type'), getVal('adminFilter'));
|
|
|
|
$this->tableDef = $tableDef;
|
|
$this->tableDefLoaded = true;
|
|
}
|
|
|
|
return $this->tableDef;
|
|
}
|
|
|
|
private function translateTableDef($tableDef)
|
|
{
|
|
$fields = $tableDef['fields'] ?? [];
|
|
|
|
// translate
|
|
foreach ($fields as $key => &$field) {
|
|
if (isset($field['translate'])) {
|
|
$translation_section = $field['translation_section'] ?? $tableDef['translation_section'] ?? getVal('type');
|
|
if ($field['translate'] === true) {
|
|
$label = translate($key, $translation_section);
|
|
} elseif (is_callable($field['translate'])) {
|
|
$label = $field['translate']($key, $translation_section);
|
|
} else {
|
|
$label = translate($field['translate'], $translation_section);
|
|
}
|
|
|
|
$field['title'] = $label;
|
|
} else {
|
|
$field['title'] = $key;
|
|
}
|
|
}
|
|
|
|
$tableDef['fields'] = $fields;
|
|
|
|
return $tableDef;
|
|
}
|
|
|
|
public function customizeTableDef($tableDef)
|
|
{
|
|
return $tableDef;
|
|
}
|
|
|
|
public function customizeMassTableDef($tableDef)
|
|
{
|
|
return $tableDef;
|
|
}
|
|
|
|
public function getTableIdColumn(): string
|
|
{
|
|
return $this->getTableDef()['id'];
|
|
}
|
|
|
|
/**
|
|
* @return \Query\QueryBuilder
|
|
*/
|
|
public function getQuery()
|
|
{
|
|
return sqlQueryBuilder()
|
|
->select($this->tableAlias ? "{$this->tableAlias}.*" : '*')
|
|
->from($this->getTableName(), $this->tableAlias)
|
|
->where(
|
|
$this->hasStringId ? Operator::inStringArray($this->getFilterIds(), $this->getTableIdColumn()) :
|
|
Operator::inIntArray($this->getFilterIds(), $this->getTableIdColumn())
|
|
)
|
|
->groupBy($this->getTableIdColumn());
|
|
}
|
|
|
|
public function getFilterIds(): array
|
|
{
|
|
// Jakmile volám getFilterIds(), používám filter query
|
|
$this->useFilterQuery = true;
|
|
|
|
$page = $this->getPage();
|
|
$divide = $this->getPageDivide();
|
|
|
|
$qb = $this->getFilterQuery();
|
|
if ($divide > 0) {
|
|
$qb->setFirstResult(ceil(($page - 1) * $divide))
|
|
->setMaxResults($divide);
|
|
}
|
|
// Ordering
|
|
$vars = [];
|
|
$vars['orderParam'] = $this->getOrder(
|
|
$this->getListName()
|
|
);
|
|
$this->applyOrder($qb, $vars);
|
|
|
|
if (!$this->useLazyNumberOfPages) {
|
|
$this->addSQLCalcFoundRows($qb);
|
|
}
|
|
|
|
$IDs = sqlFetchAll($qb->execute(), ['id' => 'id']);
|
|
|
|
if (!$this->useLazyNumberOfPages) {
|
|
$this->totalObjectsCount = returnSQLResult('SELECT FOUND_ROWS()');
|
|
}
|
|
|
|
return $IDs;
|
|
}
|
|
|
|
public function getFilterQuery(): QueryBuilder
|
|
{
|
|
return sqlQueryBuilder()
|
|
->select($this->getTableIdColumn().' as id')
|
|
->from($this->getTableName(), $this->tableAlias)
|
|
->groupBy($this->getTableIdColumn());
|
|
}
|
|
|
|
public function addSQLCalcFoundRows(QueryBuilder $qb): void
|
|
{
|
|
$selectPart = $qb->getQueryPart('select');
|
|
$selectPart[0] = 'SQL_CALC_FOUND_ROWS '.$selectPart[0];
|
|
$qb->select($selectPart);
|
|
}
|
|
|
|
private function getCountQuery(): QueryBuilder
|
|
{
|
|
if (!$this->useFilterQuery) {
|
|
// pokud jeste nepouzivam filter query, tak potrebuju nejak nacist IDcka vcetne aplikovanych filtru
|
|
// takze pouziju standardni `getQuery` a selectnu pouze idcka a podle toho zafiltruju, abych nacetl pocet
|
|
$qb = $this->getQuery();
|
|
if (is_array($qb)) {
|
|
$qb = $query['qb'] ?? null;
|
|
}
|
|
|
|
$subquery = $qb
|
|
->select($this->getTableIdColumn());
|
|
} else {
|
|
// pokud pouzivam filter query, tak jen nactu filter query a ten pouziju
|
|
$subquery = $this->getFilterQuery();
|
|
}
|
|
|
|
assert(!is_null($this->getTableName()), 'tableName can not be NULL in '.static::class);
|
|
|
|
return sqlQueryBuilder()
|
|
->select('COUNT('.$this->getTableIdColumn().')')
|
|
->from($this->getTableName(), $this->tableAlias)
|
|
->where(Operator::inSubQuery($this->getTableIdColumn(), $subquery));
|
|
}
|
|
|
|
public function getFilters()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public function getListName()
|
|
{
|
|
$fullName = explode('\\', $this->getClassName());
|
|
$name = end($fullName);
|
|
|
|
return lcfirst(preg_replace('/List/', '', $name));
|
|
}
|
|
|
|
public function getPageDivide()
|
|
{
|
|
if (isset($this->pageDivide)) {
|
|
return $this->pageDivide;
|
|
}
|
|
|
|
global $dbcfg;
|
|
|
|
return $dbcfg['page_divide'];
|
|
}
|
|
|
|
public function setPageDivide($pageDivide): void
|
|
{
|
|
$this->pageDivide = $pageDivide;
|
|
}
|
|
|
|
public function handleExport()
|
|
{
|
|
$listExporter = ServiceContainer::getService(ListExporter::class);
|
|
$this->setPageDivide(0);
|
|
$listExporter->setListObject($this);
|
|
$listExporter->listExport();
|
|
exit;
|
|
}
|
|
|
|
public function get_vars()
|
|
{
|
|
$vars = parent::get_vars();
|
|
|
|
$this->tryRights();
|
|
|
|
$qb = $this->getFinalQueryBuilder($vars);
|
|
$sql = $this->getSQL($qb);
|
|
$vars['SQL'] = $sql['SQL'];
|
|
$vars['pageCount'] = is_array($sql['SQL']) || $sql['SQL'] instanceof \Countable ? count($sql['SQL']) : $sql['SQL']->rowCount();
|
|
|
|
if (isset($sql['pages'])) {
|
|
$vars['pager'] = $this->createPager($sql);
|
|
}
|
|
|
|
$vars['columns'] = $this->getColumns();
|
|
|
|
$vars['searchWnd'] = getVal('searchWnd');
|
|
|
|
if ($this->getFilters() != null) {
|
|
$filters = $this->getFilters();
|
|
$vars['filtersValue'] = $this->getFiltersData($qb, $filters);
|
|
// $vars['filtersValue'] = $this->getFiltersData($vars['var'], $filters);
|
|
}
|
|
|
|
$vars['showExport'] = $this->showExport;
|
|
$vars['showMassEdit'] = $this->showMassEdit;
|
|
|
|
return $vars;
|
|
}
|
|
|
|
protected function evaluateColumnClosures(QueryBuilder $qb)
|
|
{
|
|
foreach ($this->getTableDef()['fields'] as $key => $field) {
|
|
if (isset($field['spec']) && $field['visible'] == 'Y') {
|
|
// pokud ma mit specku, ale nema ji definovanou
|
|
if (is_array($field['spec'])) {
|
|
throw new \RuntimeException(
|
|
sprintf('Missing field query spec for field: "%s"!', $key)
|
|
);
|
|
}
|
|
|
|
$qb->addSelect($field['spec']);
|
|
}
|
|
}
|
|
|
|
return $qb;
|
|
}
|
|
|
|
private function filtersActive()
|
|
{
|
|
$get = $_REQUEST;
|
|
|
|
unset($get['s'], $get['type'], $get['page'], $get['loadTotalCount'], $get['acn'], $get['OkStr'], $get['ErrStr'], $get['refresh']);
|
|
|
|
return count($get) > 0 || !empty($_GET['adminFilter']);
|
|
}
|
|
|
|
private function filterStorageReady(): bool
|
|
{
|
|
return $this->useFiltersStorage;
|
|
}
|
|
|
|
public function activateFilter($filter)
|
|
{
|
|
if (!$filter) {
|
|
return;
|
|
}
|
|
|
|
$this->activeFilter = $filter;
|
|
|
|
parse_str($filter['list'] ?? '', $output);
|
|
foreach ($output as $key => $filter) {
|
|
if (is_string($filter) && StringUtil::startsWith($filter, '{DATE:')) {
|
|
$date = new \DateTime();
|
|
$filter = str_replace('DATE:', '', trim($filter, '{}'));
|
|
if ($filter = intval($filter)) {
|
|
$date = $date->modify($filter.' day');
|
|
}
|
|
$filter = $date->format(\Settings::getDateFormat());
|
|
}
|
|
$_GET[$key] = $filter;
|
|
$_REQUEST[$key] = $filter;
|
|
}
|
|
}
|
|
|
|
public function activateDefaultFilter()
|
|
{
|
|
if ($this->filterStorageReady()) {
|
|
$default = $this->getDefaultFilter();
|
|
$this->activateFilter($default);
|
|
if (!empty($default['id'])) {
|
|
$_GET['adminFilter'] = $default['id'];
|
|
}
|
|
}
|
|
}
|
|
|
|
public function createPager($sql)
|
|
{
|
|
$pager = new Pager($sql['pages'], $sql['pageNumber']);
|
|
$pager->setPageInside($sql['pageNumber'] < 5 ? 5 : 3);
|
|
$pager->setPageSide(1);
|
|
$pager->setTotal($sql['totalCount']);
|
|
$pager->setOnPage($this->getPageDivide());
|
|
$pager->setUrl(
|
|
$this->getCurrentUri()
|
|
);
|
|
|
|
return $pager;
|
|
}
|
|
|
|
public function applyOrder(QueryBuilder $qb, &$vars)
|
|
{
|
|
$this->getSQLOrdering($vars, $vars['orderParam']);
|
|
|
|
if (!empty($vars['orderSpec'])) {
|
|
$qb->addSelect($vars['orderSpec']);
|
|
}
|
|
|
|
if (!empty($vars['orderField'])) {
|
|
$qb->orderBy($vars['orderField'], $vars['orderDir']);
|
|
}
|
|
|
|
return $qb;
|
|
}
|
|
|
|
public function getColumns()
|
|
{
|
|
$first = true;
|
|
$table = &$this->getTableDef();
|
|
foreach ($table['fields'] as $label => &$column) {
|
|
if ($first && $column['visible'] == 'Y') {
|
|
$idField = $this->getFieldArrayName(getVal('id', $table, 'id'));
|
|
|
|
if ($idField) {
|
|
if (!isset($column['type_id'])) {
|
|
$column['type_id'] = $idField;
|
|
}
|
|
if (!isset($column['type'])) {
|
|
$column['type'] = $GLOBALS['type'];
|
|
}
|
|
}
|
|
|
|
$first = false;
|
|
} else {
|
|
if (isset($column['type'])) {
|
|
$idField = $this->getFieldArrayName(getVal('id', $table, 'id'));
|
|
if ($idField && !isset($column['type_id'])) {
|
|
$column['type_id'] = $idField;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!isset($column['size'])) {
|
|
$column['size'] = 1;
|
|
}
|
|
}
|
|
|
|
return $table;
|
|
}
|
|
|
|
public static function getClassName()
|
|
{
|
|
return get_called_class();
|
|
}
|
|
|
|
public function getSQLOrdering(&$var, &$orderParam)
|
|
{
|
|
if (empty($var['orderField'])) {
|
|
$table = &$this->getTableDef();
|
|
$fields = $table['fields'];
|
|
$column = $orderParam['sort'];
|
|
|
|
if (isset($fields[$column])) {
|
|
$field = $fields[$column];
|
|
$var['orderField'] = !empty($field['raw_field']) ? $field['raw_field'] : $field['field'];
|
|
$var['orderDir'] = $orderParam['direction'];
|
|
// Používám spec pouze pokud používáme filterQuery
|
|
if ($field['spec'] ?? null && $this->useFilterQuery) {
|
|
$var['orderSpec'] = $field['spec'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function getPage(): int
|
|
{
|
|
$page = getVal('page');
|
|
if (empty($page)) {
|
|
$page = 1;
|
|
}
|
|
|
|
return (int) $page;
|
|
}
|
|
|
|
public function getSQL(QueryBuilder $qb)
|
|
{
|
|
if (!$this->useLazyNumberOfPages) {
|
|
$this->addSQLCalcFoundRows($qb);
|
|
}
|
|
|
|
// ################################################
|
|
|
|
$page = $this->getPage();
|
|
$divide = $this->getPageDivide();
|
|
$noPages = 0;
|
|
|
|
if (!$this->useFilterQuery && $divide > 0) {
|
|
$qb->setFirstResult(ceil(($page - 1) * $divide))->setMaxResults($divide);
|
|
}
|
|
|
|
// SQL prikaz na databazi
|
|
$SQL = $qb->execute();
|
|
|
|
if ($this->useLazyNumberOfPages) {
|
|
$totalCountCacheKey = $this->getListName().'-'.md5(json_encode($this->getCurrentFilterParams()));
|
|
$this->totalObjectsCount = getCache($totalCountCacheKey, $found);
|
|
if (!$found) {
|
|
$this->totalObjectsCount = null;
|
|
}
|
|
// loadnu totalCount a cachnu ho na 10 minut
|
|
if (getVal('loadTotalCount')) {
|
|
$this->totalObjectsCount = $this->getCountQuery()->execute()->fetchOne();
|
|
setCache($totalCountCacheKey, $this->totalObjectsCount, 600);
|
|
}
|
|
} elseif (!$this->useFilterQuery) {
|
|
// Když používám filter query, už jsem si počet objektů načetl při fetchování IDček
|
|
$this->totalObjectsCount = returnSQLResult('SELECT FOUND_ROWS()');
|
|
}
|
|
|
|
if ($divide > 0) {
|
|
// spocitat stranky
|
|
$noPages = $this->totalObjectsCount === null ? Pager::INFINITE_PAGE_COUNT : ceil($this->totalObjectsCount / $divide);
|
|
}
|
|
|
|
return [
|
|
'SQL' => $SQL,
|
|
'pages' => $noPages,
|
|
'pageNumber' => $page,
|
|
'totalCount' => $this->totalObjectsCount,
|
|
];
|
|
}
|
|
|
|
protected function getCurrentFilterParams(): array
|
|
{
|
|
$params = array_filter($_GET, function ($x) {
|
|
if ($x === '0') {
|
|
return true;
|
|
}
|
|
|
|
return !empty($x);
|
|
});
|
|
|
|
unset($params['s'], $params['type'], $params['page'], $params['order'], $params['loadTotalCount']);
|
|
|
|
return $params;
|
|
}
|
|
|
|
protected function getCurrentUri(): string
|
|
{
|
|
$uri = $_SERVER['REQUEST_URI'];
|
|
|
|
$parsed = parse_url($uri);
|
|
if (!empty($parsed['query'])) {
|
|
parse_str($parsed['query'], $query);
|
|
unset($query['loadTotalCount']);
|
|
$uri = $parsed['path'];
|
|
if (!empty($query)) {
|
|
$uri .= '?'.http_build_query($query);
|
|
}
|
|
}
|
|
|
|
return $uri;
|
|
}
|
|
|
|
public function printHeaderLabel($label, $column)
|
|
{
|
|
if (!empty($column['label'])) {
|
|
return $this->resolveCallable($column['label'], $column, $label);
|
|
}
|
|
|
|
return $label;
|
|
}
|
|
|
|
public function getListRowValue($values, $field, $default = null)
|
|
{
|
|
$field_name = $this->getFieldArrayName($field);
|
|
|
|
if (!isset($values[$field_name])) {
|
|
return $default;
|
|
}
|
|
|
|
return $values[$field_name];
|
|
}
|
|
|
|
public function printListRowLabel($column, &$values)
|
|
{
|
|
$render = getVal('render', $column);
|
|
|
|
if (is_callable($render)) {
|
|
$result = $render($this, $values);
|
|
} elseif (!empty($render)) {
|
|
$result = $this->$render($values, $column);
|
|
} else {
|
|
$result = $this->renderCell($values, $column);
|
|
}
|
|
$output = function ($snippet) {
|
|
echo $snippet instanceof HTML ? (string) $snippet : htmlspecialchars($snippet ?? '');
|
|
};
|
|
if (is_array($result)) {
|
|
foreach ($result as $part) {
|
|
$output($part);
|
|
}
|
|
} else {
|
|
$output($result);
|
|
}
|
|
}
|
|
|
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
|
|
public function printListRowItem($column, &$values)
|
|
{
|
|
$type = getVal('type', $column);
|
|
if (!$type) {
|
|
return $this->printListRowLabel($column, $values);
|
|
}
|
|
|
|
$params = getVal('params', $column);
|
|
$id = $values[$this->getFieldArrayName($column['type_id'])]; ?>
|
|
<a href="javascript:<?php if (getVal('searchWnd')) { ?>searchResult('<?php echo $id; ?>', '<?php echo base64_encode(json_encode($values)); ?>')<?php } else { ?>nw('<?php echo $type; ?>', '<?php echo $id; ?>', '<?php echo ($params) ? $params : ''; ?>')<?php } ?>;">
|
|
<?php $this->printListRowLabel($column, $values); ?>
|
|
</a>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
*/
|
|
public function printListRow(&$values)
|
|
{
|
|
$table = &$this->getTableDef();
|
|
if ($class = getVal('class', $table, '')) {
|
|
$class = $this->resolveCallable($class, $values);
|
|
} ?>
|
|
<tr class="<?php echo $class; ?>">
|
|
<?php foreach ($table['fields'] as $name => $column) {
|
|
$class = getVal('class', $column, '');
|
|
|
|
if ((getVal('wpjAdmin', $column) and !isSuperuser()) || ($column['visible'] == 'N')) {
|
|
continue;
|
|
}
|
|
|
|
if (is_callable($class)) {
|
|
$class = $class($values);
|
|
} elseif (method_exists($this, $class)) {
|
|
$class = $this->$class($values);
|
|
} ?>
|
|
|
|
<td>
|
|
<div class="list_item <?php echo $class; ?>">
|
|
<?php echo $this->printListRowItem($column, $values); ?>
|
|
</div>
|
|
</td>
|
|
<?php
|
|
} ?>
|
|
</tr>
|
|
<?php
|
|
}
|
|
|
|
public function getItemClass($class, $values)
|
|
{
|
|
if (is_callable($class)) {
|
|
$class = $class($values);
|
|
} elseif ($class && method_exists($this, $class)) {
|
|
$class = $this->$class($values);
|
|
}
|
|
|
|
return $class;
|
|
}
|
|
|
|
public function resolveCallable($class, ...$values)
|
|
{
|
|
if (empty($class)) {
|
|
return null;
|
|
}
|
|
|
|
if (is_callable($class)) {
|
|
$class = $class(...$values);
|
|
} elseif (method_exists($this, $class)) {
|
|
$class = $this->$class(...$values);
|
|
}
|
|
|
|
return $class;
|
|
}
|
|
|
|
public function printTreeRow(&$values)
|
|
{
|
|
$table = &$this->getTableDef();
|
|
$class = $this->resolveCallable(getVal('class', $table, ''), $values); ?>
|
|
<li class="<?php echo $class; ?>" data-id="<?php echo $this->getListRowValue($values, getVal('id', $table, 'id')); ?>">
|
|
<?php foreach ($table['fields'] as $name => $column) {
|
|
$class = $this->resolveCallable(getVal('class', $column, ''), $values); ?>
|
|
<div class="list_item <?php echo $class; ?>">
|
|
<?php echo $this->printListRowItem($column, $values); ?>
|
|
</div>
|
|
<?php
|
|
} ?>
|
|
</li>
|
|
<?php
|
|
}
|
|
|
|
public function getFieldArrayName($field)
|
|
{
|
|
$pos = strpos($field, '.');
|
|
if ($pos === false) {
|
|
return $field;
|
|
}
|
|
|
|
return substr($field, $pos + 1);
|
|
}
|
|
|
|
public function getFiltersData(QueryBuilder $qb, $filters)
|
|
{
|
|
$filterValues = [];
|
|
foreach ($filters as $name => $filter) {
|
|
$choiced = false;
|
|
if (getVal($name, null, '0') == '0') {
|
|
$choiced = true;
|
|
}
|
|
$values = [
|
|
'0' => [
|
|
'name' => $filter['title'],
|
|
'choiced' => $choiced,
|
|
],
|
|
];
|
|
|
|
$from = getVal('from', $filter);
|
|
$leftJoin = getVal('leftJoin', $filter);
|
|
$nameField = getVal('name', $filter, $filter['field']);
|
|
$orderField = getVal('order', $filter, 'name');
|
|
|
|
$qb->resetQueryPart('select');
|
|
$qb->select('DISTINCT '.$filter['field'].' as value', $nameField.' as name')
|
|
->leftJoin($leftJoin['fromAlias'], $leftJoin['table'], $leftJoin['alias'], $leftJoin['condition'])
|
|
->orderBy($orderField)
|
|
->setMaxResults(100);
|
|
|
|
$SQL = $qb->execute();
|
|
while (($row = sqlFetchAssoc($SQL)) !== false) {
|
|
$choiced = false;
|
|
if (getVal($name, null, '0') == $row['value']) {
|
|
$choiced = true;
|
|
}
|
|
$values[$row['value']]['name'] = $row['name'];
|
|
$values[$row['value']]['choiced'] = $choiced;
|
|
}
|
|
$filterValues[$filter['title']] = $values;
|
|
}
|
|
|
|
return $filterValues;
|
|
}
|
|
|
|
public function printMenuRow($title, $type, $params)
|
|
{
|
|
?>
|
|
<img src="<?php echo $GLOBALS['cfg']['Path']['admin_images']; ?>xp_icon_16x16_arrow1.gif" width="16" height="16" border="0" alt=""/>
|
|
<a href="javascript:nw('<?php echo $type; ?>', '0', '<?php echo $params; ?>');"><?php echo $title; ?></a>
|
|
<?php
|
|
}
|
|
|
|
public function printAddItem($params)
|
|
{
|
|
$this->printMenuRow('Přidat položku', $GLOBALS['type'], $params);
|
|
}
|
|
|
|
public function getAddItem()
|
|
{
|
|
if (!getVal('window')) {
|
|
return false;
|
|
}
|
|
|
|
if ($this->showAddItem === false) {
|
|
return false;
|
|
}
|
|
|
|
$replace = array_merge(['ID' => $this->getID()], $_GET);
|
|
$params = str_replace(array_map(function ($x) {
|
|
return '{'.$x.'}';
|
|
}, array_keys($replace)), array_values($replace), $this->showAddItem);
|
|
$params = preg_replace('/\{[^\{]+\}/i', '', $params);
|
|
|
|
return ['type' => $GLOBALS['type'], 'params' => $params];
|
|
}
|
|
|
|
/* Renderers */
|
|
public function renderCell($values, $column)
|
|
{
|
|
return $this->getListRowValue($values, $column['field']);
|
|
}
|
|
|
|
public function renderBoolean($values, $column, $tooltip = '')
|
|
{
|
|
$value = $this->renderCell($values, $column);
|
|
if ($value == 'Y' || $value == '1' || $value === true) {
|
|
return $this->renderIcon('success', 'Ano', $tooltip);
|
|
} else {
|
|
return $this->renderIcon('error', 'Ne', $tooltip);
|
|
}
|
|
}
|
|
|
|
protected function renderIcon($icon, $text = '', $tooltip = '')
|
|
{
|
|
switch ($icon) {
|
|
case 'warning':
|
|
return $this->renderFontIcon('list-warn bi bi-exclamation-triangle', $text, $tooltip);
|
|
|
|
case 'success':
|
|
return $this->renderFontIcon('list-yes bi bi-check-circle', $text, $tooltip);
|
|
|
|
case 'error':
|
|
return $this->renderFontIcon('list-no bi bi-x-circle', $text, $tooltip);
|
|
}
|
|
}
|
|
|
|
protected function renderFontIcon($class, $text, $tooltip = '')
|
|
{
|
|
$tag = HTML::create('span')
|
|
->class($class);
|
|
|
|
if (!empty($tooltip)) {
|
|
$tag->attr('title', $tooltip);
|
|
}
|
|
|
|
return $tag->tag('i')->text($text)->end();
|
|
}
|
|
|
|
public function renderIsSet($values, $column)
|
|
{
|
|
$value = $this->renderCell($values, $column);
|
|
if ($value) {
|
|
return $this->renderIcon('success', 'Ano');
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
public function renderFloat($values, $column)
|
|
{
|
|
$value = $this->renderCell($values, $column);
|
|
|
|
if ($value === null) {
|
|
return '-';
|
|
}
|
|
|
|
return floatval($value);
|
|
}
|
|
|
|
public function renderPrice($values, $column)
|
|
{
|
|
$value = $this->renderCell($values, $column);
|
|
|
|
if ($value === null) {
|
|
return '-';
|
|
}
|
|
|
|
return $this->renderFormatPrice($values, $column);
|
|
}
|
|
|
|
public function renderFormatPrice($values, $column)
|
|
{
|
|
$value = $this->renderCell($values, $column);
|
|
|
|
$params = ['printcurrency' => false];
|
|
if (!empty($column['price_params'])) {
|
|
$params += $column['price_params'];
|
|
}
|
|
|
|
$currencyContext = ServiceContainer::getService(CurrencyContext::class);
|
|
$currency = $currencyContext->getActive();
|
|
|
|
if (!empty($values['currency'])) {
|
|
$currency = $currencyContext->getAll()[$values['currency']];
|
|
$params['currency'] = $currency;
|
|
}
|
|
|
|
return [
|
|
printPrice($value, $params).' ',
|
|
HTML::create('span')->class('currency')->text($currency->getSymbol()),
|
|
];
|
|
}
|
|
|
|
public function renderPriceVAT($values, $column)
|
|
{
|
|
$value = $this->renderCell($values, $column);
|
|
$vat = $this->getListRowValue($values, 'vat', getAdminVat()['id']);
|
|
|
|
$values[$this->getFieldArrayName($column['field'])] = calcPrice($value, getVat($vat), 0);
|
|
|
|
return $this->renderFormatPrice($values, $column);
|
|
}
|
|
|
|
public function renderPriceFinal($values, $column)
|
|
{
|
|
$value = $this->renderCell($values, $column);
|
|
$vat = $this->getListRowValue($values, 'vat', getAdminVat()['id']);
|
|
$discount = $this->getListRowValue($values, 'discount', null);
|
|
|
|
$values[$this->getFieldArrayName($column['field'])] = calcPrice($value, getVat($vat), $discount);
|
|
|
|
return $this->renderFormatPrice($values, $column);
|
|
}
|
|
|
|
public function renderPricePreferred($values, $column)
|
|
{
|
|
switch (\Settings::getDefault()->prod_prefer_price_vat) {
|
|
case 'Y':
|
|
return $this->renderPriceVAT($values, $column);
|
|
|
|
case 'F':
|
|
return $this->renderPriceFinal($values, $column);
|
|
|
|
default:
|
|
case 'N':
|
|
return $this->renderPrice($values, $column);
|
|
}
|
|
}
|
|
|
|
public function renderHTML($values, $column)
|
|
{
|
|
$value = $this->renderCell($values, $column);
|
|
|
|
if (!$value) {
|
|
return '';
|
|
}
|
|
|
|
return HTML::create('span')->attr('class', 'text-dark')->text(strip_tags($value));
|
|
}
|
|
|
|
public function renderDate($values, $column)
|
|
{
|
|
$value = $this->renderCell($values, $column);
|
|
|
|
if (!$value || substr($value, 0, 10) == '0000-00-00') {
|
|
return '';
|
|
}
|
|
|
|
$date = new \DateTime($value);
|
|
|
|
$format = \Settings::getDateFormat();
|
|
|
|
return $date->format($format);
|
|
}
|
|
|
|
public function renderDateTime($values, $column)
|
|
{
|
|
$value = $this->renderCell($values, $column);
|
|
|
|
if (!$value || substr($value, 0, 19) == '0000-00-00 00:00:00') {
|
|
return '';
|
|
}
|
|
|
|
$date = new \DateTime($value);
|
|
|
|
$format = \Settings::getDateFormat().' '.\Settings::getTimeFormat();
|
|
|
|
return $date->format($format);
|
|
}
|
|
|
|
public function renderPosition($values)
|
|
{
|
|
return [
|
|
HTML::create('span')
|
|
->class('drag-drop-mover pull-right')
|
|
->tag('i')
|
|
->class('bi bi-arrows-move handle')
|
|
->end(),
|
|
HTML::create('input')
|
|
->class('sort')
|
|
->attr('type', 'hidden')
|
|
->attr('data-sort', '')
|
|
->attr('name', $values['id'])
|
|
->attr('value', $values['position'] ?? ''),
|
|
];
|
|
}
|
|
|
|
public function renderPercents($values, $column)
|
|
{
|
|
$value = $this->getListRowValue($values, $column['field']);
|
|
if (is_null($value)) {
|
|
return \KupShop\KupShopBundle\Util\HtmlBuilder\HTML::create('span')
|
|
->text('-')
|
|
->attr('style', 'font-size: 140%');
|
|
}
|
|
|
|
return round($value, 1).' %';
|
|
}
|
|
|
|
public function renderBadge($title, $badgeClass, $icon)
|
|
{
|
|
if ($icon) {
|
|
return HTML::create('span')->class('badge '.$badgeClass)
|
|
->tag('span')->class('bi bi-'.$icon)->end()
|
|
->attr('title', $title)
|
|
->tag('span')->class('tooltip-text m-l-1')->text($title)->end();
|
|
} else {
|
|
return HTML::create('span')->class('badge '.$badgeClass)
|
|
->attr('title', $title)
|
|
->text($title);
|
|
}
|
|
}
|
|
|
|
public function renderImage($values, $column)
|
|
{
|
|
$img = getImage($values['id_image'] ?? null, $values['image_2'] ?? null, $values['image_source'] ?? null, $values['image_type'] ?? null);
|
|
|
|
if (empty($img)) {
|
|
$path = '/admin/static/images/no-image.png';
|
|
} else {
|
|
$path = $this->getUrlFinder()->staticUrl($img['source']);
|
|
}
|
|
|
|
return HTML::create('img')
|
|
->class('img img-rounded')
|
|
->attr('src', $path);
|
|
}
|
|
|
|
public function exportArray($array, $separator = ', ')
|
|
{
|
|
return implode($separator, $array);
|
|
}
|
|
|
|
public function getCheckbox($name, $value, $checked = true)
|
|
{
|
|
return HTML::create('input')
|
|
->attr('type', 'checkbox')
|
|
->attr('style', 'margin: 0 10px 0 0; float:left;')
|
|
->attr($checked ? 'checked' : '', $checked ? 'checked' : '')
|
|
->attr('name', 'data['.$name.'][]')
|
|
->attr('value', $value);
|
|
}
|
|
|
|
// Label functions
|
|
public function labelPricePreferred($column)
|
|
{
|
|
switch (\Settings::getDefault()->prod_prefer_price_vat) {
|
|
case 'Y':
|
|
return 'Cena s DPH';
|
|
|
|
case 'F':
|
|
return 'Cena finální';
|
|
|
|
default:
|
|
case 'N':
|
|
return 'Cena bez DPH';
|
|
}
|
|
}
|
|
|
|
public function getFinalQueryBuilder(array &$vars): QueryBuilder
|
|
{
|
|
$vars['filtersStorage'] = $this->activateFilters();
|
|
|
|
$this->getTableDef();
|
|
$qb = $this->getQuery();
|
|
|
|
if (is_array($qb)) {
|
|
foreach ($qb as $key => $data) {
|
|
if ($key == 'qb') {
|
|
$qb = $data;
|
|
}
|
|
|
|
$vars['var'][$key] = $data;
|
|
}
|
|
}
|
|
|
|
if (isset($vars['var']['divide'])) {
|
|
$this->pageDivide = $vars['var']['divide'];
|
|
}
|
|
|
|
$vars['object'] = $this;
|
|
|
|
$name = $this->getListName();
|
|
$vars['orderParam'] = $this->getOrder($name);
|
|
|
|
$qb = $this->evaluateColumnClosures($qb);
|
|
$qb = $this->applyOrder($qb, $vars);
|
|
|
|
return $qb;
|
|
}
|
|
|
|
public function activateFilters(): ?array
|
|
{
|
|
$filtersStorage = null;
|
|
|
|
if ($this->filterStorageReady()) {
|
|
$filtersStorage = $this->getFiltersStorage();
|
|
|
|
if (!$this->filtersActive()) {
|
|
$default = $this->getDefaultFilter();
|
|
if (!empty($default['id'])) {
|
|
$_GET['adminFilter'] = $default['id'];
|
|
}
|
|
}
|
|
|
|
if (!empty($filtersStorage['storage']) && !empty($_GET['adminFilter'])) {
|
|
$filterID = $_GET['adminFilter'];
|
|
$filter = null;
|
|
foreach ($filtersStorage['storage'] as $f) {
|
|
if ($f['id'] == $filterID) {
|
|
$filter = $f;
|
|
break;
|
|
}
|
|
}
|
|
$this->activateFilter($filter);
|
|
}
|
|
}
|
|
|
|
return $filtersStorage;
|
|
}
|
|
|
|
/**
|
|
* @return string|null
|
|
*/
|
|
public function getTableName()
|
|
{
|
|
return $this->tableName;
|
|
}
|
|
|
|
public function setMassEditActive(bool $massEditActive): void
|
|
{
|
|
$this->massEditActive = $massEditActive;
|
|
}
|
|
|
|
protected function getUrlFinder(): UrlFinder
|
|
{
|
|
static $urlFinder = null;
|
|
|
|
if (!$urlFinder) {
|
|
$urlFinder = ServiceContainer::getService(UrlFinder::class);
|
|
}
|
|
|
|
return $urlFinder;
|
|
}
|
|
}
|