Practical Guide — How to upgrade from Symfony 3.x to 5.0 ( or 4.x ) — Part 2
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
);
}
}