- 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\ConfigCacheis marked as deprecated in favor of the newgetPath()method. - The namespace
Symfony\Component\Config\Definition\ReferenceDumperis marked as deprecated, useSymfony\Component\Config\Definition\Dumper\YamlReferenceDumperinstead.
-
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\DialogHelperis deprecated in favor ofSymfony\Component\Console\Helper\QuestionHelper. -
The
Symfony\Component\Console\Helper\ProgressHelperis deprecated in favor ofSymfony\Component\Console\Helper\ProgressBar. -
The method
getStep()fromSymfony\Component\Console\Helper\ProgressBaris deprecated in favor ofgetProgress(). -
The method
setCurrent()fromSymfony\Component\Console\Helper\ProgressBaris deprecated in favor ofsetProgress().
-
The
[get|set]FactoryClass(),[get|set]FactoryMethod(),[get|set]FactoryService()methods fromSymfony\Component \DependencyInjection\Definitionclass 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\Eventare 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
$precisioninIntegerToLocalizedStringTransformeris now ignored completely, because a precision does not make sense for integers. -
The method
FormInterface::getErrors()now returns an instance ofSymfony\Component\Form\FormErrorIteratorinstead 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 totruein 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\ChoiceListInterfacewas deprecated and will be removed in Symfony 3.0. You should useSymfony\Component\Form\ChoiceList\ChoiceListInterfaceinstead.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\ChoiceViewwas deprecated and will be removed in Symfony 3.0. You should useSymfony\Component\Form\ChoiceList\View\ChoiceViewinstead.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\ChoiceListwas deprecated and will be removed in Symfony 3.0. You should useSymfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactoryinstead.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\LazyChoiceListwas 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\ChoiceLoaderInterfaceinstead.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\ObjectChoiceListwas deprecated and will be removed in Symfony 3.0. You should useSymfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactoryinstead.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\SimpleChoiceListwas deprecated and will be removed in Symfony 3.0. You should useSymfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactoryinstead.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
DoctrineTypewas 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
DoctrineTypewas 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\EntityChoiceListwas deprecated and will be removed in Symfony 3.0. You should useSymfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoaderinstead.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
ORMQueryBuilderLoaderwas deprecated and will not be supported anymore in Symfony 3.0. You should pass resolved query builders only.Consequently, the arguments
$managerand$classofORMQueryBuilderLoaderhave been deprecated as well.Note that the "query_builder" option of
DoctrineTypedoes 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,FixRadioInputListenerandFixCheckboxInputListenerwere deprecated and will be removed in Symfony 3.0. Their functionality is covered by the new classesRadioListMapperandCheckboxListMapper. -
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_optionsthetranslation_domainhas been replaced with thechoice_translation_domainoption.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\Tableinstead ofSymfony\Component\Console\Helper\TableHelper.
-
The
PdoSessionHandlerto 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
sessionADDsess_lifetimeINT NOT NULL; -
Change the data column (default:
sess_value) to be a Blob type. In MySQL this would be:ALTER TABLE
sessionCHANGEsess_valuesession_valueBLOB NOT NULL;
There is also an issue that affects Windows servers.
A legacy class,
LegacyPdoSessionHandlerhas been created to ease backwards-compatibility issues when upgrading.The changes to the
PdoSessionHandlerare:- 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_modeoption, 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::createTableto initialize a correctly defined table depending on the used database vendor.
-
-
Since version 2.4, the
Symfony ProfilerListenerconstructor method must accept aRequestStackinstance 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
OptionsResolverInterfacemethodssetRequired(),setAllowedValues(),addAllowedValues(),setAllowedTypes()andaddAllowedTypes(). You must remove the type hint from your implementations. -
The interface
OptionsResolverInterfacewas deprecated, sinceOptionsResolverinstances are not supposed to be shared between classes. You should type hint againstOptionsResolverinstead.Before:
protected function configureOptions(OptionsResolverInterface $resolver){/*..*/}
After:
protected function configureOptions(OptionsResolver $resolver){/*..*/}
-
OptionsResolver::isRequired()now returnstrueif 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
Optionswas merged intoOptionsResolver. If you instantiated this class manually, you should instantiateOptionsResolvernow.Optionsis 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 anUndefinedOptionsExceptioninstead of anInvalidOptionsException.InvalidOptionsExceptionis 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 anNoSuchIndexExceptioninstead of aNoSuchPropertyExceptionwhen 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
NoSuchPropertyExceptionis still thrown when a non-existing property is accessed on an object or an array. -
UnexpectedTypeExceptionnow expects three constructor arguments: The invalid property value, thePropertyPathInterfaceobject 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
$requiredSchemestoSymfony\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%2get an error ifbarparameter doesn't exist or unexpected result otherwise. -
The
getMatcherDumperInstance()andgetGeneratorDumperInstance()methods in theSymfony\Component\Routing\Routerhave been changed fromprotectedtopublic. If you override these methods in a subclass, you will need to change your methods topublicas 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
patternsetting for a route has been deprecated in favor ofpath - The
_schemeand_methodrequirements have been moved to theschemesandmethodssettings
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
SecurityContextInterfaceis marked as deprecated in favor of theSymfony\Component\Security\Core\Authorization\AuthorizationCheckerInterfaceandSymfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface.isGranted => AuthorizationCheckerInterface getToken => TokenStorageInterface setToken => TokenStorageInterface
The Implementations have moved too, The
SecurityContextis marked as deprecated and has been split to use theAuthorizationCheckerInterfaceandTokenStorage. This change is 100% Backwards Compatible as the SecurityContext delegates the methods. -
The service
security.contextis 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\GetSetMethodNormalizerandSymfony\Component\Serializer\Normalizer\PropertyNormalizerclasses 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\ExceptionInterfaceis the new name for the now deprecatedSymfony\Component\Serializer\Exception\Exceptioninterface.
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\TwigDefaultEscapingStrategyis 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-strictandstrictemail 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 returnsGroupSequenceinstances instead of an array. The sequence implements\Traversable,\ArrayAccessand\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 acceptGroupSequenceinstances just as well as arrays.Before:
public function setGroupSequence(array $groups){/*..*/}After:
public function setGroupSequence($groupSequence){/*..*/} -
The validation engine in
Symfony\Component\Validator\Validatorwas 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: autoWhen 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-bcWhen 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.4If 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.5When 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\ExpressionValidatorwould not execute the Expression if it was attached to a property on an object and that property was set tonullor 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 elementbehavior to ignoring all the elements with the same key after the first one.Example:
parentElement: firstChild: foo secondChild: 123 firstChild: barBefore:
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=weakThe 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.
I try to update my project 2.3.* to 2.7.* but I have an error with bootstrap.php.cache. Have you an example of your composer.json ?