ВопросКаким способом лучше добавить свой счетчик нод в пунктах меню?

Здравствуйте! Дайте совет каким образом лучше это сделать, сейчас объясню как я сделал пока, но мне интуитивно кажется, что это не очень правильно.

На сайте есть небольшое главное меню с пунктами (категории таксономии). Выводится стандартными средствами через блок меню. Но мне необходимо к каждому пункту вывести кол нод из данной категории, причем при подсчете мне нужно учитывать некоторые факты. Я написал функцию:

function count_nodes($tid, $tid2) {
  $query = db_query("SELECT nid FROM term_node WHERE tid='".$tid."'");
  $count = 0;
  while($nids = db_fetch_object($query)) {
    if (db_result(db_query("SELECT count(nid) FROM {node} WHERE nid='".$nids->nid."' AND status='1'")) > 0) {
      $date_expire = db_result(db_query("SELECT field_expdate_value FROM {content_type_stock} WHERE nid='".$nids->nid."'"));
      if ($date_expire >= time()) $count = $count + db_result(db_query("SELECT count(nid) FROM term_node WHERE nid='".$nids->nid."' AND tid='".$tid2."'"));
    }
  }
  return $count;
}

и через jquery append() просто в каждую ссылку меню вставляю

<?php print count_nodes(1, $city_tid); ?>

Все работает, но возможно есть более изящное решение?

Комментарии

Аватар пользователя Spleshka
Spleshka написал:

Решение изящнее есть конечно. Только вы сначала объясните, почему сначала из {term_node} выбираются ноды для одного термина, а потом для другого. Как только объясните - будет вам кошерное решение)

18.12.2011 15:28
Аватар пользователя Гость
Гость написал:

Спасибо за советы! Объясняю: Первый $tid это категории на сайте, ну к примеру Яблоки, Груши и т.д., а второй $tid2 - город. Через фильтр views у меня запоминается текущий id города и его же подставляю в функцию. Чтобы выводило кол нод именно для конкретного города, а не все.

18.12.2011 21:15
Аватар пользователя Spleshka
Spleshka написал:

И кстати, никогда не пишите такие запросы:

db_query("SELECT nid FROM term_node WHERE tid='".$tid."'");

Это прямой путь к sql-инъекциям. Пишите так:

db_query("SELECT nid FROM term_node WHERE tid = %d", $tid);

И ещё лучше таблицу оборачивать в фигурные скобки. Т.к. в этом случае, если в settings.php у вас появятся префиксы, Друпал перепишет эти скобки с префиксами и запрос будет по-прежнему правильный:

db_query("SELECT nid FROM {term_node} WHERE tid = %d", $tid);

И ещё :) Если выбирается одна запись, пользуйтесь db_query_range() вместо db_query() - так запрос будет работать быстрее.

$date_expire = db_result(db_query_range("SELECT field_expdate_value FROM {content_type_stock} WHERE nid = %d", $node->nid, 0, 1);

Последний вариант совсем правильный :)

18.12.2011 15:29
Аватар пользователя Spleshka
Spleshka написал:

Я бы это написал так:

function count_nodes($tid, $tid2) {
 
  $result = db_query('
    SELECT tn.nid FROM {term_node} tn
    INNER JOIN {node} n ON n.nid = tn.nid
    INNER JOIN {content_type_stock} cts ON cts.nid = n.nid
    WHERE n.status = 1 AND tn.tid = %d AND cts.field_expdate_value > %d',
    $tid, time());
 
  $nids = array();
  while ($row = db_fetch_object($result)) {
    $nids[] = $row->nid;
  }
 
  return db_result(db_query('SELECT COUNT(nid) FROM {term_node} WHERE nid IN (' . db_placeholders($nids) . ') AND tid = %d', $nids, $tid2));
}

В итоге всего 2 запроса, вместо неизвестного, но явно большого количества.

18.12.2011 21:40
Аватар пользователя Spleshka
Spleshka написал:

Хотя можно попробовать вообще одним запросом обойтись:

function count_nodes($tid, $tid2) {  
  return db_result(db_query('
    SELECT COUNT(tn.nid) FROM {term_node} tn
    INNER JOIN {node} n ON n.nid = tn.nid
    INNER JOIN {content_type_stock} cts ON cts.nid = n.nid
    WHERE n.status = 1 AND tn.tid IN (%d, %d) AND cts.field_expdate_value > %d
    GROUP BY tn.nid HAVING COUNT(tn.tid) = 2',
    $tid, $tid2, time()));    
}
18.12.2011 21:46
Аватар пользователя Гость
Гость написал:

сейчас попробовал первый вариант, но что-то не сработал. Выводит 0 в том месте где по идее должно вывести больше 0. Но меня больше всего смущало, что вставляю значения через jQuery, это можно сделать друпаловскими методами? Мне по сути надо перехватить вывод нужного меню и вставить в тег свои счетчики

18.12.2011 22:54
Аватар пользователя Spleshka
Spleshka написал:

Для этого вам надо имплементировать hook_menu_link_alter(). И да, jquery - это не выход :)

19.12.2011 14:29
Аватар пользователя Гость
Гость написал:

А как именно достучаться до нужного пункта меню?

function custom_menu_link_alter(&$item, $menu) {
  print '<pre>';
    print_r($item);
    print '</pre>';
    die;
}

Вывело массив, но без каких либо путей. Что-то нигде не могу найти даже примеров. Вот, что выводит:

Array
(
    [title] => Administer
    [access arguments] => Array
        (
            [0] => access administration pages
        )
 
    [page callback] => system_main_admin_page
    [weight] => 9
    [file] => system.admin.inc
    [module] => system
    [load_functions] => 
    [to_arg_functions] => 
    [type] => 6
    [_number_parts] => 1
    [_parts] => Array
        (
            [0] => admin
        )
 
    [_fit] => 1
    [_visible] => 1
    [_tab] => 
    [tab_parent] => 
    [tab_root] => admin
    [access callback] => user_access
    [page arguments] => Array
        (
        )
 
    [block callback] => 
    [title arguments] => Array
        (
        )
 
    [title callback] => t
    [description] => 
    [position] => 
    [path] => admin
    [file path] => 
    [include file] => modules/system/system.admin.inc
    [menu_name] => navigation
    [link_title] => Administer
    [link_path] => admin
    [hidden] => 0
    [options] => Array
        (
        )
 
    [mlid] => 2
    [plid] => 0
    [has_children] => 1
    [updated] => 0
)
19.12.2011 17:49
Аватар пользователя Spleshka
Spleshka написал:

Ну тут же самый первый элемент массива - title. Просто добавьте к нему число в скобках

19.12.2011 21:06
Аватар пользователя Гость
Гость написал:

Все равно не понимаю =) Как мне выбрать меню, которое я создал через админку, например называется mymain-menu и уже конкертно к его пунктам добавлять цифры. Хотя мне не просто скобки нужно добавить а типа такого:

 <span>0</span>
20.12.2011 03:13
Аватар пользователя Spleshka
Spleshka написал:

Если я не ошибаюсь, то так:

function custom_menu_link_alter(&$item, $menu) {
  if ($menu == 'mymain-menu') {
    if ($item['path'] == 'admin') {
      $count = некая_подсчитывающая_фунция();
      $item['title'] .= '<span>' . $count . '</span>';
    }
  }
}
21.12.2011 00:13
Аватар пользователя Гость
Гость написал:

Не работает :( Вот и я не могу понять как это сделать...

print_r($menu); выводит все пути в друпале. Мне нужно как раз для терминов таксономии изменить, наверное здесь:

[taxonomy/term/%] => Array
        (
            [page callback] => views_page
            [page arguments] => Array
                (
                    [0] => stock
                    [1] => page_1
                    [2] => 2
                )
 
            [access callback] => views_access
            [access arguments] => Array
                (
                    [0] => 1
                )
 
            [load arguments] => Array
                (
                    [0] => stock
                    [1] => page_1
                    [2] => %index
                )
 
            [weight] => 0
            [type] => 4
            [load_functions] => a:1:{i:2;a:1:{s:14:"views_arg_load";a:3:{i:0;s:5:"stock";i:1;s:6:"page_1";i:2;s:6:"%index";}}}
            [to_arg_functions] => 
            [title] => 
            [_number_parts] => 3
            [_parts] => Array
                (
                    [0] => taxonomy
                    [1] => term
                    [2] => %
                )
 
            [_fit] => 6
            [_visible] => 1
            [_tab] => 
            [tab_parent] => 
            [tab_root] => taxonomy/term/%
            [block callback] => 
            [title arguments] => Array
                (
                )
 
            [title callback] => t
            [description] => 
            [position] => 
            [path] => taxonomy/term/%
            [file] => 
            [file path] => 
            [include file] => 
            [module] => 
        )

попытался посмотреть, что покажет print_r( $item ), если $menu = 'taxonom/term/%' и ничего. То есть условие if ($menu == 'taxonom/term/%') не срабатывает.

22.12.2011 13:43
Аватар пользователя Spleshka
Spleshka написал:

А, у вас это через вьюс сделано.. Тогда это меняет дело.. Наверное, придётся темизировать. Во вьюс эсть такой параметр как Темизация (theming). Вам нужно счёлкнуть на него, выбрать необходимый уровень слоя, положить в корень темы файл с названием слоя и его исходным кодом (это вам всё предоставит Views), а дальше немного дописать своего кода в этом шаблоне :)

22.12.2011 14:25

Комментировать