База данных на файлах

 

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

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

Данные которые записаны в эти файлы лежат в формате json. Кто не знает что это за формат, просто погуглите, в нем нет ничего экстраординарного, именно поэтому останавливаться на этом я не буду.

В общем идея класса проста, он

  • создает таблицы
  • создает структуру (поля) этих таблиц
  • редактирует структуру
  • наполняет эти таблицы данными
  • удаляет эти данные
  • редактирует эти данные

По сути в таблице хранится массив с данными в формате json и класс помогает с этими данными как — то взаимодействовать.

Теперь попробую описать свойства и методы которые есть в классе

Класс базы данных на файлах

Свойства

НаименованиеДоступТипОписание
path private строка хранит путь к папке где будут храниться файлы базы данных
handle private ресурс хранит ресурс открытого файла (результат работы функции fopen())
name private строка имя вызываемой таблицы
tableFields private массив хранит список полей таблицы
fields private массив хранит список полей с которыми необходимо произвести какие — либо операции. Необходим для работы методов createTable(), insert(), update(), addField(), deleteField(), renameField(), setAI()
filter private массив хранит правила фильтрации выборки (некий аналог where в скуле) необходим для метода checkRow()
order private строка хранит указания по какому полю таблицы сортировать выборку
count private число хранит количество выбранных строк. Значение объявляется в результате вызова метода select()
rows private массив хранит строки таблицы
ai private массив хранит информацию об автоинкрементном поле. содержит два ключа:
  1. int — следующее значение автоинкрементного поля
  2. field — поле которое является автоинкрементным

Методы

НаименованиеДоступТипСписок параметровОписание
create public static name — имя таблицы создает и возвращает объект класса базы данных.
__construct public   name — имя таблицы конструктор класса. объявляет свойство path и name. значение для свойства name передается по ссылке (&) из метода create()
select public   closeFile — снимать ли блок с файла (по умолчанию TRUE). не использовать при внешнем вызове метода делает выборку из файла. возвращает массив или false. результат выборки зависит от свойств filter и order. вызывается только после вызова метода getTable()
createTable public     создает новую таблицу. поля таблицы назначаются методом setField(). возвращает true в случае успеха или исключение в случае ошибки
addField public     добавляет новое поле в уже существующую таблицу. вызывается после метода getTable(). возвращает true или исключение. поля для добавления назначаются методом setField()
deleteField public     удаляет поля из существующей таблицы. вызывается после метода getTable(). возвращает true или исключение. поля для удаления назначаются методом setField()
renameField public     переименовывает поле уже существующей таблицы. возвращает true или исключение. вызывается после метода getTable(). в качестве поля которое необходимо переименовать берется первый ключ из свойства fields. в качестве имени в которое необходимо переименовать берется второй ключ из свойства fields. поля назначаются методом setField()
insert public     вставляет строку в существующую таблицу. возвращает id созданной строки при успехе. false в случае пустой выборке и исключение в случае ошибки. вызывается после метода getTable(). Значение полей назначается через метод setField()
update public     обновляет строки в существующей таблице. возвращает true или исключение. вызывается после метода getTable(). значение полей назначается через метод setField(). зависит от свойства filter
delete public     удаляет строку из уже существующей таблицы. возвращает true или исключение. вызывается после метода getTable(). зависит от свойства filter
getTable public     получает таблицу. необходимо вызывать сразу после метода create(). необходим почти для всех методов класса
filterBy public  
  1. field — поле по которому производить фильтрацию
  2. condition — знак фильтра. (= <> != > < >= <= IN LIKE)
  3. value — значение фильтра
метод аналог конструкции where в sql запросах. вызывается после метода getTable(). возвращает сам себя или исключение в случае фатальной ошибки. наполняет свойство filter. необходим для методов select(), update() и delete()
showFields public     позволяет вернуть содержание свойства tableFields.
setField public  
  1. field — наименование поля
  2. value — значение поля. (необходимо для метода update())
метод позволяет наполнить свойство fields. возвращает самого себя или исключение. необходим почти для всех методов класса.
setAI public     позволяет назначить автоинкрементное поле при создание таблицы. за автоинкрементное поле беретрся последний элемент массива из свойства fields
orderBy public  
  1. field — поле по которому необходимо сортировать
  2. direction — направление ASC или DESC
Позволяет влиять на результат работы метода select(). сортирует выборку по полю field в направление direction. возвращает самого себя или исключение
getCount public     метод возвращает кол — во выбранных строк методом select()
clear public     позволяет очистить значение свойств класса. возвращает самого себя
getSec private   date — дата в формате ГГГГ-ММ-ДД ЧЧ:ММ:СС переводит и возвращает дату в секундах прошедших с начала Эпохи Unix. метод необходим для фильтрации дат при выборке
existField private   name — имя поля проверяет существует ли поле в таблице. возвращает true или false
writeDB private   json — массив для записи в файл метод пишет информацию в таблицу базы данных. возвращает true
checkRow private   row — массив строки в базе данных метод проверяет соответствует ли строка выборке фильтру. позволяет отсеять все что не совпадает с условиями в свойстве filter. возвращает true или false
orderRows private   rowList — массив с строками базы данных метод сортирует строки по правилу указанному в свойстве order
getValue private   data — данные для перевода метод призван обработать данные в соответствие с форматом этих самых данных. в частности это касается дат. так как они хранятся в формате ГГГГ-ММ-ДД ЧЧ:ММ:СС а для сравнения нам необходимо число а не строка, то данный метод переведет строку даты в число. возвращает обработанные данные
closeFile private     метод закрывает и разблокирует файл таблицы. чистит свойство handle
returnError private   error — текст ошибки метод призван остановить отработку класса при фатальной ошибке

Как видите в классе очень много всего, поэтому такой формат подачи информации куда полезнее чем имитировать написание этого самого класса. Давайте я Вам дам пару примеров (в конце статьи можете скачать архив с примером).

Примеры

createTable()

Начнем с того что создадим таблицу тест (в архиве с примером это файл create.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // создаем поле ID
    ->setField('id')
    // говорим что поле ID автоинкрементное
    ->setAI()
                
    // создоем поле name
    ->setField('name')
                
    // исполняем метод создания таблицы
    ->createTable()
;

// выводим результат отработки метода
var_dump($result);

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

ответ метода create()

оно говорит нам что все прошло успешно. В папке database должен появиться файл test.tbl с дефолтным содержанием

insert()

Теперь давайте вставим одну строчку в нашу базу данных (в архиве с примером это файл insert.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()

    // определяем значение
    ->setField('name', 'Алексей')       

    // исполняем метод вставки значения
    ->insert()
;

// выводим результат отработки метода
var_dump($result);

после отработки скрипта мы увидим на экране вот такое сообщение

ответ метода insert()

как видите метод insert() вернул нам id новой строчки в наше базе

select()

Теперь давайте напишем простую выборку из таблицы test (в архиве с примером это файл select.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()

    // исполняем метод простейшей выборки
    ->select()
;

// выводим результат отработки метода
?><xmp><?
var_dump($result);
?></xmp><?

после запуска мы должны увидеть вот такой массив

ответ метода select()

как видите в нашей таблице сейчас есть одна строчка которую мы вставили чуть выше.

update()

Теперь давайте обновим нашу строчку (в архиве с примером это файл update.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()
    
    // устанавливаем фильтр тем самым изменим имя только у записи
    // чей ID равен единице
    ->filterBy('id', '=', 1)

    // задаем новое значение
    ->setField('name', 'Rio-Shaman')       

    // исполняем метод обновления значения
    ->update()
;

// выводим результат отработки метода
var_dump($result);

после запуска данного кода мы должны увидеть вот такую картину

ответ метода update()

Этот вывод говорит на о том что обновление прошло успешно. Теперь если запустить вот этот код (в архиве с примером это файл select.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()

    // исполняем метод простейшей выборки
    ->select()
;

// выводим результат отработки метода
?><xmp><?
var_dump($result);
?></xmp><?

мы увидим вот такой массив

ответ метода select()

delete()

Теперь давайте удалим вставленную строчку (в архиве с примером это файл delete.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()
    
    // устанавливаем фильтр тем самым удалим только запись
    // чей ID равен единице
    ->filterBy('id', '=', 1)

    // исполняем метод удаления
    ->delete()
;

// выводим результат отработки метода
var_dump($result);

после запуска видим вот такую картину

ответ метода delete()

Теперь давайте запустим вот этот код (в архиве с примером это файл select.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()

    // исполняем метод простейшей выборки
    ->select()
;

// выводим результат отработки метода
?><xmp><?
var_dump($result);
?></xmp><?

видим вот такое сообщение

ответ метода select()

оно говорит нам о том, что в выборке сейчас ничего нет. Там и нет ничего, мы ведь только что удалили из таблице единственную строчку

addField()

Теперь давайте изменим структуру таблицы, но для начала вставим что — нибудь в базу данных (в архиве с примером это файл addfield.php) исполняем вот этот код

// подключаем класс
require_once ('database.class.php');

// прежде чем добавлять новое поле, давайте
// вставим хотябы одну строчку в базу данных
$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()

    // определяем значение
    ->setField('name', 'Алексей')       

    // исполняем метод вставки значения
    ->insert()
;

теперь давайте воспользуемся методом addField()

// подключаем класс
require_once ('database.class.php');

// теперь добавляем новые поля
$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()
    
    // новые поля
    ->setField('namef')
    ->setField('nameo')
    
    // исполняем метод добавления полей
    ->addField()
;

// выводим результат отработки метода
var_dump($result); die();

вот что он нам выдаст

ответ метода addFiled()

Как вы поняли все прошло удачно. Давайте произведем выборку (в архиве с примером это файл select.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()

    // исполняем метод простейшей выборки
    ->select()
;

// выводим результат отработки метода
?><xmp><?
var_dump($result);
?></xmp><?

видим вот такую картину

ответ метода select()

как видите в структуре появились два новых поля nameo и namef

deleteField()

Теперь давайте удалим эти два поля (в архиве с примером это файл deletefield.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()

    // определяем поле которое нужно удалить
    ->setField('namef')
    ->setField('nameo')

    // исполняем метод удаление полей
    ->deleteField()
;

// выводим результат отработки метода
var_dump($result); die();

после запуска увидим вот такое сообщение

ответ метода deleteField()

если сейчас сделать выборку (в архиве с примером это файл select.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()

    // исполняем метод простейшей выборки
    ->select()
;

// выводим результат отработки метода
?><xmp><?
var_dump($result);
?></xmp><?

то увидим вот такую картинку

ответ метода select()

renameField()

Теперь пришло время попробовать переименовать поле. Исполняем вот этот код (в архиве с примером это файл renamefield.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()

    // определяем какое поле будем переименовывать
    ->setField('name')
    // на какое наименование будем менять
    ->setField('fullname')

    // исполняем метод переименовки поля
    ->renameField()
;

// выводим результат отработки метода
var_dump($result); die();

видим вот такое сообщение

ответ метода renameField()

теперь сделаем выборку (в архиве с примером это файл select.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()

    // исполняем метод простейшей выборки
    ->select()
;

// выводим результат отработки метода
?><xmp><?
var_dump($result);
?></xmp><?

увидим вот такой массив

ответ метода select()

как видно, поле теперь именуется не name а fullname

более сложный select()

Теперь давайте немного усложним нашу выборку. Но для начала добавим в табличку еще несколько имен а именно Сашу, Катю и Юлю (в архиве с примером это файл select2.php)

// подключаем класс
require_once ('database.class.php');

// вставляем Сашу в БД
database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()
    
    // устанавилваем значение
    ->setField('fullname', 'Саша')
    
    // вставляем
    ->insert()
;

// вставляем Катю в БД
database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()
    
    // устанавилваем значение
    ->setField('fullname', 'Катя')
    
    // вставляем
    ->insert()
;

// вставляем Юлю в БД
database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()
    
    // устанавилваем значение
    ->setField('fullname', 'Юля')
    
    // вставляем
    ->insert()
;

Теперь сама выборка. Предположим что нам нужно вытащить строчки id которых равны 2 — ум 3 — ем и 4 — ем. Так же необходимо отсортировать имена по алфавиту. Вот как выглядит код выборки (в архиве с примером это файл select2.php)

// подключаем класс
require_once ('database.class.php');

$result = database::create('test') // поднимаем объект класса
    // получам таблицу
    ->getTable()
    
    // вытаскиваем только Алексея, Сашу и Катю (id 2, 3 и 4 соответсвенно)
    ->filterBy('id', 'IN', '2,3,4')
    
    // сортируем выборку по алфовиту
    ->orderBy('fullname', 'ASC')

    // исполняем метод выборки
    ->select()
;

// выводим результат отработки метода
?><xmp><?
var_dump($result);
?></xmp><?

Вот что мы получаем в итоге на экране

ответ метода select()

Заключение

Ну собственно на этом все. Этот класс мы будем использовать в нашем мини движке, на котором в последствие мы соберем небольшой интернет — магазин

Есть еще один момент. Данный класс тестировался на php версии 5.3 с разрешенными short_open_tag. Так что перед тестом проверьте удовлетворяет ли Ваш сервер этим требованиям

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

Если у Вас возникнут какие — то ошибки, то пишите их в комментарии, попробуем что — нибудь придумать

Всего Вам наилучшего, на сегодня все!

 

Возможно Вам будут интересны следующие заметки

Комментарии (4)

Ваше имя *
Сайт
Ваш E-mail *
Ваше сообщение *
 
Вы не подтвердили условия политики конфиденциальности.
Poster, 28 Июня 2015 г. 12:07 пишет:
Читатель
Большое спасибо, что не забываете про свой сайт! Предвижу, что скоро мне этот урок понадобится.
Хотелось бы задать вопрос. Планируете ли вы дополнять серию уроков посвященных созданию своего блога?
Алексей, 28 Июня 2015 г. 13:07 пишет:
Автор
Планируете ли вы дополнять серию уроков посвященных созданию своего блога?
Скорее всего нет, так как сейчас пытаюсь выкраить время для написания серии статей по созданию интернет - магазина.
Ответ для пользователя: Poster
Александр, 16 Сентября 2015 г. 06:45 пишет:
Гость
Только начал знакомиться с этим циклом заметок. И сразу возникает вопрос, а почему файлы? И зачем изобретать, если есть готовые инструменты: базы данных, классы работы с ними. Конечно, я согласен, для мини-магазина файлы это хорошо, снимает множество проблем: с администрированием, смягчает требование к серверу, ускоряет работу и т.д. Но ведь есть замечательная SQLite3, такие же файлы, готовый встроенный класс для работы, использует SQL, что в последствии, при масштабировании позволит переехать на MySQL сервер и т.д. Почему?
Алексей, 16 Сентября 2015 г. 10:13 пишет:
Автор
И зачем изобретать, если есть готовые инструменты
Хотелось что-то свое
И сразу возникает вопрос, а почему файлы?
Этот вопрос более не актуальный, так как я все таки решил перейти на mysql
Ответ для пользователя: Александр