Forums / National / Russian / Тех. поддержка / [Принято] Предложение по улучшению Структуры категорий

Yusupov
#1 2015-12-19 08:33

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

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

Код измененной функции cot_load_structure() можно посмотреть тут: https://github.com/cmsworksru/cot-freelance/blob/52ce4f903035abef8c90d431f1e695a9f8617fd7/system/functions.php#L1197

В частности добавлены следующие строки: 

https://github.com/cmsworksru/cot-freelance/blob/52ce4f903035abef8c90d431f1e695a9f8617fd7/system/functions.php#L1233
https://github.com/cmsworksru/cot-freelance/blob/52ce4f903035abef8c90d431f1e695a9f8617fd7/system/functions.php#L1278-L1284

 

This post was edited by Macik (2016-03-28 15:38, 9 years ago)
Macik
#2 2015-12-22 15:15

Как дойдут руки — глану и напишу мнение. Пока не смотрел.

https://github.com/macik
правильный хостинг — https://goo.gl/fjCa1F
esclkm
#3 2015-12-23 14:55

Это исправление вызывает странное послевкусие.

Вроде все так, но не так. Увеличился объем занимаемой памяти самой структуры.

При этом от рекурсии мы не избавились? я про то, что дочерние, дочерних, что с ними?

Скорость - об этом тоже ни слова. Плюс почему исправление только в load_structure? что с get_children?

Я считаю, что все аспекты работы со структурой должны быть перенесены в объект

А информация о детях и их родителях в массиве в объекте

 

littledev.ru - мой маленький зарождающийся блог о котонти.
снижение стоимости программирования и снижение стоимости производства разные вещи. Первое можно скорее сравнить с раздачей работникам дешевых инструментов, чем со снижением зарплаты
Yusupov
#4 2015-12-23 16:46

Например предложенный мною вариант использовался для сайта, где категорий несколько тысяч и много уровней вложенности. Когда вместо этого я использовал cot_structure_children(), то сервер просто лежал. Разница в скорости очевидна, так как мы используем уже готовые списки подкатегорий из кэша вместо постоянного повторяющегося перебора. 

Если вариант не подходит, то как минимум предлагаю прописать хуки в cot_load_structure(), чтобы не приходилось постоянно писать костыли под свои задачи.

esclkm
#5 2015-12-24 07:07

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

littledev.ru - мой маленький зарождающийся блог о котонти.
снижение стоимости программирования и снижение стоимости производства разные вещи. Первое можно скорее сравнить с раздачей работникам дешевых инструментов, чем со снижением зарплаты
CrazyFreeMan
#6 2015-12-24 16:02
#41255 esclkm:

 

Я считаю, что все аспекты работы со структурой должны быть перенесены в объект

#41260 esclkm:

 

надо сделать в виде класса

crying

Говорим об памяти и быстродействии и пихаем обьект ? Я конечно не спец в этой области но кажется мешать ООП и то что есть не самая лучшая идея.  Или отказываться в котонти от легкости и переходить на полноценный ООП а то будет шопопало имхо 

Macik
#7 2015-12-26 13:52
#41261 Ярослав Романенко:
 

Говорим об памяти и быстродействии и пихаем обьект ? Я конечно не спец в этой области но кажется мешать ООП и то что есть не самая лучшая идея.  Или отказываться в котонти от легкости и переходить на полноценный ООП а то будет шопопало имхо 

Я бы не был так категоричен. Мнение, что объекты или ООП в целом, это медлено и жрет память, то же самое что сказать, что массивы в ПХП не оптимальны и потребляют от 80 до 140 байт на описание одного элемента. Это правда. Но вопрос в том, как это использовать...

Если каждую запись делать объектом, да еще поиметь оверхед на инициализацию и прочее — то да, это как раз пример «ООП это тормоз и жрет память».

В данном случае речь идет лишь об объекте-обертке с набором удобных функций для обработки (и внутренним предствалением данных, оптимизированных для скорости). 
Такой подход позволит в будущем расширять и оптимизировать функционал, без необходимости перекраивать код во многих местах.
Если еще воспользоваться структурами данных SPL, то вероятно можно дополнительно сэкономить и на потребляемой пямяти.

Мы же используем сейчас объекты для доступа к БД, кеша, шаблонов. Потому, что при грамотной реализации это удобнее в использовании и оптимальнее с точки зрения кода.

---

Резюмируя...

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

Возможно сейчас, как «быстрое решение», имеет смысл добавить хуки в cot_load_structure() .

В целом согласен с Esclkm в том, что текущая реализация не оптимальна и нуждается в переарботке.

 

https://github.com/macik
правильный хостинг — https://goo.gl/fjCa1F
Yusupov
#8 2015-12-26 19:19

Хук тоже хорошее решение. Все остальное можно под себя реализовать в зависимости от сложности проекта. Спасибо!

Еще как вариант не плохо бы иметь возможность полностью заменить функцию cot_load_structure() на cot_load_structure_custom() при ее наличии.

 

esclkm
#9 2015-12-27 05:33
Как бы ничего не мешает в global пройтись по массиву. Хук ради хука тоже как бы... не айс.. Хотя пусть будет
littledev.ru - мой маленький зарождающийся блог о котонти.
снижение стоимости программирования и снижение стоимости производства разные вещи. Первое можно скорее сравнить с раздачей работникам дешевых инструментов, чем со снижением зарплаты
Yusupov
#10 2015-12-27 13:31
#41267 esclkm:
Как бы ничего не мешает в global пройтись по массиву. 

Ну это уже совсем неприемлимо) 

 

Конечно, ни тот ни другой из озвученных здесь способов не идеальны, всегда будет что-то чем придётся жертвовать. 

Лично мое мнение, структура не должна быть частью ядра. Но раз уж так завелось, то хотелось бы, чтобы ее применение было более гибким.

Macik
#11 2016-03-07 19:29
#41265 Yusupov:

Хук тоже хорошее решение. Все остальное можно под себя реализовать в зависимости от сложности проекта. Спасибо!

Еще как вариант не плохо бы иметь возможность полностью заменить функцию cot_load_structure() на cot_load_structure_custom() при ее наличии.

 

«Возвращайся сделав круг…»

  1. Хук внутри функции у нас имеется — `structure`. Но это проблема, для структур в несколько тысяч записей, т.к. директива `include`в таком цикле может легко скушать несколько секунд.
  2. `cot_load_structure_custom()` практически не вариант, т.к. на момент вызова `cot_load_structure()` еще не сработал ни один основной хук и нам просто негде подключить кастомную ф-ю. Единственная возможность это файл `functions.custom.php` при включенной опции `$cfg['customfuncs']`.

Ваши мнения? 

 

https://github.com/macik
правильный хостинг — https://goo.gl/fjCa1F
Dr2005alex
#12 2016-03-07 21:13

Я уже давно использую parent_id для структур в своих модулях. Мне кажется для нейтрализации проблемы сжираемой памяти или ресурсов с большим количеством вложений структуры и её элементов, необходимо отказаться от загрузки по умолчанию все структуры в массив. Я лично еще не встречал, где бы приходилось выводить (обрабатывать) сразу всю структуру в несколько сотен или тысяч элементов. Мне кажется надо  модернизировать или создать функцию по выдаче части структуры, необходимой в данный момент. Тогда речь пойдет уже максимум о десятках.. Тогда можно будет передать полноценные права модулю, использующего данную структуру.. надо все? вытягивай и кешируй.. а не надо все вытащи то-что необходимо.

Еще вариант это хранить предков в отдельной сущности или чилдренов.. я использую разные подходы, в зависимости от нужд скрипта..

WebKaa.ru - Cotonti Relax
Macik
#13 2016-03-07 21:28

Да, это все в туже сторону — создание отдельного класса по управлению структурой. Править придется много — более двух сотен вхождений... И еще придется держать слой совместимости какое-то время.

https://github.com/macik
правильный хостинг — https://goo.gl/fjCa1F
This post was edited by Macik (2016-03-08 00:41, 9 years ago)
Yusupov
#14 2016-03-08 08:49

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

`cot_load_structure_custom()` практически не вариант, т.к. на момент вызова `cot_load_structure()` еще не сработал ни один основной хук и нам просто негде подключить кастомную ф-ю. Единственная возможность это файл `functions.custom.php` при включенной опции `$cfg['customfuncs']`.

Скорее всего этот вариант наиболее простой на данный момент.

Основная проблема при работе со стандартной функцией cot_load_structure() это невозможность получить список подкатегорий не прибегая к перебору всей структуры снова и снова.

Либо еще один вариант: выводить дерево категорий через ajax, генерируя нужную ветку категорий только тогда, когда она нужна (по какому-либо событию).

Добавлено 1 неделя спустя:

#41475 Macik:
`cot_load_structure_custom()` практически не вариант, т.к. на момент вызова `cot_load_structure()` еще не сработал ни один основной хук и нам просто негде подключить кастомную ф-ю. Единственная возможность это файл `functions.custom.php` при включенной опции `$cfg['customfuncs']`.

Возможно ли добавить замену внутри функции на cot_load_structure_custom() как это сделано с функцией cot_mail? 
И если да, то будет ли эта возможность добавлена до релиза 0.9.19?

Добавлено 1 день спустя:

Уважаемые разработчики, посмотрите мой pull request.

Добавил замену функции на cot_load_structure_custom().

This post was edited by Yusupov (2016-03-18 06:07, 9 years ago)
Macik
#15 2016-03-18 11:27

В целом, варианты переопределения такого типа мне не нравятся, т.к. они переопределяют функцию целиком, и не дают  возможности дальнейшего расширения или переопределения — особенно в местах аналогичных `cot_mail`, когда один плагин «врезался» в функционал, переопределив функцию, в остальных мы може легко получить либо не предсказуемое поведение, либо, что еще хуже можем получить фатальную ошибку, если другой плагин попробует ее переопределить.

Возвращаясь к теме переопределения структуры — тут вопрос не такой острый, и, пожалуй, это самое простое и быстрое решение. Поэтому пулл-реквест приму, со статусом «экспериментального» (до лучших времен, когда этот вопрос будет решен другими метдами, или потребует изменения кода).

https://github.com/macik
правильный хостинг — https://goo.gl/fjCa1F