Practical Guide — How to upgrade from Symfony 3.x to 5.0 ( or 4.x ) — Part 2

Diego Favero
3 min readMay 18, 2020

--

In a hardest way

Before Read this guide, be aware

_ This is my second blog post, I mean, from my whole life … I have cut my Starcraft2 time to do so ! Hopping this will be useful to someone ….
_ I Assume you have already read the Part 1 of this guide

_Last, but not least. I am not native english speaker. I learned by myself, so, forgive any misspelling or ugly sentence here !

So, Remember when I said …

That you won't need to rewrite your codes…
Kind of I lied … I mean, at least, I did not say everything….

There is indeed a few differences into the code beyond namespace and headers.

No More blablabla … let's do it :

Twig Filters:

The way to declare twig filters has changed :
SFY3 :

<?php
namespace MyService\MySessionHelper;

use MyService\MySession\MySession;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Request;
use Twig_Environment;
use Twig_Extension;
use Twig_Loader_String;

class MySessionHelper extends Twig_Extension{

protected $twig;
protected $container;
protected $session;

function __construct(Twig_Environment $twig, Container $container, MySession $session) {
$this->twig = $twig;
$this->container = $container;
$this->session = $session;
}

public function getFilters()
{
return array(
new \Twig_SimpleFilter('__Session', array($this, '__Session')),
);
}

SFY5 :

<?php
namespace App\MyFilter\MySessionHelper;


use Symfony\Component\HttpFoundation\Request;


use Symfony\Component\DependencyInjection\ContainerInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class MySessionHelper extends AbstractExtension{

protected $twig;
protected $container;
protected $MySession;

function __construct(ContainerInterface $container) {

$this->container = $container;
$this->MySession = $this->container->get('MySession');
}

public function getFilters()
{
return array(
new TwigFilter('__Session', array($this, '__Session')),
);
}

There is also a Lazy Way to load filters, check out the Documentation

Fetching Data from database.

I think this is the part going take most of your time :

Assuming you have correctly set up your connections, managers and repository class, Instead to do as in Sfy3

$Conn->getRepository('PersonBundle:Person')->find($id) 

Will be in SFY5 :

$Conn->getRepository(\App\Entity\PersonBundle\Person::class)->find($id)

Or, if you add :

use App\Entity\PersonBundle\Person;

You may just use as :

$Conn->getRepository(Person::class)->find($id)

Free Tip :
Took me a while to figure out how to use the repositories from dynamic class.

$table = 'Person';
$Entity = '\App\Entity\PersonBundle\\'.$table;
$Class = new $Entity;
$Conn->getRepository(get_class($Class))->findAll());

Dynamic Database Connection

My app uses 'on the fly' database connection, according to the client acessing it ( Remember from MyClient service ? ) …

In Symfony 3 it was pretty neat to do so :

Into my config file I have :

Dynamic:
driver: "%Dyn_database_driver%"
host: "%Dyn_database_host%"
port: "%Dyn_database_port%"
charset: UTF8
wrapper_class: 'USER\AuthBundle\Connection\ConnectionDynamicWrapper'

So, ConnectionDynamicWrapper it is something like this :

use Doctrine\DBAL\Connection;

use Doctrine\DBAL\Events;
use Doctrine\DBAL\Event\ConnectionEventArgs;

class ConnectionDynamicWrapper extends Connection{
/**
* {
@inheritDoc}
*/
public function connect()
{

if ($this->isConnected()) {
return true;
}
$driverOptions = isset($params['driverOptions']) ? $params['driverOptions'] : array();

$params = $this->getParams();

$this->_conn = $this->_driver->connect($params, $params['user'], $params['password'], $driverOptions);

if ($this->_eventManager->hasListeners(Events::postConnect)) {
$eventArgs = new ConnectionEventArgs($this);
$this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
}

$this->_isConnected = true;

return true;
}

Then, I also need to register this as service :

namespace USER\AuthBundle\DependencyInjection\CompilerPass;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;


/*
* @author Dawid zulus Pakula [zulus@w3des.net]
* @url : stackoverflow.com/questions/6409167/symfony-2-multiple-and-dynamic-database-connection
*/
class ConnectionCompilerPass implements CompilerPassInterface
{

/**
* {
@inheritDoc}
*/
public function process(ContainerBuilder $container)
{

// Dynamic Conn
$Dynamic = $container
->getDefinition('doctrine.dbal.Dynamic_connection')


}

Now, In Symfony 5 it is a bit easier to do so :

## DYNAMIC
Dynamic:
driver: "%env(resolve:Dyn_database_driver)%"
# host: "%env(resolve:Dyn_database_host)%"
port: "%env(resolve:Dyn_database_port)%"
charset: UTF8
wrapper_class: App\DynamicConn\ConnectionDynamicWrapper

And, only :

namespace App\DynamicConn;

use Doctrine\Common\EventManager;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver;

class ConnectionDynamicWrapper extends Connection
{
public function __construct(array $params = null, ?Driver $driver, ?Configuration $config, ?EventManager $eventManager)
{
parent::__construct($params, $driver, $config, $eventManager);
}

/**
*
@param array $Conn
*
@throws \Doctrine\DBAL\DBALException
*/
public function forceSwitch(array $Conn){



$params = $this->getParams();
if ($this->isConnected())
$this->close();
$params['url'] = "mysql://".$Conn['dbUser'].":".$Conn['dbPassword']."@".$Conn['dbHost'].":".$Conn['dbPort']."/".$Conn['dbName'];
$params['host'] = $Conn['dbHost'];
$params['port'] = $Conn['dbPort'];
$params['dbname'] = $Conn['dbName'];
$params['user'] = $Conn['dbUser'];
$params['password'] = $Conn['dbPassword'];
parent::__construct(
$params,
$this->_driver,
$this->_config,
$this->_eventManager
);

}
}

--

--

Diego Favero

Sr. Full Stack WebDeveloper — Enthusiast Rock Climber and Mountain Biker — Earthworm humus producer — DJ — Carpenter