|
|
|
| Привет всем!
В горячо любимой мной книжке «ООП на PHP» в главе 4 рассматривается построение пагинатора для работы с базой данных. Отличный класс, я разобрался в нем, переделал дизайн и некоторые функции под себя и успешно внедрил в некоторые мои проекты. Работает как швейцарские часы :-)
Однако ограничение на выборку только из одной таблицы БД должно было однажды дать о себе знать, и оно дало. В замечании на стр. 184 сказано, что «для реализации многотабличных запросов потребуется унаследовать от pager новый класс pager_mysql_multi»
Вопрос: кто-нибудь разобрался, как это сделать? У меня ничего не получилось, сколько я ни бился.
Есть комментарии к товарам, есть перечень товаров, есть категории товаров.
Задача проста: нужно вывести все комментарии к товарам определенной категории.
comments:
id | user_id | tovar_id | comment
tovar:
id | category_id | title | price
categories:
id | title
|
Хочу выводить перечень всех комментариев к товару категории id = 1 с разбивкой на страницы пагинатором. | |
|
|
|
|
|
|
|
для: KonstRuctor
(08.03.2011 в 12:39)
| | Собственно можно попытаться использовать класс как есть
<?php
$obj = new pager_mysql("comments LEFT JOIN tovar
ON (comments.tovar_id = torar.id) LEFT JOIN categories
ON (torar.category_id = categories.id)",
"WHERE categories.id = 1",
"ORDER BY toral.title DESC",
$pnumber,
$page_link,
"&category_id=1");
?>
|
Неудобство заключается в том, что вместо обычных называний столбцов у вас будут расширенные имена (с названием таблицы через точку), чтобы от них избавиться, следует перегрузить класс, добавив в конструктор еще один параметр - для столбцов.
Понятно, что получается не очень удобно в использовании - запрос разбит на куски и его логика читается с трудом. Многотабличные запросы и так не очень простая штука, а когда они разбиты, разбираться в них еще сложнее. В тоже время основная цель ООП делать код более читабельным и простым в сопровождении. Скорее всего в новую версию SoftTime FrameWork войдет новый класс, который будет работать с целым SQL-запросом, использующих ключевое слово SQL_CALC_FOUND_ROWS, для подсчета количества позиций. Собственно его можно разрабатывать прямо сейчас, унаследовав его от pager. Т.е. в конечном итоге вызов этого нового класса должен выглядеть следующим образом
<?php
$query = "SELECT
SQL_CALC_FOUND_ROWS
comments.id AS id,
comments.user_id AS user_id
comments.tovar_id AS tovar_id
comments.comment AS comment
FROM
comments LEFT JOIN tovar
ON (comments.tovar_id = tovar.id)
LEFT JOIN categories
ON (tovar.category_id = categories.id)
WHERE categories.id = 1
ORDER BY tovar.title DESC";
$obj = new pager_mysql_multy($query,
$pnumber,
$page_link,
"&category_id=1");
?>
|
| |
|
|
|
|
|
|
|
для: cheops
(08.03.2011 в 13:43)
| | Огромное спасибо за ответ! Получилось сделать как в первом варианте, все работает.
Позвольте небольшое лирическое отступление от темы пагинатора :-)
Изучал ООП с нуля по книге «ООП на PHP» (2007). Прочитал книгу 2,5 раза.
Столкнулся с тем, что зачастую я читаю текст и код и теряю связь с реальностью, не понимаю, для чего мне вообще это надо и смогут ли мне пригодиться данные знания.
Например пагинатор — без этого инструмента ни один более или менее крупный проект (магазин, каталог, блог, что угодно) работать не сможет. Причем как на сайте, так и в админке. Изучая пагинатор, я попутно изучаю принципы ООП, здесь все ясно.
Возьмем к примеру такую важную тему, как специальные методы, в частности __set() и __get(). Они рассматриваются на каком-то нелепом на мой взгляд примере с работниками, а то и вовсе «Здравствуй, мир!» на стр. 110. В результате я так и не понял что это, зачем это? Мне нужен метод — я создам метод, мне не сложно. Вообще говоря, пример с работниками, который проходит через половину книги, неудачный. Понятнее было бы рассмотреть пример из реальной жизни (юзеры на сайте, блог и комментарии, магазин и товары, фотогалерея и оценки и т.п.).
Тема интерфейсов, на мой взгляд, не раскрыта до конца. Я так и не понял пока, зачем мне их изучать и использовать, когда все то же самое можно сделать с помощью классов с различными модификаторами доступа.
Одним словом, жду новое издание книги! Если только, конечно, не разберусь с ООП сам до этого времени :-) Кстати, достойных конкурентов у данной книги, как на русском, так и на английском нет (имею в виду как учебник для начинающих).
Удачи! | |
|
|
|
|
|
|
|
для: KonstRuctor
(08.03.2011 в 14:23)
| | Да, есть такое дело, ООП хорошо демонстрировать на примере объемных систем, придумать одну такую систему и протащить её сквозь книгу задача не простая. А без этого продемонстрировать пользу тех или иных инструментов не просто. Мы попытались это частично компенсировать в книге PHP. Практика создания Web-сайтов. Однако, у последней книги цель была - построение сайта при помощи FrameWork, описываемого в ООП на PHP, а не обзор всех ООП-возможностей.
>Возьмем к примеру такую важную тему, как специальные методы, в частности __set() и
>__get(). Они рассматриваются на каком-то нелепом на мой взгляд примере с работниками, а
>то и вовсе «Здравствуй, мир!» на стр. 110.
В книгах есть определенные правила, нельзя на протяжении 270 страниц рассматривать неправильно-спроектированную систему, на 270 странице ввести к ней новые требования, для удовлетворения которым придется перелопатить все 270 страниц и сказать, что если на 10 странице мы бы воспользовались бы __set() и __get(), то поправить код можно было бы в одном месте. Такие обидные ошибки проектирования в раз позволяют понять зачем нужен тот или иной инструмент и сколько он может съэкономить время при изменениях в требованиях на поздних этапах работы, но в книгах такие издевательства над читателями не приветствуются :)))
>Тема интерфейсов, на мой взгляд, не раскрыта до конца. Я так и не понял пока, зачем мне их
>изучать и использовать, когда все то же самое можно сделать с помощью классов с
>различными модификаторами доступа.
Чтобы показать их важность, нужно классов 80... если в C++ программах это не проблема, то в PHP-проектах этого стараются избегать (классы замедляют приложения), поэтому до реального использования дело редко доходит. Ну и формат книги накладывает ограничения, она должна быть понятна читателям с разным уровнем подготовки. Примеры не должны быть слишком большими, чтобы в памяти не приходилось держать большой объем данных.
PS Да, вероятно второе издание книги появится и мы постараемся учесть все замечания. Когда мы писали эту книгу, основная цель была сделать её понятной, собственно облегченные примеры растут отсюда - не хотелось бы писать сильно запутанную книгу по ООП, которых и без нас хватает. | |
|
|
|
|
|
|
|
для: cheops
(08.03.2011 в 13:43)
| | в вашем классе в одной из версий видел такую функцию
<?php
public function get_total()
{
// Формируем запрос на получение
// общего количества записей в таблице
$query = "SELECT COUNT(*) FROM {$this->tablename}
{$this->where}
{$this->order}";
$tot = mysql_query($query);
if(!$tot)
{
throw new ExceptionMySQL(mysql_error(),
$query,
"Ошибка подсчёта количества записей");
}
return mysql_result($tot, 0);
}
?>
|
если в $this->tablename будет нескольких таблиц и LEFT JOIN, то запрос будет возвращать неверное количество записей. запрос должен выглядеть примерно так:
SELECT COUNT(DISTINCT имя_поля) FROM {$this->tablename}
|
| |
|
|
|
|
|
|
|
для: psychomc
(08.03.2011 в 14:47)
| | Это зависит от того, как вы ON-условия в LEFT JOIN выстроите, выше я привел пример, где такой ошибки не возникает, без использования DISTINCT. Но вообще да, в многотабличном запросе, лучше его полностью формировать, как это сделано в моем посте чуть выше.
PS А зашитый COUNT(*) может много неприятностей дать, не только из-за DISTINCT, но из из-за возможного использования GROUP BY. Собственно почему ООП и полезен, вместо переписывания класса, вы можете унаследовать новый класс, где достаточно переопределить метод get_total(), полностью его переписав, при этом логика остальных методов не затрагивается, в неё даже не нужно вникать. | |
|
|
|
|
|
|
|
для: cheops
(08.03.2011 в 15:07)
| | LIMIT'ы присоединять потом к нему, перед выполнением? | |
|
|
|
|
|
|
|
для: psychomc
(08.03.2011 в 15:12)
| | Да, phpMyAdmin именно так и поступает с SELECT-запросом, который поступает ему на выполнение. Нужно только убедиться, что во внешнем запросе нет LIMIT-конструкций, если есть, то вырезать или сгенерировать исключение. | |
|
|
|
|
|
|
|
для: cheops
(08.03.2011 в 15:18)
| | и я так понимаю, 2 запрос, подсчитывающий количество, будет выглядеть так:
? | |
|
|
|
|
|
|
|
для: psychomc
(08.03.2011 в 15:27)
| | Да. | |
|
|
|
|