Все, що ви хотіли знати про моделях і колекціях в Titanium

Але з якоїсь причини боялися запитати.

Моделі — досить важлива частина програми, тому що без даних нікуди.

У цій статті я постараюся максимально детально висвітлити всі аспекти використання моделей у MVC фреймворку для розробки мобільних додатків Appcelerator Titanium.

Якщо ви ще не пробували зв'язуватися з моделями, то, сподіваюся, ця стаття заощадить вам пару кілометрів нервів.

Backbone.js
Отже, перше, що варто знати при роботі з моделями в Titanium, це те, що вони засновані на моделях і колекціях з Backbone. Це означає, по-перше, ви можете використовувати всі властивості і методи, описані в документації Backbone; по-друге, буде не зайвим попередньо з нею знайомитися, якщо ви ще цього не зробили.

На всякий випадок зроблю акцент на термінології: модель — це одинична сутність, колекція — це набір однотипних моделей.

Важливо: Titanium використовує Backbone версії 0.9.2, так що деякі методи з документації Backbone можуть бути не реалізовані.

Underscore.js
Колекції так само додатково успадковують методи Underscore.js для полегшення життя розробника. Наприклад, метод .map

Створення
Створити модель можна двома рівносильними способами: з допомогою Appcelerator Studio або вручну.
Вручну ви можете створити файл спеціального формату у папці <project>/app/models/ (що, власне, і зробить за вас студія):
Формат файлу опису моделі
exports.definition = { 
config : { 
// схема даних 
}, 
extendModel: function(Model) { 
_.extend(Model.prototype, { 
// розширення Backbone.Model 
}); 
return Model; 
}, 
extendCollection: function(Collection) { 
_.extend(Collection.prototype, { 
// розширення Backbone.Collection 
}); 
return Collection; 
} 
} 


Якщо ви користуєтеся допомогою студії — просто викличте контекстне меню проекту і виберіть пункт «New -> Alloy Model». При створенні діалогове вікно запропонує вам вибрати тип адаптера: localStorage, properties або sql. Типи адаптерів описані далі.

Все, що вам потрібно описати в цьому файлі для базового функціоналу, це блок config. У ньому міститься схема даних і тип адаптера синхронізації. Цей блок повинен містити такі поля:
  • columns: словник, що описує поля моделі. Ключ — назва поля, значення — тип. Типи як в SQLite: string, varchar, int, tinyint, smallint, bigint, double, float, decimal, number, date, datetime та boolean
  • defaults: той же словник, що і columns, але тепер значення — це значення полів за замовчуванням, якщо якийсь з них не визначено при синхронізації
  • adapter: цей об'єкт містить два поля:
    • type: тип адаптера синхронізації
    • collection_name: назва колекції. Може відрізнятися від назви моделі. Значення цього поля ви будете використовувати для створення колекції
    • idAttribute: первинний ключ

Наприклад, ми створюємо модель books. Для цього створюємо в папці <project>/app/models/ файл books.js:
Приклад створеної моделі
exports.definition = { 
config: { 
"columns": { 
"title": "String", 
"author": "String" // якщо тип адаптера sql, то тут можна ще SQLite keywords додавати
}, 
"defaults": { 
"title": "-", 
"author": "-" 
}, 
"adapter": { 
"type": "sql", 
"collection_name": "books",
"idAttribute" : "title",
"db_file" : "db_books", // назва бази даних, з якою потрібно працювати. За замовчуванням _alloy_
"db_name" : "books.sqlite", // назва файлу бази щодо каталогу /app/assets. Якщо не вказано, то створиться файл [ім'я_бази].sqlite
} 
} 
} 


Тут у нас модель з двома текстовими полями: назва книги і автор. Обидва поля мають значення "-". Поки все просто.

Тип адаптера sql говорить про те, що при спробі отримати дані, модель з допомогою вбудованого адаптера спробує з'єднатися з SQLite базою на пристрої та отримати дані з таблиці books.
Власні властивості і методи в моделі можна додати так:
Приклад розширення моделі
exports.definition = { 
config : { 
// схема даних 
}, 
extendModel: function(Model) { 
_.extend(Model.prototype, { 
// розширення Backbone.Model 
customProperty: 'book', 
customFunction: function() { 
Ti.API.info('Привіт, я книга'); 
}, 
}); 
return Model; 
} 
} 


Те ж саме стосується колекцій. Якщо ви додали власні методи в extendModel, вони будуть доступні у моделі, а у колекції немає, і навпаки.

Використання
Звернутися до моделі/колекції можна двома способами:
  • Створивши глобальний сінглтон
  • Створивши локальну посилання
  • Вказавши в XML розмітки, якщо ви використовуєте Alloy

Глобальний сінглтон
В цьому випадку модель буде доступна відразу скрізь, у всіх контролерах. Якщо вона вже оголошена в одному, то в іншому виклик методу Alloy.Models.instance поверне посилання на цю оголошену модель. Приклад — модель User, вона може бути скрізь одна.

Аналогічно для колекцій.

Локальна посилання
Локальну посилання можна створити з допомогою методу Alloy.createModel. Тоді ця модель буде доступна тільки в межах того контролера, де створена. Метод — фабрика, передаєте в нього назву моделі (ім'я файлу мінус .js) і параметри. І все.

Аналогічно для колекцій.

XML
Елемент розмітки <Model> повинен бути прямим нащадком <Alloy>. І в нього повинен бути присутній атрибут src зі значенням «имя-файла-модели-минус-.јѕ». Тоді в контролері буде доступний сінглтон цієї моделі в просторі імен Alloy.Models:
XML
<Alloy> 
<Model src="book" /> 
<Window> 
<TableView id="table" /> 
</Window> 
</Alloy> 


Controller
var drama = Alloy.Models.book; 
drama.set('title', 'Далі живіть самі'); 
drama.set('author', 'Джонатан Троппер'); 


Також у цього елемента є атрибут instance. Якщо має значення true, то буде створено посилання на модель (локальна, доступна тільки всередині одного контролера). До речі, в цьому випадку модель не буде доступу в просторі імен Alloy.Models, до неї потрібно буде звертатися по id:
XML
<Alloy> 
<Model id="myBook" src="book" instance="true"/> 
<Window> 
<TableView id="table" /> 
</Window> 
</Alloy> 


Controller
var drama = $.myBook; 
drama.set('title', 'Далі живіть самі'); 
drama.set('author', 'Джонатан Троппер'); 


Аналогічно для колекцій.

Адаптери синхронізації
Нарешті ми добралися до того розділу, про який було обіцяно в розділі «Створення». Для роботи з моделями мало просто описати схему даних. Потрібно ще їх до чогось підключити. Ось цей зв'язок і є адаптер синхронізації.
Адаптер — це реалізація Backbone.sync. Так як найбільш поширена завдання — це CRUD операції на віддаленому сервері (ну, особисто з мого досвіду), то за замовчуванням метод Backbone.sync робить RESTful JSON запити за тими адресами, які ви вкажете у властивостях Model.urlRoot і Collection.url. Так свідчить офіційна документація. На практиці ж щоб добитися толку від моделей/колекцій, дуже зручно користуватися адаптером restapi, про який я розповім трохи пізніше. А поки повернемося до офіційній документації.

Адаптери можуть бути чотирьох типів:
  • sql
  • properties
  • localStorage (з версії alloy 1.5.0 не використовується, так що не будемо її розглядати)
  • тип


SQL
Якщо в конфіги в розділі adapter не визначений ключ idAttribute, то Alloy сам згенерує у вашій таблиці поле alloy_id і буде використовувати його як первинний ключ.

Зверніть увагу на поля конфига db_file і db_name (в розділі «Створення»). Тут вони важливі.
На відміну від інших типів, у цьому методі Backbone.Collection.fetch може приймати цілу рядок SQL-запиту:
Рядок запиту .fetch()
var library = Alloy.createCollection('book');
// Назва таблиці - це collection_name з конфига
var table = library.config.adapter.collection_name;
// простий запит
library.fetch({query:'SELECT * from' + table + ' where author="' + searchAuthor + '"'});
// prepared statement
library.fetch({query: { statement: 'SELECT * from' + table + ' where author = ?', params: [searchAuthor] }});


Тобто хочете простий запит — передавайте в параметрах об'єкт з ключем query, а хочете складний — передавайте запит і параметри.

До речі, можете ще передавати ключ id. У цьому випадку адаптер сам зрозуміє, що ви хочете використовувати обмеження WHERE id=?..
id
myModel.fetch({id: 123});
// те ж саме, що
myModel.fetch({query: 'select * from ... where id =' + 123 });



properties
Якщо ваша база — не SQLite, то ви можете створити свій адаптер і робити з даними все що завгодно. Для цього створіть у каталозі app/assets/alloy/sync або app/lib/alloy/sync файл адаптера, наприклад, myAdapter.js, а потім вкажіть в конфіги моделі в adapter.type назву цього файлу, тобто «myAdapter».
Власне цей файл повинен експортувати три функції:
  • module.exports.beforeModelCreate(config) (не обов'язково) — метод, як ясно з назви, виконується перед створенням моделі. У параметрах передається config цієї моделі. Тут, наприклад, можна додати baseUrl адресою запиту. Повертає модифікований об'єкт config
  • module.exports.afterModelCreate (не обов'язково) — приймає два параметри: новенький тільки що створений клас Backbone.Model і назва файлу моделі
  • module.exports.sync — реалізація методу Backbone.sync. Він повинен повертати дані


restapi
Якщо вам потрібно отримувати дані з віддаленого сервера, а створювати власний адаптер не хочеться, є чудовий адаптер restapi, який не входить в число вбудованих, але виконує свою роботу (RESTful JSON запити) на ура.
Необхідних налаштувань мінімум — поле URL в конфіги:
Приклад моделі з адаптером restapi
exports.definition = {
config: {
"URL": "http://example.com/api/modelname",
//"debug": 1,
"adapter": {
"type": "restapi",
"collection_name": "MyCollection",
"idAttribute": "id"
}
}, 
extendModel: function(Model) { 
_.extend(Model.prototype, {});
return Model;
},
extendCollection: function(Collection) { 
_.extend(Collection.prototype, {});
return Collection;
} 
}


Зрозуміло, це не всі доступні налаштування, за повним списком дивіться документацію. А що ще важливого в цьому адаптері — це те, що метод fetch в ньому бере словник з трьома можливими полями:
  • data параметри запиту
  • success callback для успішного запиту
  • error callback для помилки


Висновок
Отже, це все, що потрібно знати для того, щоб на базовому рівні вміти працювати з моделями в Titanium. Ця Тема дещо ширше, наприклад, я свідомо опустив тут опис процесу міграції між різними версіями бази, data binding, використання моделей без Alloy, а також робота з SQLite. Всі ці прогалини я сподіваюся заповнити в наступній статті, слідкуйте за оновленнями.

Ця стаття заснована на а) офіційній документації; б) власний досвід використання моделей в Alloy. Якщо серед хабрасообщества є люди, які розбираються в цьому питанні краще за мене і бачать помилки або неточності, прошу, коментуйте, обговоримо.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.