یکی از مباحثی که تقریباً در طراحی هر نوع سیستمی درگیر آن خواهید شد، بحث شاخهبندی یا موضوعبندی موجودیتهاست.
مثلاً: موضوعات مقالات در یک سیستم مدیریت مقالات. شاخهها در سیستم مدیریت موسیقی. شاخهبندی در سیستمی مثل تستا به صورتی که هر آزمون زیرمجموعه یک شاخه باشد.
در اکثر مواقع نیاز دارید که یک شاخه بتواند چندین سطح فرزند داشته باشد. به قوی علاوه بر فرزند، نوه و نتیجه هم داشته باشد (شاخه بندی چند سطحی)
به طور مثال به تصویر زیر دقت کنید:
گروه «شبکه» علاوه بر اینکه خودش فرزند «گروه اصلی» است، فرزندانی به نامهای «تست» و «TCP/IP» دارد و یک نوه نیز به نام «آی.پی» دارد.
الگوریتم کلی این است که شما در دیتابیس، در جدولی که موضوعات را نگه میدارید، یک id به هر موضوع نسبت میدهید و علاوه بر آن، یک ستون هم در نظر میگیرید برای اینکه آی.دی پدر این موضوع را نگه دارید.
به طور مثال جدول مربوط به تصویر بالا به این صورت است:
مثلاً میبینید که والد فتوشاپ برابر با 1 است. یعنی زیرمجموعه گروه اصلی است.
نکته: والد (parent) مربوط به «گروه اصلی» همیشه باید 0 باشد و خودش همیشه باید id اش برابر با 1 باشد. (شما همیشه یک شاخه اصلی دارید با این ویژگیها)
پس اگر بخشی برای ویرایش شاخهها دارید، باید دقت کنید که هیچ وقت کد و والد مربوط به شاخه اصلی نباید قابل تغییر باشد:
برای شاخه اصلی داریم:
(بررسی شده است که چون gid برابر با 1 است، پس این شاخه، شاخه اصلی است و نباید بتواند زیرمجموعه دیگری قرار بگیرد)
اما برای موضوعات دیگر داریم:
یک الگوریتم نیز نیار داریم برای اینکه بفهمیم هر شاخه چه فرزندانی دارد و هر فرزند، خود چه فرزندانی دارد.
این شاید یکی از پیچیدهترین الگوریتمها به نظر برسد، اما در کل، با استفاده از یک آرایه و یک تابع بازگشتی میتوانید این مشکل را رفع کنید:
<?php function list_groups($parent) { $has_childs = false; global $menu_array; foreach($menu_array as $key => $value) { if ($value['parent'] == $parent) { if ($has_childs === false) { $has_childs = true; echo '<ul style="list-style-image:url(\'images/L.gif\')">'; //چاپ عکس نماد زیرمجموعه (ال شکل) در کنار نام مجموعه } echo '<li>'.$value['id'].'-'.$value['name'].'</a>'; list_groups($key); echo '</li>'; } } if ($has_childs === true) echo '</ul>'; } ?>
تنها کاری که باید کنید این است که آرایه $menu_array را به این صورت پر کنید:
این آرایه global تعریف شده تا از خارج از تابع قابل پر کردن باشد.
$groups_res = mysql_query("SELECT * FROM groups ORDER BY weight");
while($groups = mysql_fetch_array($groups_res))
{
$ts = "";
$menu_array[$groups['id']] = array('id' => $groups['id'],'name' => $groups['title'],'parent' => $groups['parent'],'tests'=>$ts);
}
?>
دقت کنید:
من لیست موضوعات را از دیتابیس خواندهام و در groups ریختهام.
- یک خانه با اندیس id داریم که آی.دی هر گروه در آن قرار میگیرد.
- یک خانه با اندیس name داریم که عنوان گروه در آن است.
- یک خانه با اندیس parent داریم که والد هر شاخه در آن ریخته شده است.
- یک خانه به نام tests در نظر گرفتهام که شاید برای کار شما چندان ضرورت نداشته باشد، اما به هر حال، آن خانه شامل لیست آزمونهایی است که زیرمجموعه این گروه خاص هستند. (من نحوه پر شدن $ts با آزمونها را از حلقه حذف کردهام. فقط به این دلیل گذاشتم که بدانید میتوانید یک آرایه را به عنوان یکی از عناصر آرایه menu_array در نظر بگیرید. خیلی از اوقات لازم است)
در نهایت، هر وقت خواستید لیست موضوعات نشان داده شود، تابع list_groups را به این صورت فراخوانی کنید:
list_groups(0);
این کد یعنی فرزندان شاخه 0 را لیست کن. همانطور که میدانید، 0 یعنی همان شاخه اصلی.
توجه:
خیلی از اوقات شما یک فیلد به نام «وزن» یا weight نیاز دارید که بالاتر بودن یا پایینتر بودن یک آزمون در لیستها را با آن تعیین کنید. مثل من میتوانید یک دکمه جلو هر شاخه بگذارید که با کلیک روی آن یک واحد بر وزن آزمون افزوده شود و یا یکی کم شود:
فقط موقع لیست کردن، همانطور که در کد بالا میبینید، باید بر اساس weight بچینید: ORDER BY weight
موفق باشید؛
حمید رضا نیرومند
آدرس کوتاه مقاله:
کلمات کلیدی:
categorize, cat,folder,subject, شاخه , پوشه بندی , موضوع بندی