Форум программистов, компьютерный форум, киберфорум
PHP для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.83/18: Рейтинг темы: голосов - 18, средняя оценка - 4.83
39 / 9 / 10
Регистрация: 19.09.2016
Сообщений: 1,076

Органицация пагинации

04.07.2020, 23:48. Показов 3768. Ответов 31
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Наваял свой первый пагинатор. Сначала естественно в процедурном стиле, потом еще половина этого времени ушло, чтобы пееформатировать в ООП. С этим конечно возникли сложности, т.к. для себя я вижу разные варианты, непонятно как правильно/грамотно. Ну и сами вопросы по реализации, большей частью по представлению.
Выглядит и функционирует это конечно примитивно, но функции свои выполняет:
Название: Screenshot from 2020-07-04 22-11-51.jpg
Просмотров: 214

Размер: 3.7 Кб Название: Screenshot from 2020-07-04 22-11-42.jpg
Просмотров: 214

Размер: 3.1 Кб Название: Screenshot from 2020-07-04 22-11-33.jpg
Просмотров: 214

Размер: 2.8 Кб

Реализовал так: Во фронт-контроллере вызываю основной контроллер(для вывода статей) и получаю объект пагинатора, который с объектом статьи и комментариев рендерятся в страничку представления:
Кликните здесь для просмотра всего текста

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
 * Class MainController
 * @package MyProject\Controllers
 */
class MainController extends AbstractController
{
    /**
     * @param int $active
     * @throws DbException
     * @throws NotFoundException
     */
    public function main(int $active = 1)
    {
        $articles = Article::getAll();
        $comments = Comment::getAll();
        if (is_array($articles)) {
            $articlesInDb = count($articles);
            $articlesPerPage = 3;
            $pages = ceil($articlesInDb / $articlesPerPage);
            if ($active <=0 || $active > $pages) {
                throw new NotFoundException('Wrong page number');
            }
            $firstArticleOnPage = ($active*$articlesPerPage)-$articlesPerPage;
            $articles = Article::getByLimit($firstArticleOnPage, $articlesPerPage);
            $paginateString = new Paginator($active, $pages);
        }
        $this->view->renderHtml('main/main.php', ['articles' => $articles, 'comments' => $comments, 'paginateString' => $paginateString]);
        exit();
    }
}

Пагинатор реализовал отдельным классом с конструктором и методом получения строки пагинатора с адресами.
Кликните здесь для просмотра всего текста

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
 * Class paginator
 * @package MyProject\Services
 */
class Paginator
{
    /**
     * @var
     */
    protected $sideSize;
    /**
     * @var int
     */
    protected $active;
    /**
     * @var int
     */
    protected $pages;
    /**
     * @var
     */
    protected $start;
    /**
     * @var
     */
    protected $stop;
    /**
     * @return mixed
     */
    public function getSideSize()
    {
        return $this->sideSize;
    }
 
    /**
     * @return mixed
     */
    public function getStart()
    {
        return $this->start;
    }
 
    /**
     * @return mixed
     */
    public function getStop()
    {
        return $this->stop;
    }
 
    /**
     * @return int
     */
    public function getActive(): int
    {
        return $this->active;
    }
 
    /**
     * @return int
     */
    public function getPages(): int
    {
        return $this->pages;
    }
 
    /**
     * paginator constructor.
     * @param int $active
     * @param int $pages
     */
    public function __construct(int $active, int $pages)
    {
        $this->active = $active;
        $this->pages = $pages;
        $this->getPaginateString();
    }
 
    /**
     * @return $this
     */
    private function getPaginateString()
    {
        $this->sideSize = 2;
        $paginatePagesNumber = $this->sideSize * 2 + 1;
        $this->start = $this->active - $this->sideSize;
        $this->stop = $this->active + $this->sideSize;
       if ($this->active < ($this->sideSize + 1)){
           $this->start = 1;
           $this->stop = $paginatePagesNumber;
        }
        if ($this->active + $this->sideSize > $this->pages) {
            $this->start = $this->pages - ($paginatePagesNumber - 1);
            $this->stop = $this->pages;
        }
        return $this;
    }
}

Тут конечно у меня своя логика, хотя нюансов хоть отбавляй)) Возможно многим покажется странным, непонятным, нелогичным, но оно работает.

Представление, наверное самое несуразное, тут сама строка пагинатора:
Кликните здесь для просмотра всего текста

HTML5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<p>
    <a href="/blog/1"><<&nbsp</a>
    <a href="/blog/<?=$paginateString->getActive() == 1 ? 1 : $paginateString->getActive() - 1?>"><&nbsp</a>
 
    <?php
 
    if ($paginateString->getActive() > ($paginateString->getSideSize() + 1)) {
        echo '...';
    }?>
    <?php
 
    for ($start = $paginateString->getStart(); $start <= $paginateString->getStop(); $start++):?>
        <a href="/blog/<?=$start?>"><?=$start == $paginateString->getActive() ? '<span>'.$start.'</span>' : $start;?></a>
    <?php endfor?>
    <?php if ($paginateString->getActive() < ($paginateString->getPages() - $paginateString->getSideSize())) {
        echo '...';
    }?>
    <a href="/blog/<?=$paginateString->getActive() == $paginateString->getPages() ? $paginateString->getPages() : $paginateString->getActive() + 1?>">&nbsp></a>
    <a href="/blog/<?=$paginateString->getPages()?>">&nbsp>></a>
</p>

и кучка вопросов:
В части контроллера:
1. насколько корректно несколькими маршрутами отправлять на одну и ту же страничку? Страничка одна, а адресов несколько. Эту "проблему " не знал как по другому решить. Т.к. главная страничка - это первая страничка со статьями. А при постраничном вводе нужно как -то в составе стандартных ссылок пагинатора отправлять на первую страничку(/blog/1) = главную(/). Поэтому в контроллере задал "дефолтный" параметр. чтобы и через пагинатор можно было перейти на первую страничку и через ссылку "HOME". Количество статей на экран - опция выбора пользователем, пока захардкодил.

В части самого пагинатора:
2. Нужно ли тут вообще делать конструктор(субъективно, не вижу пока в нем необходимости, может для чего то пригодится в будущем) или оставить один метод, в который передавать параметры вместо конструктора?
3. Количество видимых страниц в строке пагинаора тоже захардкодил. Не знаю, как с ним поступать. Необходимость в такой опции - наверное скорее - экзотика и только для админа. В коде - для прямого программирования этой опции - достаточно только один раз изменить значение в методе.

В части представления:
4.Тут какая-то куча-мала... груда однотипных обращений к объектам, сам читаю и дурно становится. Может хоть где-то в начале представления пагинатора выполнить типа инициализацию объекта пагинатора и установить какие-то короткие, читаемые названия, получив в них данные через геттеры, как сделано для переменной $start в цикле?
5. на счет
PHP
1
echo'...'
; тут тоже большие сомнения в корректности такого решения. Хотя это больше к фонту относится я так понимаю,
но наверное все таки было бы как минимум лучше сделать через CSS (before/after)?

Ну и в целом - насколько все плохо?)
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
04.07.2020, 23:48
Ответы с готовыми решениями:

Оформление пагинации
Здраствуйте, не могу нормально оформить пагинацию пока сделал , что бы показывало как &quot;&quot;, через ид в стилях не работает. ...

Не отображается вторая страницы пагинации
На сайте есть раздел Акции, первая страница отображается нормально, когда перехожу на вторую страницу пагинации появляется вот это(скрин в...

Сохранение данных фильтра при пагинации
Добрый день. Подскажите пожалуйста, проблема в общем стандартная, но ответа не нашел. Есть каталог, подгружаемый из БД, есть фильтры,...

31
39 / 9 / 10
Регистрация: 19.09.2016
Сообщений: 1,076
07.07.2020, 16:19  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от estic Посмотреть сообщение
Правда, на повторное использование кода с разметкой в этом случае уже трудно рассчитывать.
Да, у меня мысли были, чтобы пагинатор можно было использовать и для комментариев например. Но до реализации не дошел. В этом случае да. нужно будет формировать нужный формат адреса заранее в отдельной функции, чтобы можно было использовать пагинатор полностью универсально и код и разметку. Спасибо, что напомнили.
Цитата Сообщение от estic Посмотреть сообщение
Если не можете скрыть формирование адреса в специальной функции
А зачем именно скрывать целенаправленно, я не понял если честно.
0
1310 / 1002 / 232
Регистрация: 01.10.2018
Сообщений: 3,896
07.07.2020, 19:48
А зачем шаблон привязывать к адресации? Чтобы каждый раз его править под конкретные адреса?

Добавлено через 5 минут
И опять-таки без этого вы теряете возможность повторного использования кода с разметкой. Например, уже не сможете использовать один и тот же шаблон для формирования страниц с абсолютными адресами /blog/ и /news/, а я внутри функции pagelink(1) могу это делать.
0
 Аватар для sad67man
2604 / 1508 / 689
Регистрация: 23.08.2015
Сообщений: 3,834
11.07.2020, 00:06
Тут можно немного порассуждать. С таким подходом мы могли бы просто передать $totalCount, $currentPage и $limit, а верстальщик все рассчитает. И у нас шаблон получится с кучами формул. Не знаю на сколько это правильно.

Возможно мой вариант не лучший. Так как мы жестко фиксируем количество выводимых страниц, а это уже дизайн, т.е. нарушается принцип единой ответственности. Так же, мы бы могли рассчитать $start и $end в конструкторе класса, таким образом реализация всех остальных методов бы значительно упростилась.

С другой стороны количество выводимых элементов на странице - это тоже можно отнести к дизайну, однако мы не можем так просто полностью возложить эту ответственность на frontend. А от $limit зависит и общее кол-во страниц.

Далее, что касается генерации ссылок. Если мы говорим об ООП, а если у нас MVC, то это должно быть ООП. То это не может быть простой функцией или статическим методом какого-нибудь хэлпера, ведь это не какой-нибудь number_format и т.д. Нам нужны доступы к роутеру, конфигам и т.д.
Функции мы можем вызвать где угодно, что не очень хорошо, так как это нарушает принципы ООП. За генерацию ссылок должен отвечать отдельная служба - UrlManager.

Допустим у нас есть класс, который умеет генерировать ссылки. Где мы передаем название роута, и параметры.
PHP
1
$urlManager->url('blog.list', ['page' => 5]);
При таком подходе мы можем в любой момент изменить ЧПУ для любого роута и на всем сайте все ссылки поменяются.
Можно и добавить метод, который будет брать текущий роут
PHP
1
$urlManager->currentUrl(['page' => 5]);
Т.е. он будет брать название текущего роута и заменять параметры. Что поможет нам с повторным использованием шаблона пагинации.
Обращаю внимание, что при переходе по пагинации у нас должны именно заменяться GET параметр page, все остальные get параметры должны оставаться. К примеру это может быть каталог товаров с фильтрами, сортировкой и т.д. Где все передается именно через GET параметры, и мы не должны их потерять при переходе по страницам пагинации.

Вопрос в том, как получить нам доступ внутри вьюхи, при этом не используя функции? На самом деле все сводится к архитектуре нашего приложения...

Давайте рассмотрим класс Renderer

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Renderer
{
    private $templatesPath;
 
    public function __construct($templatesPath)
    {
        $this->templatesPath = $templatesPath;
    }
 
    public function render(string $name, array $params = []): string
    {
        ob_start();
        extract($params);
        require $this->templatesPath . '/' . $name . '.php';
        return ob_get_clean();
    }
}
Это весьма упрощенная реализация, чисто для наглядности. Но тут можно заметить, что внутри html шаблона мы находимся в контексте данного класса, и мы можем обращаться через $this к его методам и свойствам. Т.е. мы можем к нему подрубить urlManager в конструкторе через контейнер зависимостей, и далее уже использовать внутри нашей вьюшки.

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Renderer
{
    private $templatesPath;
    private $url;
 
    public function __construct($templatesPath, UrlManager $url)
    {
        $this->templatesPath = $templatesPath;
        $this->url = $url;
    }
 
    public function render(string $name, array $params = []): string
    {
        ob_start();
        extract($params);
        require $this->templatesPath . '/' . $name . '.php';
        return ob_get_clean();
    }
}
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class BlogController
{
    private $articles;
    private $renderer;
 
    public function __construct(ArticleReader $articles, Renderer $renderer)
    {
        $this->articles = $articles;
        $this->renderer = $renderer;
    }
 
    public function index()
    {
        $pagination = new Pagination($this->articles->count(), $_GET['page'] ?? 1);
        $articles = $this->articles->list($pagination->getLimit(), $pagination->getOffset());
 
        return $this->renderer->render('blog/index', compact('articles', 'pagination'));
 
    }
}
PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
<?php
 
/**
 * @var Renderer $this
 * @var Article[] $articles
 * @var Pagination $pagination
 */
 
?>
 
<?= $this->url->url('blog.list', ['page' => 5]) ?>
<?= $this->url->currentUrl(['page' => 5]) ?>
1
1310 / 1002 / 232
Регистрация: 01.10.2018
Сообщений: 3,896
11.07.2020, 09:43
Цитата Сообщение от sad67man Посмотреть сообщение
С таким подходом мы могли бы просто передать $totalCount, $currentPage и $limit, а верстальщик все рассчитает. И у нас шаблон получится с кучами формул. Не знаю на сколько это правильно.
Не передергивайте. Верстальщику ничего считать не нужно. Нужно использовать готовое, причем по необходимости. В вопросе подсчета start/end я поддержал вас. Однако здесь есть отличный шанс сделать так, чтобы программист вовсе не знал, будет ли верстальщик в конечном итоге использовать "широкую" строку, и мог бы даже не обеспечивать наличие функций для подсчета start/end, пока верстальщик сам об этом не попросит.

Цитата Сообщение от sad67man Посмотреть сообщение
С другой стороны количество выводимых элементов на странице - это тоже можно отнести к дизайну, однако мы не можем так просто полностью возложить эту ответственность на frontend.
Абсолютно верно. Поэтому это значение обычно выносят в конфигурацию сайта. Его начальное значение обычно определяет верстальщик, но программист при необходимости может изменить (в согласованных с верстальщиком рамках). Изменение этого значения (в ограниченных рамках) обычно не так критично влияет на верстку, как изменение ширины строки навигации.

Цитата Сообщение от sad67man Посмотреть сообщение
А от $limit зависит и общее кол-во страниц.
Обратите внимание на то, что верстальщику можно работать сразу с $pageCount, тогда ему лимит не нужен. Общее количество элементов для навигации по большому счету тоже не нужно (я его упоминал только по той причине, что в представлении часто требуется значение для "всего элементов").

Добавлено через 7 минут
Цитата Сообщение от sad67man Посмотреть сообщение
а если у нас MVC, то это должно быть ООП
Промолчу Но программисты, использующие языки, в которых в принципе нет ООП, могут подумать, что их MVC - и не MVC вовсе
0
39 / 9 / 10
Регистрация: 19.09.2016
Сообщений: 1,076
11.07.2020, 17:47  [ТС]
Цитата Сообщение от sad67man Посмотреть сообщение
С другой стороны количество выводимых элементов на странице - это тоже можно отнести к дизайну, однако мы не можем так просто полностью возложить эту ответственность на frontend. А от $limit зависит и общее кол-во страниц.
Я над этим думал, но пока особо чего то однозначного не надумал. И к чему отнести обработку количества элементов на страницу и выносить ли вообще и каким образом. Это больше относится к пагинатору, как инструменту, или к странице(статьи, комментарии. пользователи и т.п.), в контексте которой отображается(для которой используется) пагинатор...

Цитата Сообщение от sad67man Посмотреть сообщение
За генерацию ссылок должен отвечать отдельная служба
Тоже была такая мысль, но пока даже конструктивно не подходил к этому вопросу, хотя генерирование ссылок "на каждом углу"...
Спасибо за примеры!!
Цитата Сообщение от estic Посмотреть сообщение
Обратите внимание на то, что верстальщику можно работать сразу с $pageCount, тогда ему лимит не нужен.
А есть какие-то правила/стандарты, где разграничивается "официально" ответственность верстальщика и программиста? Я часто не очень представляю где эта граница. Наверное все таки отправная точка - конкретный проект/задание и обозначение общих "переменных", которые должен отдать программист и которыми может оперировать верстальщик.
0
 Аватар для sad67man
2604 / 1508 / 689
Регистрация: 23.08.2015
Сообщений: 3,834
11.07.2020, 19:59
СергейСереб, Давайте немного порассуждаем.. Я не рассматриваю с точки зрения человека "верстальщика" или человека "backender-a". Для меня важнее написать код, который хотя бы не нарушал принципы ООП. В моей вселенной существует единственный правильный вариант, все остальные являются компромиссами, только нужно его найти)
Если пользователь введет в адресную строку 100 страницу, а у нас страниц всего 10. Что мы должны показать? 404 ошибку или сообщение, что записей нет. Чаще всего показывают последнюю страницу, при этом в пагинации она должна быть активной, именно поэтому у меня в методе есть коррекция текущей страницы

PHP
1
2
3
4
public function getCurrentPage()
{
    return max(1, min($this->getPagesCount(), $this->currentPage));
}
И главным образом этот объект отвечает за получения на основе коррекции текущей страницы limit, offset. Также можно получить общее кол-во записей, и общее кол-во страниц.

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Pagination
{
    private $totalCount;
    private $currentPage;
    private $limit;
 
    public function __construct(int $totalCount, int $currentPage = 1, int $limit = 5)
    {
        $this->totalCount = $totalCount;
        $this->currentPage = $currentPage;
        $this->limit = $limit;
    }
 
    public function getLimit(): int
    {
        return $this->limit;
    }
 
    public function getOffset()
    {
        return ($this->getCurrentPage() - 1) * $this->getLimit();
    }
 
    public function getPagesCount()
    {
        return ceil($this->totalCount / $this->getLimit());
    }
 
    public function getCurrentPage()
    {
        return max(1, min($this->getPagesCount(), $this->currentPage));
    }
 
    public function getTotalCount()
    {
        return $this->totalCount;
    }
}
Вот мы получили хороший законченный класс. Который не зависит от вывода. Его можно выложить на github и использовать в других проектах. А вывод может быть разным к примеру и таким
[1] ... [25][26][27][28][29][30] ... [100][101][102] ... [260]

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

Тут получается идеологический вопрос, вывод пагинации - это что? К примеру в некоторых книжках упоминалось о таком компоненте, как Презентатор. Где по аналогии с операционным слоем, где выносятся все операции, точно так же выносится логика формирования данных для вывода в отдельный класс, что позволяет нам его протестировать обособленно от http запросов и html верстки. А далее данные которые он возвращает их можно передать в ответе в разных форматах, как json или html шаблон. Или даже сформировать какой-нибудь xml или pdf)

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

Я никогда не пробовал внедрять такой подход в систему, мне представляется что это должно выглядеть примерно так

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class BlogController
{
    private $articles;
    private $renderer;
    private $presentator;
 
    public function __construct(ArticleReader $articles, BlogPresentator $presentator, Renderer $renderer)
    {
        $this->articles = $articles;
        $this->renderer = $renderer;
        $this->presentator = $presentator;
    }
 
    public function index()
    {
        return $this->renderer->render('blog/index', $this->presentator->getList());
    }
 
    public function view($id)
    {
        if (!$this->articles->hasById($id)) {
            throw new NotFoundException();
        }
 
        return $this->renderer->render('blog/view', $this->presentator->view($id));
    }
}
Здесь появляется лишний запрос hasById(), но ведь уже при таком подходе контроллер не может знать какие данные нужно доставать из БД. Нужно ли доставать статью целиком? за это уже отвечает презентатор.
Т.е. это еще один отдельный слой, и там упоминалось, что он должен формировать данные со всеми названиями кнопок, их статусами и т.д...
Вот и вопрос, в каком виде нам нужно отдавать данные для вывода пагинации. Достаточно ли нам отдать $currentPage и $totalCount, или мы должны отдать что типа такого

PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$data = [
    'pagination' => [
        'hasPrev' => true,
        'hasFirst' => true,
        'first' => '/blog',
        'last' => '/blog?page=125',
        'pages' => [
            [
                'number' => 2,
                'isCurrent' => false,
            ],
            [
                'number' => 3,
                'isCurrent' => false,
            ],
            [
                'number' => 4,
                'isCurrent' => true,
            ],
            [
                'number' => 5,
                'isCurrent' => false,
            ],
            [
                'number' => 6,
                'isCurrent' => false,
            ],
        ]
    ]
]
Для этого мы бы могли написать отдельный объект представления, который уже был бы заточен под конкретную верстку
PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class PaginationView
{
    private $pagination;
    private $size;
 
    private $start;
    private $end;
 
    public function __construct(Pagination $pagination, int $size)
    {
        $this->pagination = $pagination;
        $this->size = $size;
 
        $this->start = max(1, $this->pagination->getCurrentPage() - floor($size/2));
        $this->end = min($this->pagination->getPagesCount(), $this->start + 5);
        $this->start = max(1, $this->end - $size);
    }
    
    //...
}
Но я выше упоминал, что данные для вывода мы можем отдать как в виде html, так и JSON. Если у нас SPA приложение, где есть API и используется какой-нибудь frontend framefork, типа Vue или React. То зачем им передавать такие данные ведь они вполне могут сами сформировать шаблон для пагинации на основе $pagesCount и $currentPage.
Если проводить аналогию, то что у нас получается? логика вывода должна полностью ложиться на html шаблон и на инструменты Renderer-а? Хотя возможно такой ход рассуждения и не совсем корректный)
0
39 / 9 / 10
Регистрация: 19.09.2016
Сообщений: 1,076
11.07.2020, 23:15  [ТС]
Чисто технический нюанс...
Цитата Сообщение от sad67man Посмотреть сообщение
Если пользователь введет в адресную строку 100 страницу, а у нас страниц всего 10. Что мы должны показать? 404 ошибку или сообщение, что записей нет. Чаще всего показывают последнюю страницу
В этом случае, мне представляется это однозначно исключением, а не отправлением к последней странице. Мало ли что там пользователь напишет в адресе. Для пользователя должно быть достаточно в адресе указать только домашнюю страницу ресурса. Все остальное - через интерфейс приложения.

Цитата Сообщение от sad67man Посмотреть сообщение
Вот мы получили хороший законченный класс. Который не зависит от вывода. Его можно выложить на github и использовать в других проектах.
Посмотрел на свой класс пагинатора. он у меня скорее похож на доказательство теоремы)))
Хотя изменить логику его представления не составит никакого труда, т.к. основные моменты уже учтены. Зато усложнился код и потерялась универсальность

Цитата Сообщение от sad67man Посмотреть сообщение
я не думаю, что его нужно наделять логикой по сколько страниц выводить и т.д. Что-то подсказывает, что для вывода должен быть отдельный специальный инструмент..
Подсознательно, изначально все задачи решаются в пределах одного класса/метода, а потом начинаются логические измышления как это разбить на подзадачи и максимально отделить правильно логику и представление..

Цитата Сообщение от sad67man Посмотреть сообщение
в некоторых книжках упоминалось о таком компоненте, как Презентатор. Где по аналогии с операционным слоем, где выносятся все операции, точно так же выносится логика формирования данных для вывода в отдельный класс
Тогда он наверное дожен обладать какой то общей шаблонной логикой(что нереально) или иметь достаточно большой набор отдельных компонентов-методов - свалку "на все случаи жизни" - покрывающую все оперативные потребности.
В принципе нечто подобное, как я себе это представил)) у меня реализовано с обратной стороны. на низком уровне - на уровне моделей, в виде ActiveRecord, как общего интерфейса для работой с БД.

Цитата Сообщение от sad67man Посмотреть сообщение
Вот и вопрос, в каком виде нам нужно отдавать данные для вывода пагинации.
Я считаю, что подобные расчеты / вычисления - все таки вопрос бэкенда. нужно в представление отдать максимально готовые данные, хоть в Json, хоть в html.
0
 Аватар для sad67man
2604 / 1508 / 689
Регистрация: 23.08.2015
Сообщений: 3,834
12.07.2020, 00:54
Цитата Сообщение от СергейСереб Посмотреть сообщение
В этом случае, мне представляется это однозначно исключением, а не отправлением к последней странице.
Это один из вариантов. Я так часто что-то ввожу в адресную строку. Почему я не могу так делать? На этом форуме вы увидите последнюю страницу, а в яндексе будет ошибка. Хотя я не знаю как это влияет на SEO продвижение, для яндекса она то точно не важна)
Цитата Сообщение от СергейСереб Посмотреть сообщение
он у меня скорее похож на доказательство теоремы)))
Не понял о какой теореме идет речь. Он подтверждает что ваш класс плохой?
Цитата Сообщение от СергейСереб Посмотреть сообщение
Подсознательно, изначально все задачи решаются в пределах одного класса/метода
Не всегда так, бывает и пложу кучу классов, а потом рефакторю, значительно сокращая код. Краткость сестра таланта) Основная задача именно выразить код. К примеру вы несколько дней разбирались что нужно сделать, читали документацию и т.д. Вы не должны отталкиваться от того, что задача изначально известна и вы лишь отражаете его реализацию. Ваша задача именно показать как это работает для стороннего программиста, который вообще не в теме.
Цитата Сообщение от СергейСереб Посмотреть сообщение
Тогда он наверное дожен обладать какой то общей шаблонной логикой(что нереально) или иметь достаточно большой набор отдельных компонентов-методов - свалку "на все случаи жизни"
Нет. Как и ReadRepository или Презентатор - они служат только для выноса кода в определенный слой, а не для повторного использования или что-то типа того. Повторное использование это лишь некий бонус, который может пригодиться, если вы действительно запрашиваете одну и туже страницу только с разных приложений, (сайт и приложение на андроид). Но нельзя его рассматривать с такой точки зрения. Тут не должно быть таких вещей как на "все случаи жизни", только то что используется.

Добавлено через 10 минут
СергейСереб, Тут скорее смысл именно в написании тестов, данный класс проще протестировать, когда он принимает и возвращает максимально простые данные. И вам не нужно эмулировать запрос, и проверять html верстку. А когда меняется html верстка, то не нужно переписывать тесты.

Добавлено через 3 минуты
Цитата Сообщение от СергейСереб Посмотреть сообщение
Я считаю, что подобные расчеты / вычисления - все таки вопрос бэкенда.
Я с вами согласен, но тут есть предел. Вы же не будете отдавать название классов html элементов? Количество страниц определенно должны прилетать с бэкенда, а вот сколько страниц нужно выводить тут еще под вопросом.

Добавлено через 25 минут
Цитата Сообщение от СергейСереб Посмотреть сообщение
В этом случае, мне представляется это однозначно исключением, а не отправлением к последней странице.
Да и еще учтите тот момент, что в данном случае вам это нужно дополнительно обрабатывать, т.е. если метод $this->articles->list() возвращает пустой массив. А что если пользователь зашел на действительно пустой раздел, и по дизайну вы должны просто вывести сообщение, что раздел пуст, а не выкидывать 404 ошибку?

Добавлено через 22 минуты
Цитата Сообщение от СергейСереб Посмотреть сообщение
у меня реализовано с обратной стороны. на низком уровне - на уровне моделей, в виде ActiveRecord, как общего интерфейса для работой с БД.
Только в данном случае презентатор может брать данные с разных моделей из разных таблиц и т.д.
Скорее всего он будет использовать совокупность разных ReadRepository для формирования данных.
ActiveRecord - это объект строки базы данных. А данные мы можем доставать не только из БД. В этом и заключается смысл ReadRepository. Мы абстрагируемся от реализации получения данных. Главное что мы дергаем $this->articles->list() и чтоб он вернул массив статей, а как он это делает и откуда берет нам не важно. Мы можем использовать кеш или noSQL, к примеру ElasticSearch или Redis - как правило это все идет в совокупности. И в любой момент мы можем оптимизировать запросы.
0
Невнимательный
 Аватар для ft4l
3112 / 1290 / 359
Регистрация: 08.02.2013
Сообщений: 7,566
Записей в блоге: 2
12.07.2020, 06:58

Не по теме:

Цитата Сообщение от sad67man Посмотреть сообщение
А вывод может быть разным к примеру и таким
[1] ... [25][26][27][28][29][30] ... [100][101][102] ... [260]
На этом месте я обычно ещё задумываюсь над тем что в настройках по умолчанию должен быть размер страницы и порядок вывода (старые/новые впереди).
Которые могут переопределяться настройками модуля.
Которые могут переопределяться настройками темы/шаблона,
Которые в свою очередь должна быть возможность переопределять ,
в соответствии с предпочтениями любого отдельно взятого посетителя :)



Добавлено через 11 минут

Не по теме:

Цитата Сообщение от x_lab Посмотреть сообщение
в соответствии с предпочтениями любого отдельно взятого посетителя
в пределах дозволенного настройками :)

0
 Аватар для sad67man
2604 / 1508 / 689
Регистрация: 23.08.2015
Сообщений: 3,834
12.07.2020, 07:14
x_lab, У вас есть дизайн, где выводится по 20 элементов). Вы можете задать размер при получении данных. И зачем тут какие-то настройки модуля, какой смысл возможности их переопределения? Я бы даже не стал задумываться на этот счет)

Добавлено через 6 минут
x_lab, Если нужна возможность выбирать кол-во записей на странице, то это как правило это какой-нибудь select, который передает значение в качестве GET параметров. В любом случае тут некие настройки вообще не причем)
0
1310 / 1002 / 232
Регистрация: 01.10.2018
Сообщений: 3,896
12.07.2020, 10:26
Цитата Сообщение от sad67man Посмотреть сообщение
Чаще всего показывают последнюю страницу
Так делают студенты, начинающие изучать Web-программирование. Я показанный метод getCurrentPage даже комментировать не стал, потому что код для студентов меня не интересует. Если не хотите выводить ошибку 404, не выводите одно вместо другого, а корректируете адрес путем временного перенаправления. И даже подобная коррекция не везде уместна. Например, я делаю подобную коррекцию в админке, но мне в голову не приходит это делать в публичном сайте.
0
39 / 9 / 10
Регистрация: 19.09.2016
Сообщений: 1,076
13.07.2020, 14:10  [ТС]
Цитата Сообщение от sad67man Посмотреть сообщение
Тут скорее смысл именно в написании тестов
Вот это - интересный и важный нюанс, хотя и не относится напрямую к основному вопросу. Часто вижу упоминания о тестировании, но для меня это пока-нечно отдаленное и загадочное. типа магических методов в ПХП))
Цитата Сообщение от sad67man Посмотреть сообщение
Не понял о какой теореме идет речь. Он подтверждает что ваш класс плохой?
Просто в одном классе много всего учтено - и расчет "размера" пагинатора и его поведение в зависимости от заданных параметров и передача кучи параметров на выход. Оносительно этого тоже непонимание: на различных сайтах часто вижу опцию интерфейса "отображать на странице" - речь о количестве элементов. И практически всегда предлагаются уже заданные 3-4 значения и вывод всех элементов. Т.е. уже заложены варианты поведения пагинатора на определенные значения. Ни разу не видел предложение выбора свободного значения отображения элементов. Ну и привязывая этот нюанс к контексту вопроса - получается, что в основном никто не заморачивается вопросами особенностей представления пагинатора. а просто предлагают в качестве выбора несколько готовых вариантов? Опять же - -вопрос в контексте отдельного класса представления пагинатора - насколько это вообще необходимо/востребовано, кроме как выделения базовых вещей в одтельные классы для упрощения самой разработки(в т.ч. и тестирование)?

Цитата Сообщение от sad67man Посмотреть сообщение
Да и еще учтите тот момент, что в данном случае вам это нужно дополнительно обрабатывать, т.е. если метод $this->articles->list() возвращает пустой массив. А что если пользователь зашел на действительно пустой раздел, и по дизайну вы должны просто вывести сообщение, что раздел пуст, а не выкидывать 404 ошибку?
У меня это учитывается, уровнем выше.
Цитата Сообщение от sad67man Посмотреть сообщение
Я так часто что-то ввожу в адресную строку. Почему я не могу так делать?
Как-то на подсознательном уровне адресная строка отделяется от остального UI. У меня почему устоялось такое мнение, что адресная строка - больше для программиста. чем для пользователя. Тем более, учитывая, что и через адресную строку передаются далеко не все нужные параметры для того или иного запроса. которые можно передать через UI.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
13.07.2020, 14:10
Помогаю со студенческими работами здесь

Неправильно выводит количесвто страниц в пагинации
Здравствуйте! Собственно сама проблема в названии топика, никак не могу понять почему. function...

Как прописать условие,чтоб не было лишних ссылок пагинации?
Сделал скрипт пагинации.Но не могу придумать как прописать так чтоб когда заканчивались записи в базе данных то больше ссылок на страниц...

Создание пагинации
Здравствуйте,вот ниже мой код что читает з бд инфу и выкидывает на страницу,это ясно ,но выкидывает все записи их около 20-ти больше и не...

Улучшение моей пагинации
Сделал очень костыльную пагинацию, приходится каждый раз писать условия и создавать самому страницы, как можно это автоматизировать? ...

Изменение формы пагинации на JS
Здравствуйте. Помогите пожалуйста переписать мою форму пагинации. Сейчас она имеет вид: 123456789101112131415 и т.д. ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
32
Ответ Создать тему
Новые блоги и статьи
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru