Створення сторінок в Symfony

05/05/2015 0 symfony, пакет, середовище

Створення нової сторінки в Symfony - чи це сторінка HTML або кінцева точка JSON - є простим двокроковим процесом:

1) Створення маршруту: Маршрут це URL (наприклад, /about) вашої сторінки і він вказує на контролер;

2) Створення контролера: Контролер це функція яку ви записуєте, і яка будує сторінку. Ви берете наступну інформацію запиту і використовуєте її щоб створити об’єкт Symfony Response, який може підтримувати HTML контент, рядок JSON або будь-що інше.     

Так само як і в Інтернеті, кожна взаємодія спричиняється запитом HTTP. Ваша робота є чіткою і простою: зрозуміти цей запит і відповісти на нього.

Створення сторінки: маршрут і контролер

Перш ніж ви збираєтеся продовжити, переконайтесь що ви прочитали розділ Інсталяція і маєте доступ до нового додатку у браузері.

Припустімо, ви хочете створити сторінку - /lucky/number - яка генерує щасливе (тобто випадкове) число та виводить його на екран. Для цього створіть клас всередині з методом що буде виконуватися коли хтось переходитиме до /lucky/number:

// src/AppBundle/Controller/LuckyController.php
namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;

class LuckyController extends Controller
{
    /**
     * @Route("/lucky/number")
     */
    public function numberAction()
    {
        $number = rand(0, 100);

        return new Response(
            '<html><body>Lucky number: '.$number.'</body></html>'
        );
    }
}

Перш ніж почати, протестуйте!

http://localhost:8000/app_dev.php/lucky/number

Якщо ви встановили відповідний віртуальний хост у Apache або Nginx, замініть http://localhost:8000 ім’ям хосту - http://symfony.dev/app_dev.php/lucky/number

Якщо ви бачите щасливе число яке появилося на екрані, вітаємо! Але, перед тим як ви запустите “лотерею”, почитайте як це працює.

@Route над numberAction() називається анотацією і визначає шаблон URL. Також, ви можете писати маршрути, використовуючи YAML (або інший формат): про це читайте у розділі Маршрутизація. Фактично, більшість прикладів маршрутизації у документах містить таби, які показують як виглядає кожен формат.

Метод, який знаходиться під анотацією - numberAction - називається котнролером, він знаходиться там де ви створюєте сторінку. Єдиним правилом є те, що контролер мусить повернути об’єкт Symfony Response (скоро ви навчитеся постійно виконувати це правило).

Що ж таке app_dev.php в URL?

Чудове запитання! Включаючи app_dev.php в URL, Symfony виконується через файл - web/app_dev.php - що допомагає цьому в середовищі dev. Це чудово виправляє помилки і автоматично перебудовує закешовані файли. Для продовження, ви побачте чисті URL- ки - типу http://localhost:8000/lucky/number  - що виконує інший файл - app.php - це є оптимізованим для швидкості. Якщо ви хочете більше дізнатися про середовища, читайте розділ Налаштування Symfony i середовищ.

Створення відповіді JSON

Об’єкт Response який ви повертаєте у вашому контролері може містити HTML, JSON або навіть подвійний файл, такий як зображення або PDF. Ви можете легко розмістити заголовки HTTP у статусі коду.

Припустимо, ви хочете створити кінцеву точку JSON що повертає щасливе число. Просто додайте другий метод до LuckyController:

 // src/AppBundle/Controller/LuckyController.php
// ...

class LuckyController extends Controller
{
    // ...

    /**
     * @Route("/api/lucky/number")
     */
    public function apiNumberAction()
    {
        $data = array(
            'lucky_number' => rand(0, 100),
        );

        return new Response(
            json_encode($data),
            200,
            array('Content-Type' => 'application/json')
        );
    }
}

Спробуйте у вашому браузері:

http://localhost:8000/app_dev.php/api/lucky/number

Ви також можете скористуватись зручним JsonResponse:

// src/AppBundle/Controller/LuckyController.php
// ...

// --> don't forget this new use statement
use Symfony\Component\HttpFoundation\JsonResponse;

class LuckyController extends Controller
{
    // ...

    /**
     * @Route("/api/lucky/number")
     */
    public function apiNumberAction()
    {
        $data = array(
            'lucky_number' => rand(0, 100),
        );

        // calls json_encode and sets the Content-Type header
        return new JsonResponse($data);
    }
}

Динамічні шаблони URL: /lucky/number/{count}

Ви чудово справляєтеся! Але маршрутизаія Symfony може зробити набагато більше. Припустимо, тепер ви хочете щоб користувач мав змогу перейти до /lucky/number/5, та згенерувати 5 щасливих чисел за один раз. Оновіть маршрут, дописавши вкінці {wildcard}:

ANNOTATIONS
// src/AppBundle/Controller/LuckyController.php
// ...

class LuckyController extends Controller
{
    /**
     * @Route("/lucky/number/{count}")
     */
    public function numberAction()
    {
        // ...
    }

    // ...
}

YAML

# app/config/routing.yml
lucky_number:
    path:     /lucky/number/{count}
    defaults: { _controller: AppBundle:Lucky:number }

XML

<!-- src/Acme/DemoBundle/Resources/config/routing.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <route id="lucky_number" path="/lucky/number/{count}">
        <default key="_controller">AppBundle:Lucky:number</default>
    </route>
</routes>

PHP

// src/Acme/DemoBundle/Resources/config/routing.php
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;

$collection = new RouteCollection();
$collection->add('lucky_number', new Route('/lucky/number/{count}', array(
    '_controller' => 'AppBundle:Lucky:number',
)));

return $collection;

Через заповнювач {count}, URL для сторінки інший: тепер він працює для співпадіння /lucky/number/* - наприклад, /lucky/number/5. Найкраще з цього це те, що ви маєте доступ до значення, і можете використовувати це у вашому контролері:

class LuckyController extends Controller
{

    /**
     * @Route("/lucky/number/{count}")
     */
    public function numberAction($count)
    {
        $numbers = array();
        for ($i = 0; $i < $count; $i++) {
            $numbers[] = rand(0, 100);
        }
        $numbersList = implode(', ', $numbers);

        return new Response(
            '<html><body>Lucky numbers: '.$numbersList.'</body></html>'
        );
    }

    // ...
}

Спробуйте перейти на /lucky/number/XX  - замінивши ХХ будь-яким числом:

http://localhost:8000/app_dev.php/lucky/number/7

Ви повинні побачити 7 щасливих чисел! Ви можете дізнатися значення будь-якого {placeholder} у вашому маршруті, додавши аргумент $placeholder до вашого контролера. Лише переконайтеся що вони мають однакові назви.

Система маршрутизації здатна зробити набагато більше, наприклад підтримувати різноманітні заповнювачі (наприклад, /blog/{category}/{page})), робити їх необов’язковими та “змусити” заповнювач збігатися з регулярним виразом (наприклад, {count} повинен бути числом).

Дізнавайтесь про це все, та перетворюйтесь в експерта по маршрутизації. Детальніше читайте розділ Маршрутизація.

Надання Шаблону (разом з Сервіс Контейнером)

Якщо ви повертаєте HTML з вашого контролера, ви беззаперечно хочете отримати шаблон. Нащастя на домомогу прийде  Symfony разом з Twig: легка, потужна, і дуже цікава мова шаблонів.

Поки LuckyController не розширює ніяких базових класів. Найлегший спосіб використовувати Twig - або багато інших інструментів у Symfony - це розширити Контролер, базовий  клас Symfony:

// src/AppBundle/Controller/LuckyController.php
// ...

// --> add this new use statement
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class LuckyController extends Controller
{
    // ...
}

Використання сервісу шаблонів

Це нічого не міняє, але це надає доступ до контейнера Symfony. Контейнер Symfony подібний до масиву обє’кт, що надає вам доступ до кожного корисного об’єкта у системі. Ці корисні об’єкти називають сервісами, і Symfony транспортує разом з сервісом об’єкт, що надає шаблони Twig, a також може завантажувати повідомлення та багато іншого. 

Щоб отримати шаблон Twig, використовуйте сервіс templating:
 // src/AppBundle/Controller/LuckyController.php
// ...

class LuckyController extends Controller
{
    /**
     * @Route("/lucky/number/{count}")
     */
    public function numberAction($count)
    {
        // ...
        $numbersList = implode(', ', $numbers);

        $html = $this->container->get('templating')->render(
            'lucky/number.html.twig',
            array('luckyNumberList' => $numbersList)
        );

        return new Response($html);
    }

    // ...
}

Продовжуючи читати, ви набагато більше вивчите про важливий “сервіс контейнером”. Але на даний момент, вам слід просто знати, що він підтримує багато об’єктів, і ви можете отримати (get()) будь-який обєкт використовуючи його нікнейм, наприклад, templating або logger. Сервіс templating  є прикладом який містить метод render().

Насправді, це робится ще легше! Розширивши клас, ви отримаєте багато раціональніших методів, таких як render():

// src/AppBundle/Controller/LuckyController.php
// ...

/**
 * @Route("/lucky/number/{count}")
 */
public function numberAction($count)
{
    // ...

    /*
    $html = $this->container->get('templating')->render(
        'lucky/number.html.twig',
        array('luckyNumberList' => $numbersList)
    );

    return new Response($html);
    */

    // render: a shortcut that does the same as above
    return $this->render(
        'lucky/number.html.twig',
        array('luckyNumberList' => $numbersList)
    );
}

Вивчайте більше про раціональні методи, та про те, як вони працюють у розділі Контролер.

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

Створіть шаблон 

Якщо ви оновите сторінку, ви отримаєте помилку: Unable to find template "lucky/number.html.twi

Виправте це, створивши новий каталог app/Resources/views/lucky і вставте туди файл number.html.twig:

TWIG

{# app/Resources/views/lucky/number.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    <h1>Lucky Numbers: {{ luckyNumberList }}</h1>
{% endblock %}
 
PHP
<!-- app/Resources/views/lucky/number.html.php -->
<?php $view->extend('base.html.php') ?>

<?php $view['slots']->start('body') ?>
    <h1>Lucky Numbers: <?php echo $view->escape($luckyNumberList) ?>
<?php $view['slots']->stop() ?>

Ласкаво просимо до Twig! Цей простий файл вже показує основу: наприклад, як синтаксис {{ variableName }}  використовується щоб вивести щось на екран. luckyNumberList є змінною, яку ви передасте шаблонові з виклику render у вашому контролері.

{% extends 'base.html.twig' %} вказує на розміщення файлу за адресою app/Resources/views/base.html.twig і “приходить” з вашим новим проектом. Це лише основа, (HTML структура без стилів) і вона повністю у вашому використанні.

Частинка {% block body %} використовує систему наслідування щоб розмістити контент посередині розмітки base.html.twig.

Оновіть, для того доб побачити шаблон у дії.

http://localhost:8000/app_dev.php/lucky/number/9

Якщо ви подивитеся на вихідний код, тепер завдяки base.html.twig у вас є базова структура HTML.

І це лише маленька частинка потужного Twig. Якщо ви готові освоїти його ситнаксис, масиви, отримати інші шаблони та інші класні речі, читайте розділ Створення та використання шаблонів.

Досліджуємо проект

Ви вже створили гнучкий URL, отримали шаблон що використовує наслідування та створили кінцеву точку JSON. Так тримати! Настав час вивчати та пояснити файли у вашому проекті. Ви вже працювали у двох найважливіших каталогах.  

app/

Містить конфігурацію та шаблони. В основному, все що не є PHP кодом розміщене тут.

src/

Тут повинен бути ваш PHP код.

99% часу ви будете працювати у src/  (PHP файли) або у app/ (всі інші файли). Так як ви стаєте обізнанішими, ви вивчите що можна зробити в середині цих каталогів.

Каталог app/ вміщає декілька інших каталогів, наприклад, каталог кешу, каталог логування app/logs/ та app/AppKernel.php, які використовуються для створення нових пакетів ( і одного з найкоротших списків PHP файлів у app/).

Каталог src/ містить лише один AppBundle каталог, у якому знаходиться все інше. Пакет, або як його ще називають, плагін можна знайти у відкритому доступі і встиновити у свій проект. Навіть ваш код “проживає” у пакеті - типічному AppBundle, хоча в ньому немає нічого особливого. Щоб дізнатися більше про пакети і чому ви могли б їх створювати, читайте у розділі Система пакетів.

А тепер поговоримо про інші каталоги у проекті.

vendor/

Бібліотеки та пакети вендора завантажуються менеджером пакету Composer.

web/

Це є корінь документу для проекту який вміщає будь-які доступні файли, наприклад, CSS, зображення для фронт-контролерів Symfony, які виконують додаток (app_dev.php та app.php).

Symfony є гнучкою. Якщо вам потрібно, ви можете легко перевизначити структуру каталогів. Див. розділ Як перевизначити структуру каталогів.

Налаштування програми

Symfony містить декілька вбудованих пакетів (відкрийте файл app/AppKernel.php). Також, якщо необхідно, ви маєте змогу завантажити ще більше. Головний конфігураційний файл для пакетів: app/config/config.yml:

YAML

# app/config/config.yml
# ...

framework:
    secret: "%secret%"
    router:
        resource: "%kernel.root_dir%/config/routing.yml"
    # ...

twig:
    debug:            "%kernel.debug%"
    strict_variables: "%kernel.debug%"

# ...

XML

<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:framework="http://symfony.com/schema/dic/symfony"
    xmlns:twig="http://symfony.com/schema/dic/twig"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/symfony
        http://symfony.com/schema/dic/symfony/symfony-1.0.xsd
        http://symfony.com/schema/dic/twig
        http://symfony.com/schema/dic/twig/twig-1.0.xsd">

    <!-- ... -->

    <framework:config secret="%secret%">
        <framework:router resource="%kernel.root_dir%/config/routing.xml" />
        <!-- ... -->
    </framework:config>

    <!-- Twig Configuration -->
    <twig:config debug="%kernel.debug%" strict-variables="%kernel.debug%" />

    <!-- ... -->
</container>

PHP

// app/config/config.php
// ...

$container->loadFromExtension('framework', array(
    'secret' => '%secret%',
    'router' => array(
        'resource' => '%kernel.root_dir%/config/routing.php',
    ),
    // ...
));

// Twig Configuration
$container->loadFromExtension('twig', array(
    'debug'            => '%kernel.debug%',
    'strict_variables' => '%kernel.debug%',
));

// ...

Ключ  framework налаштовує FrameworkBundle, ключ twig налаштовує TwigBundle і так далі. Контролюйте багато властивостей у Symfony, міняючи лише одну опцію у конфігураційному файлі. Для того щоб дізнатися як це працює, читайте в оригіналі розділ Конфігурація.

Або ж,  щоб отримати кращий приклад, позбудьтеся дійсного налаштування під ключем, використовуючи зручну команду app/console:

 $ app/console config:dump-reference framework

Система налаштувань Symfony є надзвичайно потужною, включаючи середовища, імпорти та параметри. Детальніше читайте розділ Налаштування Symfony (і середовищ).

Що ж далі?

Вітаємо! Ви нарешті розпочали опановувати Symfony і вивчати повністю новий метод створення гарних, фунціональних, швидких і підтримуваних додатків.

Добре, настав час закінчити вивчати базові поняття, прочитавши ці розділи:

1) Контролер

2) Маршрутизація

3) Створення та використання шаблонів

Пізніше, почитайте та дізнайтеся у Symfony Book про сервіс контейнером, систему форм, використовуючи цю теорію (якщо вам потрібно робити запит до бази даних) та ще більше!

Ви також можете почитати Довідник, де в знайдете більш поглиблені статті, про вирішення багатьох проблем.

Насолоджуйтесь!

Поділитися