On Github cvuorinen / symfony-legacy-slides
// Load configuration
require_once ("config.php");
require_once ("includes/funcs.php");
require_once ("includes/common.php");
// Load classes
require_once ("classes/info.php");
require_once ("classes/user.php");
require_once ("classes/dir.php");
// ... ~100 lines more
switch ($page) {
case "user":
$user = new User($user_id);
if ($action == 'edit') {
$body = $user->editUser();
} else {
$body = $user->userInfo();
}
break;
case "page2":
$heading = "Some page";
$body = get_some_page();
break;
// ... ~1500 lines more
}
Legacy URL scheme (/user.html /page2.html)
class User extends Db
{
// inherits from Db (but sometimes overridden)
function save() {}
function delete() {}
function log() {}
function checkAccess() {}
function formTextInput() {}
function validateDate() {}
// ... lots more
function printMenu() {}
function printInfo() {}
function printUpdateForm() {}
// ... lots more
}
class LegacyKernel implements HttpKernelInterface
{
public function handle(Request $request, ...)
{
ob_start();
$legacyDir = dirname($this->legacyAppPath);
chdir($legacyDir);
require_once $this->legacyAppPath;
$response = new Response(ob_get_clean());
return $response;
}
}
Caveats:
class LegacyKernelListener implements EventSubscriberInterface
{
public function onKernelException($event)
{
$exception = $event->getException();
if ($exception instanceof NotFoundHttpException) {
$request = $event->getRequest();
$response = $this->legacyKernel->handle($request);
// Override 404 status code with 200
$response->headers->set('X-Status-Code', 200);
$event->setResponse($response);
}
}
}
class LegacyController extends Controller
{
/**
* @Route("/{filename}.php", name="_legacy")
*/
public function legacyAction($filename)
{
$legacyPath = $this->container
->getParameter('legacy.path');
ob_start();
chdir($legacyAppPath);
require_once $legacyAppPath . $filename . '.php';
$response = new Response(ob_get_clean());
return $response;
}
}
class LegacyKernel implements HttpKernelInterface
{
public function handle(Request $request, ...)
{
// ...
// Assign Container to a local variable
// so it can be used in legacy app
$container = $this->container;
// Request is already in a local variable
require_once $this->legacyAppPath;
// ...
}
}
// Make Symfony Container and Request global
// so they can be used in other functions & classes
/** @var \Symfony\Component\DependencyInjection\Container $container */
$GLOBALS['container'] = $container;
/** @var \Symfony\Component\HttpFoundation\Request $request */
$GLOBALS['request'] = $request;
{
"require": {
...
"cvuorinen/legacy-example": "dev-symfony-integration",
},
...
"repositories": [
{
"type": "vcs",
"url": "git@github.com:cvuorinen/legacy-example.git"
}
]
}
Works with private repos also
$ ls -l web/ app_dev.php app.php config.php css -> ../legacy/css favicon.ico images -> ../legacy/images robots.txt
{
...
"scripts": {
"post-install-cmd": [
...
"Cvuorinen\\LegacyBundle\\Composer\\AssetSymlinks::create",
],
"post-update-cmd": [
...
"Cvuorinen\\LegacyBundle\\Composer\\AssetSymlinks::create",
]
},
"extra": {
...
"legacy-app-dir": "legacy",
}
}
Works with Capifony deployments for example
...
<div id="sidebar">
{% block sidebar %}
{{ render(url('_legacy', {filename: 'menu'})) }}
{% endblock %}
</div>
...
Symfony router can be used in the legacy side to generate URLs
...
doctrine:
dbal:
...
schema_filter: ~^(?!(^some_table$)|(^stuff$) ⏎
|(^super_secret_admin_stuff$) ⏎
... # many, many tables here
(^last_table$))~
class UserRepository extends EntityRepository
{
/**
* @param User $user
*/
public function save(User $user)
{
$this->_em->persist($user);
$this->_em->flush();
}
}
function getUsername($id)
{
$sql = "SELECT username FROM user WHERE id=" . (int)$id;
$result = mysql_fetch_array(mysql_query($sql));
return $result[0];
}
function getUsername($id)
{
global $container;
$userRepository = $container->get('acme.demo.repository.user');
$user = $userRepository->find($id);
return $user->getUsername();
}
function userInfo()
{
$html = '<p><strong>Id:</strong> ' . $this->keyvalue . '</p>';
$html .= '<p><strong>Name:</strong> ' . $this->firstname . ' '
. $this->lastname . '</p>';
if (isAdmin()) {
$html .= '<h3>Actions:</h3>';
$html .= '<a href="' . $baseUrl
. '?action=edit&page=/user.html">Edit</a>';
}
return $html;
}
{% extends "CvuorinenLegacyBundle::layout.html.twig" %}
{% block body %}
<p><strong>Id:</strong> {{ user.id }}</p>
<p><strong>Name:</strong>
{{ user.firstname }} {{ user.lastname }}</p>
{% if isAdmin %}
<h3>Actions:</h3>
<a href="{{ baseUrl }}?action=edit&page=/user.html">Edit</a>
{% endif %}
{% endblock %}
function userInfo()
{
$data = [
'user' => $this->user,
'isAdmin' => isAdmin(),
'baseUrl' => $baseUrl
];
return $this->twig->render(
'CvuorinenLegacyBundle:User:info.html.twig',
$data
);
}