- assume your code doesn't use any deprecated from versions below Symfony 2.3
- update dependencies from 2.3 to 2.7
- do not support "deprecated", be "Symfony3-ready"
- list tasks component by component, bundle by bundle.
Start by updating your composer.json
changes to allow for 2.7.*
:
{
"require": {
"php": ">=5.3.3",
"symfony/symfony" : "2.7.*",
"...": "..."
}
}
Now update this with composer:
composer update symfony/symfony sensio/distribution-bundle --with-dependencies
- The
__toString()
method of the\Symfony\Component\Config\ConfigCache
is marked as deprecated in favor of the newgetPath()
method. - The namespace
Symfony\Component\Config\Definition\ReferenceDumper
is marked as deprecated, useSymfony\Component\Config\Definition\Dumper\YamlReferenceDumper
instead.
-
The
Symfony\Component\Console\Input\InputDefinition::getSynopsis()
method now has an optional argument (it previously had no arguments). If you override this method, you'll need to add this argument so that your signature matches:Before:
public function getSynopsis(){/*..*/}
After:
public function getSynopsis($short = false){/*..*/}
-
Console Text and XML representations (and options) are marked as deprecated, and be removed in 3.0.
-
The
Symfony\Component\Console\Helper\DialogHelper
is deprecated in favor ofSymfony\Component\Console\Helper\QuestionHelper
. -
The
Symfony\Component\Console\Helper\ProgressHelper
is deprecated in favor ofSymfony\Component\Console\Helper\ProgressBar
. -
The method
getStep()
fromSymfony\Component\Console\Helper\ProgressBar
is deprecated in favor ofgetProgress()
. -
The method
setCurrent()
fromSymfony\Component\Console\Helper\ProgressBar
is deprecated in favor ofsetProgress()
.
-
The
[get|set]FactoryClass()
,[get|set]FactoryMethod()
,[get|set]FactoryService()
methods fromSymfony\Component \DependencyInjection\Definition
class are deprecated, you should use[get|set]Factory()
method instead. [Symfony 2.6]Before:
use Symfony\DependencyInjection\Definition; $definition = new Definition(); $definition->setFactoryClass('\Foo\Bar') ->setFactoryMethod('doBaz'); // or $definition->setFactoryService('foo.bar') ->setFactoryMethod('doBaz');
After:
use Symfony\DependencyInjection\Definition; $definition = new Definition(); $definition->setFactory('\Foo\Bar::doBaz'); // or $definition->setFactory(array('\Foo\Bar','doBaz')); // or $definition->setFactory(array('foo.bar','doBaz')); // or $definition->setFactory('foo.baz::doBaz');
-
The
getDispatcher()
andgetName()
methods fromSymfony\Component\EventDispatcher\Event
are deprecated, the event dispatcher instance and event name can be received in the listener call instead.Before:
use Symfony\Component\EventDispatcher\Event; class Foo { public function myFooListener(Event $event) { $dispatcher = $event->getDispatcher(); $eventName = $event->getName(); $dispatcher->dispatch('log', $event); // ... more code } }
After:
use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcherInterface; class Foo { public function myFooListener(Event $event, $eventName, EventDispatcherInterface $dispatcher) { $dispatcher->dispatch('log', $event); // ... more code } }
-
The constructor parameter
$precision
inIntegerToLocalizedStringTransformer
is now ignored completely, because a precision does not make sense for integers. -
The method
FormInterface::getErrors()
now returns an instance ofSymfony\Component\Form\FormErrorIterator
instead of an array. This object is traversable, countable and supports array access. However, you can not pass it to any of PHP'sarray_*
functions anymore. You should useiterator_to_array()
in those cases where you did.Before:
$errors = array_map($callback, $form->getErrors());
After:
$errors = array_map($callback, iterator_to_array($form->getErrors()));
-
The method
FormInterface::getErrors()
now has two additional, optional parameters. Make sure to add these parameters to the method signatures of your implementations of that interface.Before:
public function getErrors(){/*..*/}
After:
public function getErrors($deep = false, $flatten = true){/*..*/}
Before:
{% if form.vars.errors %}
After:
{% if form.vars.errors|length %}
-
The "empty_value" option in the types "choice", "date", "datetime" and "time" was deprecated and replaced by a new option "placeholder". You should use the option "placeholder" together with the view variables "placeholder" and "placeholder_in_choices" now.
The option "empty_value" and the view variables "empty_value" and"empty_value_in_choices" will be removed in Symfony 3.0.
Before:
$form->add('category', 'choice', array( 'choices' => array('politics', 'media'), 'empty_value' => 'Select a category...', ));
After:
$form->add('category', 'choice', array( 'choices' => array('politics', 'media'), 'placeholder' => 'Select a category...', ));
Before:
{{ form.vars.empty_value }} {% if form.vars.empty_value_in_choices %} ... {% endif %}
After:
{{ form.vars.placeholder }} {% if form.vars.placeholder_in_choices %} ... {% endif %}
-
In form types and extension overriding the "setDefaultOptions" of the AbstractType or AbstractExtensionType has been deprecated in favor of overriding the new "configureOptions" method.
The method "setDefaultOptions(OptionsResolverInterface $resolver)" will be renamed in Symfony 3.0 to "configureOptions(OptionsResolver $resolver)".
Before:
use Symfony\Component\OptionsResolver\OptionsResolverInterface; class TaskType extends AbstractType { // ... public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'AppBundle\Entity\Task', )); } }
After:
use Symfony\Component\OptionsResolver\OptionsResolver; class TaskType extends AbstractType { // ... public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'data_class' => 'AppBundle\Entity\Task', )); } }
-
The "choice_list" option of ChoiceType was deprecated. You should use "choice_loader" and "choices_as_values" now. [Symfony 2.7]
Before:
$form->add('status', 'choice', array( 'choice_list' => new ObjectChoiceList(array( Status::getInstance(Status::ENABLED), Status::getInstance(Status::DISABLED), Status::getInstance(Status::IGNORED), )), ));
After:
$form->add('status', 'choice', array( 'choices' => array( Status::getInstance(Status::ENABLED), Status::getInstance(Status::DISABLED), Status::getInstance(Status::IGNORED), ), 'choices_as_values' => true, ));
-
You should flip the keys and values of the "choices" option in ChoiceType and set the "choices_as_values" option to
true
. The default value of that option will be switched totrue
in Symfony 3.0.Before:
$form->add('status', 'choice', array( 'choices' => array( Status::ENABLED => 'Enabled', Status::DISABLED => 'Disabled', Status::IGNORED => 'Ignored', )), ));
After:
$form->add('status', 'choice', array( 'choices' => array( 'Enabled' => Status::ENABLED, 'Disabled' => Status::DISABLED, 'Ignored' => Status::IGNORED, ), 'choices_as_values' => true, ));
-
Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
was deprecated and will be removed in Symfony 3.0. You should useSymfony\Component\Form\ChoiceList\ChoiceListInterface
instead.Before:
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface; public function doSomething(ChoiceListInterface $choiceList){ /*..*/}
After:
use Symfony\Component\Form\ChoiceList\ChoiceListInterface; public function doSomething(ChoiceListInterface $choiceList){/*..*/}
-
Symfony\Component\Form\Extension\Core\ChoiceList\View\ChoiceView
was deprecated and will be removed in Symfony 3.0. You should useSymfony\Component\Form\ChoiceList\View\ChoiceView
instead.Note that the order of the arguments passed to the constructor was inverted.
Before:
use Symfony\Component\Form\Extension\Core\ChoiceList\View\ChoiceView; $view = new ChoiceView($data, 'value', 'Label');
After:
use Symfony\Component\Form\ChoiceList\View\ChoiceView; $view = new ChoiceView('Label', 'value', $data);
-
Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList
was deprecated and will be removed in Symfony 3.0. You should useSymfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory
instead.Before:
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList; $choiceList = new ChoiceList( array(Status::ENABLED, Status::DISABLED, Status::IGNORED), array('Enabled', 'Disabled', 'Ignored'), // Preferred choices array(Status::ENABLED), );
After:
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; $factory = new DefaultChoiceListFactory(); $choices = array(Status::ENABLED, Status::DISABLED, Status::IGNORED); $labels = array('Enabled', 'Disabled', 'Ignored'); $choiceList = $factory->createListFromChoices($choices); $choiceListView = $factory->createView( $choiceList, // Preferred choices array(Status::ENABLED), // Labels function ($choice, $key) use ($labels) { return $labels[$key]; } );
-
Symfony\Component\Form\Extension\Core\ChoiceList\LazyChoiceList
was deprecated and will be removed in Symfony 3.0. You should useSymfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory::createListFromLoader()
together with an implementation ofSymfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface
instead.Before:
use Symfony\Component\Form\Extension\Core\ChoiceList\LazyChoiceList; class MyLazyChoiceList extends LazyChoiceList { public function loadChoiceList() { // load $choiceList return $choiceList; } } $choiceList = new MyLazyChoiceList();
After:
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; class MyChoiceLoader implements ChoiceLoaderInterface { // ... } $factory = new DefaultChoiceListFactory(); $choiceList = $factory->createListFromLoader(new MyChoiceLoader());
-
Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList
was deprecated and will be removed in Symfony 3.0. You should useSymfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory
instead.Before:
use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList; $choiceList = new ObjectChoiceList( array(Status::getInstance(Status::ENABLED), Status::getInstance(Status::DISABLED)), // Label property 'name' );
After:
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; $factory = new DefaultChoiceListFactory(); $choiceList = $factory->createListFromChoices(array( Status::getInstance(Status::ENABLED), Status::getInstance(Status::DISABLED), )); $choiceListView = $factory->createView( $choiceList, // Preferred choices array(), // Label property 'name' );
-
Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList
was deprecated and will be removed in Symfony 3.0. You should useSymfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory
instead.Before:
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList; $choiceList = new SimpleChoiceList(array( Status::ENABLED => 'Enabled', Status::DISABLED => 'Disabled', ));
After:
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; $factory = new DefaultChoiceListFactory(); $choices = array(Status::ENABLED, Status::DISABLED); $labels = array('Enabled', 'Disabled'); $choiceList = $factory->createListFromChoices($choices); $choiceListView = $factory->createView( $choiceList, // Preferred choices array(), // Label function ($choice, $key) use ($labels) { return $labels[$key]; } );
-
The "property" option of
DoctrineType
was deprecated. You should use the new inherited option "choice_label" instead, which has the same effect.Before:
$form->add('tags', 'entity', array( 'class' => 'Acme\Entity\MyTag', 'property' => 'name', ))
After:
$form->add('tags', 'entity', array( 'class' => 'Acme\Entity\MyTag', 'choice_label' => 'name', ))
-
The "loader" option of
DoctrineType
was deprecated and will be removed in Symfony 3.0. You should override thegetLoader()
method instead in a custom type.Before:
$form->add('tags', 'entity', array( 'class' => 'Acme\Entity\MyTag', 'loader' => new MyEntityLoader(), ))
After:
class MyEntityType extends DoctrineType { // ... public function getLoader() { return new MyEntityLoader(); } }
-
Symfony\Bridge\Doctrine\Form\ChoiceList\EntityChoiceList
was deprecated and will be removed in Symfony 3.0. You should useSymfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader
instead.Before:
use Symfony\Component\Form\Extension\Core\ChoiceList\SimpleChoiceList; $choiceList = new EntityChoiceList($em, 'Acme\Entity\MyEntity');
After:
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; $factory = new DefaultChoiceListFactory(); $choices = array(Status::ENABLED, Status::DISABLED); $labels = array('Enabled', 'Disabled'); $choiceLoader = new DoctrineChoiceLoader($factory, $em, 'Acme\Entity\MyEntity'); $choiceList = $factory->createListFromLoader($choiceLoader);
-
Passing a query builder closure to
ORMQueryBuilderLoader
was deprecated and will not be supported anymore in Symfony 3.0. You should pass resolved query builders only.Consequently, the arguments
$manager
and$class
ofORMQueryBuilderLoader
have been deprecated as well.Note that the "query_builder" option of
DoctrineType
does support closures, but the closure is now resolved in the type instead of in the loader.Before:
use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader; $queryBuilder = function () { // return QueryBuilder }; $loader = new ORMQueryBuilderLoader($queryBuilder);
After:
use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader; // create $queryBuilder $loader = new ORMQueryBuilderLoader($queryBuilder);
-
The classes
ChoiceToBooleanArrayTransformer
,ChoicesToBooleanArrayTransformer
,FixRadioInputListener
andFixCheckboxInputListener
were deprecated and will be removed in Symfony 3.0. Their functionality is covered by the new classesRadioListMapper
andCheckboxListMapper
. -
The ability to translate Doctrine type entries by the translator component is now disabled by default and to enable it you must explicitly set the option "choice_translation_domain" to true
Before:
$form->add('products', 'entity', array( 'class' => 'AppBundle/Entity/Product', ));
After:
$form->add('products', 'entity', array( 'class' => 'AppBundle/Entity/Product', 'choice_translation_domain' => true, ));
-
In the block
choice_widget_options
thetranslation_domain
has been replaced with thechoice_translation_domain
option.Before:
{{ choice.label|trans({}, translation_domain) }}
After:
{{ choice_translation_domain is sameas(false) ? choice.label : choice.label|trans({}, choice_translation_domain) }}
- The
Symfony\Bundle\FrameworkBundle\Console\Descriptor\Descriptor::renderTable()
method expects the table to be an instance ofSymfony\Component\Console\Helper\Table
instead ofSymfony\Component\Console\Helper\TableHelper
.
-
The
PdoSessionHandler
to store sessions in a database changed significantly. This introduced a backwards-compatibility break in the schema of the session table. The following changes must be made to your session table:-
Add a new integer column called
sess_lifetime
. Assuming you have the default column and table names, in MySQL this would be:ALTER TABLE
session
ADDsess_lifetime
INT NOT NULL; -
Change the data column (default:
sess_value
) to be a Blob type. In MySQL this would be:ALTER TABLE
session
CHANGEsess_value
session_value
BLOB NOT NULL;
There is also an issue that affects Windows servers.
A legacy class,
LegacyPdoSessionHandler
has been created to ease backwards-compatibility issues when upgrading.The changes to the
PdoSessionHandler
are:- By default, it now implements session locking to prevent loss of data by concurrent access to the same session.
- It does so using a transaction between opening and closing a session. For this reason, it's not recommended to use the same database connection that you also use for your application logic. Otherwise you have to make sure to access your database after the session is closed and committed. Instead of passing an existing connection to the handler, you can now also pass a DSN string which will be used to lazy-connect when a session is started.
- Since accessing a session now blocks when the same session is still open, it is best practice to save the session as soon as you don't need to write to it anymore. For example, read-only AJAX request to a session can save the session immediately after opening it to increase concurrency.
- As alternative to transactional locking you can also use advisory locks which do not require a transaction.
Additionally, you can also revert back to no locking in case you have custom logic to deal with race conditions like an optimistic concurrency control approach. The locking strategy can be chosen by passing the corresponding constant as
lock_mode
option, e.g.new PdoSessionHandler($pdoOrDsn, array('lock_mode' => PdoSessionHandler::LOCK_NONE))
. For more information please read the class documentation.
- The expected schema of the table changed.
- Session data is binary text that can contain null bytes and thus should also be saved as-is in a binary column like BLOB. For this reason, the handler does not base64_encode the data anymore.
- A new column to store the lifetime of a session is required. This allows to have different lifetimes per session configured via session.gc_maxlifetime ini setting.
- You would need to migrate the table manually if you want to keep session information of your users.
- You could use
PdoSessionHandler::createTable
to initialize a correctly defined table depending on the used database vendor.
-
-
Since version 2.4, the
Symfony ProfilerListener
constructor method must accept aRequestStack
instance to get the request instead of using the Symfony ProfilerListener::onKernelRequest method that will be removed in 3.0.Before:
public function __construct( Profiler $profiler, RequestMatcherInterface $matcher = null, $onlyException = false, $onlyMasterRequests = false, Request $request = null)
After:
public function __construct( Profiler $profiler, RequestMatcherInterface $matcher = null, $onlyException = false, $onlyMasterRequests = false, RequestStack $requestStack = null)
-
The "array" type hint was removed from the
OptionsResolverInterface
methodssetRequired()
,setAllowedValues()
,addAllowedValues()
,setAllowedTypes()
andaddAllowedTypes()
. You must remove the type hint from your implementations. -
The interface
OptionsResolverInterface
was deprecated, sinceOptionsResolver
instances are not supposed to be shared between classes. You should type hint againstOptionsResolver
instead.Before:
protected function configureOptions(OptionsResolverInterface $resolver){/*..*/}
After:
protected function configureOptions(OptionsResolver $resolver){/*..*/}
-
OptionsResolver::isRequired()
now returnstrue
if a required option has a default value set. The new methodisMissing()
exhibits the old functionality ofisRequired()
.Before:
$resolver->setRequired(array('port')); $resolver->isRequired('port'); // => true $resolver->setDefaults(array('port' => 25)); $resolver->isRequired('port'); // => false
After:
$resolver->setRequired(array('port')); $resolver->isRequired('port'); // => true $resolver->isMissing('port'); // => true $resolver->setDefaults(array('port' => 25)); $resolver->isRequired('port'); // => true $resolver->isMissing('port'); // => false
-
OptionsResolver::replaceDefaults()
was deprecated. Useclear()
andsetDefaults()
instead.Before:
$resolver->replaceDefaults(array( 'port' => 25, ));
After:
$resolver->clear(); $resolver->setDefaults(array( 'port' => 25, ));
-
OptionsResolver::setOptional()
was deprecated. UsesetDefined()
instead.Before:
$resolver->setOptional(array('port'));
After:
$resolver->setDefined('port');
-
OptionsResolver::isKnown()
was deprecated. UseisDefined()
instead.Before:
if ($resolver->isKnown('port')) {/*..*/}
After:
if ($resolver->isDefined('port')) {/*..*/}
-
The methods
setAllowedValues()
,addAllowedValues()
,setAllowedTypes()
andaddAllowedTypes()
were changed to modify one option at a time instead of batch processing options. The old API exists for backwards compatibility, but will be removed in Symfony 3.0.Before:
$resolver->setAllowedValues(array( 'method' => array('POST', 'GET'), ));
After:
$resolver->setAllowedValues('method', array('POST', 'GET'));
-
The class
Options
was merged intoOptionsResolver
. If you instantiated this class manually, you should instantiateOptionsResolver
now.Options
is now a marker interface implemented byOptionsResolver
.Before:
$options = new Options();
After:
$resolver = new OptionsResolver();
-
Normalizers for defined but unset options are not executed anymore. If you want to have them executed, you should define a default value.
Before:
$resolver->setOptional(array('port')); $resolver->setNormalizers(array( 'port' => function ($options, $value) { // return normalized value } )); $options = $resolver->resolve($options);
After:
$resolver->setDefault('port', null); $resolver->setNormalizer('port', function ($options, $value) { // return normalized value }); $options = $resolver->resolve($options);
-
When undefined options are passed,
resolve()
now throws anUndefinedOptionsException
instead of anInvalidOptionsException
.InvalidOptionsException
is only thrown when option values fail their validation constraints.Before:
$resolver->setDefaults(array( 'transport' => 'smtp', 'port' => 25, )); $resolver->setAllowedTypes(array( 'port' => 'integer', )); // throws InvalidOptionsException $resolver->resolve(array('foo' => 'bar')); // throws InvalidOptionsException $resolver->resolve(array('port' => '25'));
After:
$resolver->setDefaults(array( 'transport' => 'smtp', 'port' => 25, )); $resolver->setAllowedTypes(array( 'port' => 'integer', )); // throws UndefinedOptionsException $resolver->resolve(array('foo' => 'bar')); // throws InvalidOptionsException $resolver->resolve(array('port' => '25'));
-
The methods
isReadable()
andisWritable()
were added toPropertyAccessorInterface
. If you implemented this interface in your own code, you should add these two methods. -
The methods
getValue()
andsetValue()
now throw anNoSuchIndexException
instead of aNoSuchPropertyException
when an index is accessed on an object that does not implementArrayAccess
. If you catch this exception in your code, you should adapt the catch statement:Before:
$object = new \stdClass(); try { $propertyAccessor->getValue($object, '[index]'); $propertyAccessor->setValue($object, '[index]', 'New value'); } catch (NoSuchPropertyException $e) {/*..*/}
After:
$object = new \stdClass(); try { $propertyAccessor->getValue($object, '[index]'); $propertyAccessor->setValue($object, '[index]', 'New value'); } catch (NoSuchIndexException $e) {/*..*/}
A
NoSuchPropertyException
is still thrown when a non-existing property is accessed on an object or an array. -
UnexpectedTypeException
now expects three constructor arguments: The invalid property value, thePropertyPathInterface
object and the current index of the property path.Before:
use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException; new UnexpectedTypeException($value, $expectedType);
After:
use Symfony\Component\PropertyAccess\Exception\UnexpectedTypeException; new UnexpectedTypeException($value, $path, $pathIndex);
-
Added a new optional parameter
$requiredSchemes
toSymfony\Component\Routing\Generator\UrlGenerator::doGenerate()
-
Route conditions now support container parameters which can be injected into condition using
%parameter%
notation. Due to the fact that it works by replacing all parameters with their corresponding values before passing condition expression for compilation there can be BC breaks where you could already have used percentage symbols. Single percentage symbol usage is not affected in any way. Conflicts may occur where you might have used%
as a modulo operator, here's an example:foo%bar%2
get an error ifbar
parameter doesn't exist or unexpected result otherwise. -
The
getMatcherDumperInstance()
andgetGeneratorDumperInstance()
methods in theSymfony\Component\Routing\Router
have been changed fromprotected
topublic
. If you override these methods in a subclass, you will need to change your methods topublic
as well. Note however that this is a temporary change needed for PHP 5.3 compatibility only. It will be reverted in Symfony 3.0. -
Some route settings have been renamed:
- The
pattern
setting for a route has been deprecated in favor ofpath
- The
_scheme
and_method
requirements have been moved to theschemes
andmethods
settings
Before:
article_edit: pattern: /article/{id} requirements: { '_method': 'POST|PUT', '_scheme': 'https', 'id': '\d+' }
<route id="article_edit" pattern="/article/{id}"> <requirement key="_method">POST|PUT</requirement> <requirement key="_scheme">https</requirement> <requirement key="id">\d+</requirement> </route>
$route = new Route(); $route->setPattern('/article/{id}'); $route->setRequirement('_method', 'POST|PUT'); $route->setRequirement('_scheme', 'https');
After:
article_edit: path: /article/{id} methods: [POST, PUT] schemes: https requirements: { 'id': '\d+' }
<route id="article_edit" path="/article/{id}" methods="POST PUT" schemes="https"> <requirement key="id">\d+</requirement> </route>
$route = new Route(); $route->setPath('/article/{id}'); $route->setMethods(array('POST', 'PUT')); $route->setSchemes('https');
- The
-
The
SecurityContextInterface
is marked as deprecated in favor of theSymfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface
andSymfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface
.isGranted => AuthorizationCheckerInterface getToken => TokenStorageInterface setToken => TokenStorageInterface
The Implementations have moved too, The
SecurityContext
is marked as deprecated and has been split to use theAuthorizationCheckerInterface
andTokenStorage
. This change is 100% Backwards Compatible as the SecurityContext delegates the methods. -
The service
security.context
is deprecated along with the above change. Recommended to use instead:@security.authorization_checker => isGranted() @security.token_storage => getToken() @security.token_storage => setToken()
-
The
setCamelizedAttributes()
method of theSymfony\Component\Serializer\Normalizer\GetSetMethodNormalizer
andSymfony\Component\Serializer\Normalizer\PropertyNormalizer
classes is marked as deprecated in favor of the new NameConverter system.Before:
$normalizer->setCamelizedAttributes(array('foo_bar', 'bar_foo'));
After:
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; $nameConverter = new CamelCaseToSnakeCaseNameConverter(array('fooBar', 'barFoo')); $normalizer = new GetSetMethodNormalizer(null, $nameConverter);
-
Symfony\Component\Serializer\Exception\ExceptionInterface
is the new name for the now deprecatedSymfony\Component\Serializer\Exception\Exception
interface.
With LoggingTranslator
, a new translator class is introduced with Symfony 2.6. By default, the @translator
service is referring to this class in the debug environment.
If you have your own services that depend on the @translator
service and expect this service to be an instance of either Symfony\Component\Translation\Translator
or Symfony\Bundle\FrameworkBundle\Translation\Translator
, e.g. by type-hinting for either of these classes, you will need to change that type hint. You can use the TranslatorInterface
to be on the safe side for future changes.
Before:
use Symfony\Component\Translation\Translator;
class MyService {
public function __construct(Translator $translator){/*..*/}
}
After:
use Symfony\Component\Translation\TranslatorInterface;
class MyService {
public function __construct(TranslatorInterface $translator){/*..*/}
}
-
The
Symfony\Bundle\TwigBundle\TwigDefaultEscapingStrategy
is deprecated and no longer used in favor ofTwig_FileExtensionEscapingStrategy
. This means that CSS files automatically use the CSS escape strategy. This can cause different behaviour when outputting reserved characters.Before:
{# styles.css.twig #} {# with brand_color: '#123456' #} body { background: {{ brand_color }}; }
After:
{# styles.css.twig #} {# with brand_color: '#123456' #} body { background: {{ brand_color|raw }}; }
-
EmailValidator has changed to allow
non-strict
andstrict
email validation.Before:
Email validation was done with php's
filter_var()
After:
Default email validation is now done via a simple regex which may cause invalid emails (not RFC compliant) to be valid. This is the default behaviour.
Strict email validation has to be explicitly activated in the configuration file:
framework: //... validation: strict_email: true //...
Also you have to add to your composer.json:
"egulias/email-validator": "~1.2"
-
ClassMetadata::getGroupSequence()
now returnsGroupSequence
instances instead of an array. The sequence implements\Traversable
,\ArrayAccess
and\Countable
, so in most cases you should be fine. If you however use the sequence with PHP'sarray_*()
functions, you should cast it to an array first usingiterator_to_array()
:Before:
$sequence = $metadata->getGroupSequence(); $result = array_map($callback, $sequence);
After:
$sequence = iterator_to_array($metadata->getGroupSequence()); $result = array_map($callback, $sequence);
-
The array type hint in
ClassMetadata::setGroupSequence()
was removed. If you overwrite this method, make sure to remove the type hint as well. The method should now acceptGroupSequence
instances just as well as arrays.Before:
public function setGroupSequence(array $groups){/*..*/}
After:
public function setGroupSequence($groupSequence){/*..*/}
-
The validation engine in
Symfony\Component\Validator\Validator
was replaced by a new one inSymfony\Component\Validator\Validator\RecursiveValidator
. With that change, several classes were deprecated that will be removed in Symfony 3.0. Also, the API of the validator was slightly changed. More details about that can be found in UPGRADE-3.0.You can choose the desired API via the new "api" entry in app/config/config.yml:
framework: validation: enabled: true api: auto
When running PHP 5.3.9 or higher, Symfony will then use an implementation that supports both the old API and the new one:
framework: validation: enabled: true api: 2.5-bc
When running PHP lower than 5.3.9, that compatibility layer is not supported. On those versions, the old implementation will be used instead:
framework: validation: enabled: true api: 2.4
If you develop a new application that doesn't rely on the old API, you can also set the API to 2.5. In that case, the backwards compatibility layer will not be activated:
framework: validation: enabled: true api: 2.5
When using the validator outside of the Symfony full-stack framework, the desired API can be selected using
setApiVersion()
on the validator builder:// Previous implementation $validator = Validation::createValidatorBuilder() ->setApiVersion(Validation::API_VERSION_2_4) ->getValidator(); // New implementation with backwards compatibility support $validator = Validation::createValidatorBuilder() ->setApiVersion(Validation::API_VERSION_2_5_BC) ->getValidator(); // New implementation without backwards compatibility support $validator = Validation::createValidatorBuilder() ->setApiVersion(Validation::API_VERSION_2_5) ->getValidator();
-
The internal method
setConstraint()
was added toSymfony\Component\Validator\Context\ExecutionContextInterface
. With this method, the context is informed about the constraint that is currently being validated.If you implement this interface, make sure to add the method to your implementation. The easiest solution is to just implement an empty method:
public function setConstraint(Constraint $constraint){/*..*/}
-
Prior to 2.6
Symfony\Component\Validator\Constraints\ExpressionValidator
would not execute the Expression if it was attached to a property on an object and that property was set tonull
or an empty string.To emulate the old behaviour change your expression to something like this:
value == null or (YOUR_EXPRESSION)
-
The PHP7-incompatible constraints (Null, True, False) and related validators (NullValidator, TrueValidator, FalseValidator) are marked as deprecated in favor of their
Is
-prefixed equivalent. -
The
Symfony\Component\Validator\Validator\RecursiveValidator::validateValue()
method is deprecated, use theSymfony\Component\Validator\Validator\ValidatorInterface::validate()
method instead. [Symfony 2.5] -
The
Symfony\Component\Validator\ConstraintValidator::buildViolation()
is deprecated, use theSymfony\Component\Validator\Context\ExecutionContextInterface::buildViolation()
instead. [Symfony 2.5]Before:
class ProtocolClassValidator extends ConstraintValidator { public function validate($protocol, Constraint $constraint) { if ($protocol->getFoo() != $protocol->getBar()) { $this->context->addViolationAt( 'foo', $constraint->message, array(), null ); } } }
After:
class ProtocolClassValidator extends ConstraintValidator { public function validate($protocol, Constraint $constraint) { if ($protocol->getFoo() != $protocol->getBar()) { $this->context->buildViolation($constraint->message) ->atPath('foo') ->addViolation(); } } }
-
The
Symfony\Component\Validator\ConstraintViolation::getMessageParameters()
method is deprecated, use the ConstraintViolation::getParameters() method instead. [Symfony 2.7] -
The
Symfony\Component\Validator\ConstraintViolation::getMessagePluralization()
method is deprecated, use theSymfony\Component\Validator\ConstraintViolation::getPlural()
instead. [Symfony 2.7]
The component and the bundle are new to Symfony 2.6. We encourage you to enable the bundle in your app/AppKernel.php
for the dev or test environments. Just add this line before loading the WebProfilerBundle
:
$bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
Then enjoy dumping variables by calling dump($var)
anywhere in your PHP and {% dump var %}
or {{ dump(var) }}
in Twig. Dumps are displayed in the web debug toolbar.
-
The way Yaml handles duplicate keys in an array was changed from
rewrite with the last element
behavior to ignoring all the elements with the same key after the first one.Example:
parentElement: firstChild: foo secondChild: 123 firstChild: bar
Before:
This would be parsed in an array like this:
["parentElement" => ["firstChild" => "bar", "secondChild" => 123]]
After:
The first value is used:
["parentElement" => ["firstChild" => "foo", "secondChild" => 123]]
An elegant way to make your tests pass without upgrade all your code is to use the Symfony PHPUnit brigde created by @nicolas-grekas.
Add to your composer.json file:
{
"require-dev": {
"...": "...",
"symfony/phpunit-bridge" : "~2.7.0",
"...": "..."
}
}
Then, if you use travis you need to set SYMFONY_DEPRECATIONS_HELPER
to weak
:
env:
global:
- SYMFONY_DEPRECATIONS_HELPER=weak
The default value is "strict", and result to an error code exit (1) if some deprecations errors remains in your code.
And now all tests broken because a deprecated error will pass. Also a summary of deprecation notices will be displayed at the end of the test suite, take a look to the README.md of the project for more informations.
By the way, I have just released a new guide to help people migrate Symfony 2 apps to Symfony 3. This is still a work in progress, and I need feedbacks 👍