Как работят приложенията?
В момента четете основния документ на Nette. Ще научите всички принципи на работа на уеб приложенията. Всички подробности от А до Я, от момента на раждането до последния дъх на PHP скрипта. След като я прочетете, ще разберете:
- Как работи всичко това.
- какво представляват контейнерите Bootstrap, Presenter и DI
- как изглежда структурата на директорията
Структура на директорията
Отворете пример за скелет на уеб приложение, наречено WebProject, и можете да наблюдавате как се записват файловете.
Структурата на директорията изглежда по следния начин:
web-project/ ├── app/ ← каталог с приложением │ ├── Основни/ ← основни необходими класове │ │ └── RouterFactory.php ← конфигуриране на URL адреси │ ├── UI/ ← презентатори, шаблони и др. │ │ ├── @layout.latte ← шаблон на споделено оформление │ │ └── Home/ ← Директория за водещи │ │ ├── HomePresenter.php ← Клас на Home Presenter │ │ └── default.latte ← шаблон за действие default │ └── Bootstrap.php ← загрузочный класс Bootstrap ├── bin/ ← скрипты командной строки ├── config/ ← файлы конфигурации │ ├── common.neon │ └── services.neon ├── log/ ← журналы ошибок ├── temp/ ← временные файлы, кэш, … ├── vendor/ ← библиотеки, установленные через Composer │ ├── ... │ └── autoload.php ← автозагрузчик библиотек, установленных через Composer ├── www/ ← публичный корневой каталог проекта │ ├── .htaccess ← правила mod_rewrite и т. д. │ └── index.php ← начальный файл, запускающий приложение └── .htaccess ← запрещает доступ ко всем каталогам, кроме www
Можете да променяте структурата на директориите по всякакъв начин,
да преименувате или премествате папки и след това просто да
редактирате пътищата до log/
и temp/
във файла Bootstrap.php
и пътя до този файл в composer.json
в раздела autoload
. Нищо друго,
никакво сложно преконфигуриране, никакви постоянни промени. Nette има интелигентно
автоматично откриване.
За малко по-големи приложения можем да разделим главната папка и папките с шаблони на подпапки (на диска) и пространства от имена (в кода), които наричаме модули.
Публичната директория www/
може да бъде променена, без да се
налага да инсталирате нещо друго. Всъщност често се случва, че поради
спецификата на вашия хостинг ще трябва да я преименувате или да
инсталирате т.нар. document-root към тази директория в конфигурацията на
хостинга. Ако хостингът ви не позволява да създавате папки на едно ниво
над публичната директория, предлагаме ви да потърсите друга хостинг
услуга. В противен случай ще се изложите на значителен риск за
сигурността.
Можете също така да качвате WebProject директно, включително Nette, с помощта на Composer:
composer create-project nette/web-project
В Linux или macOS задайте разрешения за запис за
директориите log/
и temp/
.
Приложението WebProject е готово за работа, не е необходимо да
конфигурирате нищо друго и можете да го видите директно в браузъра си,
като отворите папката www/
.
HTTP заявка
Всичко започва с това, че потребителят отваря страница в браузъра и
браузърът подава HTTP заявка към сървъра. Заявката се изпраща към PHP файл,
разположен в публичната директория www/
, който се нарича
index.php
. Нека предположим, че това е заявка към
https://example.com/product/123
и ще бъде изпълнен.
Задачата му е следната:
- инициализиране на средата
- получаване на фабрика
- стартиране на приложението Nette, което обработва заявката
Какъв вид фабрика? Ние не произвеждаме трактори, а уебсайтове! Изчакайте, след малко ще бъде обяснено.
Под “инициализиране на средата” разбираме например активирането на услугата Tracy, която е невероятен инструмент за регистриране или визуализиране на грешки. Той регистрира грешките на производствения сървър и ги показва директно на сървъра за разработка. Затова по време на инициализацията трябва да решите дали сайтът ще работи в производствен режим или в режим за разработчици. Nette използва автоматично откриване за това: ако стартирате сайта на localhost, той се стартира в режим за разработчици. Не е необходимо да конфигурирате каквото и да било и приложението е готово както за разработка, така и за внедряване в производството. Тези стъпки се следват и са описани подробно в главата Bootstrap.
Третата точка (да, пропуснахме втората, но ще се върнем към нея) е да
стартирате приложението. Класът Nette\Application\Application
(наричан
по-нататък Application
) обработва HTTP заявките в Nette, така че когато
казваме “стартиране на приложение”, имаме предвид извикване на метод
с име run()
върху обект от този клас.
Nette е наставник, който ви напътства да пишете чисти приложения според
доказани методологии. Най-проверяваният от тях се нарича
имплементиране на зависимости, накратко DI. На този етап не искаме
да ви натоварваме с обяснение на DI, тъй като това е разгледано в отделна глава, важното тук е, че
ключовите обекти обикновено се създават от фабрика за обекти, наречена
DI контейнер (съкратено DIC). Да, това е същата фабрика, която беше
спомената преди време. Освен това той създава обекта Application
за
нас, така че първо се нуждаем от контейнер. Получаваме го с класа
Configurator
и му позволяваме да създаде обекта Application
, да
извика метода run()
и това стартира приложението Nette. Точно това се
случва във файла index.php.
Приложението Nette
Класът Application има една единствена задача: да отговори на HTTP заявка.
Приложенията, написани на Nette, са разделени на много така наречени презентатори (в други фреймуъркове може да срещнете термина контролер, което е същото нещо), които представляват класове, представящи определена страница на уебсайт: например начална страница; продукт в електронен магазин; регистрационна форма; rss-карта и т.н. В едно приложение може да има между един и хиляда презентатори.
Приложението започва с искане към т.нар. маршрутизатор да реши на кой
от презентаторите да изпрати текущата заявка за обработка.
Маршрутизаторът решава чия е отговорността. Той разглежда входния URL
адрес https://example.com/product/123
, който иска продукт показать
с
id: 123
като действие. Добър навик е да записвате двойките водещ +
действие, разделени с двоеточие: Продукт:показать
.
Следователно маршрутизаторът е преобразувал URL адреса в двойка
Presenter:action
+ параметри, в нашия случай Product:show
+ id
:
123. Вы можете увидеть, как выглядит маршрутизатор в файле `app/Core/RouterFactory.php
,
и ще го опишем подробно в главата Маршрутизация.
Да продължим. Приложението вече знае името на водещия и може да
продължи. Чрез създаване на обект ProductPresenter
, който е кодът на
предентера Product
. По-точно, той иска от контейнера DI да създаде
презентатора, тъй като създаването на обекти е негова работа.
Водещият може да изглежда по следния начин:
class ProductPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private ProductRepository $repository,
) {
}
public function renderShow(int $id): void
{
// получаваме данни от модела и ги предаваме на шаблона
$this->template->product = $this->repository->getProduct($id);
}
}
Заявката се обработва от водещия. И задачата е ясна: да се изпълни
действието show
с id: 123
. На езика preenter това означава да се
извика методът renderShow()
с параметър $id
, равен на
123
.
Презентаторът може да извършва няколко действия, т.е. да има няколко
метода render<Action>()
. Препоръчваме ви обаче да разработвате
преентери с едно или възможно най-малко действия.
Така че методът renderShow(123)
, чийто код е измислен пример, е
извикан, но на него можете да видите как данните се прехвърлят към
шаблона, т.е. чрез запис в $this->template
.
След това водещият връща отговор. Това може да бъде HTML страница,
изображение, XML документ, файл, изпратен от диска, JSON или пренасочване
към друга страница. Важно е да се отбележи, че ако не посочим изрично
как да се отговори (какъвто е случаят с ProductPresenter
), отговорът ще
бъде шаблон, показващ HTML страница. Защо? Ами защото в 99% от случаите
искаме да покажем шаблон, водещият приема това поведение по
подразбиране и иска да улесни работата ни. Това е гледната точка
на Нете.
Дори не е необходимо да посочваме кой шаблон да се визуализира;
рамката сама ще определи пътя. В случая с действието show
тя
просто се опитва да зареди шаблона show.latte
в директорията с класа
ProductPresenter
. Тя също така се опитва да намери оформлението във
файла @layout.latte
(повече за търсенето на шаблони).
Впоследствие шаблоните се визуализират. С това задачата на презентатора и на цялото приложение е изпълнена и работата е приключила. Ако шаблонът не съществува, ще бъде върната страница с грешка 404. Можете да прочетете повече за презентаторите на страницата Презентатори.
За да сме сигурни, нека повторим целия процес, като използваме малко по-различен URL адрес:
- URL адресът ще
https://example.com
- изтегляме приложението, създаваме контейнер и
стартираме
Application::run()
- маршрутизаторът декодира URL адреса като двойка
Home:default
- обектът е създаден
HomePresenter
- извиква се методът
renderDefault()
(ако съществува) - шаблонът
default.latte
с оформлението@layout.latte
се визуализира
Може би сега ще се сблъскате с много нови концепции, но ние смятаме, че те имат смисъл. Създаването на приложения в Nette е лесно.
Шаблони
Що се отнася до шаблоните, Nette използва системата за шаблони Latte. Ето защо файловете на шаблоните се намират на
адрес .latte
. Latte се използва, защото е най-сигурната система за
шаблони за PHP и в същото време е най-интуитивна. Не е необходимо да
научавате много, достатъчно е да знаете PHP и няколко тага за Latte. Всичко
ще научите от документацията.
В шаблона създаваме връзки към други водещи и действия, както следва:
<a n:href="Product:show $productId">страница товара</a>
Просто напишете познатата двойка Presenter:action
вместо истинския URL
адрес и включете всички параметри. Трикът е n:href
, който казва, че
този атрибут ще бъде обработен от Nette. И тя ще генерира:
<a href="/product/456">страница товара</a>
Споменатият по-горе маршрутизатор е отговорен за генерирането на URL адреса. Всъщност маршрутизаторите в Nette са уникални с това, че могат не само да извършват преобразувания от URL към двойка презентатор:действие, но и обратното – да генерират URL от име на презентатор + действие + параметри. Благодарение на това в Nette можете напълно да промените формата на URL адреса в цялото готово приложение, без да променяте нито един символ в шаблона или презентатора, само чрез промяна на маршрутизатора. Поради това работи т.нар. канонизация – още една уникална функция на Nette, която подобрява SEO оптимизацията, като автоматично предотвратява дублираното съдържание в различни URL адреси. Много програмисти намират това за невероятно.
Интерактивни компоненти
Искаме да ви кажем още нещо за водещите: те имат вградена система от компоненти. По-възрастните може да си спомнят нещо подобно от Delphi или ASP.NET Web Forms. React или Vue.js са изградени на базата на нещо отдалечено подобно. В света на PHP фреймуърците това е напълно уникална функция.
Компонентите са отделни блокове за многократна употреба, които поставяме в страници (напр. презентатори). Те могат да бъдат формуляри, решетки с данни, менюта, анкети, изобщо всичко, което има смисъл да се използва многократно. Можем да създадем собствени компоненти или да използваме някои от огромния брой компоненти с отворен код.
Компонентите променят из основи начина, по който разработваме приложения. Те ще открият нови възможности за създаване на страници от предварително дефинирани блокове. И те имат нещо общо с Холивуд.
Контейнер и конфигурация на DI
Контейнерът DI (фабрика за обекти) е сърцето на цялото приложение.
Не се притеснявайте, това не е магическа черна кутия, както може да се
предположи от предишните думи. Всъщност това е един доста скучен клас
на PHP, генериран от Nette и съхраняван в директория с кеш. Той има много
методи, наречени createServiceAbcd()
, като всеки от тях създава и връща
обект. Да, има и метод createServiceApplication()
, който създава
Nette\Application\Application
, който ни е необходим във файла index.php
, за
да стартираме приложението. Съществуват и методи за подготовка на
отделни презентатори. И така нататък.
Обектите, които контейнерът DI създава, по някаква причина се наричат услуги.
Особеността на този клас е, че той не се програмира от вас, а от
рамката. Всъщност той генерира PHP код и го съхранява на диска. Просто
давате инструкции за това какви обекти и как точно трябва да
произвежда контейнерът. Тези инструкции са записани в конфигурационни
файлове във формат NEON и затова имат
разширение .neon
.
Файловете за конфигурация се използват изключително за обучение на
контейнера DI. Така например, ако посоча expiration: 14 days
в раздела за сесията, контейнерът DI ще извика
своя метод setExpiration('14 days')
при създаването на обекта
Nette\Http\Session
, представляващ сесията, и по този начин
конфигурацията ще стане реалност.
За вас е подготвена цяла глава, в която се описва какво можете да конфигурирате и как да дефинирате собствени услуги.
След като стигнете до създаването на услуги, ще срещнете думата autowiring. Това е притурка, която ще улесни живота ви изключително много. Той може автоматично да предава обекти, когато са ви необходими (например към конструкторите на класа), без да е необходимо да правите каквото и да било. Ще видите, че контейнерът DI в Nette е малко чудо.
Какво следва?
Обхванахме основите на работата на приложенията в Nette. Засега много повърхностно, но скоро ще навлезете в дълбочина и ще създадете страхотни уеб приложения. Къде да продължим? Опитахте ли урока Създаване на първото ви приложение?
В допълнение към горното Nette разполага с цял арсенал от полезни класове, слой за бази данни и др. Опитайте се целенасочено да прегледате документацията. Или посетете блога. Ще откриете много интересни неща.
Нека тази рамка ви донесе много радост 💙.