Adopting and shifting to Laravel with an existing platform and production workload
At SportsRecruits, we decided to switch from Codeigniter to Laravel to take advantage of modern Object oriented PHP techniques.
The shift would require learning the new framework and switching a production work-load to it.
The biggest challenge however, was orchestrating the switch to the new framework in a way that breaks it up into small releasable projects, so that we wouldn’t have to do it all at once.
The approach consisted of shifting to a Laravel based API and migrating business logic to it on a feature-by-feature basis (school search, messaging, activity feed, etc…). We also added data processing that would benefit from being performed in queues, and asynchronously.
Things that got us excited about Laravel
- Laravel fully leveraged the newest capabilities of PHP7
- The eloquent ORM would allow us to stop writing raw SQL queries directly into the codebase and also protect against n+1 situations through the use of eager loading.
- Asynchronous, non blocking coding powered by Queues, which come baked into both Jobs and Events.
- Integration with testing tools for everything from unit, to integration to database.
- A growing community of open source tools and plug-ins that make it feel like we have a much larger team in house, actively developing tools that make the team more efficient (and incentivize us to stay up to date with the framework)
Doing a complete re-write from scratch would have been too time consuming and also too risky. It was also against our team’s principle of releasing things in small batches.
We decided to leverage Laravel to build a REST API and start building new features as SPAs consuming the new API. This would allow us to focus on new features or features we were redesigning or improving. The cost was having to maintain business logic across two repos, which we mitigated by decoupling logic and compartmentalizing.
The timeline looked something like this:
- Build API middleware to handle authentication compatible with our old system
- Integrate API calls into new JS framework within old Codeigniter code base.
- Build only the models and business logic needed for new (or redesigned) features
- Refactor remaining features as JS+API
- Remove all legacy code from old codebase with mostly just the front-end javascript app rendering remaining
- Transition front-end to a Laravel app and completely phase out old code base
Favorite patterns and tools we’ve leveraged
- Eloquent ORM Query builders vs relationships Deciding wether to do work in SQL or PHP is critical for when you return a query builder result. You can easily leverage how you call relationships when you realize that a User model’s relationship can be used in two ways:
// returns a query builder for the related Post model,
// which you can chain other methods onto before getting results
return User::first()->posts();
// returns the collection of results resulting from the query
// performed by the defined relationship
return User::first()->posts;
2. Collections
Collections are jam-packed with out of the box capabilities and can also be extended using macros within the AppServiceProvider.
3. Asynchronous queues
Laravel supports an awesome system for processing jobs asynchronously. It works with Beanstalkd, SQS, MySQL and Redis. Although the default driver on local environments is sync (process immediately and synchronously), I’ve found that the database driver allows you to see the job and it’s serialized format in the database and process it on demand a queue worker would using the Artisan CLI.
2. Dependency Injection
Laravel allows you to type hint a class or even an interface in a constructor definition, and will automatically inject an instance of the needed dependency, as long as you’ve defined how to resolve that class in the service provider like so:
$this->app->bind(’Notifier’, function ($app) {
return new Notifier($app->make(‘HttpClient’));
});
// you can even conditionally resolve dependency according to class name
$this->app->when(Notifier::class)
->needs(DriverContract::class)
->give(function () {
return new Driver;
});
Services
1. Forge was a huge help in the beginning managing deployments, environment variables, Laravel configuration and queue workers. Really crucial for getting started with Laravel in a production environment because you are using a Laravel-specific (created by founder of the framework, Taylor Otwell) deployment and server management product.
2. Tinkerwell brings the power of the Tinker CLI tool into its own app, allowing you to easily debug code or test new framework features
3. Laravel shift is a hugely valuable service that automatically updates your codebase from one Laravel version to the next. It applies changes to your codebase through a PR after you allow it access to your repository.
4. Spatie make tons of high quality open sources packages that integrate well with the framework.