Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В. PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. MySQL на примерах. Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Пагинатор. Выборка из нескольких таблиц
 
 автор: KonstRuctor   (08.03.2011 в 12:39)   письмо автору
 
 

Привет всем!
В горячо любимой мной книжке «ООП на 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 с разбивкой на страницы пагинатором.

  Ответить  
 
 автор: cheops   (08.03.2011 в 13:43)   письмо автору
 
   для: 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,
                             
"&amp;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,
                               
"&amp;category_id=1");
?>

  Ответить  
 
 автор: KonstRuctor   (08.03.2011 в 14:23)   письмо автору
 
   для: cheops   (08.03.2011 в 13:43)
 

Огромное спасибо за ответ! Получилось сделать как в первом варианте, все работает.

Позвольте небольшое лирическое отступление от темы пагинатора :-)

Изучал ООП с нуля по книге «ООП на PHP» (2007). Прочитал книгу 2,5 раза.
Столкнулся с тем, что зачастую я читаю текст и код и теряю связь с реальностью, не понимаю, для чего мне вообще это надо и смогут ли мне пригодиться данные знания.
Например пагинатор — без этого инструмента ни один более или менее крупный проект (магазин, каталог, блог, что угодно) работать не сможет. Причем как на сайте, так и в админке. Изучая пагинатор, я попутно изучаю принципы ООП, здесь все ясно.

Возьмем к примеру такую важную тему, как специальные методы, в частности __set() и __get(). Они рассматриваются на каком-то нелепом на мой взгляд примере с работниками, а то и вовсе «Здравствуй, мир!» на стр. 110. В результате я так и не понял что это, зачем это? Мне нужен метод — я создам метод, мне не сложно. Вообще говоря, пример с работниками, который проходит через половину книги, неудачный. Понятнее было бы рассмотреть пример из реальной жизни (юзеры на сайте, блог и комментарии, магазин и товары, фотогалерея и оценки и т.п.).

Тема интерфейсов, на мой взгляд, не раскрыта до конца. Я так и не понял пока, зачем мне их изучать и использовать, когда все то же самое можно сделать с помощью классов с различными модификаторами доступа.

Одним словом, жду новое издание книги! Если только, конечно, не разберусь с ООП сам до этого времени :-) Кстати, достойных конкурентов у данной книги, как на русском, так и на английском нет (имею в виду как учебник для начинающих).

Удачи!

  Ответить  
 
 автор: cheops   (08.03.2011 в 15:04)   письмо автору
 
   для: KonstRuctor   (08.03.2011 в 14:23)
 

Да, есть такое дело, ООП хорошо демонстрировать на примере объемных систем, придумать одну такую систему и протащить её сквозь книгу задача не простая. А без этого продемонстрировать пользу тех или иных инструментов не просто. Мы попытались это частично компенсировать в книге PHP. Практика создания Web-сайтов. Однако, у последней книги цель была - построение сайта при помощи FrameWork, описываемого в ООП на PHP, а не обзор всех ООП-возможностей.

>Возьмем к примеру такую важную тему, как специальные методы, в частности __set() и
>__get(). Они рассматриваются на каком-то нелепом на мой взгляд примере с работниками, а
>то и вовсе «Здравствуй, мир!» на стр. 110.
В книгах есть определенные правила, нельзя на протяжении 270 страниц рассматривать неправильно-спроектированную систему, на 270 странице ввести к ней новые требования, для удовлетворения которым придется перелопатить все 270 страниц и сказать, что если на 10 странице мы бы воспользовались бы __set() и __get(), то поправить код можно было бы в одном месте. Такие обидные ошибки проектирования в раз позволяют понять зачем нужен тот или иной инструмент и сколько он может съэкономить время при изменениях в требованиях на поздних этапах работы, но в книгах такие издевательства над читателями не приветствуются :)))

>Тема интерфейсов, на мой взгляд, не раскрыта до конца. Я так и не понял пока, зачем мне их
>изучать и использовать, когда все то же самое можно сделать с помощью классов с
>различными модификаторами доступа.
Чтобы показать их важность, нужно классов 80... если в C++ программах это не проблема, то в PHP-проектах этого стараются избегать (классы замедляют приложения), поэтому до реального использования дело редко доходит. Ну и формат книги накладывает ограничения, она должна быть понятна читателям с разным уровнем подготовки. Примеры не должны быть слишком большими, чтобы в памяти не приходилось держать большой объем данных.

PS Да, вероятно второе издание книги появится и мы постараемся учесть все замечания. Когда мы писали эту книгу, основная цель была сделать её понятной, собственно облегченные примеры растут отсюда - не хотелось бы писать сильно запутанную книгу по ООП, которых и без нас хватает.

  Ответить  
 
 автор: psychomc   (08.03.2011 в 14:47)   письмо автору
 
   для: 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($tot0);
    }
?>


если в $this->tablename будет нескольких таблиц и LEFT JOIN, то запрос будет возвращать неверное количество записей. запрос должен выглядеть примерно так:

SELECT COUNT(DISTINCT имя_поля) FROM {$this->tablename}

  Ответить  
 
 автор: cheops   (08.03.2011 в 15:07)   письмо автору
 
   для: psychomc   (08.03.2011 в 14:47)
 

Это зависит от того, как вы ON-условия в LEFT JOIN выстроите, выше я привел пример, где такой ошибки не возникает, без использования DISTINCT. Но вообще да, в многотабличном запросе, лучше его полностью формировать, как это сделано в моем посте чуть выше.

PS А зашитый COUNT(*) может много неприятностей дать, не только из-за DISTINCT, но из из-за возможного использования GROUP BY. Собственно почему ООП и полезен, вместо переписывания класса, вы можете унаследовать новый класс, где достаточно переопределить метод get_total(), полностью его переписав, при этом логика остальных методов не затрагивается, в неё даже не нужно вникать.

  Ответить  
 
 автор: psychomc   (08.03.2011 в 15:12)   письмо автору
 
   для: cheops   (08.03.2011 в 15:07)
 

LIMIT'ы присоединять потом к нему, перед выполнением?

  Ответить  
 
 автор: cheops   (08.03.2011 в 15:18)   письмо автору
 
   для: psychomc   (08.03.2011 в 15:12)
 

Да, phpMyAdmin именно так и поступает с SELECT-запросом, который поступает ему на выполнение. Нужно только убедиться, что во внешнем запросе нет LIMIT-конструкций, если есть, то вырезать или сгенерировать исключение.

  Ответить  
 
 автор: psychomc   (08.03.2011 в 15:27)   письмо автору
 
   для: cheops   (08.03.2011 в 15:18)
 

и я так понимаю, 2 запрос, подсчитывающий количество, будет выглядеть так:

SELECT FOUND_ROWS();


?

  Ответить  
 
 автор: cheops   (08.03.2011 в 15:31)   письмо автору
 
   для: psychomc   (08.03.2011 в 15:27)
 

Да.

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования