Installing & setting up the symfony framework

Creating Symfony Applications¶

Open your console terminal and run any of these commands to create a new Symfony application:

1
2
3
4
5
# run this if you are building a traditional web application
$ symfony new my_project_name --full

# run this if you are building a microservice, console application or API
$ symfony new my_project_name

The only difference between these two commands is the number of packages installed by default. The option installs all the packages that you usually need to build web applications, so the installation size will be bigger.

If you’re not using the Symfony binary, run these commands to create the new Symfony application using Composer:

1
2
3
4
5
# run this if you are building a traditional web application
$ composer create-project symfony/website-skeleton my_project_name

# run this if you are building a microservice, console application or API
$ composer create-project symfony/skeleton my_project_name

No matter which command you run to create the Symfony application. All of them will create a new directory, download some dependencies into it and even generate the basic directories and files you’ll need to get started. In other words, your new application is ready!

Checking out the Project Structure¶

Great news! You’ve already worked inside the most important directories in your project:

Contains… configuration!. You will configure routes, services and packages.
All your PHP code lives here.
All your Twig templates live here.

Most of the time, you’ll be working in , or . As you keep reading, you’ll learn what can be done inside each of these.

So what about the other directories in the project?


The famous file lives here (and other, less important executable files).
This is where automatically-created files are stored, like cache files () and logs ().
Third-party (i.e. “vendor”) libraries live here! These are downloaded via the Composer package manager.
This is the document root for your project: you put any publicly accessible files here.

Technical Requirements¶

Before creating your first Symfony application you must:

  • Install PHP 7.2.5 or higher and these PHP extensions (which are installed and enabled by default in most PHP 7 installations): Ctype, iconv, JSON, PCRE, Session, SimpleXML, and Tokenizer;
  • Install Composer, which is used to install PHP packages.

Optionally, you can also install Symfony CLI. This creates a binary called that provides all the tools you need to develop and run your Symfony application locally.

The binary also provides a tool to check if your computer meets all requirements. Open your console terminal and run this command:

1
$ symfony check:requirements

Migrations & Adding more Fields¶

But what if you need to add a new field property to , like a ? You can edit the class to add the new property. But, you can also use again:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ php bin/console make:entity

Class name of the entity to create or update
> Product

New property name (press <return> to stop adding fields):
> description

Field type (enter ? to see all types) string:
> text

Can this field be null in the database (nullable) (yes/no) no:
> no

New property name (press <return> to stop adding fields):
>
(press enter again to finish)

This adds the new property and and methods:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// src/Entity/Product.php
// ...

class Product
{
    // ...

+     /**
+      * @ORM\Column(type="text")
+      */
+     private $description;

    // getDescription() & setDescription() were also added
}

The new property is mapped, but it doesn’t exist yet in the table. No problem! Generate a new migration:

1
$ php bin/console make:migration

This time, the SQL in the generated file will look like this:

1
ALTER TABLE product ADD description LONGTEXT NOT NULL

The migration system is smart. It compares all of your entities with the current state of the database and generates the SQL needed to synchronize them! Like before, execute your migrations:

1
$ php bin/console doctrine:migrations:migrate

This will only execute the one new migration file, because DoctrineMigrationsBundle knows that the first migration was already executed earlier. Behind the scenes, it manages a table to track this.

Each time you make a change to your schema, run these two commands to generate the migration and then execute it. Be sure to commit the migration files and execute them when you deploy.

Окружения (environments)

Если Вы заглянете в директорию , Вы найдете два PHP-файла: и . Эти файлы называются фронт- контроллерами; все запросы к приложению проходят через них. Но почему мы должны иметь два фронт-контроллера для каждого приложения?

Оба файла относятся к одному приложению, но к разным окружениям. Когда Вы разрабатываете приложение, исключая случаи, когда Вы работаете непосредственно на промышленном сервере, Вам нужно несколько окружений:

  • Окружение разработки: Используется веб-разработчиками, когда они работают над приложением, чтобы добавить новый функционал, исправить ошибки и т.д.

  • Тестовое окружение: Используется для запуска автоматизированных тестов приложения.

  • Демонстрационное (staging) окружение: Используется заказчиком для поиска ошибок и недоделок.

  • Промышленное (production) окружение: Используется конечными пользователями.

Что делает окружение уникальным? К примеру в окружении разработки, приложение должно логгировать все детали запроса для облегчения отладки, а система кэширования должна быть отключена, чтобы все сделанные в коде изменения, сразу же были видны. Т.о., окружение разработки должно быть оптимальным для разработчика. Лучшей иллюстрацией будет ситуация возникновения исключения. Чтобы помочь разработчику быстрее понять, что произошло, Symfony отображает всю информацию об исключении и текущих параметрах запроса прямо в браузере:

Однако, в промышленном окружении, кэш должен быть включен, и, конечно, приложение должно отображать понятные пользователям сообщения об ошибках, вместо описания исключений. Т.о., промышленное окружение доложно быть оптимизировано для максимального комфорта конечного пользователя.

tip

Если Вы откроете файлы фронт-контроллеров, Вы увидите, что их содержимое одинаково, за исключением настройки окружения:

// web/index.php
<?php
 
require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');
 
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', false);
sfContext::createInstance($configuration)->dispatch();

Панель отладки тоже является хорошим примером использования разных окружений. Она присутствует на всех страницах в окружении разработки и дает Вам доступ к большому количеству информации при помощи кликов по различным иконкам: текущая конфигурация приложения, логи текущего запроса, SQL-запросы, выполненные в базе данных, используемая память, время загрузки страницы.

Фабрики (Factories)

В течение всего учебника Jobeet, мы говорим об объектах ядра Symfony, таких как , , , , и тому подобных. Эти объекты автоматически создаются, настраиваются и управляются фреймворком Symfony. Все они доступны при помощи объекта , и так же, как многие вещи во фреймворке, они настраиваются в конфигурационном файле: . Этот файл позволяет настраивать различные окружения.

Когда инициализирует фабрики объектов ядра, он читает файл , чтобы узнать имя класса () и параметры (), которые будут переданы в конструктор объекта:

response:
  class: sfWebResponse
  param:
    send_http_headers: false

В предыдущем фрагменте кода, чтобы создать фабрику ответов сервера, Symfony создает объект и передает его конструктору значение опции в качестве параметра.

Возможность настройки объектов ядра означает, что Вы можете использовать свой собственный класс для объектов ядра Symfony вместо используемого по умолчанию. Вы можете также изменять поведение этих классов, меняя параметры конструкторов.

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

Имена куки-объектов (cookies)

Для хранения информации о сессии пользователя, Symfony использует куки. Эти куки имеют имя по умолчанию , которое может быть изменено в файле . После ключа добавьте следующую конфигурацию, чтобы сменить имя куки на :

# apps/frontend/config/factories.yml
storage:
  class: sfSessionStorage
  param:
    session_name: jobeet

Хранение сессии

По умолчанию для хранения сессий используется класс . Он использует файловую систему для хранения информации о сессиях. Если у Вас несколько веб-серверов, Вы можете захотеть хранить информацию о сессии в централизованном хранилище, таком, как таблица базы данных:

# apps/frontend/config/factories.yml
storage:
  class: sfPDOSessionStorage
  param:
    session_name: jobeet
    db_table:     session
    database:     doctrine
    db_id_col:    id
    db_data_col:  data
    db_time_col:  time

Таймаут сессии

По умолчанию время жизни пользовательской сессии секунд. Этот параметр может быть изменен в секции :

# apps/frontend/config/factories.yml
user:
  class: myUser
  param:
    timeout: 1800

Логгирование

По умолчанию в окружении логгирование выключено, поскольку имя класса логгера :

# apps/frontend/config/factories.yml
prod:
  logger:
    class:   sfNoLogger
    param:
      level:   err
      loggers: ~

Вы можете, к примеру, разрешить логгирование в файловой системе, изменив имя класса логгера на :

# apps/frontend/config/factories.yml
logger:
  class: sfFileLogger
  param:
    level: error
    file:  %SF_LOG_DIR%/%SF_APP%_%SF_ENVIRONMENT%.log

note

В конфигурационном файле , строки вида заменяются соответствующими значениями из объекта . Так, в файле конфигурации эквивалентно в коде PHP. Эта нотация также может быть использована в файле . Это очень удобно, когда Вам нужно использовать путь в конфигурационном файле без жесткого кодирования пути (, , …).

Fetching Objects from the Database¶

Fetching an object back out of the database is even easier. Suppose you want to be able to go to to see your new product:

// src/Controller/ProductController.php
// ...

/**
 * @Route("/product/{id}", name="product_show")
 */
public function show($id)
{
    $product = $this->getDoctrine()
        ->getRepository(Product::class)
        ->find($id);

    if (!$product) {
        throw $this->createNotFoundException(
            'No product found for id '.$id
        );
    }

    return new Response('Check out this great product: '.$product->getName());

    // or render a template
    // in the template, print things with {{ product.name }}
    // return $this->render('product/show.html.twig', );
}

Another possibility is to use the using Symfony’s autowiring and injected by the dependency injection container:

// src/Controller/ProductController.php
// ...
use App\Repository\ProductRepository;

/**
 * @Route("/product/{id}", name="product_show")
 */
public function show($id, ProductRepository $productRepository)
{
    $product = $productRepository
        ->find($id);

    // ...
}

Try it out!

When you query for a particular type of object, you always use what’s known as its “repository”. You can think of a repository as a PHP class whose only job is to help you fetch entities of a certain class.

Once you have a repository object, you have many helper methods:

$repository = $this->getDoctrine()->getRepository(Product::class);

// look for a single Product by its primary key (usually "id")
$product = $repository->find($id);

// look for a single Product by name
$product = $repository->findOneBy();
// or find by name and price
$product = $repository->findOneBy();

// look for multiple Product objects matching the name, ordered by price
$products = $repository->findBy(
    'name' => 'Keyboard'],
    'price' => 'ASC'
);

// look for *all* Product objects
$products = $repository->findAll();

You can also add custom methods for more complex queries! More on that later in the section.

Установка Symfony

Инициализация директории проекта

Прежде, чем инсталлировать Symfony, Вы сначала должны создать директорию, которая будет содержать все файлы, относящиеся к Jobeet:

Или на Windows:

note

Пользователям Windows рекомендуется устанавливать Symfony в папку, путь которой не содержит пробелов. Старайтесь не использовать папку , а также папки типа

TIP: Если Вы создали директорию проекта Symfony в корневой директории веб-сервера, Вам не нужно дополнительно конфигурировать сервер. Конечно, для промышленного использования мы настоятельно рекомендуем Вам настроить свой веб-сервер, как описано в секции «Настройка веб-сервера: безопасный способ».

Выбор версии Symfony

Теперь Вам нужно установить Symfony. Поскольку Symfony имеет несколько стабильных релизов, Вам нужно выбрать один, который Вы хотите установить, прочитав страницу инсталляции на сайте Symfony.

Эта книга предполагает, что Вы выбрали Symfony 1.3 или Symfony 1.4.

Выбор инсталляционной директории Symfony

Вы можете установить Symfony на своей машине глобально, либо встраивать ее в каждый свой проект. Последний вариант предпочтительнее, поскольку тогда все Ваши проекты будут полностью независимы друг от друга. Обновляя локально установленную Symfony, Вы не нарушите неожиданно работу остальных своих приложений. Это означает, что Вы можете использовать в разных проектах разные версии Symfony и обновлять их по одной, если увидите в этом необходимость.

Поскольку это является лучшей практикой, многие разработчики устанавливают файлы Symfony в директорию своего проекта. Таким образом, для начала создайте эту директорию:

Установка из архива

Самый простой способ установить Symfony — скачать архив выбранной Вами версии с сайта Symfony. Перейдите на страницу инсталляции для выбранной версии, например 1.4.

В секции «Source Download» Вы найдете архив в формате или . Скачайте его, положите в свежесозданную директорию , разархивируйте, и переименуйте появившуюся директорию в :

Под Windows распакуйте zip-файл, используя проводник Windows (Explorer). Когда Вы переименуете директорию в , структура директорий будет примерно такой .

Установка из Subversion (рекомендуемый вариант)

Если Вы используете Subversion, то лучший вариант — использовать свойство , чтобы встроить Symfony в Ваш проект, в директорию :


note

Импорт Вашего проекта в новый репозиторий Subversion описывается в конце главы.

Если все сделано правильно, эта команда откроет Ваш любимый текстовый редактор, чтобы дать возможность настроить внешнюю ссылку Subversion.

tip

Под Windows Вы можете использовать интерфейс к Subversion, например TortoiseSVN, чтобы выполнять всю работу, не используя консоль.

Если Вы консервативны, свяжите свой проект с конкретным релизом (тэгом Subversion):

Как только новый релиз будет анонсирован (см. Symfony blog), Вам нужно будет поменять URL на новую версию.

Если же Вы хотите находиться на переднем крае, используйте ветку 1.4:

Использование ветки дает Вашему проекту преимущество в использовании всех исправлений (bug fixes) автоматически, как только Вы запустите .

Проверка правильности установки

Теперь, когда Symfony установлена, проверим, что все работает, используя командную строку Symfony для отображения текущей версии (обратите внимание на заглавную ):

На Windows:

Опция также выводит путь к инсталляционной директории Symfony, которая хранится в файле .

Если путь к Symfony абсолютный (чего не должно быть по умолчанию, если Вы следовали вышеприведенным инструкциям), измените его так, чтобы он выглядел примерно так (для обеспечения переносимости):

// config/ProjectConfiguration.class.php
require_once dirname(__FILE__).'/../lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php';

Таким образом, Вы сможете переносить директорию проекта в любой место на своей или другой машине, и все будет работать.

tip

Если Вам не терпится узнать, что командная строка Symfony может сделать для Вас, наберите , чтобы увидеть список всех доступных задач и опций:

На Windows:

Командная строка Symfony — это лучший друг разработчика. Она обеспечивает большое число утилит, для повышения продуктивности Ваший ежедневных действий, таких как очистка кэша, генерация кода и многое другое.

Подготовка промышленного сервера

Прежде чем развертывать наше приложения на промышленном сервере, мы должны убедиться, что сервер настроен правильно. Можете перечитать урок 1, где объяснялось, как настраивать веб-сервер.

В этой главе мы предполагаем, что Вы уже установили веб-сервер, сервер базы данных и PHP 5.2.4 или более поздний.

note

Если Вы не имеете доступа к веб-серверу по SSH, пропустите ту часть, где Вам нужно иметь доступ к командной строке.

Конфигурация сервера

Сначала Вы должны убедиться, что PHP установлено со всеми необходимыми расширениями и правильно настроено. Так же, как в уроке 1, мы будем использовать скрипт , предоставляемый Symfony. Так как мы не будем устанавливать Symfony на промышленном сервере, скачайте файл напрямую с сайта Symfony:

Скопируйте файл в корневую директорию веб-сервера и запустите его и в браузере, и из командной строки:

Исправьте все фатальные ошибки, которые обнаружил скрипт, и повторите процесс, пока все не будет работать хорошо в обеих средах.

PHP ускоритель (Accelerator)

Для промышленного сервера Вы, возможно, хотите получить лучшую возможную производительность. Установка PHP ускорителя даст Вам лучшее ускорение за Ваши деньги.

note

Из Википедии: PHP ускоритель кэширует скомпилированный байт-код PHP скриптов, чтобы избежать интерпретации и компиляции исходного кода на каждый запрос.

APC — один из самых популярных ускорителей, который очень просто установить:

В зависимости от Вашей операционной системы, Вам возможно также придется установить его при помощи ОС-зависимого менеджера пакетов.

note

Потратьте некоторое время, чтобы изучить, как настроить APC.

Testing HTTP Clients and Responses¶

This component includes the and classes to use them in tests that need an HTTP client which doesn’t make actual HTTP requests.

The first way of using is to pass a list of responses to its constructor. These will be yielded in order when requests are made:

use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;

$responses = 
    new MockResponse($body1, $info1),
    new MockResponse($body2, $info2),
];

$client = new MockHttpClient($responses);
// responses are returned in the same order as passed to MockHttpClient
$response1 = $client->request('...'); // returns $responses
$response2 = $client->request('...'); // returns $responses

Another way of using is to pass a callback that generates the responses dynamically when it’s called:

use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;

$callback = function ($method, $url, $options) {
    return new MockResponse('...');
};

$client = new MockHttpClient($callback);
$response = $client->request('...'); // calls $callback to get the response

The responses provided to the mock client don’t have to be instances of . Any class implementing will work (e.g. ).

However, using allows simulating chunked responses and timeouts:

$body = function () {
    yield 'hello';
    // empty strings are turned into timeouts so that they are easy to test
    yield '';
    yield 'world';
};

$mockResponse = new MockResponse($body());

Persisting Objects to the Database¶

It’s time to save a object to the database! Let’s create a new controller to experiment:

1
$ php bin/console make:controller ProductController

Inside the controller, you can create a new object, set data on it, and save it:

// src/Controller/ProductController.php
namespace App\Controller;

// ...
use App\Entity\Product;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Response;

class ProductController extends AbstractController
{
    /**
     * @Route("/product", name="create_product")
     */
    public function createProduct() Response
    {
        // you can fetch the EntityManager via $this->getDoctrine()
        // or you can add an argument to the action: createProduct(EntityManagerInterface $entityManager)
        $entityManager = $this->getDoctrine()->getManager();

        $product = new Product();
        $product->setName('Keyboard');
        $product->setPrice(1999);
        $product->setDescription('Ergonomic and stylish!');

        // tell Doctrine you want to (eventually) save the Product (no queries yet)
        $entityManager->persist($product);

        // actually executes the queries (i.e. the INSERT query)
        $entityManager->flush();

        return new Response('Saved new product with id '.$product->getId());
    }
}

Try it out!

Congratulations! You just created your first row in the table. To prove it, you can query the database directly:

1
2
3
4
$ php bin/console doctrine:query:sql 'SELECT * FROM product'

# on Windows systems not using Powershell, run this command instead:
# php bin/console doctrine:query:sql "SELECT * FROM product"

Take a look at the previous example in more detail:

  • line 18 The method gets Doctrine’s entity manager object, which is the most important object in Doctrine. It’s responsible for saving objects to, and fetching objects from, the database.
  • lines 20-23 In this section, you instantiate and work with the object like any other normal PHP object.
  • line 26 The call tells Doctrine to “manage” the object. This does not cause a query to be made to the database.
  • line 29 When the method is called, Doctrine looks through all of the objects that it’s managing to see if they need to be persisted to the database. In this example, the object’s data doesn’t exist in the database, so the entity manager executes an query, creating a new row in the table.

Note

If the call fails, a exception is thrown. See Transactions and Concurrency.

Where Symfony Delivers¶

In the rest of the documentation articles, you’ll learn more about how each piece of Symfony works and how you can organize your project. For now, celebrate how migrating the blog from flat PHP to Symfony has improved your life:

  • Your application now has clear and consistently organized code (though Symfony doesn’t force you into this). This promotes reusability and allows for new developers to be productive in your project more quickly;
  • 100% of the code you write is for your application. You don’t need to develop or maintain low-level utilities such as autoloading, routing, or rendering controllers;
  • Symfony gives you access to open source tools such as Doctrine and the Templating, Security, Form, Validator and Translation components (to name a few);
  • The application now enjoys fully-flexible URLs thanks to the Routing component;
  • Symfony’s HTTP-centric architecture gives you access to powerful tools such as HTTP caching powered by Symfony’s internal HTTP cache or more powerful tools such as Varnish. This is covered in another article all about caching.

And perhaps best of all, by using Symfony, you now have access to a whole set of high-quality open source tools developed by the Symfony community! A good selection of Symfony community tools can be found on GitHub.

Creating a Page: Route and Controller¶

Tip

Before continuing, make sure you’ve read the Setup article and can access your new Symfony app in the browser.

Suppose you want to create a page — — that generates a lucky (well, random) number and prints it. To do that, create a “Controller” class and a “controller” method inside of it:

<?php
// src/Controller/LuckyController.php
namespace App\Controller;

use Symfony\Component\HttpFoundation\Response;

class LuckyController
{
    public function number() Response
    {
        $number = random_int(, 100);

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

Now you need to associate this controller function with a public URL (e.g. ) so that the method is executed when a user browses to it. This association is defined by creating a route in the file:

1
2
3
4
5
6
# config/routes.yaml

# the "app_lucky_number" route name is not important yet
app_lucky_number
    path /lucky/number
    controller App\Controller\LuckyController::number

That’s it! If you are using Symfony web server, try it out by going to: http://localhost:8000/lucky/number

If you see a lucky number being printed back to you, congratulations! But before you run off to play the lottery, check out how this works. Remember the two steps to creating a page?

Importing Many Services at once with resource¶

You’ve already seen that you can import many services at once by using the key. For example, the default Symfony configuration contains this:

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # config/services.yaml
    services
        # ... same as before
    
        # makes classes in src/ available to be used as services
        # this creates a service per class whose id is the fully-qualified class name
        App\
            resource '../src/*'
            exclude '../src/{DependencyInjection,Entity,Tests,Kernel.php}'
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <!-- config/services.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"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            https://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <!-- ... same as before -->
    
            <prototype namespace="App\" resource="../src/*" exclude="../src/{DependencyInjection,Entity,Tests,Kernel.php}"/>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // config/services.php
    namespace Symfony\Component\DependencyInjection\Loader\Configurator;
    
    return function(ContainerConfigurator $configurator) {
        // ...
    
        // makes classes in src/ available to be used as services
        // this creates a service per class whose id is the fully-qualified class name
        $services->load('App\\', '../src/*')
            ->exclude('../src/{DependencyInjection,Entity,Tests,Kernel.php}');
    };
    

Tip

The value of the and options can be any valid glob pattern.

This can be used to quickly make many classes available as services and apply some default configuration. The of each service is its fully-qualified class name. You can override any service that’s imported by using its id (class name) below (e.g. see ). If you override a service, none of the options (e.g. ) are inherited from the import (but the overridden service does still inherit from ).

You can also certain paths. This is optional, but will slightly increase performance in the environment: excluded paths are not tracked and so modifying them will not cause the container to be rebuilt.

Note

Wait, does this mean that every class in is registered as a service? Even model classes? Actually, no. As long as you keep your imported services as , all classes in that are not explicitly used as services are automatically removed from the final container. In reality, the import means that all classes are “available to be used as services” without needing to be manually configured.

The Crawler¶

A Crawler instance is returned each time you make a request with the Client. It allows you to traverse HTML documents, select nodes, find links and forms.

Traversing

Like jQuery, the Crawler has methods to traverse the DOM of an HTML/XML document. For example, the following finds all elements, selects the last one on the page, and then selects its immediate parent element:

$newCrawler = $crawler->filter('input')
    ->last()
    ->parents()
    ->first()
;

Many other methods are also available:

Nodes that match the CSS selector.
Nodes that match the XPath expression.
Node for the specified index.
First node.
Last node.
Siblings.
All following siblings.
All preceding siblings.
Returns the parent nodes.
Returns children nodes.
Nodes for which the callable does not return false.

Since each of these methods returns a new instance, you can narrow down your node selection by chaining the method calls:

$crawler
    ->filter('h1')
    ->reduce(function ($node, $i) {
        if (!$node->attr('class')) {
            return false;
        }
    })
    ->first()
;

Tip

Use the function to get the number of nodes stored in a Crawler:

Extracting Information

The Crawler can extract information from the nodes:

use Symfony\Component\DomCrawler\Crawler;

// returns the attribute value for the first node
$crawler->attr('class');

// returns the node value for the first node
$crawler->text();

// returns the default text if the node does not exist
$crawler->text('Default text content');

// pass TRUE as the second argument of text() to remove all extra white spaces, including
// the internal ones (e.g. "  foo\n  bar    baz \n " is returned as "foo bar baz")
$crawler->text(null, true);

// extracts an array of attributes for all nodes
// (_text returns the node value)
// returns an array for each element in crawler,
// each with the value and href
$info = $crawler->extract();

// executes a lambda for each node and return an array of results
$data = $crawler->each(function (Crawler $node, $i) {
    return $node->attr('href');
});

ШАГ 5. Создание первой страницы

Для создания новой страницы нам нужно:

1. Настроить маршрут

Маршрутом (route) принято называть соответствие пути в адресной строке определенному контроллеру.

Symfony предлагает нам несколько вариантов задания роутов: xml, yml, ini, php, annotation. Рекомендуемый разработчиками подход — annotation. По их словам, это позволяет нам иметь всю необходимую информацию под рукой и не просматривать несколько файлов конфигурации.

Основные правила роутинга хранятся в файле /app/config/routing.yml. По умолчанию мы можем увидеть там следующее:


Это означает, что все роуты для контроллеров в папке /src/AppBundle/Controllers описываются с помощью аннотаций в контроллерах.

2. Создать контроллер для страницы

Назовем наш контроллер IndexController и сохраним в файле /src/AppBundle/IndexController.php. Сразу скажу, что разработчики фреймворка рекомендуют создавать только один бандл приложения AppBundle  и располагать там все компоненты приложения, если только вы не хотите использовать какой-либо функционал в другом приложении.

Пишем следующий код в контроллере.

Таким образом, мы создали action hello, который ожидает параметр name, далее мы отрисовываем наше представление, передавая этот параметр.

Тут важно отметить, что любой action в Symfony  должен возвращать объект Response. Поэтому в коде мы видем оператор return

3. Создать файл представления для страницы (view)

Symfony и тут дает нам право выбора шаблонизатора, но мы будем пользоваться дефолтным — Twig, ибо он воистину прекрасен и дает возможность наследовать шаблоны, и, соответственно, переопределять некоторые их блоки. Здесь мы создаем папку, одноименную с нашим контроллером — index, и, собственно, файл представления hello.html.twig.  Имя файла расшифровывается следующим образом:

— hello: имя action

— html: формат представления. Также может быть xml, json и др.

Пишем следующий код в файле:

Ну что, посмотрим на результат.

Подведем итоги. Мы научились разворачивать новый Symfony проект, посмотрели на структуру директорий в нем, бегло познакомились с конфигурацией проекта, маршрутами и шаблонизатором. Теперь все это, в том числе и создание новой страницы не должно быть проблемой. Но это только начало, основа основ. Symfony таит в себе множество интересного. Еще несколько интересных базовых вещей ищите в продолжении этой статьи.

Часть 1 | Часть 2


С этим читают