Постраничный листер средствами TS без PHP и доп. расширений

Задача: Реализовать постраничное перелистование табличных данных, с навигационными кнопками «вперед», «назад», используя только средства typoscript

Реализация: Посредством контент элементов CONTENT, TEXT, LOAD_REGISTER, так же будут использованы функции stdWrap, if, select

Основная проблема: Если кто пытался реализовать данную функцию с помощью CONTENT элемента, то каждый сталкивался с тем, что напрямую реализовать не возможно, так как в функции select нет динамической обработки через stdWrap значений begin и max, поэтому никак не возможно передать туда значения аргументов из строки запроса.

Решение основной проблемы: Заключается в реализации не большого хака, а именно SQL-инъекции на уровне TS-кода, сразу оговорюсь будьте предельно внимательны при использование данного подхода, так как вы будете работать напрямую с запросом к БД, обязательно перед тем как передавать значения, убедитесь в том, что вы проверили (отфильтровали) передаваемые данные.

Основная идея:

...
  table = tx_tslister_data
  select{
    ... 
    andWhere = 1=1 LIMIT {register:begin},{register:end} #
    andWhere.insertData = 1
    ...
  }
...

Из всех параметров функции select, только 2 могут быть обработаны через stdWrap, я выбрал andWhere потому что он прибавляется к запросу позже чем pidInList, и так в результате у нас получился запрос:

SELECT * FROM tx_tslister_data 
WHERE tx_tslister_data.pid IN (5) AND 1=1 
LIMIT 1,10 # AND tx_tslister_data.deleted=0 AND tx_tslister_data.hidden=0
 
Так бы он выполнялся если бы мы не использовали данный подход:
 
SELECT * FROM tx_tslister_data 
WHERE tx_tslister_data.pid IN (5) 
AND tx_tslister_data.deleted=0 AND tx_tslister_data.hidden=0

Рабочий пример:
Страница с uid 5 используется для хранения записей таблицы, с uid 4 страница на которой находиться листер.

page = PAGE
 
sql{
  table = tx_tslister_data
  select{
    pidInList = 5
    andWhere = tx_tslister_data.deleted=0 AND tx_tslister_data.hidden=0 {register:sql_limitpart} #
    andWhere.insertData = 1
  }
}
 
page.1 = LOAD_REGISTER
page.1{
  #кол-во элементов в списке листера
  sql_perpage.cObject = TEXT
  sql_perpage.cObject.value = 10
 
  #Передаем значение и фильтруем значения номера страницы из запроса к серверу
  sql_page.cObject = TEXT
  sql_page.cObject.data = GPvar:page
  sql_page.cObject.intval = 1
 
  #Расчет начала ограничения запроса
  sql_start.cObject = TEXT
  sql_start.prioriCalc = 1
  sql_start.cObject{
    if.isPositive.data = register:sql_page
    value =  {register:sql_perpage}*({register:sql_page} - 1)
    insertData = 1
  }
 
  #Расчет конечного ограничения запроса
  sql_limit.cObject = TEXT
  sql_limit.prioriCalc = 1
  sql_limit.cObject{
    value =  ({register:sql_perpage}*({register:sql_page} - 1))+{register:sql_perpage}
    insertData = 1
  }
 
  #Формируем LIMIT, эмуляция IF(...){...}ELSE{...}
  sql_limitpart.cObject = COA
  sql_limitpart.cObject{
    10 = COA
    10{
      #IF 'limit' > 0
      if.isPositive.data = register:sql_limit
 
      #IF 'limit' && 'start' > 0
      10 = TEXT
      10{
        if.isPositive.data = register:sql_start
        value = LIMIT {register:sql_start},{register:sql_limit}
        insertData = 1
      }
 
      #ELSE 'start' == False
      20 = TEXT
      20{
        if.isFalse.data = register:sql_start
        value = LIMIT {register:sql_limit}
        insertData = 1
      }
    }
 
    #IF limit == False
    20 = TEXT
    20{
      if.isFalse.data = register:sql_limit
      value = LIMIT 10
    }
  }
 
  #Общее кол-во записей
  sql_total.cObject = TEXT
  sql_total.cObject.numRows{
    table < sql.table
    select < sql.select
  }
}
 
#Страница листера
page.20 = CONTENT
page.20{
  table < sql.table
  select < sql.select
  renderObj = COA
  renderObj{
    wrap = <div style="border-top:1px solid #999;padding:3px;">|</div>
 
    10 = TEXT
    10.field = title
    10.wrap = |</br>
 
    20 = TEXT
    20.field = body
  }
}
 
#Навигация по листеру
page.30 = COA
page.30{
  1 = LOAD_REGISTER
  1{
    #Определяем предыдущую страницу
    pager_prev.cObject = TEXT
    pager_prev.cObject{
      value = {register:sql_page}-1
      insertData = 1
    }
    pager_prev.prioriCalc=1
 
    #Определяем следующуя страницу
    pager_next.cObject = TEXT
    pager_next.cObject{
      value = {register:sql_page}+1
      insertData = 1
    }
    pager_next.prioriCalc=1
  }
 
 
  #Кнопка назад
  10 = TEXT
  10{
    if.isPositive.data = register:sql_start
    value = < back
    typolink{ 
      parameter = 4
      additionalParams.cObject = TEXT
      additionalParams.cObject{
        value = &page={register:pager_prev}
        insertData=1
      }
    }
  }
 
  #Кнопка вперед
  30 = TEXT
  30{
    if.value.data = register:sql_limit
    if.isGreaterThan.data = register:sql_total
    value = forward >
    typolink{
      parameter = 4
      additionalParams.cObject = TEXT
      additionalParams.cObject{
        value = &page={register:pager_next}
        insertData=1
      }
    }
  }
}

P.S. и не забудьте создать табличку в БД, вот такого плана

--
-- Структура таблицы `tx_tslister_data`
--
 
CREATE TABLE IF NOT EXISTS `tx_tslister_data` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `pid` int(11) NOT NULL DEFAULT '0',
  `tstamp` int(11) NOT NULL DEFAULT '0',
  `crdate` int(11) NOT NULL DEFAULT '0',
  `cruser_id` int(11) NOT NULL DEFAULT '0',
  `deleted` tinyint(4) NOT NULL DEFAULT '0',
  `hidden` tinyint(4) NOT NULL DEFAULT '0',
  `title` tinytext NOT NULL,
  `body` text NOT NULL,
  PRIMARY KEY (`uid`),
  KEY `parent` (`pid`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=13 ;
 
--
-- Дамп данных таблицы `tx_tslister_data`
--
 
INSERT INTO `tx_tslister_data` (`uid`, `pid`, `tstamp`, `crdate`, `cruser_id`, `deleted`, `hidden`, `title`, `body`) VALUES
(1, 5, 1266902311, 1266902311, 1, 0, 0, 'title - 1', 'body - 1'),
(2, 5, 1266902321, 1266902321, 1, 0, 0, 'title - 2', 'body - 2'),
(3, 5, 1266902333, 1266902333, 1, 0, 0, 'title - 3', 'body - 3'),
(4, 5, 1266902361, 1266902361, 1, 0, 0, 'title - 3', 'body - 3'),
(5, 5, 1266902361, 1266902361, 1, 0, 0, 'title - 2', 'body - 2'),
(6, 5, 1266902361, 1266902361, 1, 0, 0, 'title - 1', 'body - 1'),
(7, 5, 1266902365, 1266902365, 1, 0, 0, 'title - 3', 'body - 3'),
(8, 5, 1266902365, 1266902365, 1, 0, 0, 'title - 2', 'body - 2'),
(9, 5, 1266902365, 1266902365, 1, 0, 0, 'title - 1', 'body - 1'),
(10, 5, 1266902369, 1266902369, 1, 0, 0, 'title - 3', 'body - 3'),
(11, 5, 1266902369, 1266902369, 1, 0, 0, 'title - 2', 'body - 2'),
(12, 5, 1266902369, 1266902369, 1, 0, 0, 'title - 1', 'body - 1');

1 ответ

  1. Нехватает только увидеть результат этой реализации, на боевом сайте.

Оставьте отзыв