OKStyle
| Дата: Воскресенье, 12.10.2014, 22:52 | Сообщение # 1 |
 Архивариус
Группа: Администраторы
Зарегистрирован: 19.02.2011
Сообщений: 125
Репутация: 8
Статус: Offline
| ORM - облегченный сценарий запросов. Доступен с версии R33 в плагине MySQL от BlueG. ( сейчас разрабатывается Pain123/maddinat0r ).
Первое, что необходимо сделать, это создать ORM экземпляр, идентификатор - id = orm_create(nametable[]) где nametable - название таблицы базы данных, которую мы будем использовать. Теперь некоторые глобальные (или static) переменные должны быть "привязаны" к ORM процессу путем вызова функции.
Для начала, давайте вспомним, какие запросы мы в основном посылаем к БД - SELECT(выборка информации из БД), INSERT(Вставка информации в БД), UPDATE(Обновление уже существующей информации в БД) и в редких случаях - DELETE. Рассмотрим банальный запрос, который существует в большинстве модах:
Код new mSQL[256+1]; //мутим переменную для запроса mysql_format(Actconnect,mSQL,"SELECT * FROM `my_user` WHERE Name = %s",his_name); //составляем запрос mysql_tquery(Actconnect,mSQL,"PlayerDataLoad","d",playerid); //обращаемся к серверу
Что-то похожее явно есть у Вас в гейммоде. А вот как выполняется этот же запрос при помощи ORM:
Код orm_select(PlayerInfo[playerid][ID_ORM],"OnPlayerDataLoad","d",playerid); //ORM сценарий выборки данных игрока
Компактно, не правда ли? А теперь давайте рассмотрим callback первого и второго варианта. В первом случае, мы будем иметь что-то похожее на это:
Код forward OnPlayerDataLoad(playerid); public OnPlayerDataLoad(playerid) { new r,f; // кол-во строк и столбцов cache_get_data(r,f); // Обрабатываем запрос, получаем кол-во строк и столбцов if(rows) { //Смотрим, существует ли такая строка в таблице
PlayerInfo[playerid][pLevel] = cache_get_field_content_int(0,"Level"); // Заполнение переменых PlayerInfo[playerid][pAdmin] = cache_get_field_content_int(0,"Admin"); PlayerInfo[playerid][pLeader] = cache_get_field_content_int(0,"Leader"); PlayerInfo[playerid][pMember] = cache_get_field_content_int(0,"Member"); PlayerInfo[playerid][pSkin] = cache_get_field_content_int(0,"Skin"); } else print("Упс! Мы не нашли такого человека в базе!"); // Игрока нет return 1; }
Второй снова порадует своей компактностью:
Код forward OnPlayerDataLoad(playerid); public OnPlayerDataLoad(playerid) { switch(orm_errno(Player[playerid][ID_ORM])){ case ERROR_OK: printf("Player with ID:%d data load!"); //Все отлично, сценарий заполнил все данные игрока case ERROR_NO_DATA: printf("Player with ID:%d - LOADING ERROR"); //Ошибка, мы не нашли данных на этого игрока! } return 1; }
Круто, не правда ли? Однако, чтобы давольствоваться такими прелестями нам всё же придется кое-где "заморочиться". Теперь, когда вы
примерно понимаете, в чем разница, начнем сначала и рассмотрим детали.
Для начала, разберемся в ORM-функциях, которые нам предлагают разработчики:
orm_create("название_таблицы") - создание ORM orm_destroy(id:ORM) - удаление ранее созданного ORM
Код new ORM:myorm = orm_create("players_table"); //создали orm_destroy(myorm); //удалили
orm_errno(ORM:id) - проверка на ошибки при обработке. Вызывать в callback'ах основных сценариев.
Код switch(orm_errno(myorm)) { case ERROR_OK: printf("Player with ID:%d data load!"); //Все отлично, сценарий заполнил все данные игрока case ERROR_NO_DATA: printf("Player with ID:%d - LOADING ERROR"); //Ошибка, мы не нашли данных на этого игрока! }
Основные сценарии:
orm_select(ORM:id,callback,format,float) и orm_load(ORM:id,callback,format,float) - сценарии идентичны запросу
SELECT (Получение информации) orm_update(ORM:id) - сценарий идентичны запросу UPDATE (обновление) orm_insert(ORM:id,callback,format,float) - сценарий идентичны запросу INSERT (вставка строки) orm_delete(ORM:id) - сценарий идентичны запросу DELETE (удаление строки) orm_save(ORM:id,callback,format,float) -очень умный сценарий. Комбинация INSERT и UPDATE. Если данной
строки нет в таблицы, то он выполняет INSERT(вставку), если же есть - UPDATE (обновление)
Функции привязки:
orm_addvar_int(ORM:id, &var, varname[]) - привязка целочисленной переменной. orm_addvar_float(ORM:id, &var, varname[]) - привязка числа с плавающей точкой. orm_addvar_string(ORM:id, &var, var_maxlen, varname[]) - привязка строки.
И немаловажные: orm_setkey(ORM:id,varname[]) - относительно каких переменных выполняем поиск.(Что-то вроде конструкции: WHERE ID =) orm_apply_cache(ORM:id, row) - применить кэширование. Используется при циклической загрузки множества данных.
Практическое применение...
Код //глобальные переменные new kills, Float:kd_ratio, name[MAX_PLAYER_NAME+1];
// ... структура запросов в функции orm_addvar_int(id, kills, "kills"); // orm_addvar_int(ORM:id, переменная, поле в БД[]) orm_addvar_float(id, kd_ratio, "ratio"); // orm_addvar_float(ORM:id, переменная, поле в БД[]) orm_addvar_string(id, name, sizeof(name), "name"); // orm_addvar_string(ORM:id, массив[], максимальная длина, поле в БД[])
Эти три запроса считают наши данные. Переменная должна быть либо глобальная либо статическая - другими словами, она не может быть в стеке! Теперь, когда вы поняли, что делает этот макрос, а, если нет, то мне придется показать вам то, что он делает - Он считывает ваши данные из таблицы. Покажу уже на более крупном примере.
Код #include <a_mysql>
enum E_PLAYER { ORM:ORM_ID, // создаем идентификатор в енуменаторе. ID, Name[MAX_PLAYER_NAME+1], Money, Level, Float:PosX, Float:PosY, Float:PosZ, }; new Player[MAX_PLAYERS][E_PLAYER];
public OnPlayerConnect(playerid) { GetPlayerName(playerid, Player[playerid][Name], MAX_PLAYER_NAME); new ORM:ormid = Player[playerid][ORM_ID] = orm_create("players"); // Создаем наше соединение! // Считываем данные orm_addvar_int(ormid, Player[playerid][ID], "ID"); orm_addvar_string(ormid, Player[playerid][Name], MAX_PLAYER_NAME+1, "Name"); orm_addvar_int(ormid, Player[playerid][Money], "Money"); orm_addvar_int(ormid, Player[playerid][Level], "Level"); orm_addvar_float(ormid, Player[playerid][PosX], "PosX"); orm_addvar_float(ormid, Player[playerid][PosY], "PosY"); orm_addvar_float(ormid, Player[playerid][PosZ], "PosZ"); orm_setkey(ormid, "Name"); // Устанавливаем имя для нашей дальнейшей проверки orm_select(ormid, "OnPlayerDataLoad", "d", playerid); // Переходим к коллбеку return 1; }
forward OnPlayerDataLoad(playerid); public OnPlayerDataLoad(playerid) { switch(orm_errno(Player[playerid][ORM_ID])) // Проверяем на ошибки { case ERROR_OK: { ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Авторизация", "Введите ваш пароль", "Login", "Abort"); } case ERROR_NO_DATA: { ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Регистрация", "Введите ваш пароль", "Register", "Abort"); } } orm_setkey(Player[playerid][ORM_ID], "ID"); // Установим идентификатор игрока для будущих запросов! return 1; }
public OnPlayerDisconnect(playerid, reason) { if(Player[playerid][ID] != 0) { orm_update(Player[playerid][ORM_ID]); // Обновляем наши данные } orm_destroy(Player[playerid][ORM_ID]); // Удаляем наш идентификатор который мы создали в енуменаторе
for(new E_PLAYER:e; e < E_PLAYER; ++e) Player[playerid][e] = 0; // Обнуляем переменные игрока return 1; }
Теперь по-подробнее объясню об этой части:
Код orm_setkey(ormid, "Имя"); orm_select(ormid, "OnPlayerDataLoad", "d", playerid);[/php]
Что мы сделали? 1) Установили поле Name для запроса ( путем `Name` (WHERE часть запроса) ) 2) Создали запрос: "SELECT `ID`,`Name`,`Money`,`Level`,`PosX`,`PozY`,`PosZ` FROM `players` WHERE `Name`='%s' LIMIT 1" (%s ник игрока) 3) Выполняем запрос ( Это делается в отдельном потоке! ) 4) Обновляем данные с запрашиваемой информации. 5) Вызываем OnPlayerDataLoad с playerid в качестве единственного параметра после завершения запроса
При успешном запросе orm_error возвращает 0, при неудачном - 1. * ERROR_OK (0) * ERROR_NO_DATA (1)
Так ERROR_OK, для нас в данном случае обозначает, что игрок уже существует в базе данных, и мы можем продолжить нашу проверку пользователя - попросим его авторизоваться.
Но другое дело здесь в том, что для будущих запросов, мы установили новый ключ в поле для запроса:
[code]orm_setkey(Player[playerid][ORM_ID], "ID");
Это понадобится нам для дальнейших запросов, например, с orm_update (как показано в OnPlayerDisconnect), orm_select или orm_delete. После того, как игрок отключается, мы удалить экземпляр с ORM orm_destroy(ORM:id). До этого, можно назвать все orm-уроженцы кроме orm_select и orm_update. Игрок должен зарегистрироваться на сервере, нам понадобится - orm_insert. Она создает запись в таблице. Синтаксис аналогичен orm_select:
Код orm_insert(Плеер[playerid][ORM_ID], "OnPlayerRegister", "d", playerid);
Вы заметили, что значение Player[playerid][ID] обновляется. Мы послали запрос INSERT, далее мы должны использовать orm_setkey для идентификатора переменной перед вызовом orm_insert. Если вы этого не сделаете, новый ID будет сохранен в старую переменную переменной, и получится не то что мы хотим. Как обновить существующие данные в базу данных? Вот где мы должны будем использовать orm_update. Этот макрос создает UPDATE-запрос со всеми текущими значениями имеющихся у нас переменных. Например, пользователь User1 имеет ID 65 (не playerid, ID игрока-в таблице!), 4 уровня, имеет 54634$ и находится где-то в Лос-Сантосе. В этом случае, orm_update бы создать такой запрос:
Код UPDATE `игроков` SET `Name`='User1', `Деньги`='54634', `Level`='3', `PosX`='745.231', `Букет`='-967.1425', `PosZ`='14.2543', ГДЕ `ID`='65'
Использование:
Теперь мы можем генерировать практически все важные типы запросов, только DELETE-запрос отсутствует. Но не беспокойся, мы сейчас рассмотрим - orm_delete. Как вы могли догадаться, этот макрос создает DELETE-запрос. В нашем примере это было бы сформировать и отправить запрос:
Код DELETE FROM `players` WHERE `ID`='65'
В отличие от orm_insert, orm_delete имеет дополнительный (необязательный) параметр с именем "clearvars". Если задано значение true, orm_delete не только стереть нужную запись в соответствующей таблице, он также восстановит регистрацию путем установки значениям переменных нулю (все зарегистрированные переменные, даже ключ). В этом уроке мы использовали в качестве примера систему аккаунта, но вы не должны ограничивать себя в этом! Вы можете управлять любыми данными, которые вы хотите, например, данные автомобилей или домов. Вот один пример того, как можно было бы загрузить транспортные средства с ORM системой:
Код new SQL = -1;
enum e_Vehicle { ORM:ORM_ID, VID, ID, ModelID, Color1, Plate[32], Float:Pos[4], }; new Vehicle[MAX_VEHICLES][e_Vehicle];
public OnGameModeInit() { mysql_log(); SQL = mysql_connect("127.0.0.1", "root", "test", "pass"); //загружаем автомобили mysql_tquery(SQL, "SELECT * FROM `vehicles`", "OnVehiclesLoad", ""); return 1; }
forward OnVehiclesLoad(); public OnVehiclesLoad() { for(new r=0; r < cache_num_rows(); ++r) { new ORM:ormid = Vehicle[r][ORM_ID] = orm_create("vehicles");
orm_addvar_int(ormid, Vehicle[r][ID], "ID"); //это наш ключ orm_setkey(ormid, "ID"); //сейчас мы ставим наш ключ для дальнейших запросов orm_addvar_int(ormid, Vehicle[r][ModelID], "ModelID"); orm_addvar_int(ormid, Vehicle[r][Color1], "Color1"); orm_addvar_string(ormid, Vehicle[r][Plate], 32, "Plate"); orm_addvar_float(ormid, Vehicle[r][Pos][0], "PosX"); orm_addvar_float(ormid, Vehicle[r][Pos][1], "PosY"); orm_addvar_float(ormid, Vehicle[r][Pos][2], "PosZ"); orm_addvar_float(ormid, Vehicle[r][Pos][3], "PosA");
orm_apply_cache(ormid, r);
Vehicle[r][VID] = CreateVehicle(Vehicle[r][ModelID], Vehicle[r][Pos][0], Vehicle[r][Pos][1], Vehicle[r][Pos][2], Vehicle[r][Pos][3], Vehicle[r][Color1], -1, -1); }
return 1; }
Авторы: georJik, Rex_Doberman
|
|
| |