Migrating a legacy PHP application to Laravel
When I started working at Zonneplan in 2016, I was tasked with the goal to migrate our legacy PHP architecture to a standardized solution.
The application itself was running just fine, but to allow the team to scale, we needed to make sure that the architecture could scale with it. Since I had previous experience with Laravel, we choose to adopt it as our framework-of-choice.
At the time, the main application that had to be migrated contained about 100.000 lines of code, mostly written in a non-MVC manner combining both HTML and PHP in loose files.
Rewriting this application into another framework would have taken months (at least) and would probably have resulted in a feature-freeze and dozens of bugs in the process.
In the end, we did not rewrite the application, but simply "wrapped" it in a Laravel container. In this article, I will show you we did it.
Heads up: this is not going to be pretty, but it works oh-so-well 🙈
First steps: get your directory structure in order
- Create an empty Laravel application Choose whatever method you wish to create a new Laravel application, as long as you end up with an empty skeleton.
- Create a new folder to contain your legacy application
We called it
legacy-app
to make the distinction between the regularapp
folder clear while still showing it's purpose. - Copy your legacy application into that folder
Create a fallback route
In your router file (usually web.php
) create a route like this:
Route::any('{all}', ['uses' => 'LegacyController@index'])
Create a layout file wrapper
{-- legacy.index.blade.php --}
@extends('layouts.app')
@section('content')<?php require_once $includePath; ?>@endsection
@section('title', 'Legacy')
Create a fallback controller
Last, we created a fallback controller that acts like a proxy between Laravel and our legacy application.
class LegacyController extends Controller
{
public function index(Request $request)
{
$path = base_path('/legacy-app/') . $request->path();
// If the path does not end with PHP, assume we're requesting an index file
if (substr($path, -3) != 'php') {
$path .= '/index.php';
}
return $this->renderPath($path);
}
protected function renderPath($path)
{
view()->addNamespace('legacy', base_path('legacy-app/'));
if (file_exists($path)) {
return view('legacy.index', ['includePath' => $path]);
} else {
abort(404);
}
}
}
Conclusion
- Migrating a legacy app into Laravel does not always have to be as hard as it looks.
- This method of wrapping your application into a Laravel container allows you to keep developing new features using new techniques while maintaining backwards compatibility.
- This sure ain't "pretty code", but it gets the job done very well.
This code is still powering our codebase as to this day and basically has not changed since I have written it.
If you're tasked with the job of migrating a legacy application into Laravel, I hope this technique will make things easier for you.