By Shubham Chawala, Architect
25th July, 2025
Upgrading the system, including framework versions and database versions is a critical technical change necessary for ensuring system stability and security. As software evolves, older versions often include deprecated features that are no longer supported. Additionally, each new version introduces enhancements and additional capabilities that can significantly improve performance and scalability.
Upgradation also addresses vulnerabilities identified in older versions, reducing the risk of exploits and ensuring compliance with modern security standards. Furthermore, newer versions often bring optimization improvements, making the system more efficient, reliable, and prepared to handle increased workloads or complex operations.
Staying up to date is essential for maintaining compatibility with modern tools, libraries, and integrations, ensuring the system remains robust and future-ready.
For our system, we are using CakePHP, a PHP framework that has served us well over the years. However, as technology evolves, upgrading becomes inevitable. Initially, we planned to upgrade from CakePHP 2 to a newer version. However, after thorough research and team discussions, we decided to explore migrating to Laravel, which is the most popular php framework.
While this is out of scope for this article. But to just give gist around it. Laravel stands out because of its robust capabilities, a large and thriving community, and an extensive market skill set. One of the most compelling reasons for considering Laravel is its frequent releases and consistent community support. Unlike CakePHP, which has slower release cycles and a relatively limited community, Laravel’s ecosystem provides the latest features, better documentation, and long-term support that align with modern software development needs.
While both CakePHP and Laravel are PHP frameworks, they differ significantly in terms of architecture, configurations, session management, folder structures, and much more. Migrating from CakePHP to Laravel isn’t just about rewriting code; it involves rethinking the way the entire system functions.
One of the biggest challenges is the scale of our product, Bizom, a feature-rich platform serving over 600+ clients. With new customers going live every month, fulfilling customer requirements, and enhancing the product, we have a large and continuous development pipeline. A complete migration before launching would not only be a monumental task but would also disrupt ongoing development and operations.
However, in engineering, the word “impossible” simply does not exist. So, how do we achieve this migration? The solution lies in a phased approach—module-based migration.
To execute a module-based migration, we needed to run CakePHP and Laravel frameworks in parallel. This posed two major technical challenges:
To address these challenges, we first analyzed how system processes requests:
We considered two solutions to run CakePHP and Laravel simultaneously:
We opted for the second solution—routing requests at the front controller level. This allows us to run both frameworks in parallel without impacting performance.
Here’s pseudo code for how we implemented the logic in front-controller to serve requests efficiently:
// Load configuration for Laravel integration
configData = parseJson(readFile(“laravelConfigurations.json”))
laravelAdapter = new LaravelAdapter(configData)
global.adapter = laravelAdapter
requestUri = getRequestUri()
if (global.adapter.isLaravelModule(requestUri)) {
// Delegate to Laravel module entry-point
entryPoint = buildPath(“../path_to_laravel”)
include(entryPoint)
} else {
// Proceed with custom or legacy app handling
handleCustomApp()
}
This is how we make a decision about which framework will serve the request based on the api path. To facilitate this, we created a JSON file called laravelConfiguration.json. This file specifies which apis have been migrated to Laravel. Below is the JSON structure:
{
“enable”: true,
“routes”: {
“SampleController”: {
“SampleAction”: false
},
“api_path/”: true,
},
“session”: {
“csrfTokenName”: “_token”
}
}
If you look at the JSON, api_path it is under a feature flag. In the configuration, certain modules can be selectively enabled or disabled. If a module is marked as enabled, it will be handled by one system; otherwise, it defaults to being handled by another. This allows for flexible routing between systems based on module-level settings.
In summary, the router checks whether the module is enabled in the configuration. If it is, the request is redirected to laravel framework. Otherwise, it continues to be served by CakePHP.