Commit 764549f6 by Borales

[Uk] Guide corrections and fixes. Adding images [skip ci]

parent 5c3bef88
...@@ -24,7 +24,7 @@ All Rights Reserved. ...@@ -24,7 +24,7 @@ All Rights Reserved.
* [Робота з формами](start-forms.md) * [Робота з формами](start-forms.md)
* [Робота з базами даних](start-databases.md) * [Робота з базами даних](start-databases.md)
* [Генерація коду за допомогою Gii](start-gii.md) * [Генерація коду за допомогою Gii](start-gii.md)
* [Що далі?](start-looking-ahead.md) * [Наступні кроки](start-looking-ahead.md)
Структура додатка Структура додатка
...@@ -35,24 +35,24 @@ All Rights Reserved. ...@@ -35,24 +35,24 @@ All Rights Reserved.
* [Додатки](structure-applications.md) * [Додатки](structure-applications.md)
* [Компоненти додатка](structure-application-components.md) * [Компоненти додатка](structure-application-components.md)
* [Контролери](structure-controllers.md) * [Контролери](structure-controllers.md)
* [Представлення](structure-views.md)
* [Моделі](structure-models.md) * [Моделі](structure-models.md)
* **TBD** [Фільтри](structure-filters.md) * [Представлення](structure-views.md)
* **TBD** [Віджети](structure-widgets.md) * [Модулі](structure-modules.md)
* **TBD** [Модулі](structure-modules.md) * [Фільтри](structure-filters.md)
* [Віджети](structure-widgets.md)
* [Ресурси](structure-assets.md) * [Ресурси](structure-assets.md)
* **TBD** [Розширення](structure-extensions.md) * [Розширення](structure-extensions.md)
Обробка запитів Обробка запитів
--------------- ---------------
* **TBD** [Bootstrapping](runtime-bootstrapping.md) * [Огляд](runtime-overview.md)
* **TBD** [Роутінг](runtime-routing.md) * [Bootstrapping](runtime-bootstrapping.md)
* **TBD** [Запити](runtime-requests.md) * [Роутінг та створення URL](runtime-routing.md)
* **TBD** [Відповіді](runtime-responses.md) * [Запити](runtime-requests.md)
* **TBD** [Сесії та кукі](runtime-sessions-cookies.md) * [Відповіді](runtime-responses.md)
* [Розбір та генерація URL](runtime-url-handling.md) * [Сесії та кукі](runtime-sessions-cookies.md)
* [Обробка помилок](runtime-handling-errors.md) * [Обробка помилок](runtime-handling-errors.md)
* [Логування](runtime-logging.md) * [Логування](runtime-logging.md)
...@@ -74,10 +74,10 @@ All Rights Reserved. ...@@ -74,10 +74,10 @@ All Rights Reserved.
Робота з базами даних Робота з базами даних
--------------------- ---------------------
* [Обʼєкти доступу до даних (DAO)](db-dao.md) - Зʼєднання з базою даних, прості запити, транзакції і робота зі схемою. * [Обʼєкти доступу до даних (DAO)](db-dao.md) - Зʼєднання з базою даних, прості запити, транзакції і робота зі схемою
* [Конструктор запитів](db-query-builder.md) - Запити до бази даних через простий шар абстракції. * [Конструктор запитів](db-query-builder.md) - Запити до бази даних через простий шар абстракції
* [Active Record](db-active-record.md) - Отримання обʼєктів AR, робота з ними та визначення звʼязків. * [Active Record](db-active-record.md) - Отримання обʼєктів AR, робота з ними та визначення звʼязків
* [Міграції](db-migrations.md) - Контроль версій схеми даних при роботі в команді. * [Міграції](db-migrations.md) - Контроль версій схеми даних при роботі в команді
* **TBD** [Sphinx](db-sphinx.md) * **TBD** [Sphinx](db-sphinx.md)
* **TBD** [Redis](db-redis.md) * **TBD** [Redis](db-redis.md)
* **TBD** [MongoDB](db-mongodb.md) * **TBD** [MongoDB](db-mongodb.md)
...@@ -88,19 +88,20 @@ All Rights Reserved. ...@@ -88,19 +88,20 @@ All Rights Reserved.
------------------------------- -------------------------------
* [Створення форм](input-forms.md) * [Створення форм](input-forms.md)
* [Валідація](input-validation.md) * [Валідація вводу](input-validation.md)
* **TBD** [Завантаження файлів](input-file-uploading.md) * [Завантаження файлів](input-file-uploading.md)
* **TBD** [Робота з декількома моделями](input-multiple-models.md) * **TBD** [Робота з декількома моделями](input-multiple-models.md)
Відображення даних Відображення даних
------------------ ------------------
* **TBD** [Форматування даних](output-formatting.md) * [Форматування даних](output-formatter.md)
* **TBD** [Посторінкове розбиття](output-pagination.md) * **TBD** [Посторінкове розбиття](output-pagination.md)
* **TBD** [Сортування](output-sorting.md) * **TBD** [Сортування](output-sorting.md)
* [Провайдери даних](output-data-providers.md) * [Провайдери даних](output-data-providers.md)
* [Віджети для даних](output-data-widgets.md) * [Віджети даних](output-data-widgets.md)
* [Робота з клієнтськими скриптами](output-client-scripts.md)
* [Темізація](output-theming.md) * [Темізація](output-theming.md)
...@@ -118,14 +119,14 @@ All Rights Reserved. ...@@ -118,14 +119,14 @@ All Rights Reserved.
--------- ---------
* [Огляд](caching-overview.md) * [Огляд](caching-overview.md)
* [Кешуванная даних](caching-data.md) * [Кешування даних](caching-data.md)
* [Кешуванная фрагментів](caching-fragment.md) * [Кешування фрагментів](caching-fragment.md)
* [Кешуванная сторінок](caching-page.md) * [Кешування сторінок](caching-page.md)
* [HTTP кешуванная](caching-http.md) * [HTTP кешування](caching-http.md)
Веб-сервіси REST RESTful веб-сервіси
---------------- -------------------
* [Швидкий старт](rest-quick-start.md) * [Швидкий старт](rest-quick-start.md)
* [Ресурси](rest-resources.md) * [Ресурси](rest-resources.md)
...@@ -133,7 +134,7 @@ All Rights Reserved. ...@@ -133,7 +134,7 @@ All Rights Reserved.
* [Роутінг](rest-routing.md) * [Роутінг](rest-routing.md)
* [Форматування відповіді](rest-response-formatting.md) * [Форматування відповіді](rest-response-formatting.md)
* [Аутентифікація](rest-authentication.md) * [Аутентифікація](rest-authentication.md)
* [Обмеження кількості запитів](rest-rate-limiting.md) * [Обмеження частоти запитів](rest-rate-limiting.md)
* [Версіонування](rest-versioning.md) * [Версіонування](rest-versioning.md)
* [Обробка помилок](rest-error-handling.md) * [Обробка помилок](rest-error-handling.md)
...@@ -150,57 +151,49 @@ All Rights Reserved. ...@@ -150,57 +151,49 @@ All Rights Reserved.
---------- ----------
* [Огляд](test-overview.md) * [Огляд](test-overview.md)
* **TBD** [Модульні тести](test-unit.md) * [Налаштування середовища тестування](test-environment-setup.md)
* **TBD** [Функціональні тести](test-functional.md) * [Модульні тести](test-unit.md)
* **TBD** [Приймальні тести](test-acceptance.md) * [Функціональні тести](test-functional.md)
* [Приймальні тести](test-acceptance.md)
* [Фікстури](test-fixtures.md) * [Фікстури](test-fixtures.md)
Розширення Yii
--------------
* [Створення розширень](extend-creating-extensions.md)
* [Розширення коду фреймворку](extend-customizing-core.md)
* [Використання сторонніх бібліотек](extend-using-libs.md)
* **TBD** [Інтеграція Yii в сторонні системи](extend-embedding-in-others.md)
* **TBD** [Одночасне використання Yii 1.1 та 2.0](extend-using-v1-v2.md)
* [Використання Composer](extend-using-composer.md)
Спеціальні теми Спеціальні теми
--------------- ---------------
* [Шаблон додатка advanced](tutorial-advanced-app.md) * [Розширений шаблон додатка](tutorial-advanced-app.md)
* [Створення додатка з нуля](tutorial-start-from-scratch.md) * [Створення додатка з нуля](tutorial-start-from-scratch.md)
* [Консольні команди](tutorial-console.md) * [Консольні команди](tutorial-console.md)
* [Основні валідатори](tutorial-core-validators.md)
* [Інтернаціонализація](tutorial-i18n.md) * [Інтернаціонализація](tutorial-i18n.md)
* [Відправка пошти](tutorial-mailing.md) * [Робота з поштою](tutorial-mailing.md)
* [Вдосконалення продуктивності](tutorial-performance-tuning.md) * [Вдосконалення продуктивності](tutorial-performance-tuning.md)
* **TBD** [Робота на shared хостингу](tutorial-shared-hosting.md) * [Робота на shared хостингу](tutorial-shared-hosting.md)
* [Шаблонізатори](tutorial-template-engines.md) * [Шаблонізатори](tutorial-template-engines.md)
* [Робота із стороннім кодом](tutorial-yii-integration.md)
Віджети Віджети
------- -------
* GridView: link to demo page * GridView: **TBD** link to demo page
* ListView: link to demo page * ListView: **TBD** link to demo page
* DetailView: link to demo page * DetailView: **TBD** link to demo page
* ActiveForm: link to demo page * ActiveForm: **TBD** link to demo page
* Pjax: link to demo page * Pjax: **TBD** link to demo page
* Menu: link to demo page * Menu: **TBD** link to demo page
* LinkPager: link to demo page * LinkPager: **TBD** link to demo page
* LinkSorter: link to demo page * LinkSorter: **TBD** link to demo page
* [Віджети Bootstrap](bootstrap-widgets.md) * [Віджети Bootstrap](widget-bootstrap.md)
* **TBD** [Віджети Jquery UI](jui-widgets.md) * [Віджети Jquery UI](widget-jui.md)
Хелпери Хелпери
------- -------
* [Огляд](helper-overview.md) * [Огляд](helper-overview.md)
* **TBD** [ArrayHelper](helper-array.md) * [ArrayHelper](helper-array.md)
* **TBD** [Html](helper-html.md) * **TBD** [Html](helper-html.md)
* **TBD** [Url](helper-url.md) * [Url](helper-url.md)
* **TBD** [Security](helper-security.md) * **TBD** [Security](helper-security.md)
Кешування фрагментів Кешування фрагментів
================ ====================
Кешування фрагментів відноситься до кешуванню фрагментів сторінки. Наприклад, якщо сторінка відображає в таблиці сумарні річні продажі, ми можемо зберегти цю таблицю в кеші з метою економії часу, необхідного для створення таблиці при кожному запиті. Кешування фрагментів засноване на [кешуванні даних](caching-data.md). Кешування фрагментів відноситься до кешування фрагментів веб-сторінки. Наприклад, якщо сторінка відображає в таблиці сумарні
річні продажі, ви можете зберегти цю таблицю в кеші з метою економії часу, необхідного для створення таблиці при кожному запиті.
Кешування фрагментів засноване на [кешуванні даних](caching-data.md).
Для кешування фрагментів використовуйте наступний код в [виді](structure-views.md): Для кешування фрагментів використовуйте наступний код у [представленні](structure-views.md):
```php ```php
if ($this->beginCache($id)) { if ($this->beginCache($id)) {
// ... тут створюємо вміст ... // ... тут створюємо зміст ...
$this->endCache(); $this->endCache();
} }
``` ```
Таким чином укладіть те, що ви хочете закешовану між викликом [[yii\base\View::beginCache()|beginCache()]] та Таким чином, розташуйте логіку генерації вмісту у комбінацію викликів [[yii\base\View::beginCache()|beginCache()]] та
[[yii\base\View::endCache()|endCache()]]. Якщо вміст буде знайдено в кеші, [[yii\base\View::beginCache()|beginCache()]] [[yii\base\View::endCache()|endCache()]]. Якщо вміст буде знайдено у кеші, [[yii\base\View::beginCache()|beginCache()]]
відобразить закешований вміст і поверне false, минаючи генерацію вмісту. відобразить закешований вміст і поверне false, оминаючи генерацію вмісту.
В іншому випадку, буде виконаний код генерації контента і коли буде викликаний [[yii\base\View::endCache()|endCache()]], то сгенерированное вміст буде записано і збережено в кеші. В іншому випадку, буде виконано логіку генерації вмісту і з викликом [[yii\base\View::endCache()|endCache()]]
згенерований вміст буде записаний до кешу.
Также как и [кэширование данных](caching-data.md), для кэширования фрагментов требуется уникальный идентификатор для определения кэшируемого фрагмента. Подібно до [кешування даних](caching-data.md), для кешування фрагментів необхідний унікальний ідентифікатор
для визначення кешувального фрагмента.
## Параметры кэширования <a name="caching-options"></a> ## Параметри кешування <a name="caching-options"></a>
Вызывая метод [[yii\base\View::beginCache()|beginCache()]], мы можем передать в качестве второго аргумента массив, содержащий параметры кэширования для управления кэшированием фрагмента. Заглядывая за кулисы, можно увидеть, что этот массив будет использоваться для настройки виджета [[yii\widgets\FragmentCache]], который реализует фактическое кэширование фрагментов. Ви можете вказати додаткові параметри про кешуванні фрагментів, передавши масив опцій в якості другого параметра метода
[[yii\base\View::beginCache()|beginCache()]]. За лаштунками, цей масив параметрів буде використано для налаштування віджета
[[yii\widgets\FragmentCache]], який реалізує фактичну функціональність кешування фрагментів.
### Срок хранения <a name="duration"></a>
Наверное, наиболее часто используемым параметром является [[yii\widgets\FragmentCache::duration|duration]]. ### Тривалість <a name="duration"></a>
Он определяет какое количество секунд содержимое будет оставаться действительным (корректным). Следующий код помещает фрагмент в кэш не более, чем на час::
Мабуть найбільш часто використовуваною опцією кешування фрагмента є [[yii\widgets\FragmentCache::duration|duration]].
Вона визначає на скільки секунд зміст може залишатися дійсним у кеші. Код нижче кешує фрагмент не більше, ніж на одну:
```php ```php
if ($this->beginCache($id, ['duration' => 3600])) { if ($this->beginCache($id, ['duration' => 3600])) {
// ... здесь создаём содержимое ... // ... тут створюємо зміст ...
$this->endCache(); $this->endCache();
} }
``` ```
Если мы не установим длительность (срок хранения), она будет равна значению по умолчанию (60 секунд). Это значит, что кэшированное содержимое станет недействительным через 60 секунд. Якщо опцію тривалості не задано, то вона прийме значенне за замовчування (60), що означає, що вміст в кеші стане недійсним через 60 секунд.
### Зависимости <a name="dependencies"></a> ### Залежності <a name="dependencies"></a>
Также как и [кэширование данных](caching-data.md#cache-dependencies), кэшируемое содержимое фрагмента тоже может иметь зависимости. Например, отображение содержимого сообщения зависит от того, изменено или нет это сообщение. Подібно до [кешування даних](caching-data.md#cache-dependencies), фрагмент вмісту у кеші також може мати залежності.
Наприклад, вміст поста, що відображається, залежить від того, чи був він змінений.
Для определения зависимости мы устанавливаем параметр [[yii\widgets\FragmentCache::dependency|dependency]], который может быть либо объектом [[yii\caching\Dependency]], либо массивом настроек, который может быть использован для создания объекта [[yii\caching\Dependency]]. Следующий код определяет содержимое фрагмента, зависящее от изменения значения столбца `updated_at`: Для визначення залежності, встановіть опцію [[yii\widgets\FragmentCache::dependency|dependency]],
яка може бути або обʼєктом [[yii\caching\Dependency]] або масивом налаштувань для створення обʼєкта залежностей.
Наступний код визначає, що вміст фрагмента залежить від зміни значення стовпця `updated_at`:
```php ```php
$dependency = [ $dependency = [
...@@ -57,91 +67,109 @@ $dependency = [ ...@@ -57,91 +67,109 @@ $dependency = [
if ($this->beginCache($id, ['dependency' => $dependency])) { if ($this->beginCache($id, ['dependency' => $dependency])) {
// ... здесь создаём содержимое ... // ... тут створюємо зміст ...
$this->endCache(); $this->endCache();
} }
``` ```
### Вариации <a name="variations"></a> ### Варіації <a name="variations"></a>
Кэшируемое содержимое может быть изменено в соответствии с некоторыми параметрами. Например, для веб-приложений, поддерживающих несколько языков, одна и та же часть кода может создавать содержимое на нескольких языках. Поэтому у вас может возникнуть желание кэшировать содержимое в зависимости от текущего языка приложения. Вміст, що кешується, може бути змінено відповідно до деяких параметрів.
Наприклад, для веб-додатка із підтримкою декількох мов, один і той же шматок представлення коду може генерувати контент на різних мовах.
Таким чином, ви можете змінювати кешований вміст відповідно до поточної мови додатка.
Чтобы задать вариации кэша, установите параметр [[yii\widgets\FragmentCache::variations|variations]], который должен быть массивом, содержащим скалярные значения, каждое из которых представляет определенный коэффициент вариации. Например, Щоб вказати варіації кешу, встановіть опцію [[yii\widgets\FragmentCache::variations|variations]],
чтобы кэшировать содержимое в зависимости от языка приложения, вы можете использовать следующий код: яка повинна бути масивом скалярних значень, кожне з яких представляє певний коефіцієнт варіації.
Наприклад, щоб кешувати вміст у залежності від мови додатка, ви можете використовувати наступний код:
```php ```php
if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) { if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) {
// ... здесь создаём содержимое ... // ... тут створюємо зміст ...
$this->endCache(); $this->endCache();
} }
``` ```
### Переключение кэширования <a name="toggling-caching"></a> ### Перемикання кешування <a name="toggling-caching"></a>
Иногда может потребоваться включать кеширование фрагментов только для определённых условий. Например, страницу с формой мы хотим кэшировать только тогда, когда обращение к ней произошло впервые (посредством GET запроса). Любое последующее отображение формы (посредством POST запроса) не должно быть кэшировано, потому что может содержать данные, введённые пользователем. Для этого мы задаём параметр [[yii\widgets\FragmentCache::enabled|enabled]]: Іноді, ви можете захотіти увімкнути кешування фрагмента тільки за певних умов. Наприклад, для сторінки, яка відображає форму,
ви хочете кешувати тільки форму при її початковому запиті (через GET-запит). Будь-яке подальше відображення (через POST-запит)
форми не повинне кешуватися, тому що форма може містити дані, що ввів користувач.
Щоб зробити це, ви можете встановити опцію [[yii\widgets\FragmentCache::enabled|enabled]] наступним чином:
```php ```php
if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) { if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) {
// ... здесь создаём содержимое ... // ... тут створюємо зміст ...
$this->endCache(); $this->endCache();
} }
``` ```
## Вложенное кэширование <a name="nested-caching"></a> ## Вкладене кешування <a name="nested-caching"></a>
Кэширование фрагментов может быть вложенным. Это значит, что кэшируемый фрагмент окружён более крупным фрагментом (содержится в нём), который также кэшируется. Например, комментарии кэшируются во внутреннем фрагменте кэша, и они же кэшируются вместе с содержимым сообщения во внешнем фрагменте кэша. Следующий код демонстрирует как два фрагмента кэша могут быть вложенными: Кешування фрагментів може бути вкладеним. Тобто, кешований фрагмент може бути укладений в інший фрагмент, що також кешується.
Наприклад, коментарі кешируются у внутрішньому фрагменті кешу, і вони ж кешуються разом із вмістом поста у зовнішньому
фрагменті кеша. Наступний код показує, як два кеша фрагментів можуть бути вкладеними:
```php ```php
if ($this->beginCache($id1)) { if ($this->beginCache($id1)) {
// ...логика создания контента... // ...логіка створення контента...
if ($this->beginCache($id2, $options2)) { if ($this->beginCache($id2, $options2)) {
// ...логика создания контента... // ...логіка створення контента...
$this->endCache(); $this->endCache();
} }
// ...логика создания контента... // ...логіка створення контента...
$this->endCache(); $this->endCache();
} }
``` ```
Параметры кэширования могут быть различными для вложенных кэшей. Например, внутренний и внешний кэши в вышеприведённом примере могут иметь разные сроки хранения. Даже когда данные внешнего кэша уже не являются актуальными, внутренний кеш может содержать актуальный фрагмент. Тем не менее, обратное не верно. Если внешний кэш актуален, данные будут отдаваться из него даже если внутренний кэш содержит устаревшие данные. Следует проявлять осторожность при выставлении срока хранения и задания зависимостей для вложенных кэшей. В противном случае вы можете получить устаревшие данные. Для вкладених кешів можут бути встановлені різні опції кешування. Наприклад, внутрішні кеші і зовнішні кеші можуть використовувати
різні значення тривалості кеша. Навіть коли дані зовнішнього кеша вже є недійсними, внутрішній кеш все ще може містити актуальний фрагмент.
Тим не менш, це не є вірним у зворотньому напрямку. Якщо зовнішній кеш є дійсним, то він буде продовжувати віддавати кешовану копію,
навіть якщо внутрішній кеш є недійсним. Таким чином, ви повинні бути обережні у визначенні тривалості або залежностей вкладених кешей,
в іншому випадку застарілі внутрішні фрагменти можуть зберігатися в зовнішньому фрагменті.
## Динамическое содержимое <a name="dynamic-content"></a> ## Динамічний зміст <a name="dynamic-content"></a>
Когда используется кэширование фрагментов, вы можете столкнуться с ситуацией когда большой фрагмент содержимого статичен за исключением одного или нескольких мест. Например, заголовок страницы может отображаться в главном меню вместе с При використанні кешування фрагментів, ви можете зіткнутися із ситуацією, коли великий фрагмент змісту є відносно статичним,
именем текущего пользователя. Еще одна проблема в том, что содержимое, которое было закэшировано, может содержать PHP код, который должен выполняться для каждого запроса (например код для регистрации в asset bundle). Обе проблемы могут быть решены с помощью, так называемой функции *динамического содержимого*. за винятком одного або декількох місць. Наприклад, заголовок сторінки може відображатися у головному меню разом
з імʼям поточного користувача. Інша проблема в тому, що закешований зміст може містити код PHP, який повинен
виконуватися при кожному запиті (наприклад, код для реєстрації пакету ресурсів). Обидві ці проблеми можуть бути
вирішені за допомогою так званої функції *динамічного змісту*.
Динамическое содержимое значит, что часть вывода не будет закэширована даже если она заключена в кэширование фрагментов. Чтобы сделать содержимое динамическим постоянно, оно должно быть создано, используя специальный PHP код. Динамічний зміст означає фрагмент виведення, який не повинен кешуватися, навіть якщо він укладений у кешування фрагментів.
Для того, щоб зробити зміст динамічним постійно, він повинен бути створений за допомогою деякого PHP коду для кожного запиту,
навіть якщо зміст віддаєтся із кеша.
Вы можете вызвать [[yii\base\View::renderDynamic()]] в пределах кэширования фрагмента для вставки динамического содержимого Ви можете викликати [[yii\base\View::renderDynamic()]] в кеші фрагмента для вставки динамічного контенту у потрібне місце,
в нужное место, как в примере ниже: як у прикладі нижче:
```php ```php
if ($this->beginCache($id1)) { if ($this->beginCache($id1)) {
// ...логика создания контента... // ...логіка створення контента...
echo $this->renderDynamic('return Yii::$app->user->identity->name;'); echo $this->renderDynamic('return Yii::$app->user->identity->name;');
// ...логика создания контента... // ...логіка створення контента...
$this->endCache(); $this->endCache();
} }
``` ```
Метод [[yii\base\View::renderDynamic()|renderDynamic()]] принимает некоторую часть PHP кода как параметр. Метод [[yii\base\View::renderDynamic()|renderDynamic()]] бере деяку частину коду PHP в якості параметра.
Возвращаемое значение этого кода будет вставлено в динамическое содержимое. Этот PHP код будет выполняться для каждого запроса, независимо от того находится ли он внутри кэширования фрагмента или нет. Значення, що повертається від коду PHP, трактується як динамічний зміст. Цей код PHP буде виконуватися при кожному запиті,
незалежно від того, чи віддається фрагмент із кешу або ні.
Псевдоніми Псевдоніми
========= ==========
Псевдоніми використовуються для позначення шляхів до файлів або URL адрес і допомагають уникнути використання абсолютних шляхів Псевдоніми використовуються для позначення шляхів до файлів або URL адрес і допомагають уникнути використання абсолютних шляхів
або URL в коді. Для того, щоб не переплутати псевдонім із звичайним шляхом до файлу або URL, він повинен починатися з `@`. В Yii або URL в коді. Для того, щоб не переплутати псевдонім із звичайним шляхом до файлу або URL, він повинен починатися з `@`. В Yii
є безліч заздалегідь визначених псевдонімів. Наприклад, `@yii` вказує на директорію, в яку був встановлений є багато заздалегідь визначених псевдонімів. Наприклад, `@yii` вказує на директорію, в яку був встановлений
Yii framework, а `@web` можна використовувати для отримання базового URL поточного додатку. Yii framework, а `@web` можна використовувати для отримання базового URL поточного додатку.
Створення псевдонімів <a name="defining-aliases"></a> Створення псевдонімів <a name="defining-aliases"></a>
---------------------------------------------- ---------------------
Для створення псевдоніма шляху до файлу або URL використовується метод [[Yii::setAlias()]]: Для створення псевдоніма шляху до файлу або URL використовується метод [[Yii::setAlias()]]:
...@@ -20,12 +20,14 @@ Yii::setAlias('@foo', '/path/to/foo'); ...@@ -20,12 +20,14 @@ Yii::setAlias('@foo', '/path/to/foo');
Yii::setAlias('@bar', 'http://www.example.com'); Yii::setAlias('@bar', 'http://www.example.com');
``` ```
> Примітка: псевдонім шляху до файлу або URL *не* обов'язково вказує на існуючий файл або ресурс. > Примітка: псевдонім шляху до файлу або URL *не* обовʼязково вказує на існуючий файл або ресурс.
Використовуючи вже заданий псевдонім, ви можете отримати на основі нього новий без виклику [[Yii :: setAlias ​​()]]. Зробити це можна, додавши в його кінець `/`, за яким слід один або більше сегментів шляху. Псевдоніми, визначені за допомогою Використовуючи вже заданий псевдонім, ви можете отримати на основі нього новий (без виклику [[Yii::setAlias()]]),
[[Yii::setAlias()]], є *кореневими псевдонімами*, в той час як отримані з них називаються похідними псевдонімами. На приклад, `@foo` є кореневим псевдонімом, а `@foo/bar/file.php` — похідним. додавши в його кінець `/`, за яким слідує один або більше сегментів шляху. Псевдоніми, визначені за допомогою
[[Yii::setAlias()]], є *кореневими псевдонімами*, в той час як отримані з них називаються *похідними псевдонімами*.
На приклад, `@foo` є кореневим псевдонімом, а `@foo/bar/file.php` — похідним.
Ви можете задати новий псевдонім, використовуючи раніше створений псевдонім (не важливо, кореневої він чи похідний): Ви можете задати новий псевдонім, використовуючи раніше створений псевдонім (не важливо, кореневий він чи похідний):
```php ```php
Yii::setAlias('@foobar', '@foo/bar'); Yii::setAlias('@foobar', '@foo/bar');
...@@ -48,9 +50,10 @@ return [ ...@@ -48,9 +50,10 @@ return [
Перетворення псевдонімів <a name="resolving-aliases"></a> Перетворення псевдонімів <a name="resolving-aliases"></a>
---------------------------------------------------- ------------------------
Метод [[Yii :: getAlias ​​()]] перетворює кореневої псевдонім в шлях до файлу або URL, який цей псевдонім представляє. Цей же метод може працювати і з похідними псевдонімами: Виклик [[Yii::getAlias()]] перетворює кореневий псевдонім в шлях до файлу або URL, який цей псевдонім представляє.
Цей же метод може працювати і з похідними псевдонімами:
```php ```php
echo Yii::getAlias('@foo'); // виведе: /path/to/foo echo Yii::getAlias('@foo'); // виведе: /path/to/foo
...@@ -58,11 +61,13 @@ echo Yii::getAlias('@bar'); // виведе: http://www.example.co ...@@ -58,11 +61,13 @@ echo Yii::getAlias('@bar'); // виведе: http://www.example.co
echo Yii::getAlias('@foo/bar/file.php'); // виведе: /path/to/foo/bar/file.php echo Yii::getAlias('@foo/bar/file.php'); // виведе: /path/to/foo/bar/file.php
``` ```
Шлях або URL, представлений похідним псевдонімом, визначається шляхом заміни в ньому частині, що відповідає кореневого псевдоніму, на відповідний йому шлях або URL. Шлях або URL, представлений похідним псевдонімом, визначається шляхом заміни в ньому частині, що відповідає кореневого псевдоніму,
на відповідний йому шлях або URL.
> Примітка: Метод [[Yii :: getAlias ​​()]] не перевіряє фактичного існування одержуваного шляху або URL. > Примітка: Метод [[Yii::getAlias()]] не перевіряє фактичного існування одержуваного шляху або URL.
Кореневої псевдонім може містити знаки '/'. При цьому метод [[Yii::getAlias()]] коректно визначить, яка частина псевдоніма є кореневої і вірно сформує шлях або URL: Кореневий псевдонім може містити знаки `/`. При цьому метод [[Yii::getAlias()]] коректно визначить, яка частина
псевдоніма є кореневої і вірно сформує шлях або URL:
```php ```php
Yii::setAlias('@foo', '/path/to/foo'); Yii::setAlias('@foo', '/path/to/foo');
...@@ -73,10 +78,13 @@ Yii::getAlias('@foo/bar/file.php'); // виведе: /path2/bar/file.php ...@@ -73,10 +78,13 @@ Yii::getAlias('@foo/bar/file.php'); // виведе: /path2/bar/file.php
Якби `@foo/bar` не був оголошений кореневим псевдонімом, остання строка вивела б `/path/to/foo/bar/file.php`. Якби `@foo/bar` не був оголошений кореневим псевдонімом, остання строка вивела б `/path/to/foo/bar/file.php`.
Використання псевдонімів. <a name="using-aliases"></a>
------------------------------------------------
Псевдоніми розпізнаються в багатьох частинах Yii без необхідності попередньо викликати [[Yii::getAlias()]] для отримання шляху або URL. Наприклад, [[yii\caching\FileCache::cachePath]] приймає як звичайний шлях до файлу, так і псевдонім шляху завдяки префіксу `@`, який дозволяє їх розрізняти. Використання псевдонімів <a name="using-aliases"></a>
------------------------
Псевдоніми розпізнаються в багатьох частинах Yii без необхідності попереднього виклику [[Yii::getAlias()]]
для отримання шляху або URL. Наприклад, [[yii\caching\FileCache::cachePath]] приймає як звичайний шлях до файлу,
так і псевдонім шляху завдяки префіксу `@`, який дозволяє їх розрізняти.
```php ```php
use yii\caching\FileCache; use yii\caching\FileCache;
...@@ -90,28 +98,36 @@ $cache = new FileCache([ ...@@ -90,28 +98,36 @@ $cache = new FileCache([
Заздалегідь визначені псевдоніми <a name="predefined-aliases"></a> Заздалегідь визначені псевдоніми <a name="predefined-aliases"></a>
---------------------------------------------------------- --------------------------------
В Yii заздалегідь визначені псевдоніми для часто використовуваних шляхів до файлів і URL: В Yii заздалегідь визначені псевдоніми для часто використовуваних шляхів до файлів і URL:
- `@yii`: директорія, в якій знаходиться файл `BaseYii.php` (директорія фреймворка). - `@yii`: директорія, в якій знаходиться файл `BaseYii.php` (директорія фреймворка).
- `@app`: [[yii\base\Application::basePath|базовий шлях]] поточного додатку. - `@app`: [[yii\base\Application::basePath|базовий шлях]] поточного додатку.
- `@runtime`: [[yii\base\Application::runtimePath|директорія runtime]] поточного додатку. - `@runtime`: [[yii\base\Application::runtimePath|директорія runtime]] поточного додатку. За замовчуванням `@app/runtime`.
- `@vendor`: [[yii\base\Application::vendorPath|директорія vendor Composer]. - `@webroot`, коренева веб-директорія поточного веб-додатку. Визначається на основі директорії розташування вхідного скрипта.
- `@webroot`: вебрут поточного веб додатка (там де `index.php`). - `@web`, базовий URL поточного додатку. Має таке ж значення, як і [[yii\web\Request::baseUrl]].
- `@web`: базовий URL поточного додатку. - `@vendor`, [[yii\base\Application::vendorPath|директорія vendor Composer]]. За замовчуванням `@app/vendor`.
- `@bower`, директорія, що містить [пакети bower](http://bower.io/). За замовчуванням `@vendor/bower`.
- `@npm`, директорія, що містить [пакети npm](https://www.npmjs.org/). За замовчуванням `@vendor/npm`.
Псевдонім `@yii` задається в момент підключення файлу `Yii.php` у [вхідному скрипті](structure-entry-scripts.md). Псевдонім `@yii` задається в момент підключення файлу `Yii.php` у [вхідному скрипті](structure-entry-scripts.md).
Решта псевдоніми задаються в конструкторі додатки в момент застосування [конфигурації](concept-configurations.md). Решта псевдонімів задаються в конструкторі додатка в момент застосування [конфигурації](concept-configurations.md).
Псевдоніми розширень <a name="extension-aliases"></a> Псевдоніми розширень <a name="extension-aliases"></a>
------------------------------------------------ --------------------
Each alias is named after the root namespace of the extension as declared in its `composer.json` file, and each alias
represents the root directory of the package. For example, if you install the `yiisoft/yii2-jui` extension,
you will automatically have the alias `@yii/jui` defined during the [bootstrapping](runtime-bootstrapping.md) stage, equivalent to:
Для кожного [розширення](structure-extensions.md), встановлюваного через Composer, автоматично задається псевдонім. Для кожного [розширення](structure-extensions.md), що встановлюється через Composer, автоматично задається псевдонім.
Його ім'я відповідає кореневого простору імен розширення відповідно до його `composer.json`. Псевдонім представляє Його імʼя відповідає кореневому простору імен розширення відповідно до його `composer.json`, і кожен псевдонім представляє
шлях до кореневої директорії пакета. Наприклад, якщо ви встановите розширення `yiisoft/yii2-jui`, то вам автоматично стане доступний псевдонім `@yii/jui`. Він створюється на етапі [первинного завантаження (bootstrapping)](runtime-bootstrapping.md) шлях до кореневої директорії пакета. Наприклад, якщо ви встановите розширення `yiisoft/yii2-jui`,
приблизно так: то вам автоматично стане доступним псевдонім `@yii/jui`, який будет створено на етапі
[первинного завантаження (bootstrapping)](runtime-bootstrapping.md) наступним чином:
```php ```php
Yii::setAlias('@yii/jui', 'VendorPath/yiisoft/yii2-jui'); Yii::setAlias('@yii/jui', 'VendorPath/yiisoft/yii2-jui');
......
Автозавантаження класів Автозавантаження класів
================= =======================
Пошук і підключення файлів класів в Yii реалізовано за допомогою Пошук і підключення файлів класів в Yii реалізовано за допомогою
[автозавантаження класів](http://www.php.net/manual/ru/language.oop5.autoload.php). Фреймворк надає свій швидкий сумісний з [PSR-4](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md) [автозавантаження класів](http://www.php.net/manual/ru/language.oop5.autoload.php).
автозавантажувач, який встановлюється в момент підключення `Yii.php`. Фреймворк надає власний швидкісний автозавантажувач, що сумісний з
[PSR-4](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md),
який встановлюється в момент підключення файлу `Yii.php`.
> Примітка: Для простоти опису, в цьому розділі ми будемо говорити тільки про автозавантаження класів.
Тим не менш, все описане також стосується до інтерфейсів і трейтів.
> Примітка: Для простоти оповіді, в цьому розділі ми будемо говорити тільки про автозавантаження класів. Тим не менш, все описане може бути застосовно до інтерфейсів і трейтів.
Як використовувати автозавантажувач Yii <a name="using-yii-autoloader"></a> Використання автозавантажувача Yii <a name="using-yii-autoloader"></a>
-------------------------------------------------------------- ----------------------------------
При використанні автозавантажувача класів Yii слід дотримуватися два простих правила створення і іменування класів: Для використання автозавантажувача класів Yii слід дотримуватися два простих правила створення і іменування класів:
* Кожен клас повинен належати простору імен (тобто `foo\bar\MyClass`). * Кожен клас повинен належати простору імен (тобто `foo\bar\MyClass`)
* Кожен клас повинен знаходитися в окремому файлі, шлях до якого визначаться наступним правилом: * Кожен клас повинен знаходитися в окремому файлі, шлях до якого визначаться наступним правилом:
```php ```php
// $className — це абсолютне ім'я класу, що починається з "\" // $className — це абсолютне імʼя класу, що починається з "\"
$classFile = Yii::getAlias('@' . str_replace('\\', '/', $className) . '.php'); $classFile = Yii::getAlias('@' . str_replace('\\', '/', $className) . '.php');
``` ```
Наприклад, якщо абсолютне ім'я класу `foo\bar\MyClass`, то [псевдонім шляху](concept-aliases.md) даного файлу буде Наприклад, якщо абсолютне імʼя класу `foo\bar\MyClass`, то [псевдонім шляху](concept-aliases.md) даного файлу класу буде
`@foo/bar/MyClass.php`. Для того, щоб даний псевдонім можна було перетворити в шлях до файлу, необхідно щоб або `@foo` або `@foo/bar` був [кореневим псевдонімом](concept-aliases.md#defining-aliases). `@foo/bar/MyClass.php`. Для того, щоб даний псевдонім можна було перетворити в шлях до файлу, необхідно щоб або `@foo`
або `@foo/bar` був [кореневим псевдонімом](concept-aliases.md#defining-aliases).
при використанні [шаблону додатку basic](start-basic.md) ви можете зберігати свої класи в просторі імен `app`. При використанні [базового шаблону додатка](start-installation.md) ви можете зберігати свої класи в просторі імен
В цьому випадку вони будуть завантажуватися автоматично без створення нового псевдоніма. Це працює тому як `@app` верхнього рівня `app`, щоб вони могли бути автоматично завантажені Yii без створення нового псевдоніма.
є [заздалегідь певним псевдонімом](concept-aliases.md#predefined-aliases) і таке ім'я класу як Це працює, тому як `@app` є [заздалегідь визначеним псевдонімом](concept-aliases.md#predefined-aliases) і таке імʼя класу,
`app\components\MyClass` відповідно до описаного вище алготімом перетвориться в шлях як `app\components\MyClass` відповідно до описаного вище алготімом перетвориться в шлях `AppBasePath/components/MyClass.php`.
`директорияПриложения/components/MyClass.php`.
В [шаблоні додатку advanced](tutorial-advanced-app.md) кожен рівень додатку володіє власним кореневим псевдонімом. Наприклад, для frontend кореневим псевдонімом є `@frontend`, а для backend — `@backend`. Це дозволяє У [розширеному шаблоні додатка](tutorial-advanced-app.md) кожен рівень додатку володіє власним кореневим псевдонімом.
розмістити класи frontend в простір імен `frontend`, а класи backend в простір імен `backend`. При цьому класи будуть завантажені автоматично. Наприклад, для frontend кореневим псевдонімом є `@frontend`, а для backend — `@backend`. Це дозволяє розмістити класи
frontend в простір імен `frontend`, а класи backend в простір імен `backend`. При цьому класи будуть завантажені автоматично.
Карта класів <a name="class-map"></a> Мапа класів <a name="class-map"></a>
--------------------------------- -----------
Автозавантажувач Yii підтримує *карту класів*. Ця можливість дозволяє вказати шлях до файлу для кожного імені класу. Автозавантажувач Yii підтримує *мапу класів*. Ця можливість дозволяє вказати шлях до файлу для кожного імені класу.
При завантаженні класу автозавантажувач перевіряє наявність класу в карті. Якщо він там є, відповідний файл буде завантажений При завантаженні класу автозавантажувач перевіряє наявність класу в мапі. Якщо він там є, відповідний файл буде завантажений
безпосередньо без будь-яких додаткових перевірок. Це робить автозагрузку дуже швидкою. Всі класи самого фреймворка безпосередньо без будь-яких додаткових перевірок. Це робить автозагрузку дуже швидкою. Всі класи самого фреймворка
завантажуються саме цим способом. завантажуються саме цим способом.
Ви маєте можливість додати клас в карту `Yii::$classMap` наступним чином: Ви маєте можливість додати клас в мапу `Yii::$classMap` наступним чином:
```php ```php
Yii::$classMap['foo\bar\MyClass'] = 'path/to/MyClass.php'; Yii::$classMap['foo\bar\MyClass'] = 'path/to/MyClass.php';
``` ```
Для вказівки шляхів до файлів класів можна використовувати [псевдоніми](concept-aliases.md). Карту класів необхідно сформувати в процесі [первинного завантаження](runtime-bootstrapping.md) так як вона повинна бути готова до використання класів. Для вказівки шляхів до файлів класів можна використовувати [псевдоніми](concept-aliases.md). Мапу класів необхідно сформувати
в процесі [первинного завантаження](runtime-bootstrapping.md), так як вона повинна бути сформована до використання класів.
Використання інших автозавантажувачів <a name="using-other-autoloaders"></a> Використання інших автозавантажувачів <a name="using-other-autoloaders"></a>
------------------------------------------------------------------ -------------------------------------
Так як Yii використовує Composer в якості менеджера залежностей, рекомендується додатково встановити його автозавантажувач. Оскільки Yii використовує Composer у якості менеджера залежностей, рекомендується додатково встановити його автозавантажувач.
Якщо ви використовуєте які-небудь сторонні бібліотеки, в яких є свої Автозавантажувач, ці Автозавантажувач також необхідно Якщо ви використовуєте які-небудь сторонні бібліотеки із власними автозавантажувачами, то ці автозавантажувачі також необхідно
встановити. встановити.
При використанні додаткових автозавантажувач файл `Yii.php` повинен бути підключений *після* їх установки. це дозволить При використанні додаткових автозавантажувачів, файл `Yii.php` повинен бути підключений *після* їх установки.
автозавантажувачу Yii першим пробувати завантажити клас. Приміром, наведений нижче код взятий з Це дозволить автозавантажувачу Yii першим намагатися завантажити клас. Наприклад, наведений нижче код взятий з
[вхідного скрипта](structure-entry-scripts.md) [шаблону додатку basic](start-basic.md). Перший рядок встановлює автозавантажувач Composer, а друга - автозавантажувач Yii: [вхідного скрипта](structure-entry-scripts.md) [базового шаблону додатка](start-basic.md).
Перший рядок встановлює автозавантажувач Composer, а другий - автозавантажувач Yii:
```php ```php
require(__DIR__ . '/../vendor/autoload.php'); require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php'); require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
``` ```
Ви можете використовувати автозавантажувач Composer без автозавантажувачa Yii. Однак, швидкість автозавантаження в цьому випадку може зменшиться. Також вам буде необхідно слідувати правилам автозавантажувача Composer. Ви можете використовувати автозавантажувач Composer без автозавантажувачa Yii, однак, швидкість автозавантаження в
цьому випадку може зменшиться. До того ж вам буде необхідно слідувати правилам автозавантажувача Composer.
> Інформація: Якщо ви не хочете використовувати автозавантажувач Yii, створіть свою версію файлу `Yii.php` > Інформація: Якщо ви не хочете використовувати автозавантажувач Yii, створіть свою версію файлу `Yii.php`
і підключіть його в [вхідному скрипті](structure-entry-scripts.md). і підключіть його у [вхідному скрипті](structure-entry-scripts.md).
Автозавантаження класів розширень <a name="autoloading-extension-classes"></a> Автозавантаження класів розширень <a name="autoloading-extension-classes"></a>
------------------------------------------------------------------- ---------------------------------
Автозавантажувач Yii може автоматично завантажувати класи [розширень](structure-extensions.md) в тому випадку, якщо дотримується єдине правило. Розширення повинно правильно описати розділ 'autoload' у файлі 'composer.json'. Більш докладно про це можна дізнатися з [офіційній документації Composer](https://getcomposer.org/doc/04-schema.md#autoload). Автозавантажувач Yii може автоматично завантажувати класи [розширень](structure-extensions.md), при умові виконання вимоги
коректного визначення секції `autoload` у файлі `composer.json`. Більш докладно про це можна дізнатися з
[офіційної документації Composer](https://getcomposer.org/doc/04-schema.md#autoload).
Якщо ви не використовуєте автозавантажувач Yii, то класи розширень можуть бути автоматично завантажені з допомогою автозавантажувач Composer. Якщо ви не використовуєте автозавантажувач Yii, то класи розширень можуть бути автоматично завантажені з допомогою автозавантажувач Composer.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.12.2-->
<key for="graphml" id="d0" yfiles.type="resources"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
<key for="port" id="d3" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d4"/>
<key attr.name="description" attr.type="string" for="node" id="d5"/>
<key for="node" id="d6" yfiles.type="nodegraphics"/>
<key attr.name="Description" attr.type="string" for="graph" id="d7"/>
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<data key="d7"/>
<node id="n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="35.0" width="100.0" x="872.1807999999999" y="-14.764159999999947"/>
<y:Fill color="#FFCC99" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" modelName="custom" textColor="#000000" visible="true" width="69.712890625" x="15.1435546875" y="1.3671875">компонент
додатка<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="35.0" width="100.0" x="702.4223999999999" y="-91.97375999999994"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="70.28125" x="14.859375" y="8.43359375">вхідний скрипт<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="35.0" width="100.0" x="702.4223999999999" y="-14.764159999999947"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="68.21875" x="15.890625" y="8.43359375">додаток<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n3">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="35.0" width="100.0" x="702.4223999999999" y="62.44544000000004"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="60.267578125" x="19.8662109375" y="8.433593750000007">контролер<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n4">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="35.0" width="100.0" x="872.1807999999999" y="62.44544000000005"/>
<y:Fill color="#FFCC99" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="31.43359375" x="34.283203125" y="8.43359375">фільтр<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n5">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="35.0" width="100.0" x="532.664" y="23.901600000000087"/>
<y:Fill color="#FF9900" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="47.728515625" x="26.1357421875" y="8.43359375">модуль<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n6">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="35.0" width="100.0" x="618.4047999999991" y="139.65504000000004"/>
<y:Fill color="#99CC00" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="29.611328125" x="35.1943359375" y="8.43359375">представлення<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n7">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="35.0" width="100.0" x="786.161599999999" y="139.65504000000004"/>
<y:Fill color="#99CCFF" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="40.28125" x="29.859375" y="8.43359375">модель<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n8">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="35.0" width="100.0" x="532.664" y="216.86464000000004"/>
<y:Fill color="#99CC00" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="42.923828125" x="28.5380859375" y="8.43359375">віджет<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n9">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="35.0" width="100.0" x="702.4223999999999" y="216.86464000000004"/>
<y:Fill color="#99CC00" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="77.986328125" x="11.0068359375" y="8.43359375">asset bundle<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<edge id="e0" source="n2" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="22.97265625" x="2.5392475585936154" y="-25.635106635436955">1:1<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="14.025600000000054" distanceToCenter="true" position="right" ratio="0.17992697197425173" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n0" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="-48.97602119140629" y="-23.09200633216852">0..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="14.025599999999994" distanceToCenter="true" position="right" ratio="0.5470891790487767" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n5" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="15.193962466822086" y="30.674065521861735">0..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="44.894496863129426" distanceToCenter="true" position="right" ratio="0.25416574623968574" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n3" target="n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="2.7719538085937074" y="-26.04470613037104">1..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="15.254400000000032" distanceToCenter="true" position="right" ratio="0.2090245199765919" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n3" target="n5">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="-57.39355288912964" y="-63.846685518352906">0..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="43.47658308018222" distanceToCenter="true" position="right" ratio="0.881412889692355" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e5" source="n5" target="n5">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
<y:Point x="582.664" y="-3.598399999999913"/>
</y:Path>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="-17.888505566406252" y="-42.41848039245597">0..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="16.483200000000004" distanceToCenter="true" position="right" ratio="5.822600000000001" segment="-2"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e6" source="n6" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="-12.223966589163297" y="-24.76668258085064">0..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="11.385360101663515" distanceToCenter="true" position="left" ratio="0.10670293331985262" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e7" source="n7" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="-9.313146217848043" y="-26.098020948340803">0..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="14.669798038586146" distanceToCenter="true" position="right" ratio="0.1670192242704811" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e8" source="n9" target="n6">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="-9.797233483694527" y="-25.82443358614151">0..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="14.15599378957306" distanceToCenter="true" position="right" ratio="0.15481212573620068" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e9" source="n8" target="n6">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="-15.633139430038" y="-24.050683308790553">0..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="13.24330808446041" distanceToCenter="true" position="left" ratio="0.05506723556297327" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e10" source="n4" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="-47.337621191406356" y="-22.682408449706998">0..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="13.616000000000007" distanceToCenter="true" position="right" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e11" source="n9" target="n8">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="-44.265598339843905" y="-19.61040553222648">0..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="10.543999999999983" distanceToCenter="true" position="right" ratio="0.4117077892835431" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e12" source="n7" target="n6">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="line" width="1.0"/>
<y:Arrows source="none" target="diamond"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="24.96484375" x="-44.81721357421975" y="-19.610410805664003">0..*<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="10.543999999999983" distanceToCenter="true" position="right" ratio="0.4531592446547025" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources/>
</data>
</graphml>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.12.2-->
<key for="graphml" id="d0" yfiles.type="resources"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
<key for="port" id="d3" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d4"/>
<key attr.name="description" attr.type="string" for="node" id="d5"/>
<key for="node" id="d6" yfiles.type="nodegraphics"/>
<key attr.name="Description" attr.type="string" for="graph" id="d7"/>
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<data key="d7"/>
<node id="n0">
<data key="d6">
<y:SVGNode>
<y:Geometry height="70.13700103759766" width="56.558998107910156" x="198.38633947503078" y="261.099458694458"/>
<y:Fill color="#CCCCFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="26.279499053955078" y="74.13700103759766">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="-0.5" nodeRatioX="0.0" nodeRatioY="0.5" offsetX="0.0" offsetY="4.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="27.34375" x="-31.34375" y="25.717914581298828">користувач<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.5" labelRatioY="0.0" nodeRatioX="-0.5" nodeRatioY="0.0" offsetX="-4.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="1"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="119.0" x="789.0653619766235" y="637.1271178722382"/>
<y:Fill color="#99CCFF" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="36.68359375" x="41.158203125" y="13.1494140625">модель<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d6">
<y:SVGNode>
<y:Geometry height="46.887996673583984" width="39.527000427246094" x="828.8018617630005" y="544.9831195354463"/>
<y:Fill color="#CCCCFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="53.376953125" x="-6.924976348876953" y="-30.723247528076172">база даних<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.5" nodeRatioX="0.0" nodeRatioY="-0.5" offsetX="0.0" offsetY="-12.022075653076172" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="17.763500213623047" y="21.443998336791992">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:SVGNodeProperties usingVisualBounds="true"/>
<y:SVGModel svgBoundsPolicy="0">
<y:SVGContent refid="2"/>
</y:SVGModel>
</y:SVGNode>
</data>
</node>
<node id="n3">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="119.0" x="789.0653619766235" y="713.6271178722382"/>
<y:Fill color="#99CC00" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="28.005859375" x="45.4970703125" y="13.1494140625">представлення<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n4" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="377.0372841596604" width="219.27949905395508" x="527.4919853210449" y="407.9266515731811"/>
<y:Fill color="#FFEFD6" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#FF9900" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="219.27949905395508" x="0.0" y="0.0">контролер</y:NodeLabel>
<y:Shape type="rectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="2" leftF="1.7335329055786133" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="313.2978515625" y="412.2765645980835"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" y="0.0">Folder 1</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n4:">
<node id="n4::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="150.55899810791016" x="563.2124862670898" y="445.3031164169311"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="72.70703125" x="38.92598342895508" y="5.6494140625">створення дії<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n4::n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="159.91864204406738" x="558.5326642990112" y="521.8166599273682"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="77.34765625" x="41.28549289703369" y="13.1494140625">накладання
фільтрів<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="diamond"/>
</y:ShapeNode>
</data>
</node>
<node id="n4::n2" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="162.71328270435333" width="187.54596614837646" x="544.2255182266235" y="607.2506530284882"/>
<y:Fill color="#99336635" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#993366" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#FFFFFF" visible="true" width="187.54596614837646" x="0.0" y="0.0">дія</y:NodeLabel>
<y:Shape type="rectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="4" bottomF="3.8368178606033325" left="4" leftF="3.9869680404663086" right="3" rightF="3.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" y="0.0">Folder 3</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n4::n2:">
<node id="n4::n2::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="150.55899810791016" x="563.2124862670898" y="644.6271178722382"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="62.705078125" x="43.92695999145508" y="5.6494140625">завантаження моделі<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n4::n2::n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="150.55899810791016" x="563.2124862670898" y="721.1271178722382"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="66.02734375" x="42.26582717895508" y="5.6494140625">відображення
представлення<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
</graph>
</node>
<node id="n5">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="119.0" x="198.3863394750308" y="713.6271178722382"/>
<y:Fill color="#FFCC99" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="116.072265625" x="1.4638671875000284" y="13.1494140625">компонент
відповіді<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n6">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="119.0" x="789.0653619766235" y="254.50096702575684"/>
<y:Fill color="#FFCC99" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="106.732421875" x="6.1337890625" y="13.1494140625">компонент
запиту<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n7" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="144.132230758667" width="219.27949905395508" x="527.4919853210449" y="222.86873626708984"/>
<y:Fill color="#FFEFD6" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#FF9900" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="219.27949905395508" x="0.0" y="0.0">додаток</y:NodeLabel>
<y:Shape type="rectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="21" leftF="20.720500946044922" right="18" rightF="18.0" top="2" topF="1.7557659149169922"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="0.0" y="60.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" y="0.0">Folder 2</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n7:">
<node id="n7::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="150.55899810791016" x="563.2124862670898" y="262.00096702575684"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="73.369140625" x="38.59492874145508" y="5.6494140625">визначення маршруту<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n7::n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="150.55899810791016" x="563.2124862670898" y="322.00096702575684"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="90.0390625" x="30.259967803955078" y="5.6494140625">створення контролера<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<node id="n8" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="142.37646484375" width="159.91864204406738" x="313.2978515625" y="224.62450218200684"/>
<y:Fill color="#FFCC0024" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" backgroundColor="#FFCC00" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="159.91864204406738" x="0.0" y="0.0">вхідний скрипт</y:NodeLabel>
<y:Shape type="rectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="1" leftF="0.9186420440673828" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="313.2978515625" y="225.33495140075684"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="22.37646484375" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="59.02685546875" x="-4.513427734375" y="0.0">Folder 4</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n8:">
<node id="n8::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="129.0" x="329.2164936065674" y="262.00096702575684"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="85.3984375" x="21.80078125" y="5.6494140625">завантаження
конфігурації<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n8::n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="129.0" x="329.2164936065674" y="322.00096702575684"/>
<y:Fill color="#FFFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.701171875" modelName="custom" textColor="#000000" visible="true" width="82.052734375" x="23.4736328125" y="5.6494140625">запуск додатка<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<edge id="e0" source="n2" target="n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n5" target="n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-31.22050094604495" sy="-22.49430537223816" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="4.0" x="28.00000600945461" y="-193.17557203769684">
<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="right" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="17.34765625" x="-8.673822115545391" y="-200.52615797519684">11<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n6" target="n7::n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="10.673828125" x="-29.525518994973595" y="-10.349628448486328">3<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="0.9990329742431641" distanceToCenter="true" position="right" ratio="0.25395048761528816" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n7::e0" source="n7::n0" target="n7::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n0" target="n8">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="-79.9882439360955" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="10.673828125" x="36.76878085201736" y="-9.523307113000556">1<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n7::n1" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="2.408647025755731" ty="-181.21658369302781"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="10.673828125" x="-4.962140296002758" y="18.61224679946895">4<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="30.0" distanceToCenter="false" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e5" source="n3" target="n4::n2::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="10.673828125" x="-30.100868416252297" y="-9.35060429573059">9<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="10.0" distanceToCenter="false" position="center" ratio="0.26448415477215953" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e6" source="n4::n2::n1" target="n5">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="-2.2737367544323206E-13" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="17.34765625" x="-83.18526519030615" y="-9.350604295730818">10<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.2786124840137136" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e7" source="n8::n1" target="n7">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="55.750299312644984" sy="0.355224609375" tx="-109.63961141576266" ty="42.066115379333496"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="10.673828125" x="29.326010704040527" y="-9.508390885372137">2<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e8" source="n1" target="n4::n2::n0">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="10.673828125" x="-31.270312699786246" y="-10.35060429573059">8<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="1.0" distanceToCenter="true" position="right" ratio="0.2858946861565087" segment="-1"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e9" source="n4::n1" target="n5">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-79.9882439360951" sy="2.2737367544323206E-13" tx="30.048898971244075" ty="-1.4999999999999991">
<y:Point x="287.93523844627487" y="544.3166599273684"/>
</y:Path>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="10.673828125" x="-76.70009317381192" y="-9.350576400756609">6<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="30.0" distanceToCenter="true" position="center" ratio="0.23459266172695797" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n4::e0" source="n4::n0" target="n4::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#FFEFD6" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="10.673828125" x="-5.336933135986328" y="4.999985313415493">5<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.0" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n4::e1" source="n4::n1" target="n4::n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="-81.01828954355172"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" backgroundColor="#FFEFD6" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasLineColor="false" height="18.701171875" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="10.673828125" x="-5.4491733540852465" y="5.039560317993164">7<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="30.0" distanceToCenter="false" position="center" ratio="0.0" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n4::n2::e0" source="n4::n2::n0" target="n4::n2::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n8::e0" source="n8::n0" target="n8::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#666666" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources>
<y:Resource id="1">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="57px" height="66px" viewBox="0 0 57 66" enable-background="new 0 0 57 66" xml:space="preserve"&gt;
&lt;g&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="26.3799" y1="-2276.8809" x2="27.6209" y2="-2306.6792" gradientTransform="matrix(1 0 0 -1 0.2803 -2252.9199)"&gt;
&lt;stop offset="0.2711" style="stop-color:#FFAB4F"/&gt;
&lt;stop offset="1" style="stop-color:#FFD28F"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M49.529,51.225c-4.396-4.396-10.951-5.884-12.063-6.109
V37.8H19.278c0,0,0.038,6.903,0,6.868c0,0-6.874,0.997-12.308,6.432C1.378,56.691,0.5,62.77,0.5,62.77
c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;path id="body_13_" fill="#ECECEC" stroke="#9B9B9B" stroke-miterlimit="10" d="M0.5,62.768c0,1.938,1.575,3.494,3.523,3.494h48.51
c1.947,0,3.521-1.559,3.521-3.494c0,0-1.844-6.861-6.525-11.543c-4.815-4.813-11.244-6.146-11.244-6.146
c-1.771,1.655-5.61,3.802-10.063,3.802c-4.453,0-8.292-2.146-10.063-3.802c0,0-5.755,0.586-11.189,6.021
C1.378,56.689,0.5,62.768,0.5,62.768z"/&gt;
&lt;path fill="#2068A3" stroke="#2068A3" d="M28.106,33.487c-8.112,0-12.688,4.312-12.688,10.437c0,7.422,12.688,10.438,12.688,10.438
s14.688-3.016,14.688-10.438C42.793,38.75,36.215,33.487,28.106,33.487z M26.288,53.051c0,0-7.135-2.093-8.805-7.201
c-0.222-0.682,0.147-1.156,0.795-1.521V37.8h20.188v6.663c0.235,0.352,1.109,0.737,1.229,1.387
C40.445,49.917,26.288,53.051,26.288,53.051z"/&gt;
&lt;radialGradient id="SVGID_2_" cx="14.2417" cy="9.1006" r="53.247" gradientTransform="matrix(1 0 0 -1 0.04 65.1543)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#74AEEE"/&gt;
&lt;stop offset="1" style="stop-color:#2068A3"/&gt;
&lt;/radialGradient&gt;
&lt;path fill="url(#SVGID_2_)" stroke="#2068A3" stroke-miterlimit="10" d="M49.529,51.225c-2.239-2.24-5.041-3.724-7.396-4.67
c-2.854,5.51-14.022,7.807-14.022,7.807s-10.472-2.484-12.387-8.514c-2.439,0.771-5.787,2.287-8.749,5.25
c-5.592,5.592-6.47,11.67-6.47,11.67c0,1.938,1.575,3.492,3.523,3.492h48.51c1.947,0,3.521-1.558,3.521-3.492
C56.055,62.768,54.211,55.906,49.529,51.225z"/&gt;
&lt;path fill="#5491CF" stroke="#2068A3" d="M13.404,44.173c1.15-1.81,2.039-3.832,3.332-5.397c-0.514,1.027-1.669,4.084-1.669,5.148
c0,5.186,10.366,9.079,14.688,10.438c-3.472,1.627-9.134-1.498-11.335-2.36c-3.601-1.419-4.071-3.063-5.89-4.854
C12.523,47.135,12.878,45,13.404,44.173z"/&gt;
&lt;path fill="#5491CF" stroke="#2068A3" d="M45.777,43.924c-1.317-1.568-5.11-9.424-6.604-6.617c0.516,1.025,3.617,3.693,3.617,6.617
c0,5.186-10.27,8.576-16.698,9.145c1.429,4.938,11.372,1.293,13.804-0.313c3.563-2.354,4.563-5.133,7.854-3.705
C47.754,49.045,48.006,46.574,45.777,43.924z"/&gt;
&lt;path fill="none" stroke="#2068A3" stroke-linecap="round" d="M30.777,54.167c0.357,0.836-0.153,1.983-0.352,2.813
c-0.256,1.084-0.072,2.104,0.102,3.186c0.164,1.02,0.156,2.107,0.25,3.167c0.082,0.916,0.482,1.849,0.357,2.75"/&gt;
&lt;path fill="none" stroke="#2068A3" stroke-linecap="round" d="M23.695,53.417c-0.508,0.584-0.476,2.209-0.398,3
c0.116,1.183,0.456,2.099,0.333,3.333c-0.192,1.943,0.154,4.479-0.436,6.333"/&gt;
&lt;radialGradient id="face_x5F_white_1_" cx="27.623" cy="-2278.646" r="23.425" fx="23.0534" fy="-2281.1357" gradientTransform="matrix(1 0 0 -1 0.2803 -2252.9199)" gradientUnits="userSpaceOnUse"&gt;
&lt;stop offset="0" style="stop-color:#FFD28F"/&gt;
&lt;stop offset="1" style="stop-color:#FFAB4F"/&gt;
&lt;/radialGradient&gt;
&lt;path id="face_x5F_white_3_" fill="url(#face_x5F_white_1_)" stroke="#ED9135" stroke-miterlimit="10" d="M43.676,23.357
c0.086,10.2-6.738,18.52-15.25,18.586c-8.5,0.068-15.464-8.146-15.55-18.344C12.794,13.4,19.618,5.079,28.123,5.012
C36.627,4.945,43.59,13.158,43.676,23.357z"/&gt;
&lt;linearGradient id="face_highlight_1_" gradientUnits="userSpaceOnUse" x1="5761.7578" y1="11330.6484" x2="5785.3872" y2="11424.0977" gradientTransform="matrix(0.275 0 0 0.2733 -1558.9874 -3088.4209)"&gt;
&lt;stop offset="0" style="stop-color:#FFFFFF;stop-opacity:0.24"/&gt;
&lt;stop offset="1" style="stop-color:#FFFFFF;stop-opacity:0.16"/&gt;
&lt;/linearGradient&gt;
&lt;path id="face_highlight_3_" fill="url(#face_highlight_1_)" d="M27.958,6.333c-6.035,0.047-10.747,4.493-12.787,10.386
c-0.664,1.919-0.294,4.043,0.98,5.629c2.73,3.398,5.729,6.283,9.461,8.088c3.137,1.518,7.535,2.385,11.893,1.247
c2.274-0.592,3.988-2.459,4.375-4.766c0.187-1.094,0.293-2.289,0.283-3.553C42.083,13.952,36.271,6.268,27.958,6.333z"/&gt;
&lt;path id="Hair_Young_Brown_1_" fill="#CC9869" stroke="#99724F" stroke-linecap="round" stroke-linejoin="round" d="M20.278,13.25
c3.417,4.333,9.333,6.917,9.333,6.917l-1.417-3.5c0,0,7.094,4.691,8.083,4.333c0.968-0.2-1.082-3.807-1.082-3.807
s3.138,1.795,4.854,3.969c1.803,2.28,4.285,3.504,4.285,3.504S47.027,2.719,27.289,2.744C8.278,2.709,12.058,27.678,12.058,27.678
L14.695,17c0,0,0.914,5.757,1.399,4.875C17.861,15.211,18.861,11.5,20.278,13.25z"/&gt;
&lt;path fill="#4B4B4B" stroke="#4B4B4B" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M28.105,2
C22.464,2,20.2,4.246,18.13,5.533C29.753,2.865,41.152,10.375,44.46,20.5C44.459,16.875,44.459,2,28.105,2z"/&gt;
&lt;path fill="#9B9B9B" stroke="#4B4B4B" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M11.151,17.751
C12.878,8.25,18.686,6.309,25.273,7.127C31.295,7.875,36.93,10.491,44.459,20.5C37.777,7.125,20.278-3.375,9.903,3.921
C5.569,6.97,4.903,13.375,11.151,17.751z"/&gt;
&lt;/g&gt;
&lt;/svg&gt;
</y:Resource>
<y:Resource id="2">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;svg version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" width="41px" height="48px" viewBox="-0.875 -0.887 41 48" enable-background="new -0.875 -0.887 41 48"
xml:space="preserve"&gt;
&lt;defs&gt;
&lt;/defs&gt;
&lt;linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-979.1445" x2="682.0508" y2="-979.1445" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"&gt;
&lt;stop offset="0" style="stop-color:#3C89C9"/&gt;
&lt;stop offset="0.1482" style="stop-color:#60A6DD"/&gt;
&lt;stop offset="0.3113" style="stop-color:#81C1F0"/&gt;
&lt;stop offset="0.4476" style="stop-color:#95D1FB"/&gt;
&lt;stop offset="0.5394" style="stop-color:#9CD7FF"/&gt;
&lt;stop offset="0.636" style="stop-color:#98D4FD"/&gt;
&lt;stop offset="0.7293" style="stop-color:#8DCAF6"/&gt;
&lt;stop offset="0.8214" style="stop-color:#79BBEB"/&gt;
&lt;stop offset="0.912" style="stop-color:#5EA5DC"/&gt;
&lt;stop offset="1" style="stop-color:#3C89C9"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_1_)" d="M19.625,36.763C8.787,36.763,0,34.888,0,32.575v10c0,2.313,8.787,4.188,19.625,4.188
c10.839,0,19.625-1.875,19.625-4.188v-10C39.25,34.888,30.464,36.763,19.625,36.763z"/&gt;
&lt;linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-973.1445" x2="682.0508" y2="-973.1445" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"&gt;
&lt;stop offset="0" style="stop-color:#9CD7FF"/&gt;
&lt;stop offset="0.0039" style="stop-color:#9DD7FF"/&gt;
&lt;stop offset="0.2273" style="stop-color:#BDE5FF"/&gt;
&lt;stop offset="0.4138" style="stop-color:#D1EEFF"/&gt;
&lt;stop offset="0.5394" style="stop-color:#D9F1FF"/&gt;
&lt;stop offset="0.6155" style="stop-color:#D5EFFE"/&gt;
&lt;stop offset="0.6891" style="stop-color:#C9E7FA"/&gt;
&lt;stop offset="0.7617" style="stop-color:#B6DAF3"/&gt;
&lt;stop offset="0.8337" style="stop-color:#9AC8EA"/&gt;
&lt;stop offset="0.9052" style="stop-color:#77B0DD"/&gt;
&lt;stop offset="0.9754" style="stop-color:#4D94CF"/&gt;
&lt;stop offset="1" style="stop-color:#3C89C9"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_2_)" d="M19.625,36.763c10.839,0,19.625-1.875,19.625-4.188l-1.229-2c0,2.168-8.235,3.927-18.396,3.927
c-9.481,0-17.396-1.959-18.396-3.927l-1.229,2C0,34.888,8.787,36.763,19.625,36.763z"/&gt;
&lt;path fill="#3C89C9" d="M19.625,26.468c10.16,0,19.625,2.775,19.625,2.775c-0.375,2.721-5.367,5.438-19.554,5.438
c-12.125,0-18.467-2.484-19.541-4.918C-0.127,29.125,9.465,26.468,19.625,26.468z"/&gt;
&lt;linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-965.6948" x2="682.0508" y2="-965.6948" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"&gt;
&lt;stop offset="0" style="stop-color:#3C89C9"/&gt;
&lt;stop offset="0.1482" style="stop-color:#60A6DD"/&gt;
&lt;stop offset="0.3113" style="stop-color:#81C1F0"/&gt;
&lt;stop offset="0.4476" style="stop-color:#95D1FB"/&gt;
&lt;stop offset="0.5394" style="stop-color:#9CD7FF"/&gt;
&lt;stop offset="0.636" style="stop-color:#98D4FD"/&gt;
&lt;stop offset="0.7293" style="stop-color:#8DCAF6"/&gt;
&lt;stop offset="0.8214" style="stop-color:#79BBEB"/&gt;
&lt;stop offset="0.912" style="stop-color:#5EA5DC"/&gt;
&lt;stop offset="1" style="stop-color:#3C89C9"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_3_)" d="M19.625,23.313C8.787,23.313,0,21.438,0,19.125v10c0,2.313,8.787,4.188,19.625,4.188
c10.839,0,19.625-1.875,19.625-4.188v-10C39.25,21.438,30.464,23.313,19.625,23.313z"/&gt;
&lt;linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-959.6948" x2="682.0508" y2="-959.6948" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"&gt;
&lt;stop offset="0" style="stop-color:#9CD7FF"/&gt;
&lt;stop offset="0.0039" style="stop-color:#9DD7FF"/&gt;
&lt;stop offset="0.2273" style="stop-color:#BDE5FF"/&gt;
&lt;stop offset="0.4138" style="stop-color:#D1EEFF"/&gt;
&lt;stop offset="0.5394" style="stop-color:#D9F1FF"/&gt;
&lt;stop offset="0.6155" style="stop-color:#D5EFFE"/&gt;
&lt;stop offset="0.6891" style="stop-color:#C9E7FA"/&gt;
&lt;stop offset="0.7617" style="stop-color:#B6DAF3"/&gt;
&lt;stop offset="0.8337" style="stop-color:#9AC8EA"/&gt;
&lt;stop offset="0.9052" style="stop-color:#77B0DD"/&gt;
&lt;stop offset="0.9754" style="stop-color:#4D94CF"/&gt;
&lt;stop offset="1" style="stop-color:#3C89C9"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_4_)" d="M19.625,23.313c10.839,0,19.625-1.875,19.625-4.188l-1.229-2c0,2.168-8.235,3.926-18.396,3.926
c-9.481,0-17.396-1.959-18.396-3.926l-1.229,2C0,21.438,8.787,23.313,19.625,23.313z"/&gt;
&lt;path fill="#3C89C9" d="M19.476,13.019c10.161,0,19.625,2.775,19.625,2.775c-0.375,2.721-5.367,5.438-19.555,5.438
c-12.125,0-18.467-2.485-19.541-4.918C-0.277,15.674,9.316,13.019,19.476,13.019z"/&gt;
&lt;linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-952.4946" x2="682.0508" y2="-952.4946" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"&gt;
&lt;stop offset="0" style="stop-color:#3C89C9"/&gt;
&lt;stop offset="0.1482" style="stop-color:#60A6DD"/&gt;
&lt;stop offset="0.3113" style="stop-color:#81C1F0"/&gt;
&lt;stop offset="0.4476" style="stop-color:#95D1FB"/&gt;
&lt;stop offset="0.5394" style="stop-color:#9CD7FF"/&gt;
&lt;stop offset="0.636" style="stop-color:#98D4FD"/&gt;
&lt;stop offset="0.7293" style="stop-color:#8DCAF6"/&gt;
&lt;stop offset="0.8214" style="stop-color:#79BBEB"/&gt;
&lt;stop offset="0.912" style="stop-color:#5EA5DC"/&gt;
&lt;stop offset="1" style="stop-color:#3C89C9"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_5_)" d="M19.625,10.113C8.787,10.113,0,8.238,0,5.925v10c0,2.313,8.787,4.188,19.625,4.188
c10.839,0,19.625-1.875,19.625-4.188v-10C39.25,8.238,30.464,10.113,19.625,10.113z"/&gt;
&lt;linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="642.8008" y1="-946.4946" x2="682.0508" y2="-946.4946" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"&gt;
&lt;stop offset="0" style="stop-color:#9CD7FF"/&gt;
&lt;stop offset="0.0039" style="stop-color:#9DD7FF"/&gt;
&lt;stop offset="0.2273" style="stop-color:#BDE5FF"/&gt;
&lt;stop offset="0.4138" style="stop-color:#D1EEFF"/&gt;
&lt;stop offset="0.5394" style="stop-color:#D9F1FF"/&gt;
&lt;stop offset="0.6155" style="stop-color:#D5EFFE"/&gt;
&lt;stop offset="0.6891" style="stop-color:#C9E7FA"/&gt;
&lt;stop offset="0.7617" style="stop-color:#B6DAF3"/&gt;
&lt;stop offset="0.8337" style="stop-color:#9AC8EA"/&gt;
&lt;stop offset="0.9052" style="stop-color:#77B0DD"/&gt;
&lt;stop offset="0.9754" style="stop-color:#4D94CF"/&gt;
&lt;stop offset="1" style="stop-color:#3C89C9"/&gt;
&lt;/linearGradient&gt;
&lt;path fill="url(#SVGID_6_)" d="M19.625,10.113c10.839,0,19.625-1.875,19.625-4.188l-1.229-2c0,2.168-8.235,3.926-18.396,3.926
c-9.481,0-17.396-1.959-18.396-3.926L0,5.925C0,8.238,8.787,10.113,19.625,10.113z"/&gt;
&lt;linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="644.0293" y1="-943.4014" x2="680.8223" y2="-943.4014" gradientTransform="matrix(1 0 0 -1 -642.8008 -939.4756)"&gt;
&lt;stop offset="0" style="stop-color:#9CD7FF"/&gt;
&lt;stop offset="1" style="stop-color:#3C89C9"/&gt;
&lt;/linearGradient&gt;
&lt;ellipse fill="url(#SVGID_7_)" cx="19.625" cy="3.926" rx="18.396" ry="3.926"/&gt;
&lt;path opacity="0.24" fill="#FFFFFF" enable-background="new " d="M31.04,45.982c0,0-4.354,0.664-7.29,0.781
c-3.125,0.125-8.952,0-8.952,0l-2.384-10.292l0.044-2.108l-1.251-1.154L9.789,23.024l-0.082-0.119L9.5,20.529l-1.65-1.254
L5.329,8.793c0,0,4.213,0.903,7.234,1.07s8.375,0.25,8.375,0.25l3,9.875l-0.25,1.313l1.063,2.168l2.312,9.645l-0.521,1.416
l1.46,1.834L31.04,45.982z"/&gt;
&lt;/svg&gt;
</y:Resource>
</y:Resources>
</data>
</graphml>
Робота з базами даних Робота з базами даних
====================== =====================
Цей розділ описує, як створити нову сторінку, яка буде відображати назву країни, отриману з таблиці бази даних `country`. Для досягнення цієї мети, вам необхідно буде налаштувати з'єднання з базою даних, отримати необхідні дані з допомогою класу [Active Record](db-active-record.md), створити [подію](structure-controllers.md), Цей розділ описує, як створити нову сторінку, яка буде відображати дані країни, отримані з таблиці бази даних `country`.
і зобразити все в [представленні](structure-views.md). Для цього, вам необхідно буде налаштувати зʼєднання з базою даних, створити клас [Active Record](db-active-record.md),
визначити [дію](structure-controllers.md) та створити [представлення](structure-views.md).
З допомогою даного посібника ви дізнаєтесь як: За допомогою даного посібника ви дізнаєтесь як:
* Налаштувати зєднання з базою даних * Налаштувати зʼєднання з базою даних
* Оголосити Active Record класс * Оголосити Active Record класс
* Створювати запити використовуючи Active Record клас * Запитувати дані за допомогою класу Active Record
* Відображати дані в представленні з нумерацією сторінок * Відображати дані у представленні із розбиттям по сторінках
Зверніть увагу, що для того, щоб закінчити цей розділ, ви повинні мати базові знання і досвід використання баз даних. Зокрема, ви повинні знати, як створювати бази даних, як виконувати SQL-запити , використовуючи клієнти баз даних. Зверніть увагу, що для того, щоб закінчити цей розділ, ви повинні мати базові знання і досвід використання баз даних.
Зокрема, ви повинні знати, як створювати бази даних, як виконувати SQL-запити за допомогою клієнтських додатків баз даних.
Підготовка бази даних <a name="preparing-database"></a> Підготовка бази даних <a name="preparing-database"></a>
-------------------- ---------------------
Для початку створіть базу даних `yii2basic`, з якої і будете надалі отримувати дані. Ви можете використовувати SQLite, MySQL, PostgreSQL, MSSQL або Oracle бази даних, Yii має вбудовану підтримку для багатьох баз даних. Для початку, створіть базу даних `yii2basic`, з якої і будете надалі отримувати дані.
Ви можете використовувати SQLite, MySQL, PostgreSQL, MSSQL або Oracle бази даних, Yii має вбудовану підтримку для багатьох баз даних.
Для простоти, будемо вважати що використовується MySQL у подальшому описі.
Далі, створіть таблицю `country`, і внесіть декілька прикладів. Можете використати наступний SQL-запит, як приклад: Далі, створіть таблицю `country`, і внесіть декілька прикладів. Можете використати наступний SQL-запит, як приклад:
...@@ -43,11 +47,13 @@ INSERT INTO `country` VALUES ('US','United States',278357000); ...@@ -43,11 +47,13 @@ INSERT INTO `country` VALUES ('US','United States',278357000);
На даний момент, у вас є база даних `yii2basic` і таблиця `country` з трьома колонками, що містять десять рядків даних. На даний момент, у вас є база даних `yii2basic` і таблиця `country` з трьома колонками, що містять десять рядків даних.
Налаштування підключення до БД <a name="configuring-db-connection"></a> Налаштування підключення до БД <a name="configuring-db-connection"></a>
--------------------------- ------------------------------
Перш ніж продовжити, переконайтеся, що у вас налаштовано [PDO](http://www.php.net/manual/en/book.pdo.php) PHP розширення і PDO драйвер для вашої БД (наприклад `pdo_mysql` для MySQL). Це є основною вимогою якщо ваш додаток використовує реляційну базу даних. Перш ніж продовжити, переконайтеся, що у вас налаштовано [PDO](http://www.php.net/manual/en/book.pdo.php) PHP розширення
і PDO драйвер для вашої БД (наприклад `pdo_mysql` для MySQL). Це є основною вимогою, якщо ваш додаток використовує реляційну базу даних.
Згідно того, що у вас встановлено, відкрийте файл `config/db.php` і замініть на коректні дані вашої БД. За замовчуванням, файл містить наступне: Згідно того, що у вас встановлено, відкрийте файл `config/db.php` і замініть на коректні дані вашої БД.
За замовчуванням, файл містить наступне:
```php ```php
<?php <?php
...@@ -61,18 +67,22 @@ return [ ...@@ -61,18 +67,22 @@ return [
]; ];
``` ```
Файл конфігурації `config/db.php` є типовим інструментом на основі файлів [налаштування](concept-configurations.md). Даний файл конфігурації визначає параметри, які необхідні для створення і ініціалізації [[yii\db\Connection]] примірника, через який ви можете робити SQL-запити до основної бази даних. Файл конфігурації `config/db.php` є типовим інструментом [налаштування](concept-configurations.md) на основі файлів.
Даний файл конфігурації визначає параметри, які необхідні для створення і ініціалізації [[yii\db\Connection]] примірника,
через який ви можете робити SQL-запити до основної бази даних.
З’єднання з БД описане вище може бути доступне в коді програми за допомогою виразу `Yii::$app->db`. З’єднання з БД, описане вище, може бути доступне в коді додатка за допомогою виразу `Yii::$app->db`.
> Інформація: Файл конфігурації `config/db.php` буде включений до конфігурації головного додатка `config/web.php`, який визначає як має бути проініційований сам [додаток](structure-applications.md). > Інформація: Файл конфігурації `config/db.php` буде включений до конфігурації головного додатка `config/web.php`,
Для отримання додаткової інформації, будь ласка, зверніться до розділу [Налаштування](concept-configurations.md). який визначає як має бути проініційований сам [додаток](structure-applications.md). Для отримання додаткової інформації,
будь ласка, зверніться до розділу [Налаштування](concept-configurations.md).
Створення Active Record <a name="creating-active-record"></a> Створення Active Record <a name="creating-active-record"></a>
------------------------- -----------------------
Для відображення і отримання даних з таблиці `country` створіть [Active Record](db-active-record.md) клас з іменем `Country`, і збережіть в файл `models/Country.php`. Для відображення і отримання даних з таблиці `country` створіть [Active Record](db-active-record.md) клас
з іменем `Country`, і збережіть в файл `models/Country.php`.
```php ```php
<?php <?php
...@@ -86,17 +96,18 @@ class Country extends ActiveRecord ...@@ -86,17 +96,18 @@ class Country extends ActiveRecord
} }
``` ```
Клас `Country` наслідує [[yii\db\ActiveRecord]]. Вам не потрібно писати ніякого коду всередині нього! Всього лише за допомогою описаного вище коду, Клас `Country` наслідує [[yii\db\ActiveRecord]]. Вам не потрібно писати ніякого коду всередині нього!
Yii отримає відповідне ім'я таблиці з імені класу. Всього лише за допомогою описаного вище коду, Yii самостійно вгадає відповідне імʼя таблиці з імені класу.
> Інформація: Якщо немає прямого співпадіння з імені класу і таблиці, ви можете використати метод [[yii\db\ActiveRecord::tableName()]] щоб задати відповідне ім'я таблиці. > Інформація: Якщо немає прямого співпадіння з імені класу і таблиці,
ви можете використати метод [[yii\db\ActiveRecord::tableName()]] щоб задати відповідне імʼя таблиці.
Використовуючи клас `Country`, ви можете легко маніпулювати даними з таблиці `country`, як показано в наступному фрагменті: Використовуючи клас `Country`, ви можете легко маніпулювати даними з таблиці `country`, як показано в наступному фрагменті:
```php ```php
use app\models\Country; use app\models\Country;
// отримати всі рядки з таблиці country і замовити їх по "name" // отримати всі рядки з таблиці country і відсортувати їх по "name"
$countries = Country::find()->orderBy('name')->all(); $countries = Country::find()->orderBy('name')->all();
// отримати рядок, по основному ключу "US" // отримати рядок, по основному ключу "US"
...@@ -110,13 +121,17 @@ $country->name = 'U.S.A.'; ...@@ -110,13 +121,17 @@ $country->name = 'U.S.A.';
$country->save(); $country->save();
``` ```
> Інформація: Active Record є потужним засобом для доступу і управління даними в базі даних в об'єктно-орієнтованому стилі. Ви можете знайти більш детальну інформацію в розділі [Active Record](db-active-record.md). Крім того, ви також можете взаємодіяти з базою даних, використовуючи для доступу метод передачі даних нижнього рівня під назвою [Data Access Objects](db-dao.md). > Інформація: Active Record є потужним засобом для доступу і управління даними в базі даних в обʼєктно-орієнтованому стилі.
Ви можете знайти більш детальну інформацію в розділі [Active Record](db-active-record.md). Крім того, ви також можете
взаємодіяти з базою даних, використовуючи для доступу метод передачі даних нижнього рівня під назвою [Data Access Objects](db-dao.md).
Створення події <a name="creating-action"></a> Створення дії <a name="creating-action"></a>
------------------ -------------
Щоб відобразити дані про країну кінцевим користувачам, необхідно створити нову подію. Замість розміщення нової події в контролері `site`, який ви використовували в попередніх розділах, є сенс створити новий контролер спеціально для всіх подій пов’язаних з даними таблиці країн. Створіть навий контролер з іменем `CountryController` і подію `index`, як показано нижще. Щоб відобразити дані про країну кінцевим користувачам, необхідно створити нову дію. Замість розміщення нової дії
у контролері `site`, який ви використовували в попередніх розділах, є сенс створити новий контролер спеціально для всіх дій,
пов’язаних з даними країн. Створіть новий контролер з іменем `CountryController` і дію `index`, як показано нижче:
```php ```php
<?php <?php
...@@ -153,21 +168,23 @@ class CountryController extends Controller ...@@ -153,21 +168,23 @@ class CountryController extends Controller
Збережіть цей код у файл `controllers/CountryController.php`. Збережіть цей код у файл `controllers/CountryController.php`.
Подія `index` викликає метод `Country::find()`. Цей Active Record метод будує запит і отримує всі дані з таблиці `country`. Дія `index` викликає метод `Country::find()`. Цей метод Active Record будує запит бази даних і отримує всі дані з таблиці `country`.
Щоб обмежити кількість країн, які будуть отримуватись в кожному запиті, сам запит розбивається на сторінки, за допомогою Щоб обмежити кількість країн, які будуть отримуватись в кожному запиті, сам запит розбивається на сторінки, за допомогою об’єкта
[[yii\data\Pagination]] об'єкта. Об’єкт `Pagination` служить двом цілям: [[yii\data\Pagination]]. Об’єкт `Pagination` служить двом цілям:
* Встановлює `положення` і `ліміт` для SQL-запиту так, щоб він повертав лише одну сторінку даних за один раз (не більше 5 рядків в сторінці). * Встановлює `offset` і `limit` для SQL-запиту так, щоб він повертав лише одну сторінку даних за один раз
* Використовується в цілях відображення пейджера, що складається зі списку кнопок сторінок, як буде описано в наступному підрозділі. (не більше 5 рядків на сторінці).
* Використовується у представленнях для відображення пейджера, який складається із переліку кнопок переходу по сторінкам,
про що буде описано у наступному підрозділі.
Наприкінці, подія `index` повертає представлення `index` і передає дані по країнах, з розбивкою на сторінки. Наприкінці, дія `index` повертає представлення `index` і передає дані по країнах, з розбивкою на сторінки.
Створення представлення <a name="creating-view"></a> Створення представлення <a name="creating-view"></a>
--------------- -----------------------
В директорії `views` створіть спочатку підкаталог `country`. Цей каталог буде використовуватись для всіх представленнь контролера `country`. В каталозі `views/country`, створіть файл з іменем`index.php` В директорії `views` створіть спочатку підкаталог `country`. Цей каталог буде використовуватись для всіх представленнь
що містить наступне: контролера `country`. В каталозі `views/country`, створіть файл з іменем`index.php` що містить наступне:
```php ```php
<?php <?php
...@@ -187,12 +204,14 @@ use yii\widgets\LinkPager; ...@@ -187,12 +204,14 @@ use yii\widgets\LinkPager;
<?= LinkPager::widget(['pagination' => $pagination]) ?> <?= LinkPager::widget(['pagination' => $pagination]) ?>
``` ```
Дане представлення містить два розділи для відображення даних по країнам. У першій частині, відображаються дані про країни у вигляді невпорядкованого списку HTML. У другій частині, [[yii\widgets\LinkPager]] віджет з використанням інформації про нумерацію сторінок. Дане представлення містить два розділи для відображення даних по країнам. У першій частині, відображаються дані про країни
`LinkPager` віджет показується у вигляді списку кнопок. При натисканні на будь-якій з них будуть оновлюватись дані країн у відповідній сторінці. у вигляді невпорядкованого списку HTML. У другій частині, [[yii\widgets\LinkPager]] віджет з використанням інформації
про нумерацію сторінок. Віджет `LinkPager` відображаться у вигляді переліку кнопок.
При натисканні на будь-якій з них будуть оновлюватись дані країн на відповідній сторінці.
Спробуєм <a name="trying-it-out"></a> Спробуєм <a name="trying-it-out"></a>
------------- --------
Щоб побачити все, що було створено під час роботи, відкрийте в браузері наступний URL: Щоб побачити все, що було створено під час роботи, відкрийте в браузері наступний URL:
...@@ -200,28 +219,35 @@ use yii\widgets\LinkPager; ...@@ -200,28 +219,35 @@ use yii\widgets\LinkPager;
http://hostname/index.php?r=country/index http://hostname/index.php?r=country/index
``` ```
![Перелік країн](../guide/images/start-country-list.png) ![Перелік країн](images/start-country-list.png)
Спочатку, ви побачите сторінку з переліком п'яти країн. Нижче країн, ви побачите пейджер з чотирма кнопками. Спочатку, ви побачите сторінку з переліком пʼяти країн. Нижче країн, ви побачите пейджер з чотирма кнопками.
Якщо ви натиснете на кнопку "2", ви побачите сторінку ще п'ять країн з бази даних: другу сторінку записів. Якщо ви натиснете на кнопку "2", ви побачите сторінку з іншими пʼятьма країнами з бази даних: другу сторінку записів.
Придивившись більш уважно, ви побачите, що URL в браузері також змінюється на Придивившись більш уважно, ви побачите, що URL в браузері також змінюється на
``` ```
http://hostname/index.php?r=country/index&page=2 http://hostname/index.php?r=country/index&page=2
``` ```
За лаштунками, [[yii\data\Pagination|Pagination]] надає всю необхідну функціональність для розбивки набору даних на сторінки: За лаштунками, [[yii\data\Pagination|Pagination]] надає всю необхідну функціональність для розбиття набору даних на сторінки:
* Спочатку, [[yii\data\Pagination|Pagination]] представляє першу сторінку, яка відображає країни запитом SELECT з умовою `LIMIT 5 OFFSET 0`. В результаті, будуть відображені перші знайдені п'ять країн. * Спочатку, [[yii\data\Pagination|Pagination]] представляє першу сторінку, яка відображає країни запитом SELECT
* [[yii\widgets\LinkPager|LinkPager]] віджет відображає кнопки сторінок з URL-адресами створеними за допомогою [[yii\data\Pagination::createUrl()|Pagination]]. URL-адреси будуть містити параметр запиту `page`, який представляє різні номери сторінок. з умовою `LIMIT 5 OFFSET 0`. В результаті, будуть відображені перші знайдені пʼять країн.
* [[yii\widgets\LinkPager|LinkPager]] віджет відображає кнопки сторінок з URL-адресами створеними за допомогою
[[yii\data\Pagination::createUrl()|Pagination]]. URL-адреси будуть містити параметр запиту `page`,
який представляє різні номери сторінок.
* Якщо ви натиснете кнопку "2", спрацює новий запит, який буде відправлений на `country/index` з подальшим опрацюванням. * Якщо ви натиснете кнопку "2", спрацює новий запит, який буде відправлений на `country/index` з подальшим опрацюванням.
[[yii\data\Pagination|Pagination]] зчитає параметр `page` з URL-запиту і встановить номер поточної сторінки в 2-ку. [[yii\data\Pagination|Pagination]] зчитає параметр `page` з URL-запиту і встановить номер поточної сторінки в 2-ку.
Таким чином, новий запит буде мати пункт `LIMIT 5 OFFSET 5` і поверне наступні п'ять країн для відображення. Таким чином, новий запит буде мати визначення `LIMIT 5 OFFSET 5` і поверне наступні пʼять країн для відображення.
Резюме <a name="summary"></a> Підсумок <a name="summary"></a>
------- --------
В цьому розділі ви дізналися, як працювати з базою даних. Ви також дізналися, як вибирати і відображати дані на сторінках за допомогою [[yii\data\Pagination]] і [[yii\widgets\LinkPager]]. В цьому розділі ви дізналися, як працювати з базою даних. Ви також дізналися, як вибирати і відображати дані на сторінках
за допомогою [[yii\data\Pagination]] і [[yii\widgets\LinkPager]].
У наступному розділі ви дізнаєтеся, як використовувати потужний інструмент генерації коду, що називається [Gii](tool-gii.md), який допоможе вам швидко здійснювати деякі часто необхідні функції, такі як Create-Read-Update-Delete (CRUD) операції для роботи з даними в таблицях баз даних. Насправді, код, який ви щойно написали, Yii може автоматично сгенерувати з допомогою функції Gii. У наступному розділі ви дізнаєтеся, як використовувати потужний інструмент генерації коду, що називається [Gii](tool-gii.md),
який допоможе вам швидко здійснювати деякі часто необхідні функції, такі як Create-Read-Update-Delete (CRUD)
операції для роботи з даними в таблицях баз даних.
Насправді, код, який ви щойно написали, Yii може автоматично сгенерувати з допомогою функції Gii.
Робота з формами Робота з формами
================ ================
В даному розділі ми обговоримо отримання даних від користувачів. На сторінці буде розміщена форма з полями, де можна буде вказати ім’я та email. Отримані дані будуть зображені на сторінці для їх підтвердження. В даному розділі ми обговоримо отримання даних від користувачів. На сторінці буде розміщена форма з полями,
де можна буде вказати ім’я та email. Отримані дані будуть зображені на сторінці для їх підтвердження.
Для того, щоб досягти дану ціль, крім створення [події](structure-controllers.md) і двох [представлень](structure-views.md) Для того, щоб досягти дану ціль, крім створення [дії](structure-controllers.md) і двох [представлень](structure-views.md)
ви створите [модель](structure-models.md). ви створите [модель](structure-models.md).
В даному керівництві ви дізнаєтесь: В даному керівництві ви дізнаєтесь:
* Як створити [модель](structure-models.md) для даних, вказаних користувачем; * Як створити [модель](structure-models.md) для даних, вказаних користувачем
* Як оголосити правила перевірки переданих даних; * Як оголосити правила перевірки введених даних
* Як створити HTML форму в [представлені](structure-views.md). * Як створити HTML форму в [представленні](structure-views.md)
Створення моделі <a name="creating-model"></a> Створення моделі <a name="creating-model"></a>
--------------------------------------------- ----------------
У файлі `models/EntryForm.php` створіть клас моделі `EntryForm` як показано нижче. Він буде використовуватись для зберігання даних, вказаних користувачем. Детальніше про присвоєння імен файлам класів читайте в розділі Створіть клас моделі `EntryForm` та збережіть у файлі `models/EntryForm.php` як показано нижче. Він буде використовуватись
«[Автозавантаження класів](concept-autoloading.md)». для зберігання даних, введених користувачем. Детальніше про присвоєння імен файлам класів читайте в розділі
[Автозавантаження класів](concept-autoloading.md).
```php ```php
<?php <?php
...@@ -43,21 +45,40 @@ class EntryForm extends Model ...@@ -43,21 +45,40 @@ class EntryForm extends Model
Даний клас розширює клас [[yii\base\Model]], який є складовою частиною фреймворка і зазвичай використовується для роботи з даними форм. Даний клас розширює клас [[yii\base\Model]], який є складовою частиною фреймворка і зазвичай використовується для роботи з даними форм.
> Інформація: Клас [[yii\base\Model]] використовується як батьківський клас для класів моделей, які *не* асоційовані
з таблицями бази даних. Клас [[yii\db\ActiveRecord]] зазвичай є батьківським для класів моделей, що відповідають
таблицям бази даних.
Клас містить 2 публічні властивості `name` і `email`, які використовуються для зберігання даних, вказаних користувачем. Клас містить 2 публічні властивості `name` і `email`, які використовуються для зберігання даних, вказаних користувачем.
Він також містить метод `rules()`, який повертає набір правил поведінки даних. Правила, оголошені в коді вище означають наступне: Він також містить метод `rules()`, який повертає набір правил перевірки даних. Правила перевірки,
оголошені в коді вище означають наступне:
* Поля `name` і `email` обов’язкові для заповнення; * Поля `name` і `email` обов’язкові для заповнення
* Поле `email` повино містити правильну адресу email. * Поле `email` повино містити правильну адресу email
Якщо об’єкт `EntryForm` заповнений даними користувача, то для їх перевірки ви можете викликати метод Якщо об’єкт `EntryForm` заповнений даними користувача, то для їх перевірки ви можете викликати метод
[[yii\base\Model::validate()|validate()]]. У випадку невдалої перевірки властивість [[yii\base\Model::hasErrors|hasErrors]] [[yii\base\Model::validate()|validate()]]. У випадку невдалої перевірки властивість [[yii\base\Model::hasErrors|hasErrors]]
дорівнюватиме `true`. За допомогою [[yii\base\Model::getErrors|errors]] можна дізнатись, які саме виникли помилки. дорівнюватиме `true`. За допомогою [[yii\base\Model::getErrors|errors]] можна дізнатись, які саме виникли помилки.
```php
<?php
$model = new EntryForm();
$model->name = 'Qiang';
$model->email = 'bad';
if ($model->validate()) {
// Good!
} else {
// Failure!
// Use $model->getErrors()
}
```
Створення події <a name="creating-action"></a> Створення дії <a name="creating-action"></a>
------------------------------------------------ -------------
Далі створіть подію `entry` в контролері `site`, точно так, як ви робили це раніше. Далі створіть дію `entry` в контролері `site`, точно так, як ви робили це раніше.
Процес створення та використання дій описано у розділі [Говоримо «Привіт»](start-hello.md).
```php ```php
<?php <?php
...@@ -77,7 +98,7 @@ class SiteController extends Controller ...@@ -77,7 +98,7 @@ class SiteController extends Controller
$model = new EntryForm; $model = new EntryForm;
if ($model->load(Yii::$app->request->post()) && $model->validate()) { if ($model->load(Yii::$app->request->post()) && $model->validate()) {
// дані в $model успішно провірені // дані в $model успішно перевірені
// робимо щось корисне з $model ... // робимо щось корисне з $model ...
...@@ -91,21 +112,25 @@ class SiteController extends Controller ...@@ -91,21 +112,25 @@ class SiteController extends Controller
``` ```
Подія створює об’єкт `EntryForm`. Потім вона намагається заповнити модель даними із масива `$_POST`, доступ Подія створює об’єкт `EntryForm`. Потім вона намагається заповнити модель даними із масива `$_POST`, доступ
до якого забеспечує Yii за допомогою [[yii\web\Request::post()]]. Якщо модель успішно заповнена, тобто користувач відправив дані з HTML форми, то для перевірки даних буде викликаний метод [[yii\base\Model::validate()|validate()]]. до якого забеспечує Yii за допомогою [[yii\web\Request::post()]]. Якщо модель успішно заповнена, тобто користувач відправив
дані з HTML форми, то для перевірки даних буде викликаний метод [[yii\base\Model::validate()|validate()]].
> Інформація: `Yii::$app` являє собою глобально доступний екземпляр-одинак [додатка](structure-applications.md)
(singleton). Одночасно це є [Service Locator](concept-service-locator.md), який надає доступ до компонентів, типу
`request`, `response`, `db` і так далі. В коді выще для доступу до даних з `$_POST` був використаний компонент `request`.
Якщо все гаразд, подія зобразить представлення `entry-confirm`, яке покаже користувачу вказані ним дані. Якщо все гаразд, подія зобразить представлення `entry-confirm`, яке покаже користувачу вказані ним дані.
В іншому випадку буде зображено представлення `entry`, яке містить HTML форму і помилки перевірки даних, якщо вони є. В іншому випадку буде зображено представлення `entry`, яке містить HTML форму і помилки перевірки даних, якщо вони є.
> Інформація: `Yii::$app` являє собою глобально доступний екземпляр-одинак > Примітка: У цьому дуже простому прикладі ми просто відобразили сторінку підтвердження відправки даних.
[додатка](structure-applications.md) (singleton). Одночасно це [Service Locator](concept-service-locator.md), На практиці, ви повинні розглянути використання [[yii\web\Controller::refresh()|refresh()]] або [[yii\web\Controller::redirect()|redirect()]]
який надає доступ до компонентів типу `request`, `response`, `db` і так далі. В коді выще для доступу до даних з `$_POST` для уникнення [проблеми повторного відправлення даних форми](http://en.wikipedia.org/wiki/Post/Redirect/Get).
був використаний компонент `request`.
Створення представлення <a name="creating-views"></a> Створення представлення <a name="creating-views"></a>
---------------------------------------------------- -----------------------
В завершення, створюємо два представлення з іменами `entry-confirm` і `entry`, котрі зображаються подією `entry` з минулого підрозділа. На завершення, створюємо два представлення з іменами `entry-confirm` і `entry`, котрі зображаються дією `entry` з минулого підрозділу.
Представлення `entry-confirm` просто зображає ім’я та email. Воно мусить бути збережене у файлі `views/site/entry-confirm.php`. Представлення `entry-confirm` просто зображає ім’я та email. Воно мусить бути збережене у файлі `views/site/entry-confirm.php`.
...@@ -142,14 +167,15 @@ use yii\widgets\ActiveForm; ...@@ -142,14 +167,15 @@ use yii\widgets\ActiveForm;
``` ```
Для побудови HTML форми представлення використовує потужний [віджет](structure-widgets.md) [[yii\widgets\ActiveForm|ActiveForm]]. Для побудови HTML форми представлення використовує потужний [віджет](structure-widgets.md) [[yii\widgets\ActiveForm|ActiveForm]].
Методи `begin()` і `end()` виводять відкриваючий і закриваючий теги форми. Між цими викликами створюються поля для заповнення за допомогою метода [[yii\widgets\ActiveForm::field()|field()]]. Першим іде поле для "name", другим — для "email". Методи `begin()` і `end()` виводять відкриваючий і закриваючий теги форми. Між цими викликами створюються поля для заповнення
за допомогою метода [[yii\widgets\ActiveForm::field()|field()]]. Першим іде поле для "name", другим — для "email".
Далі для генерації кнопки відправлення даних викликається метод [[yii\helpers\Html::submitButton()]]. Далі для генерації кнопки відправлення даних викликається метод [[yii\helpers\Html::submitButton()]].
Спробуєм <a name="trying-it-out"></a> Спробуємо <a name="trying-it-out"></a>
-------------------------------------- ---------
Щоб побачити все, що було створено під час роботи, відкрийте в браузері наступний URL: Щоб побачити, як це працює, відкрийте в браузері наступний URL:
``` ```
http://hostname/index.php?r=site/entry http://hostname/index.php?r=site/entry
...@@ -159,21 +185,27 @@ http://hostname/index.php?r=site/entry ...@@ -159,21 +185,27 @@ http://hostname/index.php?r=site/entry
інформацію слід вказувати. Якщо ви натиснете на кнопку відправлення даних без самих даних або якщо вкажете email в невірному інформацію слід вказувати. Якщо ви натиснете на кнопку відправлення даних без самих даних або якщо вкажете email в невірному
форматі, то ви побачите повідомлення з помилкою біля кожного проблемного поля. форматі, то ви побачите повідомлення з помилкою біля кожного проблемного поля.
![Форма з помилками](../guide/images/start-form-validation.png) ![Форма з помилками](images/start-form-validation.png)
Після введення вірних даних і їх відправки, ви побачите сторінку з даними, які щойно вказали. Після введення вірних даних і їх відправки, ви побачите сторінку з даними, які щойно вказали.
![Підтвердження введених даних](../guide/images/start-entry-confirmation.png) ![Підтвердження введених даних](images/start-entry-confirmation.png)
### Як працює вся ця "магія" <a name="magic-explained"></a>
### Як працює вся ця «магія» <a name="magic-explained"></a> Ви, більш за все, ставите питанням про те, як все ж ця HTML форма працює насправді і яким чином.
Весь процес може здатися трохи магічним: те як зображаються підписи до полів, помилки перевірки даних при некоректному
заповненні і те що все це відбувається без перезавантаження сторінки.
Ви, більш за все, ставите питанням про те, як все ж ця HTML форма працює насправді і яким чином. Весь процес може здатися трохи магічним: те як зображаються підписи до полів, помилки перевірки даних при некоректному заповненні і те що все це відбувається без перезавантаження сторінки. Так, початкова перевірка даних дійсно проходить на стороні клієнта за допомогою JavaScript, і повторно перевіряється
на стороні сервера (PHP). [[yii\widgets\ActiveForm]] достатньо продуманий, щоб взяти правила перевірки, які ви
оголосили в `EntryForm`, перетворити їх в JavaScript код і використовувати його для проведення перевірки.
На випадок, якщо в браузері буде вимкнено JavaScript валідація проходить і на стороні сервера, як показано в методі
`actionEntry()`. Це дає впевненість в тому, що дані коректні за будь-яких обставин.
Так, провірка даних дійсно проходить на стороні клієнта за допомогою JavaScript і на стороні сервера. > Попередження: перевірка даних на стороні клієнта це зручність, яке забезпечує кращий користувальницький досвід.
[[yii\widgets\ActiveForm]] достатньо продуманий, щоб взяти правила перевірки, які ви оголосили в `EntryForm`, Перевірка на стороні сервера завжди обов’язкова, незважаючи на клієнтську.
перетворити їх в JavaScript код і використовувати його для проведення перевірки. На випадок, якщо в браузері буде вимкнено JavaScript валідація проходить і на стороні сервера, як показано в методі `actionEntry()`. Це дає впевненість в тому, що дані коректні за любих обставин.
Підписи для полів генеруються методом `field()`, на основі імен властивостей моделі. Наприклад, підпис `Name` генерується Підписи для полів генеруються методом `field()`, на основі імен властивостей моделі. Наприклад, підпис `Name` генерується
для властивості `name`. Ви можете модифікувати підписи наступним чином: для властивості `name`. Ви можете модифікувати підписи наступним чином:
...@@ -184,14 +216,16 @@ http://hostname/index.php?r=site/entry ...@@ -184,14 +216,16 @@ http://hostname/index.php?r=site/entry
``` ```
> Інформація: У Yii є велика кількість віджетів, які дозволяють швидко будувати складні і динамічні представлення. > Інформація: У Yii є велика кількість віджетів, які дозволяють швидко будувати складні і динамічні представлення.
Як ви дізнаєтесь пізніше, розробляти нові віджети доволі просто. Багато із представленнь можна винести у віджети, щоб використовувати це повторно в інших частинах і тим самим спростити розробку в майбутньому. Як ви дізнаєтесь пізніше, розробляти нові віджети доволі просто. Багато із представленнь можна винести у віджети,
щоб використовувати їх повторно в інших частинах і тим самим спростити розробку в майбутньому.
Резюме <a name="summary"></a> Підсумок <a name="summary"></a>
----------------------------- --------
В даному розділі ви випробували кожну частину шаблона проектування MVC. Ви дізналися як створювати класи моделей для опрацювання і перевірки даних вказаних користувачем. В даному розділі ви випробували кожну частину шаблона проектування MVC. Ви дізналися як створювати класи моделей
для опрацювання і перевірки даних вказаних користувачем.
Також, ви дізналися як отримати дані від користувача і як їх відобразити тому ж користувачу. Ця задача може займати багато часу в процесі розробки. Yii надає потужні віджети, які роблять задачу максимально простою. Також, ви дізналися як отримати дані від користувача і як їх відобразити тому ж користувачу. Ця задача може займати
багато часу в процесі розробки. Yii надає потужні віджети, які роблять задачу максимально простою.
В наступному розділі ви дізнаєтесь як працювати з базами даних, що необхідно в більшості додатків. В наступному розділі ви дізнаєтесь як працювати з базами даних, що необхідно в більшості додатків.
Генерація коду за допомогою Gii Генерація коду за допомогою Gii
======================== ===============================
Цей розділ описує, як використовувати [Gii](tool-gii.md) для автоматичної генерації коду, процедура якої має певні спільні риси з веб-сайтом. Використання Gii для автоматичного створення коду є простою процедурою введення правильної інформації згідно інструкцій, які містяться на Цей розділ описує, як використовувати [Gii](tool-gii.md) для автоматичної генерації коду, процедура якої має певні
Gii. спільні риси з веб-сайтом. Використання Gii для автоматичного створення коду є простою процедурою введення
правильної інформації згідно інструкцій, які містяться на Gii.
В даному керівництві ви дізнаєтесь: В даному керівництві ви дізнаєтесь:
* Включити Gii у вашому додатку * Увімкнути Gii у вашому додатку
* Використання Gii для генерації Active Record класів * Використання Gii для генерації класів Active Record
* Використання Gii для генерації коду по операціям CRUD бази даних * Використання Gii для генерації коду по операціям CRUD бази даних
* Налаштування коду, що був згенерований Gii * Налаштування коду, що був згенерований Gii
Підготовка Gii <a name="starting-gii"></a> Підготовка Gii <a name="starting-gii"></a>
------------ --------------
[Gii](tool-gii.md) надається як [модуль](structure-modules.md). Ви можете підключити Gii налаштувавши його модуль [[yii\base\Application::modules|modules]] в налаштуваннях додатка. В залежності від налаштувань вашого додатка, ви можете знайти наступний код в конфігураційному файлі `config/web.php`: [Gii](tool-gii.md) надається як [модуль](structure-modules.md). Ви можете підключити модуль Gii, налаштувавши відповідну
властивість [[yii\base\Application::modules|modules]] в налаштуваннях додатка. В залежності від налаштувань вашого додатка,
ви можете знайти наступний код в конфігураційному файлі `config/web.php`:
```php ```php
$config = [ ... ]; $config = [ ... ];
...@@ -26,64 +29,87 @@ if (YII_ENV_DEV) { ...@@ -26,64 +29,87 @@ if (YII_ENV_DEV) {
} }
``` ```
Наведена вище конфігурація підключає модуль `gii` в тому випадку, коли ваш додаток знаходиться в [середовищі розробки](concept-configurations.md#environment-constants) і наслідує клас [[yii\gii\Module]]. Наведена вище конфігурація підключає модуль `gii` у тому випадку, коли ваш додаток знаходиться в
[середовищі розробки](concept-configurations.md#environment-constants) і наслідує клас [[yii\gii\Module]].
Якщо ви перевірите [вхідний скрипт](structure-entry-scripts.md) `web/index.php` вашого додатку, то знайдете наступний рядок `YII_ENV_DEV`, який переводить додаток в середовище розробки. Якщо ви перевірите [вхідний скрипт](structure-entry-scripts.md) `web/index.php` вашого додатку, то знайдете наступний
рядок `YII_ENV_DEV`, який переводить додаток в середовище розробки.
```php ```php
defined('YII_ENV') or define('YII_ENV', 'dev'); defined('YII_ENV') or define('YII_ENV', 'dev');
``` ```
Завдяки даному рядку, ваш додаток знаходиться в режимі розробки, і буде підключати Gii, із вищевказаною конфігурацією. Тепер ви можете отримати доступ до Gii за наступною адресою: Завдяки даному рядку, ваш додаток знаходиться в режимі розробки, і буде підключати Gii, із вищевказаною конфігурацією.
Тепер ви можете отримати доступ до Gii за наступною адресою:
``` ```
http://hostname/index.php?r=gii http://hostname/index.php?r=gii
``` ```
![Gii](../guide/images/start-gii.png) > Примітка: Якщо ви звертаєтеся до Gii від машини, крім локальної, доступ буде заборонений за замовчуванням із міркувань
безпеки. Ви можете налаштувати Gii, додавши дозволені IP адреси, як показано нижче,
>
```php
'gii' => [
'class' => 'yii\gii\Module',
'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.178.20'] // налаштувати для ваших потреб
],
```
![Gii](images/start-gii.png)
Генерація класу Active Record <a name="generating-ar"></a> Генерація класу Active Record <a name="generating-ar"></a>
--------------------------------- -----------------------------
Використовуючи Gii для генерації класу Active Record, виберіть "Model Generator" (натиснувши на посилання на сторінці Gii). Далі заповніть форму наступними даними: Використовуючи Gii для генерації класу Active Record, виберіть "Model Generator" (натиснувши на посилання на сторінці Gii).
Далі заповніть форму наступними даними:
* Ім’я таблиці: `country` * Ім’я таблиці: `country`
* Клас моделі: `Country` * Клас моделі: `Country`
![Герератор моделі](../guide/images/start-gii-model.png) ![Генератор моделі](images/start-gii-model.png)
Далі, натисніть на кнопку "Перегляду". Ви побачите файл `models/Country.php` який буде створений в результаті даних дій. Ви можете натиснути на ім'я файлу класу для перегляду його вмісту. Далі, натисніть на кнопку "Перегляду" ("Preview"). Ви побачите файл `models/Country.php`, який буде створено в результаті
даних дій. Ви можете натиснути на ім’я файлу класу для перегляду його вмісту.
Якщо при використанні Gii, раніше вже був створений файл моделі, то він буде перезаписаний. Для того, щоб переглянути відмінності в коді натисніть на кнопку `diff` поруч з ім'ям файлу. Якщо при використанні Gii, раніше вже був створений файл моделі, то він буде перезаписаний. Для того, щоб переглянути
відмінності в коді натисніть на кнопку `diff` поруч з ім’ям файлу.
![Прев'ю генератора моделі](../guide/images/start-gii-model-preview.png) ![Прев’ю генератора моделі](images/start-gii-model-preview.png)
При перезаписі існуючого файлу, встановіть прапорець поруч із чекбоксом "перезаписати", а потім натисніть кнопку "Створити". При створенні нового файлу, ви можете просто натиснути на кнопку "Створити". При перезаписі існуючого файлу, встановіть прапорець поруч із чекбоксом "перезаписати" ("overwrite"), а потім натисніть
кнопку "Створити" ("Generate"). При створенні нового файлу, ви можете просто натиснути на кнопку "Створити" ("Generate").
Далі, ви побачите сторінку підтвердження із відображенням коду, який був сгенерований. Якщо ви перезаписували вже існуючий файл, то побачите повідомлення про те, що він був переписаний і замінений на щойно згенерований код. Далі, ви побачите сторінку підтвердження із відображенням коду, який був сгенерований. Якщо ви перезаписували вже існуючий
файл, то побачите повідомлення про те, що він був переписаний і замінений на щойно згенерований код.
Генерація коду CRUD <a name="generating-crud"></a> Генерація коду CRUD <a name="generating-crud"></a>
-------------------- -------------------
CRUD розшифровується як Створити, Прочитати, Оновити, і Видалити, це операції що вирішують чотири спільні завдання з маніпулюванням даними на більшості веб-сайтів. Щоб створити CRUD інтерфейс використовуючи Gii, виберіть "CRUD Generator" (натиснувши відповідну кнопку на сторінці Gii). Наприклад, для таблиці "country", заповніть наступні поля форми: CRUD розшифровується як Створити, Прочитати, Оновити, і Видалити, це операції що вирішують чотири спільні завдання
з маніпулюванням даними на більшості веб-сайтів. Щоб створити CRUD інтерфейс використовуючи Gii, оберіть
"CRUD Generator" (натиснувши відповідну кнопку на сторінці Gii). Наприклад, для таблиці "country", заповніть наступні поля форми:
* Клас моделі: `app\models\Country` * Клас моделі: `app\models\Country`
* Клас моделі пошуку: `app\models\CountrySearch` * Клас моделі пошуку: `app\models\CountrySearch`
* Клас контролера: `app\controllers\CountryController` * Клас контролера: `app\controllers\CountryController`
![CRUD генератор](../guide/images/start-gii-crud.png) ![CRUD генератор](images/start-gii-crud.png)
Далі, натисніть на кнопку "Перегляду". Ви побачите файл `models/Country.php` який буде створений в результаті даних дій. Ви можете натиснути на ім'я файлу класу для перегляду його вмісту. Далі, натисніть на кнопку "Перегляду" ("Preview"). Ви побачите файл `models/Country.php` який буде створений в
результаті даних дій. Ви можете натиснути на ім’я файлу класу для перегляду його вмісту.
[[NEED THE IMAGE HERE]] ![Прев’ю CRUD генератор](images/start-gii-crud-preview.png)
Якщо ви попередньо створили контролер `controllers/CountryController.php` і файл предствлення `views/country/index.php` (в розділі "Робота з базами даних" даного посібника), виберіть чекбокс "перезаписати" і замініть їх. (Попередні версії файлів на мають повного CRUD функціоналу.) Якщо ви попередньо створили контролер `controllers/CountryController.php` і файл представлення `views/country/index.php`
(в розділі "Робота з базами даних" даного посібника), оберіть чекбокс "перезаписати" і замініть їх.
(Попередні версії файлів на мають повного CRUD функціоналу.)
Спробуєм <a name="trying-it-out"></a> Спробуємо <a name="trying-it-out"></a>
------------- ---------
Щоб побачити все, що було створено під час роботи, відкрийте в браузері наступний URL: Щоб побачити все, що було створено під час роботи, відкрийте в браузері наступний URL:
...@@ -91,24 +117,30 @@ CRUD розшифровується як Створити, Прочитати, ...@@ -91,24 +117,30 @@ CRUD розшифровується як Створити, Прочитати,
http://hostname/index.php?r=country/index http://hostname/index.php?r=country/index
``` ```
Ви побачите таблицю даних, що показує країни з таблиці бази даних. Ви зможете відсортувати сітку, або відфільтрувати пошук, вказавши умови фільтрації в заголовках стовпців. Ви побачите таблицю даних, що показує країни з таблиці бази даних. Ви зможете відсортувати сітку, або відфільтрувати
пошук, вказавши умови фільтрації в заголовках стовпців.
Для кожної країни, що відображаються в таблиці, ви можете використати функції перегляду деталей, оновлення даних, або взагалі видалити її. Ви також можете натиснути на кнопку "Створити країну" зверху сітки відображення, яка переадресує вас на форму створення нової країни. Для кожної країни, що відображається в таблиці, ви можете використати функції перегляду деталей, оновлення даних, або
взагалі видалити її. Ви також можете натиснути на кнопку "Створити країну" зверху сітки відображення, яка переадресує
вас на форму створення нової країни.
![Сітка даних країн](../guide/images/start-gii-country-grid.png) ![Сітка даних країн](images/start-gii-country-grid.png)
![Оновлення даних країни](../guide/images/start-gii-country-update.png) ![Оновлення даних країни](images/start-gii-country-update.png)
Нижче представлений список файлів, згенерованих Gii, в тому разі, якщо ви захочете дослідити, як реалізовані ці можливості, або доналаштувати їх під свої потреби: Нижче наведено перелік файлів, згенерованих Gii, у тому разі, якщо ви захочете дослідити, як реалізовані ці можливості,
або доналаштувати їх під свої потреби:
* Контролер: `controllers/CountryController.php` * Контролер: `controllers/CountryController.php`
* Моделі: `models/Country.php` і `models/CountrySearch.php` * Моделі: `models/Country.php` і `models/CountrySearch.php`
* Представлення: `views/country/*.php` * Представлення: `views/country/*.php`
> Інформація: Gii це гнучкий і розширюваний інструмент для генерації коду. При правильному використувані, від дозволить вам значно прискорити розробку ваших додатків. Для більш докладної інформації, будьласка, зверніться до розділу [Gii](tool-gii.md). > Інформація: Gii це гнучкий і розширюваний інструмент для генерації коду. При правильному використувані, від дозволить
вам значно прискорити розробку ваших додатків. Для більш докладної інформації, будьласка, зверніться до розділу [Gii](tool-gii.md).
Резюме <a name="summary"></a> Підсумок <a name="summary"></a>
------- --------
В цьому розділі ви дізналися, як використовуючи Gii генерувати код, який реалізує повну функціональність CRUD для маніпулювання даними що зберігаються в таблицях баз даних. В цьому розділі ви дізналися як, використовуючи Gii, генерувати код, який реалізує повну функціональність CRUD для
маніпулювання даними, що зберігаються в таблицях баз даних.
Говоримо «Привіт» Говоримо «Привіт»
================ =================
В даному розділі розглянемо як створити нову сторінку з надписом «Привіт». В процесі вирішеня задачі ви створите В даному розділі розглянемо як створити нову сторінку з надписом «Привіт». В процесі вирішеня задачі ви створите
[подію контролера](structure-controllers.md) і [представлення](structure-views.md): [дію контролера](structure-controllers.md) і [представлення](structure-views.md):
* Додаток опрацює запит і передасть управління відповідній події; * Додаток опрацює запит і передасть управління відповідній дії
* Подія, в свою чергу, відобразить представлення з надписом "Привіт" кінцевому користувачу. * Дія, в свою чергу, відобразить представлення з надписом "Привіт" кінцевому користувачу
З допомогою даного керівництва ви вивчите З допомогою даного керівництва ви вивчите:
* Як створити [подію](structure-controllers.md), яка буде відповідати на запити; 1. Як створити [дію](structure-controllers.md), яка буде відповідати на запити
* Як створити [представлення](structure-views.md), щоб формувати зміст відповіді; 2. Як створити [представлення](structure-views.md), щоб формувати зміст відповіді
* Як додаток відправляє запити до [події](structure-controllers.md). 3. Як додаток відправляє запити до [дії](structure-controllers.md).
Створення Події <a name="creating-action"></a> Створення дії <a name="creating-action"></a>
------------------------------------------------ -------------
Для нашої задачі знадобиться [подія](structure-controllers.md) `say`, котра читає параметр `message` із Для нашої задачі знадобиться [дія](structure-controllers.md#creating-actions) `say`, котра читає параметр `message` із
запиту і відображає його значення користувачу. Якщо в запиті відсутній параметр `message`, то подія буде відображати «Привіт». запиту і відображає його значення користувачу. Якщо в запиті відсутній параметр `message`, то дія буде відображати «Привіт».
> Інформація: [Події](structure-controllers.md) можуть бути запущені безпосередньо користувачем і згруповані в > Інформація: [Дії](structure-controllers.md#creating-actions) можуть бути запущені безпосередньо користувачем і
[контролери](structure-controllers.md). Результатом виконання події є відповідь, яку отримує користувач. згруповані в [контролери](structure-controllers.md). Результатом виконання дії є відповідь, яку отримує користувач.
Події оголошуються в [контролерах](structure-controllers.md). Для зручності, ви можете оголосити подію Дії оголошуються в [контролерах](structure-controllers.md). Для зручності, ви можете оголосити дію
`say` в уже існуючому контролері `SiteController`, який оголошений у файлі класа `controllers/SiteController.php`: `say` в уже існуючому контролері `SiteController`, який оголошений у файлі класа `controllers/SiteController.php`:
```php ```php
...@@ -44,26 +44,34 @@ class SiteController extends Controller ...@@ -44,26 +44,34 @@ class SiteController extends Controller
} }
``` ```
В наведеному коді подія `say` оголошена як метод `actionSay` в класі `SiteController`.
Yii використовує префікс `action` для того, щоб відрізняти методи-події і звичайні методи. Назва після префікса `action`
вважається ідентифікатором відповідної події.
> Інформація: Ідентифікатори подій задаються в нижньому регістрі. Якщо ідентифікатор складається з декількох слів, вони В наведеному коді дія `say` оголошена як метод `actionSay` в класі `SiteController`.
з’єднуються дефісами, тобто `create-comment`. Імена методів подій отримуються шляхом видалення дефісів з ідентифікатора, перетворення першої літери кожного слова у верхній регістр і добавлення префікса `action`. Yii використовує префікс `action` для того, щоб відрізняти методи-дії і звичайні методи. Назва після префікса `action`
Наприклад, ідентифікатор події `create-comment` відповідає методу `actionCreateComment`. вважається ідентифікатором відповідної дії.
Метод події приймає параметр `$message`, який за замовчуванням дорівнює `"Привіт"`. Коли додаток отримує запит і визначає, що подія `say` відповідає за його опрацювання, параметр наповнюється одноіменним значенням із запиту. Коли черга доходить до іменування дій, слід розуміти як Yii відноситься до ідентифікаторів дій.
Ідентифікатори дій задаються в нижньому регістрі. Якщо ідентифікатор складається з декількох слів, вони
з’єднуються дефісами, тобто `create-comment`. Імена методів дій отримуються шляхом видалення дефісів з ідентифікатора,
перетворення першої літери кожного слова у верхній регістр і додавання префікса `action`.
Наприклад, ідентифікатор дії `create-comment` відповідає методу `actionCreateComment`.
Всередені метода події, для відображення [представлення](structure-views.md) з ім’ям `say`, використовується метод Метод дії приймає параметр `$message`, який за замовчуванням дорівнює `"Привіт"` (так само, як ви звикли визначати
значення за замовчуванням для аргументів методу у PHP). Коли додаток отримує запит і визначає,
що дія `say` відповідає за його опрацювання, параметр наповнюється одноіменним значенням із запиту.
Іншими словами, якщо запит містить параметр `message` із значенням `"До побачення"`, то змінній `$message`
всередині дії буде призначено це значення.
Всередені метода дії, для відображення [представлення](structure-views.md) з ім’ям `say`, використовується метод
[[yii\web\Controller::render()|render()]]. Для того, щоб вивести повідомлення, у представлення передається параметр `message`. [[yii\web\Controller::render()|render()]]. Для того, щоб вивести повідомлення, у представлення передається параметр `message`.
Результат відображення з допомогою `return` передається додатку, котрий віддає його користувачу. Результат відображення з допомогою `return` передається додатку, котрий віддає його користувачу.
Створення представлення <a name="creating-view"></a> Створення представлення <a name="creating-view"></a>
--------------------------------------------------- -----------------------
[Представлення](structure-views.md) є скриптами, які використовуються для формування тіла відповіді. Для нашого [Представлення](structure-views.md) є скриптами, які використовуються для формування тіла відповіді. Для нашого
додатку ви створите представлення `say`, яке буде виводити параметр `message`, отриманий із метода події: додатку ви створите представлення `say`, яке буде виводити параметр `message`, отриманий із метода дії:
```php ```php
<?php <?php
...@@ -73,11 +81,11 @@ use yii\helpers\Html; ...@@ -73,11 +81,11 @@ use yii\helpers\Html;
``` ```
Представлення `say` мусить бути збережено у файлі `views/site/say.php`. Коли метод [[yii\web\Controller::render()|render()]] Представлення `say` мусить бути збережено у файлі `views/site/say.php`. Коли метод [[yii\web\Controller::render()|render()]]
викликається в події, він буде шукати PHP файл з ім’ям виду `views/ControllerID/ActionID/ViewName.php`. викликається в дії, він буде шукати PHP файл з ім’ям виду `views/ControllerID/ActionID/ViewName.php`.
Варто замітити, що в коді вище параметр `message` [[yii\helpers\Html::encode()|екранується для HTML]] перед відображенням. Варто відмітити, що в коді вище параметр `message` [[yii\helpers\Html::encode()|екранується для HTML]] перед відображенням.
Це обов’язково так як параметр приходить від користувача, котрий може спробувати провести Це обов’язково, так як параметр приходить від користувача, котрий може спробувати провести
[XSS атаку](http://uk.wikipedia.org/wiki/%D0%9C%D1%96%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D0%B8%D0%B9_%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D1%96%D0%BD%D0%B3) [XSS атаку](http://uk.wikipedia.org/wiki/%D0%9C%D1%96%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D0%B8%D0%B9_%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D1%96%D0%BD%D0%B3),
шляхом вставки небезпечного JavaScript кода. шляхом вставки небезпечного JavaScript кода.
Ви можете доповнити представлення `say` HTML тегами, текстом або кодом PHP. Фактично, представлення `say` є Ви можете доповнити представлення `say` HTML тегами, текстом або кодом PHP. Фактично, представлення `say` є
...@@ -85,43 +93,47 @@ use yii\helpers\Html; ...@@ -85,43 +93,47 @@ use yii\helpers\Html;
скриптом представлення, буде передано додатком користувачу. скриптом представлення, буде передано додатком користувачу.
Спробуєм <a name="trying-it-out"></a> Спробуємо <a name="trying-it-out"></a>
-------------------------------------- ---------
Після створення події і представлення ви можете перейти на нову сторінку по наступному URL: Після створення дії і представлення, ви можете перейти на нову сторінку по наступному URL:
``` ```
http://hostname/index.php?r=site/say&message=Привіт+світ http://hostname/index.php?r=site/say&message=Привіт+світ
``` ```
![Привіт, світ](../guide/images/start-hello-world.png) ![Привіт, світ](images/start-hello-world.png)
Буде відображена сторінка з надписом "Привіт світ". Вона використовує ту ж шапку і футер, що і решта сторінок додатка.
Буде відображена сторінка з надписом Привіт світ. Вона використовує ту ж шапку і футер, що і решта сторінок додатка.
Якщо ви не вкажете параметр `message`, то побичите на сторінці лише «Привіт». Це відбувається тому, що `message` передається Якщо ви не вкажете параметр `message`, то побичите на сторінці лише «Привіт». Це відбувається тому, що `message` передається
в метод `actionSay()` і значення за замовчуванням — «Привіт». в метод `actionSay()` і значення за замовчуванням — «Привіт».
> Інформація: Нова сторінка використовує ту ж шапку і футер, що і решта сторінок, тому що метод > Інформація: Нова сторінка використовує ту ж шапку і футер, що і решта сторінок, тому що метод
[[yii\web\Controller::render()|render()]] автоматично підставляється в результат представлення `say` в, так називаємий, [[yii\web\Controller::render()|render()]] автоматично підставляється в результат представлення `say` в, так званий,
[макет](structure-views.md) `views/layouts/main.php`. [макет](structure-views.md#layouts) `views/layouts/main.php`.
Параметр `render` потребує додаткових пояснень. Він пов’язаний з [маршрутом (route)](runtime-routing.md), який являє собою унікальний ідентифікатор, який вказує на подію. Його формат `ControllerID/ActionID`. Коли додаток отримує запит, він перевіряє параметр `render` і, використовуючи `ControllerID`, визначає який контролер слід використовувати для опрацювання запиту. Потім, контролер використовує частину `ActionID`, щоб визначити яка подія виконує реальну роботу. Параметр `r` потребує додаткових пояснень. Він пов’язаний з [маршрутом (route)](runtime-routing.md), який являє
В нашому випадку маршрут `site/say` буде відповідати контролеру `SiteController` і його події `say`. собою унікальний ідентифікатор, який вказує на дію. Його формат `ControllerID/ActionID`. Коли додаток отримує запит,
В результаті, для відпрацювання запиту буде визваний метод `SiteController::actionSay()`. він перевіряє цей параметр і, використовуючи `ControllerID`, визначає який контролер слід використовувати для
опрацювання запиту. Потім, контролер використовує частину `ActionID`, щоб визначити яка дія виконує реальну роботу.
> Інформація: Як і події, контролери також мають ідентифікатори, котрі однозначно визначають їх в додатку. В нашому випадку маршрут `site/say` буде відповідати контролеру `SiteController` і його дії `say`.
Ідентифікатори контролерів використовують ті ж самі правила, що і ідентифікатори подій. Імена класів В результаті, для відпрацювання запиту буде викликано метод `SiteController::actionSay()`.
контролерів отримуються шляхом видалення дефісів з ідентифікатора, перетворення першої літери кожного слова у верхній регістр і додавання в кінець `Controller`. Наприклад, ідентифікатор контролера `post-comment` відповідає
> Інформація: Як і дії, контролери також мають ідентифікатори, котрі однозначно визначають їх в додатку.
Ідентифікатори контролерів використовують ті ж самі правила, що і ідентифікатори дій. Імена класів
контролерів отримуються шляхом видалення дефісів з ідентифікатора, перетворення першої літери кожного слова у верхній
регістр і додавання в кінець `Controller`. Наприклад, ідентифікатор контролера `post-comment` відповідає
імені класа контролера `PostCommentController`. імені класа контролера `PostCommentController`.
Резюме <a name="summary"></a> Підсумок <a name="summary"></a>
----------------------------- --------
В даному розділі ви затронули тему контролерів і представленнь в паттерні MVC. Ви створили подію як частину контролера, В даному розділі ви торкнулися теми контролерів і представлень в паттерні MVC. Ви створили дію, як частину контролера,
який опрацьовує запити, і представлення, яке приймає участь у формувані відповіді. В цьому процесі ніяк не була задіяна який опрацьовує запити, і представлення, яке приймає участь у формувані відповіді. В цьому процесі ніяк не була задіяна
модель, так як в ролі даних виступає тільки простий параметр `message`. модель, так як в ролі даних виступає тільки простий параметр `message`.
Також ви ознайомились із концепцією маршрутизації, котра є сполучною ланкою між запитом користувача і подією контролера. Також ви ознайомились із концепцією маршрутизації, котра є сполучною ланкою між запитом користувача і дією контролера.
В наступному розділі ви дізнаєтесь як створювати моделі і добавляти нові сторінки з HTML формами. В наступному розділі ви дізнаєтесь як створювати моделі і добавляти нові сторінки з HTML формами.
Встановлення Yii Встановлення Yii
============== ================
Ви можете встановити Yii двома шляхами: використовуючи [Composer](http://getcomposer.org/) або завантаживши архів. Ви можете встановити Yii двома шляхами: використовуючи [Composer](http://getcomposer.org/) або завантаживши архів.
Перший варіант бажаніший тому, що дозволить встановити всі нові [розширення](structure-extensions.md) Перший варіант бажаніший тому, що дозволить встановити всі нові [розширення](structure-extensions.md)
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
Встановлення за допомогою Composer <a name="installing-via-composer"></a> Встановлення за допомогою Composer <a name="installing-via-composer"></a>
----------------------- ----------------------------------
Якщо Composer все ще не встановлено, то це можна зробити за допомогою інструкції на [getcomposer.org](https://getcomposer.org/download/), або одним із перерахованих способів: Якщо Composer все ще не встановлено, то це можна зробити за допомогою інструкції на [getcomposer.org](https://getcomposer.org/download/), або одним із перерахованих способів:
......
Запуск додатка Запуск додатка
==================== ==============
Після встановлення Yii, базовий додаток буде доступний або по URL `http://hostname/basic/web/index.php`, або по `http://hostname/index.php`, в залежності від налаштування Web сервера. Даний розділ - загальне введення в організацію коду, вбудований функціонал і опрацювання звернень додатком Yii. > Info: For simplicity, throughout this "Getting Started" tutorial, it's assumed that you have set `basic/web`
as the document root of your Web server, and configured, the URL for accessing
your application to be `http://hostname/index.php` or something similar.
For your needs, please adjust the URLs in our descriptions accordingly.
Після встановлення Yii, базовий додаток буде доступний або по URL `http://hostname/basic/web/index.php`,
або по `http://hostname/index.php`, в залежності від налаштування Web сервера. Даний розділ - загальне введення в
організацію коду, вбудований функціонал і опрацювання запитів додатком Yii.
> Інформація: Для спрощення, далі в даному посібнику передбачається, що Yii встановлений в директорію `basic/web`,
яка, в свою чергу, встановлена, як коренева директорія в налаштуваннях Web сервера. В результаті, звернувшись до URL
`http://hostname/index.php` ви отримаєте доступ до додатку. Відрегулюйте URL-адреси для ваших потреб.
> Інформація: Далі, в даному посібнику передбачається що Yii встановлений в теку `basic/web`, яка, в свою чергу, встановлена як коренева директорія в налаштуваннях Web сервера. В результаті, звернувшись по URL `http://hostname/index.php` ви отримаєте доступ до додатку, розміщенному в `basic/web`. Детальніше з процесом початкового налаштування можна ознайомитись в розділі [Встановлення Yii](start-installation.md).
Функціонал <a name="functionality"></a> Функціонал <a name="functionality"></a>
--------------- ----------
Вбудований шаблон простого додатку складається з чотирьох сторінок: Вбудований шаблон простого додатку складається з чотирьох сторінок:
* домашня сторінка, відображається при переході по URL `http://hostname/index.php` * домашня сторінка, відображається при переході по URL `http://hostname/index.php`
* "About" ("Про нас") * "About" ("Про нас")
* на сторінці "Contact" знаходиться форма зворотнього зв’язку, на якій користувач може звернутися до розробника по e-mail * на сторінці "Contact" знаходиться форма зворотнього зв’язку, на якій користувач може звернутися до розробника по e-mail
* на сторінці "Login" відображається форма авторизації. Спробуйте авторизуватись з логіном/паролем "admin/admin". Зверніть увагу на зміну розділу "Login" в головному меню на "Logout". * на сторінці "Login" відображається форма авторизації. Спробуйте авторизуватись з логіном/паролем "admin/admin".
Зверніть увагу на зміну розділу "Login" в головному меню на "Logout".
Ці сторінки використовують суміжний хедер (шапка сайта) і футер (підвал). В "шапці" знаходиться головне меню, за допомогою якого користувач переміщається по сайту. В "підвалі" - копірайт і загальна інформація. Ці сторінки використовують спільний хедер (шапка сайта) і футер (підвал). В "шапці" знаходиться головне меню, за
допомогою якого користувач переміщається по сайту.
В самій верхній частині вікна ви будете бачити системні повідомлення Yii - журнал, відлагоджувальну інформацію, повідомлення про помилки, запити до бази даних і т.п. Відображенням данної інформацію керує [вбудований відладчик](tool-debugger.md), він записує і відображає інформацію про хід виконання додатку. У нижній частині вікна ви зможете бачити системні повідомлення Yii - журнал, відлагоджувальну інформацію,
повідомлення про помилки, запити до бази даних і т.п. Відображенням данної інформацію керує
[вбудований відладчик](tool-debugger.md), він записує і відображає інформацію про хід виконання додатку.
Структура додатка Yii <a name="application-structure"></a> Структура додатка Yii <a name="application-structure"></a>
--------------------- ---------------------
Нижще наведений перелік основних директорій і файлів вашого додатку (вважаєм, що додаток встановлений в директорію `basic`): Нижче наведений перелік основних директорій і файлів вашого додатку (вважаємо, що додаток встановлений в директорію `basic`):
``` ```
basic/ кореневий каталог додатка basic/ кореневий каталог додатка
...@@ -43,36 +58,42 @@ basic/ кореневий каталог додатка ...@@ -43,36 +58,42 @@ basic/ кореневий каталог додатка
yii скрипт виконання консольного додатку Yii yii скрипт виконання консольного додатку Yii
``` ```
В цілому, додаток Yii можна розділити на дві категорії файлів: розміщенні в `basic/web` і розміщенні в інших директоріях. Перша категорія доступна через Web (наприклад, браузером), друга недоступна зовні та і не повинна бути так як містить службову інформацію. The following diagram shows the static structure of an application.
В цілому, додаток Yii можна розділити на дві категорії файлів: розміщенні в `basic/web` і розміщенні в інших директоріях.
Перша категорія доступна через HTTP (наприклад, браузером), друга недоступна зовні, та і не повинна бути, так як містить службову інформацію.
В Yii реалізована схема проектування [модель-представлення-контролер (MVC)](http://http://uk.wikipedia.org/wiki/Model-View-Controller), В Yii реалізована схема проектування [модель-представлення-контролер (MVC)](http://http://uk.wikipedia.org/wiki/Model-View-Controller),
яка відповідає структурі директорій додатка. В директорії `models` знаходяться [Моделі](structure-models.md), яка відповідає структурі директорій додатка. В директорії `models` знаходяться класи [моделей](structure-models.md),
в `views` розміщені [Представлення](structure-views.md), а в каталозі `controllers` всі [Контролери](structure-controllers.md) додатка. в `views` розміщені скрипти [представлень](structure-views.md), а в каталозі `controllers` всі класи [контролерів](structure-controllers.md) додатка.
Діаграма нижче демонструє внутрішню будову додатка. Діаграма нижче демонструє статичну структуру додатка.
![внутрішня будова додатка](../guide/images/application-structure.png) ![Статична структура додатка](images/application-structure.png)
В кожному додатку Yii є місце входження в додаток, `web/index.php` це єдиний PHP-скрипт доступний для виконання через Web. Він отримує вхідний запит і створює екземпляр [додатку](structure-applications.md). В кожному додатку Yii є місце входження в додаток, `web/index.php` - це єдиний PHP-скрипт доступний для виконання через Web.
[Додаток](structure-applications.md) опрацьовує вхідні запити з допомогою [компонентів](concept-components.md) і відправляє запит контролеру. [Віджети](structure-widgets.md) використовуються у [Представленнях](structure-views.md) для побудови динамічних інтерфейсів сайта. Він отримує вхідний запит і створює екземпляр [додатку](structure-applications.md). [Додаток](structure-applications.md)
опрацьовує вхідні запити з допомогою [компонентів](concept-components.md) і відправляє запит контролеру.
[Віджети](structure-widgets.md) використовуються у [представленнях](structure-views.md) для побудови динамічних інтерфейсів сайта.
Життєвий цикл запиту користувача <a name="request-lifecycle"></a> Життєвий цикл запиту <a name="request-lifecycle"></a>
----------------- --------------------
На діаграмі показано як додаток опрацьовує запит. На діаграмі показано, як додаток відпрацьовує запит.
![Життєвий цикл запиту](../guide/images/request-lifecycle.png) ![Життєвий цикл запиту](images/request-lifecycle.png)
1. Користувач звертається до [місця входження](structure-entry-scripts.md) `web/index.php`. 1. Користувач робить запит до [місця входження](structure-entry-scripts.md) `web/index.php`.
2. Скрипт завантажує конфігурацію [configuration](concept-configurations.md) і створює екземпляр [додатку](structure-applications.md) для наступного опрацювання запиту. 2. Скрипт завантажує конфігурацію [configuration](concept-configurations.md) і створює екземпляр
3. Додаток визначає [маршрут](runtime-routing.md) запиту за допомогою компонента додатка [запит](runtime-requests.md). [додатку](structure-applications.md) для наступного опрацювання запиту.
3. Додаток визначає [маршрут](runtime-routing.md) запиту за допомогою компонента [запиту](runtime-requests.md) додатка.
4. Додаток створює екземпляр [контролера](structure-controllers.md) для виконання запиту. 4. Додаток створює екземпляр [контролера](structure-controllers.md) для виконання запиту.
5. Контролер, в свою чергу, створює [подію](structure-controllers.md) і накладає на неї фільтри. 5. Контролер, в свою чергу, створює [дію](structure-controllers.md) і накладає на неї фільтри.
6. Якщо хоч один фільтр поверне помилку - виконання додатку зупиняється. 6. Якщо хоч один фільтр поверне помилку - виконання додатку зупиняється.
7. Якщо всі фільтри пройдені - додаток виконується. 7. Якщо всі фільтри пройдені - додаток виконується.
8. Подія завантажує модель даних. Скоріше за все із бази даних. 8. Дія завантажує модель даних. Скоріше за все із бази даних.
9. Подія генерує представлення, відображаючи в ньому дані (в т.ч. і отримані із моделі). 9. Дія генерує представлення, відображаючи в ньому дані (в т.ч. і отримані із моделі).
10. Згенерований вид додатку передається як компонент [відповідь](runtime-responses.md). 10. Згенерований вид додатку передається як компонент [відповіді](runtime-responses.md).
11. Компонент "відповідь" відправляє готовий результат роботи додатку браузеру користувача. 11. Компонент "відповіді" відправляє готовий результат роботи додатку браузеру користувача.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment