Миграция с Symfony 2.0 до 2.6

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

Менеджер зависимостей

В каждом проекте Symfony есть свои зависимости (бандлы). В версии 2.0 зависимости указывались в файле deps и подтягивались командой:

 php bin/vendors install

Сейчас для этих целей актуально использовать Composer.

Скачиваем Composer в корень репозитория:

php -r "readfile('https://getcomposer.org/installer');" | php


Затем мы создаем в корне проекта файл composer.json с следующим содержанием:
github.com/symfony/symfony/blob/2.6/composer.json
И выполням команду:

php composer.phar update

После этого к нашему проекту подтянется Symfony 2.6 со всеми нужными для него зависимостями и создастся файл composer.lock, в который запишутся актуальные версии скачанных зависимостей.

Все, что нам осталось — это добавить в файл composer.json нужные нам зависимости. Это можно сделать вручную, редактируя файл:

"require": {
        "{название зависимости}":"{версия зависимости}"
    },

Либо с помощью команды:

php composer.phar require {название зависимости}:{версия зависимости}

Теперь у нас есть все необходимы бандлы и мы можем удалить файлы deps и deps.lock, но для корректной работы фреймворка нам так же следует обновить файлы web/app.php и web/app_dev.php:

app.php

<?php

use Symfony\Component\ClassLoader\ApcClassLoader;
use Symfony\Component\HttpFoundation\Request;

$loader = require_once __DIR__.'/../app/bootstrap.php.cache';

// Enable APC for autoloading to improve performance.
// You should change the ApcClassLoader first argument to a unique prefix
// in order to prevent cache key conflicts with other applications
// also using APC.
/*
$apcLoader = new ApcClassLoader(sha1(__FILE__), $loader);
$loader->unregister();
$apcLoader->register(true);
*/

require_once __DIR__.'/../app/AppKernel.php';
//require_once __DIR__.'/../app/AppCache.php';

$kernel = new AppKernel('prod', false);
$kernel->loadClassCache();
//$kernel = new AppCache($kernel);

// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
//Request::enableHttpMethodParameterOverride();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);


app_dev.php

<?php

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Debug\Debug;

// If you don't want to setup permissions the proper way, just uncomment the following PHP line
// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
//umask(0000);

// This check prevents access to debug front controllers that are deployed by accident to production servers.
// Feel free to remove this, extend it, or make something more sophisticated.
if (isset($_SERVER['HTTP_CLIENT_IP'])
    || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
    || !(in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1')) || php_sapi_name() === 'cli-server')
) {
    header('HTTP/1.0 403 Forbidden');
    exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}

$loader = require_once __DIR__.'/../app/bootstrap.php.cache';
Debug::enable();

require_once __DIR__.'/../app/AppKernel.php';

$kernel = new AppKernel('dev', true);
$kernel->loadClassCache();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

Параметры

Для версии Symfony 2.0 параметры подгружались из файла app/config/parameters.ini. Все что нам нужно — это переименовать его в app/config/parameters.yml и привести к виду yml файла:

Before:


[parameters] 
     locale = en 

After:


parameters:
     locale: en 

Затем в app/config/config.yml пропишем путь для нашего файла:

imports:
    - { resource: parameters.yml }

Параметры изменены и подключены.

Обратная совместимость функций

С версии 2.0 до 2.6 произошло довольно много изменений, я бы хотел рассказать только о некоторых из них.

Формы:

Некоторые функции теперь вызывают исключения, если их использовать на уже отправленной форме:
add(), remove(), setParent(), bind() and setData()


Их можно вызывать из listener в formBuilder непосредственно перед отправкой формы, либо немного изменить логику работы вашей формы. Но в качестве временной меры можно воспользоваться таким вот кодом:

$formData = $form->getData();
$form = $this->createForm(new YourForm());
$form->setData($formData);

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

Валидация форм:

Вместо использования в FormBulder более не существующего класса CallbackValidation мы просто используем EventListener, после того, как форма уже отправлена т.е. POST_SUBMIT.

Before:

 $builder->addValidator(new CallbackValidator(function (FormInterface $form) {
                $value = $form['date']->getData();
                if ($value != null) {
                    $form['date']->addError(new FormError('Введена некорректная дата'));
                }
            }));

After:

  $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
            $form = $event->getForm();
            $value = $form['date']->getData();
            if ($value != null) {
                $form['date']->addError(new FormError('Введена некорректная дата'));
            }
        });


Добавление своей опции в поле формы

При создании своей опции в поле формы MyBundle\Forms\ExtensionExtensionForm.php; необходимо указывать, для какого типа полей будут добавляются эти опции:

public function getExtendedType()
    {
        return 'text';
    }

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

 public function getExtendedType()
    {
        return 'form';
    }


Полный перечень изменений


github.com/symfony/symfony/blob/2.7/UPGRADE-2.1.md
github.com/symfony/symfony/blob/2.7/UPGRADE-2.2.md
github.com/symfony/symfony/blob/2.7/UPGRADE-2.3.md
github.com/symfony/symfony/blob/2.7/UPGRADE-2.4.md
github.com/symfony/symfony/blob/2.7/UPGRADE-2.5.md
github.com/symfony/symfony/blob/2.7/UPGRADE-2.6.md

Официальная документация Symfony: symfony.com/doc/current/cookbook/index.html
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 9

    +8
    И выполням команду:

    И все хорошо ровно до того момента, пока мы не понимаем что там же еще целый ворах бандлов у нас в проекте юзается! И как это не смешно, парочка уже настолько старые, что их авторы удалили репозитории!
      0
      Мне повезло, бандлы, которые использовались в проекте все еще существуют и развиваются. Некоторые поменяли свои названия или были разбиты на более мелкие бандлы. Конечно, если репозиторий бандла более не существует, то логично функицонал, который использовался с этим бандлом, переписать на другой, более новый, либо оставить старую версию прямо в папке vendors. Если мы будет подтягивать зависимости composer'ом, то папку этого бандла он не затрет.
        0
        у меня был неприятный опыт обновления с 2.0 до 2.3 помниться, и я страдал, подбирая версии вендоров и перенося код. Благо это было давно, да и боль обычно именно 2.0 -> 2.1 + composer. А потом как-то спокойнее. Благо с обратной совместимостью у симфони все круто.
          0
          Да, внедрение composer больнее всего было, так как парадигма подключения вендоров менялась. Остальное более-менее покрывалось UPGRADE гайдами.
      +3
      Браво! Безумству храбрых поем мы песню!

      Если проект активно развивается, мне кажется его основа тоже не должна быть 3-4 летней давности. Правда заказчику пофиг какое там симфони под капотом… Приходится искать баланс между качеством — временем внедрения и стоимостью ))

        +1
        Породируя анекдоты про эстонцев «Что-то симфони обновилось...»

        Такое обновление происходит только в случае когда проект воскрес через 3-4 года после того как его забросили или же в еще более тяжелом случае, когда предыдущие разработчики были приверженцами «работает не трогай» в терминальной стадии.

        Мне кажется что в конце пропущена фраза «а потом смотрим что из проекта еще вдруг случайно заработало», потому что количество изменений которые произошли просто огромно
          0
          На сколько понимаю, возможные сложности с обновлением фреймворка и стали причиной, по которой отказались от схемы «один фреймворк на всю систему» (так было в 1.х) в пользу «каждому проекту свой фреймворк». Косвенно это подтверждает и версионность документации. Что касается проблемы с совместимостью сторонних бандлов, то всегда можно склонировать, прописать в зависимости и развивать свою версию (а благодаря git изменения оригинального можно подтягивать по мере необходимости).
            0
            Не «каждому проекту свой фреймворк» а «для каждой задачи свой компонент». Все же есть разница. Это позволяет проектировать более гибкую систему, такую систему проще поддерживать. less is more как говорится. Обновление отдельных компонентов так же проще чем обновление всего фреймворка, но это как следствие а не основная причина.
              0
              Я имел в виду то, что версия 1.х устанавливалась как расширение php и использовалась совместно всеми проектами на данном сервере. В версии 2.х от этого отказались, и для каждого проекта используется свой экземпляр. Фабиэн писал о том, что так сделали именно для того, чтобы не было проблем с версиями. Какая проекту версия нужна, такая в нем и содержится.

          Only users with full accounts can post comments. Log in, please.