Bug Tracker: установка фреймворка и создание базы данных (часть вторая)
Сегодня я продолжаю рассказывать о разработке собственной системы отслеживания ошибок. В прошлой статье только вкратце была описана общая идея и возможности, а также показан предварительный эскиз приложения.
Но прежде чем переходить к основной теме, хочу поблагодарить всех комментаторов и особенно AmdY, Big_Shark и Алексея Качаева за советы!
Первоначально я планировал доделать приложение полностью, и только потом опубликовать этот цикл постов. Но так получается даже лучше. Всегда есть шанс, что читатели найдут недостатки, и мне не придется переделывать все приложение чтобы их исправить
В прошлый раз с инструментами мы определились (используем PHP, фреймворк CodeIgniter, MySQL и jQuery).
Сейчас нам нужно их установить и настроить.
Я предполагаю, что web сервер, PHP и MySQL у вас уже настроены, поэтому нам нужно только скачать CodeIgniter и jQuery. После этого распаковываем архивы в какую-нибудь папку на сервере. В результате должна получиться примерно следующая структура папок.
index.php .htaccess system/ js/ jquery-1.3.2.min.js css/
Файл index.php и папка system – из дистрибутива CodeIgniter.
.htaccess – самый обычный. Сразу приведу его содержимое.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^system.*
RewriteRule ^(.*)$ /index.php?/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(index\.php|images|robots\.txt|css|js)
RewriteRule ^(.*)$ index.php?/$1 [L]
</IfModule>
<IfModule !mod_rewrite.c>
ErrorDocument 404 /index.php
</IfModule>
Основное его назначение – автоматически подставлять index.php в ссылки. Т.е. ссылка вида
bugtracker.local/bugtracker/page/2
будет преобразована в
bugtracker.local/index.php/bugtracker/page/2
При этом преобразование происходит, только если указанного в URL файла на самом деле не существует. Т.е. если запрос будет к js или css файлу, то index.php подставляться не будет.
Кстати, если вы хотите, чтобы приложение находилось в какой-нибудь папке (например, mysite.domen/bugtracker/), то нужно будет изменить параметр RewriteBase.
На настройке CodeIgniter подробно останавливаться не буду. Просто перечислю файлы, в которые нужно внести изменения.
Все конфигурационные файлы находятся в папке system/application/.
autoload.php – загружаем библиотеку для работы с базой данных и URL хелпер
-
$autoload['libraries'] = array('database');
-
$autoload['helper'] = array('url');
config.php – здесь указываем адрес приложения, например,
-
$config['base_url'] = "http://bugtracker.local/";
и добавляем ещё один параметр
-
$config['bugs_per_page'] = 5;
Как несложно догадаться его значение определяет количество записей о багах на странице.
routes.php – тут нужно указать только название контроллера, который будет использоваться по-умолчанию. Я решил его называть bugtracker.
-
$route['default_controller'] = "bugtracker";
database.php – здесь заполняем массив с параметрами подключения к базе данных.
Примечание. Подробнее о настройке фреймворка можно почитать в статье «PHP framework CodeIgniter. Установка и настройка.»
Теперь переходим к созданию базы данных.
Нам потребуются три таблицы:
1) bugs – используется для хранения информации о найденных багах и комментариях к ним.
Поля:
id – первичный ключ;
title – заголовок;
uname – имя пользователя, который оставил сообщение;
categoryid – id категрии к которой относится баг (должно совпадать с соответствующим полем в таблице categories);
description – описание бага;
status – здесь будет храниться информация о состоянии бага (по-умолчанию, «не исправлено»);
replyto – это поле устанавливает связь между багами и комментариями к ним (подробнее на этом мы остановимся чуть позже).
2) categories – список категорий.
Поля:
id – первичный ключ;
link – ссылка на категорию (латинскими буквами);
name – названии категории.
3) users – информация о пользователях. В данном случае этими пользователями будут только администраторы баг трекера. Оставлять сообщения и комментарии сможет кто угодно без авторизации.
id – первичный ключ;
name – имя пользователя;
pass – пароль.
Теперь посмотрите на запросы, которые создают эти таблицы.
-
CREATE TABLE `bugs` (
-
`id` int(11) NOT NULL AUTO_INCREMENT,
-
`title` varchar(300) NOT NULL,
-
`uname` varchar(100) NOT NULL,
-
`categoryid` int(11) DEFAULT NULL,
-
`description` text NOT NULL,
-
`status` varchar(100) NOT NULL DEFAULT 'не исправлено',
-
`replyto` int(11) DEFAULT NULL,
-
PRIMARY KEY (`id`),
-
KEY `replyto` (`replyto`)
-
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
-
-
ALTER TABLE `bugs`
-
ADD CONSTRAINT `bugs_ibfk_1` FOREIGN KEY (`replyto`) REFERENCES `bugs` (`id`) ON DELETE CASCADE;
-
-
CREATE TABLE `categories` (
-
`id` int(11) NOT NULL AUTO_INCREMENT,
-
`link` varchar(100) NOT NULL,
-
`name` varchar(300) NOT NULL,
-
PRIMARY KEY (`id`)
-
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
-
-
CREATE TABLE `users` (
-
`id` int(11) NOT NULL AUTO_INCREMENT,
-
`name` varchar(100) NOT NULL,
-
`pass` varchar(100) NOT NULL,
-
PRIMARY KEY (`id`)
-
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Самый интересный момент здесь касается таблицы bugs, а точнее её поля replyto. Оно даёт возможность отличить комментарий к багу от самого бага. Если значение в нём не равно NULL, то это комментарий, если равно – баг. При этом число, записанное в поле replyto, указывает, к какому багу относится данный комментарий.
Например, в таблице есть четыре следующий записи:
| id | title | … | replyto |
| 1 | Bug 1 | … | NULL |
| 2 | Comment 1 | … | 1 |
| 3 | Comment 2 | … | 1 |
| 4 | Bug 2 | … | NULL |
Это означает, что мы имеем два бага (записи 1 и 4) и два комментария (записи 2 и 3), которые относятся к первому багу.
Кстати, значение поля categoryid для всех комментариев равно NULL.
Тут возникает проблема. Что будет с комментариями, если мы удалим баг к которому они относятся? Можно, конечно, решить эту проблему так:
1) найти все комментарии, которые относятся к данному багу;
2) удалить их;
3) удалить сам баг.
Но будет лучше, если движок MySQL автоматически удалит все связанные комментарии при удалении бага.
Для этого мы объявляем поле replyto внешним ключом (т.е. связываем его с полем id) и указываем опцию ON DELETE CASCADE (каскадное удаление) (строки 13-15). Теперь при удалении записи у которой поле id = 3 движок БД будет искать в этой же таблице все записи у которых replyto = 3 и удалять их.
И, кроме того, это поле (replyto) мы будем использовать при выводе сообщений о багах на страницах нашего баг трекера.
Но об этом в следующий раз.
До встречи!
Интересно почитать:
Слушать радио онлайн
Понравилась статья? Подписывайтесь на продолжение
!
Опубликовано в Ajax, CodeIgniter, JavaScript, MySQL, PHP, Web разработка, htaccess Комментарии (22) »
Комментарии (22)
Вы можете отслеживать обсуждение записи с помощью RSS 2.0 ![]()
Вы также можете оставить комментарий, или трекбек с Вашего сайта.









Мне кажется было бы удобнее делать баги в 1 таблицы а комментарии в другой
так как у комментариев не будет статуса так далее.
Можно сказать классика
дб багтреков
В твоем случае, всетаки яб разделил комменты и сами баги, Big_Shark +1
Так как захочется добавить файло к багам – табличку еще одну создал и вперед
так сказать "с перспективой на будущее"
хм, сранно както линк сработал, повторяю
Честно говоря, я и сам думал разделить таблицы. Но потом возникла идея сделать комментарии с любым уровнем вложенности, т.е. в поле replyto может быть не только ссылка на баг, но и на другой комментарий. Даже написал рекурсивную функцию, которая преобразовывала такую таблицу в структурированный список.
Чуть позже я на это все посмотрел и получилось, что от таких комментариев больше проблем чем пользы. Код сильно усложняется, а ведь это не социальная сеть
В общем, решил сделать один уровень вложенности, а таблица осталась в неизменном виде.
Пример zend'а. У них немного другие задачи
Например, таблица bugs используется для хранения информации о багах в разных продуктах. А таблицы с комментариями вообще нет.
С файлами я планировал сделать немного проще. После загрузки файла – вставлять ссылку на него в текст описания бага…
Пишу я этот комментарий и понимаю, что структура БД у меня явно недодуманная. И, самое главное, я не определился четко с перечнем функций. И начинаются мысли, то ли так сделать, то ли по-другому
Не понимаю следующих вещей в .htaccess:
RewriteCond %{REQUEST_URI} ^system.*RewriteRule ^(.*)$ /index.php?/$1 [L]
для чего это?
RewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(index\.php|images|robots\.txt|css|js)
Если мы уже проверили существует ли файл или директория, то зачем выполнять третье условие?
К примеру, мой список условий:
RewriteCond $1 !^(index\.php)RewriteCond %{REQUEST_URI} !\.(css|js|jpg|gif|png)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Если не запрашивается index.php,
если не запращиваются файлы с окончаниями css|js|jpg|gif|png,
только после этого еще раз дополнительно проверяем наличие запрашиваемого файла, диреткории на реальное существование (то есть будет происходить обращение к файловой системе, до этого все исходные данные брались из адресной строки)
Если какое-либо из условий возращает false, то дальнейшая цепочка условий прекращается.
Пожалуйста, поправьте меня, если я не прав. Если ваше решение лучше, объясните, пожалуйста, почему и что к чему.
Первый фрагмент
RewriteCond %{REQUEST_URI} ^system.*RewriteRule ^(.*)$ /index.php?/$1 [L]
закрывает доступ в папку system для посетителей (только через index.php).
А вот насчет второго фрагмента вы правы. Третья строка вообще лишняя. У меня все прекрасно работает и без неё. Но я видел несколько сообщений на форумах о том, что без этой строки были проблемы с доступом к статическим файлам. Скорее всего, у них были ещё какие-то правила, которые влияли на результат, но я решил не рисковать и поэтому привел файл из codeigniter wiki без каких-либо изменений.
На сколько я знаю, тут еще важен порядок, то есть в моем случае, веб-сервер, если первое условие возращает false, в дальнейшем не обращается к файловой системе за проверкой на существование файлов/директорий. Могу ошибаться, поправьте, если не прав.
По мне так
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Вообще лишнее
так как как мы открывает доступ к определенным папкам
RewriteCond $1 !^(index\.php|images|robots\.txt|css|js)
А значит следовательно дальше этих папок не куда вылезти пользователь не должен
Big_Shark, а как на счет, к примеру, ссылок на файлы для скачивания?
RewriteCond $1 !^(index\.php|images|robots\.txt|css|js|fales)
Дописываем папку для файлов и пускай себе качает на здоровья с этой папки.
Понял, спасибо, так будет лучше – без обращения к файловой системе )
Почему-то раньше я не обращал на этот нюанс внимание. Действительно, если есть возможность убрать обращение к файловой системе, то это нужно сделать.
Еще один момент насчет ограничения доступа. Можно вынести папку system за пределы DOCUMENT_ROOT (например, на уровень выше), тогда в корне сайта останутся папки со статическими файлами и index.php. Т.е. всё к чему доступ разрешен. И можно будет вообще убрать
RewriteCond %{REQUEST_URI} ^system.*RewriteRule ^(.*)$ /index.php?/$1 [L]
Тоже хороший вариант)
У меня вопрос. Вы в дампе указали движок InnoDB. Мой провайдер позволяет только MyISAM использовать. Будут ли какие то проблемы если я буду MyISAM юзать?? Спасибо.
Будут. Большие.
Да, проблемы будут. И, к сожалению, SM прав, большие.
MyISAM не поддерживает каскадное удаление данных. В багтрекере при удалении записи о баге автоматически (движком MySQL) удалятся все связанные с ней комментарии. Т.к. при создании таблицы багов мы указали внешний ключ в таблице комментариев и указали опцию ON DELETE CASCADE. В случае с MyISAM вам придется удалять эти комментарии вручную, т.е. отдельными запросами.
В MyISAM можно сделать нечто подобное на триггерах after_update, типа грохнуть все коменты к багу, которого нет в таблице багов … чёт намудрил
)
я имелл ввиду такое
DELETE * from bugs where replyto not in (select bug_id from bugs where replyto is NULL)
Что-то не пойму как этот запрос работает
select bug_id from bugs where replyto is NULL
выберет все записи первого уровня (т.е. те, которые не являются комментариями)
DELETE * from bugs where replyto not in…
удалит все остальное, т.е. все комментарии, а нужно удалить один баг (первый уровень) и все комментарии к нему (всех уровней вложенности).
Да, всё верно, после удаления бага его ИД не будет в подзапросе (select bug_id from bugs where replyto is NULL),
соответственно все комментарии на него удаляться
Удаляться не только все комментарии к данному багу, но и ко всем остальным. Т.е. ВООБЩЕ ВСЕ комментарии. Останутся только записи о самих багах.
У каждого комментария в поле replyto записано какое-то значение, либо id бага, либо id другого комментария (для комментариев с уровнем вложенности 2 и >).
это всего-лишь MyISAM………..
при желании можно и чтото путёвое написать……..тот тригер был рервой идеей……..
Согласен, сделать можно. Но мне в голову приходит только выполнение запросов внутри рекурсивной функции (если не ограничивать уровень вложенности комментариев). А это может оказаться довольно ресурсоёмким решением.